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

📄 write.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/fs/nfs/write.c * * Writing file data over NFS. * * We do it like this: When a (user) process wishes to write data to an * NFS file, a write request is allocated that contains the RPC task data * plus some info on the page to be written, and added to the inode's * write chain. If the process writes past the end of the page, an async * RPC call to write the page is scheduled immediately; otherwise, the call * is delayed for a few seconds. * * Just like readahead, no async I/O is performed if wsize < PAGE_SIZE. * * Write requests are kept on the inode's writeback list. Each entry in * that list references the page (portion) to be written. When the * cache timeout has expired, the RPC task is woken up, and tries to * lock the page. As soon as it manages to do so, the request is moved * from the writeback list to the writelock list. * * Note: we must make sure never to confuse the inode passed in the * write_page request with the one in page->inode. As far as I understand * it, these are different when doing a swap-out. * * To understand everything that goes on here and in the NFS read code, * one should be aware that a page is locked in exactly one of the following * cases: * *  -	A write request is in progress. *  -	A user process is in generic_file_write/nfs_update_page *  -	A user process is in generic_file_read * * Also note that because of the way pages are invalidated in * nfs_revalidate_inode, the following assertions hold: * *  -	If a page is dirty, there will be no read requests (a page will *	not be re-read unless invalidated by nfs_revalidate_inode). *  -	If the page is not uptodate, there will be no pending write *	requests, and no process will be in nfs_update_page. * * FIXME: Interaction with the vmscan routines is not optimal yet. * Either vmscan must be made nfs-savvy, or we need a different page * reclaim concept that supports something like FS-independent * buffer_heads with a b_ops-> field. * * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> */#include <linux/config.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/swap.h>#include <linux/pagemap.h>#include <linux/file.h>#include <linux/sunrpc/clnt.h>#include <linux/nfs_fs.h>#include <linux/nfs_mount.h>#include <linux/nfs_flushd.h>#include <linux/nfs_page.h>#include <asm/uaccess.h>#include <linux/smp_lock.h>#define NFSDBG_FACILITY		NFSDBG_PAGECACHE/* * Local structures * * This is the struct where the WRITE/COMMIT arguments go. */struct nfs_write_data {	struct rpc_task		task;	struct inode		*inode;	struct rpc_cred		*cred;	struct nfs_writeargs	args;		/* argument struct */	struct nfs_writeres	res;		/* result struct */	struct nfs_fattr	fattr;	struct nfs_writeverf	verf;	struct list_head	pages;		/* Coalesced requests we wish to flush */};/* * Local function declarations */static struct nfs_page * nfs_update_request(struct file*, struct inode *,					    struct page *,					    unsigned int, unsigned int);static void	nfs_strategy(struct inode *inode);static void	nfs_writeback_done(struct rpc_task *);#ifdef CONFIG_NFS_V3static void	nfs_commit_done(struct rpc_task *);#endif/* Hack for future NFS swap support */#ifndef IS_SWAPFILE# define IS_SWAPFILE(inode)	(0)#endifstatic kmem_cache_t *nfs_wdata_cachep;static __inline__ struct nfs_write_data *nfs_writedata_alloc(void){	struct nfs_write_data	*p;	p = kmem_cache_alloc(nfs_wdata_cachep, SLAB_NOFS);	if (p) {		memset(p, 0, sizeof(*p));		INIT_LIST_HEAD(&p->pages);	}	return p;}static __inline__ void nfs_writedata_free(struct nfs_write_data *p){	kmem_cache_free(nfs_wdata_cachep, p);}static void nfs_writedata_release(struct rpc_task *task){	struct nfs_write_data	*wdata = (struct nfs_write_data *)task->tk_calldata;	nfs_writedata_free(wdata);}/* * This function will be used to simulate weak cache consistency * under NFSv2 when the NFSv3 attribute patch is included. * For the moment, we just call nfs_refresh_inode(). */static __inline__ intnfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr){	if ((fattr->valid & NFS_ATTR_FATTR) && !(fattr->valid & NFS_ATTR_WCC)) {		fattr->pre_size  = NFS_CACHE_ISIZE(inode);		fattr->pre_mtime = NFS_CACHE_MTIME(inode);		fattr->pre_ctime = NFS_CACHE_CTIME(inode);		fattr->valid |= NFS_ATTR_WCC;	}	return nfs_refresh_inode(inode, fattr);}/* * Write a page synchronously. * Offset is the data offset within the page. */static intnfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,		   unsigned int offset, unsigned int count){	struct rpc_cred	*cred = NULL;	loff_t		base;	unsigned int	wsize = NFS_SERVER(inode)->wsize;	int		result, refresh = 0, written = 0, flags;	u8		*buffer;	struct nfs_fattr fattr;	struct nfs_writeverf verf;	if (file)		cred = get_rpccred(nfs_file_cred(file));	if (!cred)		cred = get_rpccred(NFS_I(inode)->mm_cred);	dprintk("NFS:      nfs_writepage_sync(%x/%Ld %d@%Ld)\n",		inode->i_dev, (long long)NFS_FILEID(inode),		count, (long long)(page_offset(page) + offset));	buffer = kmap(page) + offset;	base = page_offset(page) + offset;	flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;	do {		if (count < wsize && !IS_SWAPFILE(inode))			wsize = count;		result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,						 base, wsize, buffer, &verf);		nfs_write_attributes(inode, &fattr);		if (result < 0) {			/* Must mark the page invalid after I/O error */			ClearPageUptodate(page);			goto io_error;		}		if (result != wsize)			printk("NFS: short write, wsize=%u, result=%d\n",			wsize, result);		refresh = 1;		buffer  += wsize;	        base    += wsize;		written += wsize;		count   -= wsize;		/*		 * If we've extended the file, update the inode		 * now so we don't invalidate the cache.		 */		if (base > inode->i_size)			inode->i_size = base;	} while (count);	if (PageError(page))		ClearPageError(page);io_error:	kunmap(page);	if (cred)		put_rpccred(cred);	return written? written : result;}static intnfs_writepage_async(struct file *file, struct inode *inode, struct page *page,		    unsigned int offset, unsigned int count){	struct nfs_page	*req;	loff_t		end;	int		status;	req = nfs_update_request(file, inode, page, offset, count);	status = (IS_ERR(req)) ? PTR_ERR(req) : 0;	if (status < 0)		goto out;	if (!req->wb_cred)		req->wb_cred = get_rpccred(NFS_I(inode)->mm_cred);	nfs_unlock_request(req);	nfs_strategy(inode);	end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count);	if (inode->i_size < end)		inode->i_size = end; out:	return status;}/* * Write an mmapped page to the server. */intnfs_writepage(struct page *page){	struct inode *inode;	unsigned long end_index;	unsigned offset = PAGE_CACHE_SIZE;	int err;	struct address_space *mapping = page->mapping;	if (!mapping)		BUG();	inode = mapping->host;	if (!inode)		BUG();	end_index = inode->i_size >> PAGE_CACHE_SHIFT;	/* Ensure we've flushed out any previous writes */	nfs_wb_page(inode,page);	/* easy case */	if (page->index < end_index)		goto do_it;	/* things got complicated... */	offset = inode->i_size & (PAGE_CACHE_SIZE-1);	/* OK, are we completely out? */	err = -EIO;	if (page->index >= end_index+1 || !offset)		goto out;do_it:	lock_kernel();	if (NFS_SERVER(inode)->wsize >= PAGE_CACHE_SIZE && !IS_SYNC(inode)) {		err = nfs_writepage_async(NULL, inode, page, 0, offset);		if (err >= 0)			err = 0;	} else {		err = nfs_writepage_sync(NULL, inode, page, 0, offset); 		if (err == offset)			err = 0;	}	unlock_kernel();out:	UnlockPage(page);	return err; }/* * Check whether the file range we want to write to is locked by * us. */static intregion_locked(struct inode *inode, struct nfs_page *req){	struct file_lock	*fl;	loff_t			rqstart, rqend;	/* Don't optimize writes if we don't use NLM */	if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)		return 0;	rqstart = page_offset(req->wb_page) + req->wb_offset;	rqend = rqstart + req->wb_bytes;	for (fl = inode->i_flock; fl; fl = fl->fl_next) {		if (fl->fl_owner == current->files && (fl->fl_flags & FL_POSIX)		    && fl->fl_type == F_WRLCK		    && fl->fl_start <= rqstart && rqend <= fl->fl_end) {			return 1;		}	}	return 0;}/* * Insert a write request into an inode * Note: we sort the list in order to be able to optimize nfs_find_request() *	 & co. for the 'write append' case. For 2.5 we may want to consider *	 some form of hashing so as to perform well on random writes. */static inline voidnfs_inode_add_request(struct inode *inode, struct nfs_page *req){	struct list_head *pos, *head;	unsigned long pg_idx = page_index(req->wb_page);	if (!list_empty(&req->wb_hash))		return;	if (!NFS_WBACK_BUSY(req))		printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");	head = &inode->u.nfs_i.writeback;	if (list_empty(head))		igrab(inode);	list_for_each_prev(pos, head) {		struct nfs_page *entry = nfs_inode_wb_entry(pos);		if (page_index(entry->wb_page) < pg_idx)			break;	}	inode->u.nfs_i.npages++;	list_add(&req->wb_hash, pos);	req->wb_count++;}/* * Insert a write request into an inode */static inline voidnfs_inode_remove_request(struct nfs_page *req){	struct inode *inode;	spin_lock(&nfs_wreq_lock);	if (list_empty(&req->wb_hash)) {		spin_unlock(&nfs_wreq_lock);		return;	}	if (!NFS_WBACK_BUSY(req))		printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");	inode = req->wb_inode;	list_del(&req->wb_hash);	INIT_LIST_HEAD(&req->wb_hash);	inode->u.nfs_i.npages--;	if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))		printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");	if (list_empty(&inode->u.nfs_i.writeback)) {		spin_unlock(&nfs_wreq_lock);		iput(inode);	} else		spin_unlock(&nfs_wreq_lock);	nfs_release_request(req);}/* * Find a request */static inline struct nfs_page *_nfs_find_request(struct inode *inode, struct page *page){	struct list_head	*head, *pos;	unsigned long pg_idx = page_index(page);	head = &inode->u.nfs_i.writeback;	list_for_each_prev(pos, head) {		struct nfs_page *req = nfs_inode_wb_entry(pos);		unsigned long found_idx = page_index(req->wb_page);		if (pg_idx < found_idx)			continue;		if (pg_idx != found_idx)			break;		req->wb_count++;		return req;	}	return NULL;}static struct nfs_page *nfs_find_request(struct inode *inode, struct page *page){	struct nfs_page		*req;	spin_lock(&nfs_wreq_lock);	req = _nfs_find_request(inode, page);	spin_unlock(&nfs_wreq_lock);	return req;}/* * Add a request to the inode's dirty list. */static inline voidnfs_mark_request_dirty(struct nfs_page *req){	struct inode *inode = req->wb_inode;	spin_lock(&nfs_wreq_lock);	nfs_list_add_request(req, &inode->u.nfs_i.dirty);	inode->u.nfs_i.ndirty++;	__nfs_del_lru(req);	__nfs_add_lru(&NFS_SERVER(inode)->lru_dirty, req);	spin_unlock(&nfs_wreq_lock);	mark_inode_dirty(inode);}/* * Check if a request is dirty */static inline intnfs_dirty_request(struct nfs_page *req){	struct inode *inode = req->wb_inode;	return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;}#ifdef CONFIG_NFS_V3/* * Add a request to the inode's commit list. */static inline voidnfs_mark_request_commit(struct nfs_page *req){	struct inode *inode = req->wb_inode;	spin_lock(&nfs_wreq_lock);	nfs_list_add_request(req, &inode->u.nfs_i.commit);	inode->u.nfs_i.ncommit++;	__nfs_del_lru(req);	__nfs_add_lru(&NFS_SERVER(inode)->lru_commit, req);	spin_unlock(&nfs_wreq_lock);

⌨️ 快捷键说明

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