⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 write.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
	status = 0;	if (synchronous) {		int error;		error = nfs_sync_file(inode, file, page_index(page), 1, FLUSH_SYNC|FLUSH_STABLE);		if (error < 0 || (error = file->f_error) < 0)			status = error;		file->f_error = 0;	} else {		/* If we wrote past the end of the page.		 * Call the strategy routine so it can send out a bunch		 * of requests.		 */		if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE)			nfs_strategy(inode);	}	nfs_release_request(req);done:        dprintk("NFS:      nfs_updatepage returns %d (isize %Ld)\n",                                                status, (long long)inode->i_size);	if (status < 0)		ClearPageUptodate(page);	return status;}/* * Set up the argument/result storage required for the RPC call. */static voidnfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data){	struct nfs_page		*req;	struct iovec		*iov;	unsigned int		count;	/* Set up the RPC argument and reply structs	 * NB: take care not to mess about with data->commit et al. */	iov = data->args.iov;	count = 0;	while (!list_empty(head)) {		struct nfs_page *req = nfs_list_entry(head->next);		nfs_list_remove_request(req);		nfs_list_add_request(req, &data->pages);		iov->iov_base = kmap(req->wb_page) + req->wb_offset;		iov->iov_len = req->wb_bytes;		count += req->wb_bytes;		iov++;		data->args.nriov++;	}	req = nfs_list_entry(data->pages.next);	data->inode = req->wb_inode;	data->cred = req->wb_cred;	data->args.fh     = NFS_FH(req->wb_inode);	data->args.offset = page_offset(req->wb_page) + req->wb_offset;	data->args.count  = count;	data->res.fattr   = &data->fattr;	data->res.count   = count;	data->res.verf    = &data->verf;}/* * Create an RPC task for the given write request and kick it. * The page must have been locked by the caller. * * It may happen that the page we're passed is not marked dirty. * This is the case if nfs_updatepage detects a conflicting request * that has been written but not committed. */static intnfs_flush_one(struct list_head *head, struct inode *inode, int how){	struct rpc_clnt 	*clnt = NFS_CLIENT(inode);	struct nfs_write_data	*data;	struct rpc_task		*task;	struct rpc_message	msg;	int                     flags,				async = !(how & FLUSH_SYNC),				stable = (how & FLUSH_STABLE);	sigset_t		oldset;	data = nfs_writedata_alloc();	if (!data)		goto out_bad;	task = &data->task;	/* Set the initial flags for the task.  */	flags = (async) ? RPC_TASK_ASYNC : 0;	/* Set up the argument struct */	nfs_write_rpcsetup(head, data);	if (stable) {		if (!inode->u.nfs_i.ncommit)			data->args.stable = NFS_FILE_SYNC;		else			data->args.stable = NFS_DATA_SYNC;	} else		data->args.stable = NFS_UNSTABLE;	/* Finalize the task. */	rpc_init_task(task, clnt, nfs_writeback_done, flags);	task->tk_calldata = data;	/* Release requests */	task->tk_release = nfs_writedata_release;#ifdef CONFIG_NFS_V3	msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE;#else	msg.rpc_proc = NFSPROC_WRITE;#endif	msg.rpc_argp = &data->args;	msg.rpc_resp = &data->res;	msg.rpc_cred = data->cred;	dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",		task->tk_pid, 		inode->i_dev,		(long long)NFS_FILEID(inode),		data->args.count, data->args.nriov);	rpc_clnt_sigmask(clnt, &oldset);	rpc_call_setup(task, &msg, 0);	rpc_execute(task);	rpc_clnt_sigunmask(clnt, &oldset);	return 0; out_bad:	while (!list_empty(head)) {		struct nfs_page *req = nfs_list_entry(head->next);		nfs_list_remove_request(req);		nfs_mark_request_dirty(req);		nfs_unlock_request(req);	}	return -ENOMEM;}static intnfs_flush_list(struct inode *inode, struct list_head *head, int how){	LIST_HEAD(one_request);	struct nfs_page		*req;	int			error = 0;	unsigned int		pages = 0,				wpages = NFS_SERVER(inode)->wpages;	while (!list_empty(head)) {		pages += nfs_coalesce_requests(head, &one_request, wpages);		req = nfs_list_entry(one_request.next);		error = nfs_flush_one(&one_request, req->wb_inode, how);		if (error < 0)			break;	}	if (error >= 0)		return pages;	while (!list_empty(head)) {		req = nfs_list_entry(head->next);		nfs_list_remove_request(req);		nfs_mark_request_dirty(req);		nfs_unlock_request(req);	}	return error;}/* * This function is called when the WRITE call is complete. */static voidnfs_writeback_done(struct rpc_task *task){	struct nfs_write_data	*data = (struct nfs_write_data *) task->tk_calldata;	struct nfs_writeargs	*argp = &data->args;	struct nfs_writeres	*resp = &data->res;	struct inode		*inode = data->inode;	struct nfs_page		*req;	struct page		*page;	dprintk("NFS: %4d nfs_writeback_done (status %d)\n",		task->tk_pid, task->tk_status);	/* We can't handle that yet but we check for it nevertheless */	if (resp->count < argp->count && task->tk_status >= 0) {		static unsigned long    complain;		if (time_before(complain, jiffies)) {			printk(KERN_WARNING			       "NFS: Server wrote less than requested.\n");			complain = jiffies + 300 * HZ;		}		/* Can't do anything about it right now except throw		 * an error. */		task->tk_status = -EIO;	}#ifdef CONFIG_NFS_V3	if (resp->verf->committed < argp->stable && task->tk_status >= 0) {		/* We tried a write call, but the server did not		 * commit data to stable storage even though we		 * requested it.		 * Note: There is a known bug in Tru64 < 5.0 in which		 *	 the server reports NFS_DATA_SYNC, but performs		 *	 NFS_FILE_SYNC. We therefore implement this checking		 *	 as a dprintk() in order to avoid filling syslog.		 */		static unsigned long    complain;		if (time_before(complain, jiffies)) {			dprintk("NFS: faulty NFSv3 server %s:"				" (committed = %d) != (stable = %d)\n",				NFS_SERVER(inode)->hostname,				resp->verf->committed, argp->stable);			complain = jiffies + 300 * HZ;		}	}#endif	/*	 * Update attributes as result of writeback.	 * FIXME: There is an inherent race with invalidate_inode_pages and	 *	  writebacks since the page->count is kept > 1 for as long	 *	  as the page has a write request pending.	 */	nfs_write_attributes(inode, resp->fattr);	while (!list_empty(&data->pages)) {		req = nfs_list_entry(data->pages.next);		nfs_list_remove_request(req);		page = req->wb_page;		kunmap(page);		dprintk("NFS: write (%x/%Ld %d@%Ld)",			req->wb_inode->i_dev,			(long long)NFS_FILEID(req->wb_inode),			req->wb_bytes,			(long long)(page_offset(page) + req->wb_offset));		if (task->tk_status < 0) {			ClearPageUptodate(page);			SetPageError(page);			if (req->wb_file)				req->wb_file->f_error = task->tk_status;			nfs_inode_remove_request(req);			dprintk(", error = %d\n", task->tk_status);			goto next;		}#ifdef CONFIG_NFS_V3		if (resp->verf->committed != NFS_UNSTABLE) {			nfs_inode_remove_request(req);			dprintk(" OK\n");			goto next;		}		memcpy(&req->wb_verf, resp->verf, sizeof(req->wb_verf));		req->wb_timeout = jiffies + NFS_COMMIT_DELAY;		nfs_mark_request_commit(req);		dprintk(" marked for commit\n");#else		nfs_inode_remove_request(req);#endif	next:		nfs_unlock_request(req);	}}#ifdef CONFIG_NFS_V3/* * Set up the argument/result storage required for the RPC call. */static voidnfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data){	struct nfs_page		*first, *last;	struct inode		*inode;	loff_t			start, end, len;	/* Set up the RPC argument and reply structs	 * NB: take care not to mess about with data->commit et al. */	list_splice(head, &data->pages);	INIT_LIST_HEAD(head);	first = nfs_list_entry(data->pages.next);	last = nfs_list_entry(data->pages.prev);	inode = first->wb_inode;	/*	 * Determine the offset range of requests in the COMMIT call.	 * We rely on the fact that data->pages is an ordered list...	 */	start = page_offset(first->wb_page) + first->wb_offset;	end = page_offset(last->wb_page) + (last->wb_offset + last->wb_bytes);	len = end - start;	/* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */	if (end >= inode->i_size || len < 0 || len > (~((u32)0) >> 1))		len = 0;	data->inode	  = inode;	data->cred	  = first->wb_cred;	data->args.fh     = NFS_FH(inode);	data->args.offset = start;	data->res.count   = data->args.count = (u32)len;	data->res.fattr   = &data->fattr;	data->res.verf    = &data->verf;}/* * Commit dirty pages */static intnfs_commit_list(struct list_head *head, int how){	struct rpc_message	msg;	struct rpc_clnt		*clnt;	struct nfs_write_data	*data;	struct rpc_task         *task;	struct nfs_page         *req;	int                     flags,				async = !(how & FLUSH_SYNC);	sigset_t		oldset;	data = nfs_writedata_alloc();	if (!data)		goto out_bad;	task = &data->task;	flags = (async) ? RPC_TASK_ASYNC : 0;	/* Set up the argument struct */	nfs_commit_rpcsetup(head, data);	req = nfs_list_entry(data->pages.next);	clnt = NFS_CLIENT(req->wb_inode);	rpc_init_task(task, clnt, nfs_commit_done, flags);	task->tk_calldata = data;	/* Release requests */	task->tk_release = nfs_writedata_release;	msg.rpc_proc = NFS3PROC_COMMIT;	msg.rpc_argp = &data->args;	msg.rpc_resp = &data->res;	msg.rpc_cred = data->cred;	dprintk("NFS: %4d initiated commit call\n", task->tk_pid);	rpc_clnt_sigmask(clnt, &oldset);	rpc_call_setup(task, &msg, 0);	rpc_execute(task);	rpc_clnt_sigunmask(clnt, &oldset);	return 0; out_bad:	while (!list_empty(head)) {		req = nfs_list_entry(head->next);		nfs_list_remove_request(req);		nfs_mark_request_commit(req);		nfs_unlock_request(req);	}	return -ENOMEM;}/* * COMMIT call returned */static voidnfs_commit_done(struct rpc_task *task){	struct nfs_write_data	*data = (struct nfs_write_data *)task->tk_calldata;	struct nfs_writeres	*resp = &data->res;	struct nfs_page		*req;	struct inode		*inode = data->inode;        dprintk("NFS: %4d nfs_commit_done (status %d)\n",                                task->tk_pid, task->tk_status);	nfs_write_attributes(inode, resp->fattr);	while (!list_empty(&data->pages)) {		req = nfs_list_entry(data->pages.next);		nfs_list_remove_request(req);		dprintk("NFS: commit (%x/%Ld %d@%Ld)",			req->wb_inode->i_dev,			(long long)NFS_FILEID(req->wb_inode),			req->wb_bytes,			(long long)(page_offset(req->wb_page) + req->wb_offset));		if (task->tk_status < 0) {			if (req->wb_file)				req->wb_file->f_error = task->tk_status;			nfs_inode_remove_request(req);			dprintk(", error = %d\n", task->tk_status);			goto next;		}		/* Okay, COMMIT succeeded, apparently. Check the verifier		 * returned by the server against all stored verfs. */		if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) {			/* We have a match */			nfs_inode_remove_request(req);			dprintk(" OK\n");			goto next;		}		/* We have a mismatch. Write the page again */		dprintk(" mismatch\n");		nfs_mark_request_dirty(req);	next:		nfs_unlock_request(req);	}}#endifint nfs_flush_file(struct inode *inode, struct file *file, unsigned long idx_start,		   unsigned int npages, int how){	LIST_HEAD(head);	int			res,				error = 0;	res = nfs_scan_dirty(inode, &head, file, idx_start, npages);	if (res)		error = nfs_flush_list(inode, &head, how);	if (error < 0)		return error;	return res;}int nfs_flush_timeout(struct inode *inode, int how){	LIST_HEAD(head);	int			pages,				error = 0;	pages = nfs_scan_dirty_timeout(inode, &head);	if (pages)		error = nfs_flush_list(inode, &head, how);	if (error < 0)		return error;	return pages;}#ifdef CONFIG_NFS_V3int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start,		    unsigned int npages, int how){	LIST_HEAD(head);	int			res,				error = 0;	res = nfs_scan_commit(inode, &head, file, idx_start, npages);	if (res)		error = nfs_commit_list(&head, how);	if (error < 0)		return error;	return res;}int nfs_commit_timeout(struct inode *inode, int how){	LIST_HEAD(head);	int			pages,				error = 0;	pages = nfs_scan_commit_timeout(inode, &head);	if (pages) {		pages += nfs_scan_commit(inode, &head, NULL, 0, 0);		error = nfs_commit_list(&head, how);	}	if (error < 0)		return error;	return pages;}#endifint nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start,		  unsigned int npages, int how){	int	error,		wait;	wait = how & FLUSH_WAIT;	how &= ~FLUSH_WAIT;	if (!inode && file)		inode = file->f_dentry->d_inode;	do {		error = 0;		if (wait)			error = nfs_wait_on_requests(inode, file, idx_start, npages);		if (error == 0)			error = nfs_flush_file(inode, file, idx_start, npages, how);#ifdef CONFIG_NFS_V3		if (error == 0)			error = nfs_commit_file(inode, file, idx_start, npages, how);#endif	} while (error > 0);	return error;}int nfs_init_nfspagecache(void){	nfs_page_cachep = kmem_cache_create("nfs_page",					    sizeof(struct nfs_page),					    0, SLAB_HWCACHE_ALIGN,					    NULL, NULL);	if (nfs_page_cachep == NULL)		return -ENOMEM;	nfs_wdata_cachep = kmem_cache_create("nfs_write_data",					     sizeof(struct nfs_write_data),					     0, SLAB_HWCACHE_ALIGN,					     NULL, NULL);	if (nfs_wdata_cachep == NULL)		return -ENOMEM;	return 0;}void nfs_destroy_nfspagecache(void){	if (kmem_cache_destroy(nfs_page_cachep))		printk(KERN_INFO "nfs_page: not all structures were freed\n");	if (kmem_cache_destroy(nfs_wdata_cachep))		printk(KERN_INFO "nfs_write_data: not all structures were freed\n");}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -