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

📄 write.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	while (!list_empty(&list)) {		data = list_entry(list.next, struct nfs_write_data, pages);		list_del(&data->pages);		nfs_writedata_free(data);	}	nfs_mark_request_dirty(req);	nfs_unlock_request(req);	return -ENOMEM;}/* * 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 int nfs_flush_one(struct list_head *head, struct inode *inode, int how){	struct nfs_page		*req;	struct page		**pages;	struct nfs_write_data	*data;	unsigned int		count;	if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE)		return nfs_flush_multi(head, inode, how);	data = nfs_writedata_alloc();	if (!data)		goto out_bad;	pages = data->pagevec;	count = 0;	while (!list_empty(head)) {		req = nfs_list_entry(head->next);		nfs_list_remove_request(req);		nfs_list_add_request(req, &data->pages);		ClearPageError(req->wb_page);		SetPageWriteback(req->wb_page);		*pages++ = req->wb_page;		count += req->wb_bytes;	}	req = nfs_list_entry(data->pages.next);	data->complete = nfs_writeback_done_full;	/* Set up the argument struct */	nfs_write_rpcsetup(req, data, count, 0, how);	nfs_execute_write(data);	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;}intnfs_flush_list(struct list_head *head, int wpages, int how){	LIST_HEAD(one_request);	struct nfs_page		*req;	int			error = 0;	unsigned int		pages = 0;	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_context->dentry->d_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;}/* * Handle a write reply that flushed part of a page. */static void nfs_writeback_done_partial(struct nfs_write_data *data, int status){	struct nfs_page		*req = data->req;	struct page		*page = req->wb_page;	dprintk("NFS: write (%s/%Ld %d@%Ld)",		req->wb_context->dentry->d_inode->i_sb->s_id,		(long long)NFS_FILEID(req->wb_context->dentry->d_inode),		req->wb_bytes,		(long long)req_offset(req));	if (status < 0) {		ClearPageUptodate(page);		SetPageError(page);		req->wb_context->error = status;		dprintk(", error = %d\n", status);	} else {#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)		if (data->verf.committed < NFS_FILE_SYNC) {			if (!NFS_NEED_COMMIT(req)) {				nfs_defer_commit(req);				memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));				dprintk(" defer commit\n");			} else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) {				nfs_defer_reschedule(req);				dprintk(" server reboot detected\n");			}		} else#endif			dprintk(" OK\n");	}	if (atomic_dec_and_test(&req->wb_complete))		nfs_writepage_release(req);}/* * Handle a write reply that flushes a whole page. * * 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. */static void nfs_writeback_done_full(struct nfs_write_data *data, int status){	struct nfs_page		*req;	struct page		*page;	/* Update attributes as result of writeback. */	while (!list_empty(&data->pages)) {		req = nfs_list_entry(data->pages.next);		nfs_list_remove_request(req);		page = req->wb_page;		dprintk("NFS: write (%s/%Ld %d@%Ld)",			req->wb_context->dentry->d_inode->i_sb->s_id,			(long long)NFS_FILEID(req->wb_context->dentry->d_inode),			req->wb_bytes,			(long long)req_offset(req));		if (status < 0) {			ClearPageUptodate(page);			SetPageError(page);			req->wb_context->error = status;			end_page_writeback(page);			nfs_inode_remove_request(req);			dprintk(", error = %d\n", status);			goto next;		}		end_page_writeback(page);#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)		if (data->args.stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) {			nfs_inode_remove_request(req);			dprintk(" OK\n");			goto next;		}		memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));		nfs_mark_request_commit(req);		dprintk(" marked for commit\n");#else		nfs_inode_remove_request(req);#endif	next:		nfs_unlock_request(req);	}}/* * This function is called when the WRITE call is complete. */void nfs_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;	dprintk("NFS: %4d nfs_writeback_done (status %d)\n",		task->tk_pid, task->tk_status);#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)	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 NFS server %s:"				" (committed = %d) != (stable = %d)\n",				NFS_SERVER(data->inode)->hostname,				resp->verf->committed, argp->stable);			complain = jiffies + 300 * HZ;		}	}#endif	/* Is this a short write? */	if (task->tk_status >= 0 && resp->count < argp->count) {		static unsigned long    complain;		/* Has the server at least made some progress? */		if (resp->count != 0) {			/* Was this an NFSv2 write or an NFSv3 stable write? */			if (resp->verf->committed != NFS_UNSTABLE) {				/* Resend from where the server left off */				argp->offset += resp->count;				argp->pgbase += resp->count;				argp->count -= resp->count;			} else {				/* Resend as a stable write in order to avoid				 * headaches in the case of a server crash.				 */				argp->stable = NFS_FILE_SYNC;			}			rpc_restart_call(task);			return;		}		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 except throw an error. */		task->tk_status = -EIO;	}	/*	 * Process the nfs_page list	 */	data->complete(data, task->tk_status);}#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)static void nfs_commit_release(struct rpc_task *task){	struct nfs_write_data	*wdata = (struct nfs_write_data *)task->tk_calldata;	nfs_commit_free(wdata);}/* * Set up the argument/result storage required for the RPC call. */static void nfs_commit_rpcsetup(struct list_head *head,		struct nfs_write_data *data, int how){	struct rpc_task		*task = &data->task;	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_init(head, &data->pages);	first = nfs_list_entry(data->pages.next);	last = nfs_list_entry(data->pages.prev);	inode = first->wb_context->dentry->d_inode;	/*	 * Determine the offset range of requests in the COMMIT call.	 * We rely on the fact that data->pages is an ordered list...	 */	start = req_offset(first);	end = req_offset(last) + last->wb_bytes;	len = end - start;	/* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */	if (end >= i_size_read(inode) || len < 0 || len > (~((u32)0) >> 1))		len = 0;	data->inode	  = inode;	data->cred	  = first->wb_context->cred;	data->args.fh     = NFS_FH(data->inode);	data->args.offset = start;	data->args.count  = len;	data->res.count   = len;	data->res.fattr   = &data->fattr;	data->res.verf    = &data->verf;		NFS_PROTO(inode)->commit_setup(data, how);	data->task.tk_priority = flush_task_priority(how);	data->task.tk_cookie = (unsigned long)inode;	data->task.tk_calldata = data;	/* Release requests */	data->task.tk_release = nfs_commit_release;		dprintk("NFS: %4d initiated commit call\n", task->tk_pid);}/* * Commit dirty pages */intnfs_commit_list(struct list_head *head, int how){	struct nfs_write_data	*data;	struct nfs_page         *req;	data = nfs_commit_alloc();	if (!data)		goto out_bad;	/* Set up the argument struct */	nfs_commit_rpcsetup(head, data, how);	nfs_execute_write(data);	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 */voidnfs_commit_done(struct rpc_task *task){	struct nfs_write_data	*data = (struct nfs_write_data *)task->tk_calldata;	struct nfs_page		*req;	int res = 0;        dprintk("NFS: %4d nfs_commit_done (status %d)\n",                                task->tk_pid, task->tk_status);	while (!list_empty(&data->pages)) {		req = nfs_list_entry(data->pages.next);		nfs_list_remove_request(req);		dprintk("NFS: commit (%s/%Ld %d@%Ld)",			req->wb_context->dentry->d_inode->i_sb->s_id,			(long long)NFS_FILEID(req->wb_context->dentry->d_inode),			req->wb_bytes,			(long long)req_offset(req));		if (task->tk_status < 0) {			req->wb_context->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);		res++;	}	sub_page_state(nr_unstable,res);}#endifint nfs_flush_inode(struct inode *inode, unsigned long idx_start,		   unsigned int npages, int how){	struct nfs_inode *nfsi = NFS_I(inode);	LIST_HEAD(head);	int			res,				error = 0;	spin_lock(&nfsi->req_lock);	res = nfs_scan_dirty(inode, &head, idx_start, npages);	spin_unlock(&nfsi->req_lock);	if (res)		error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how);	if (error < 0)		return error;	return res;}#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)int nfs_commit_inode(struct inode *inode, unsigned long idx_start,		    unsigned int npages, int how){	struct nfs_inode *nfsi = NFS_I(inode);	LIST_HEAD(head);	int			res,				error = 0;	spin_lock(&nfsi->req_lock);	res = nfs_scan_commit(inode, &head, idx_start, npages);	if (res) {		res += nfs_scan_commit(inode, &head, 0, 0);		spin_unlock(&nfsi->req_lock);		error = nfs_commit_list(&head, how);	} else		spin_unlock(&nfsi->req_lock);	if (error < 0)		return error;	return res;}#endifint nfs_sync_inode(struct inode *inode, unsigned long idx_start,		  unsigned int npages, int how){	int	error,		wait;	wait = how & FLUSH_WAIT;	how &= ~FLUSH_WAIT;	do {		error = 0;		if (wait)			error = nfs_wait_on_requests(inode, idx_start, npages);		if (error == 0)			error = nfs_flush_inode(inode, idx_start, npages, how);#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)		if (error == 0)			error = nfs_commit_inode(inode, idx_start, npages, how);#endif	} while (error > 0);	return error;}int nfs_init_writepagecache(void){	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;	nfs_wdata_mempool = mempool_create(MIN_POOL_WRITE,					   mempool_alloc_slab,					   mempool_free_slab,					   nfs_wdata_cachep);	if (nfs_wdata_mempool == NULL)		return -ENOMEM;	nfs_commit_mempool = mempool_create(MIN_POOL_COMMIT,					   mempool_alloc_slab,					   mempool_free_slab,					   nfs_wdata_cachep);	if (nfs_commit_mempool == NULL)		return -ENOMEM;	return 0;}void nfs_destroy_writepagecache(void){	mempool_destroy(nfs_commit_mempool);	mempool_destroy(nfs_wdata_mempool);	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 + -