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

📄 write.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 3 页
字号:
	mark_inode_dirty(inode);}#endif/* * Wait for a request to complete. * * Interruptible by signals only if mounted with intr flag. */static intnfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages){	struct list_head	*p, *head;	unsigned long		idx_end;	unsigned int		res = 0;	int			error;	if (npages == 0)		idx_end = ~0;	else		idx_end = idx_start + npages - 1;	head = &inode->u.nfs_i.writeback; restart:	spin_lock(&nfs_wreq_lock);	list_for_each_prev(p, head) {		unsigned long pg_idx;		struct nfs_page *req = nfs_inode_wb_entry(p);		if (file && req->wb_file != file)			continue;		pg_idx = page_index(req->wb_page);		if (pg_idx < idx_start)			break;		if (pg_idx > idx_end)			continue;		if (!NFS_WBACK_BUSY(req))			continue;		req->wb_count++;		spin_unlock(&nfs_wreq_lock);		error = nfs_wait_on_request(req);		nfs_release_request(req);		if (error < 0)			return error;		res++;		goto restart;	}	spin_unlock(&nfs_wreq_lock);	return res;}/** * nfs_scan_lru_dirty_timeout - Scan LRU list for timed out dirty requests * @server: NFS superblock data * @dst: destination list * * Moves a maximum of 'wpages' requests from the NFS dirty page LRU list. * The elements are checked to ensure that they form a contiguous set * of pages, and that they originated from the same file. */intnfs_scan_lru_dirty_timeout(struct nfs_server *server, struct list_head *dst){	struct inode *inode;	int npages;	npages = nfs_scan_lru_timeout(&server->lru_dirty, dst, server->wpages);	if (npages) {		inode = nfs_list_entry(dst->next)->wb_inode;		inode->u.nfs_i.ndirty -= npages;	}	return npages;}/** * nfs_scan_lru_dirty - Scan LRU list for dirty requests * @server: NFS superblock data * @dst: destination list * * Moves a maximum of 'wpages' requests from the NFS dirty page LRU list. * The elements are checked to ensure that they form a contiguous set * of pages, and that they originated from the same file. */intnfs_scan_lru_dirty(struct nfs_server *server, struct list_head *dst){	struct inode *inode;	int npages;	npages = nfs_scan_lru(&server->lru_dirty, dst, server->wpages);	if (npages) {		inode = nfs_list_entry(dst->next)->wb_inode;		inode->u.nfs_i.ndirty -= npages;	}	return npages;}/* * nfs_scan_dirty - Scan an inode for dirty requests * @inode: NFS inode to scan * @dst: destination list * @file: if set, ensure we match requests from this file * @idx_start: lower bound of page->index to scan. * @npages: idx_start + npages sets the upper bound to scan. * * Moves requests from the inode's dirty page list. * The requests are *not* checked to ensure that they form a contiguous set. */static intnfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages){	int	res;	res = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, idx_start, npages);	inode->u.nfs_i.ndirty -= res;	if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty))		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");	return res;}#ifdef CONFIG_NFS_V3/** * nfs_scan_lru_commit_timeout - Scan LRU list for timed out commit requests * @server: NFS superblock data * @dst: destination list * * Finds the first a timed out request in the NFS commit LRU list and moves it * to the list dst. If such an element is found, we move all other commit * requests that apply to the same inode. * The assumption is that doing everything in a single commit-to-disk is * the cheaper alternative. */intnfs_scan_lru_commit_timeout(struct nfs_server *server, struct list_head *dst){	struct inode *inode;	int npages;	npages = nfs_scan_lru_timeout(&server->lru_commit, dst, 1);	if (npages) {		inode = nfs_list_entry(dst->next)->wb_inode;		npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0);		inode->u.nfs_i.ncommit -= npages;	}	return npages;}/** * nfs_scan_lru_commit_timeout - Scan LRU list for timed out commit requests * @server: NFS superblock data * @dst: destination list * * Finds the first request in the NFS commit LRU list and moves it * to the list dst. If such an element is found, we move all other commit * requests that apply to the same inode. * The assumption is that doing everything in a single commit-to-disk is * the cheaper alternative. */intnfs_scan_lru_commit(struct nfs_server *server, struct list_head *dst){	struct inode *inode;	int npages;	npages = nfs_scan_lru(&server->lru_commit, dst, 1);	if (npages) {		inode = nfs_list_entry(dst->next)->wb_inode;		npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0);		inode->u.nfs_i.ncommit -= npages;	}	return npages;}/* * nfs_scan_commit - Scan an inode for commit requests * @inode: NFS inode to scan * @dst: destination list * @file: if set, ensure we collect requests from this file only. * @idx_start: lower bound of page->index to scan. * @npages: idx_start + npages sets the upper bound to scan. * * Moves requests from the inode's 'commit' request list. * The requests are *not* checked to ensure that they form a contiguous set. */static intnfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages){	int	res;	res = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, idx_start, npages);	inode->u.nfs_i.ncommit -= res;	if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit))		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");	return res;}#endif/* * Try to update any existing write request, or create one if there is none. * In order to match, the request's credentials must match those of * the calling process. * * Note: Should always be called with the Page Lock held! */static struct nfs_page *nfs_update_request(struct file* file, struct inode *inode, struct page *page,		   unsigned int offset, unsigned int bytes){	struct nfs_page		*req, *new = NULL;	unsigned long		rqend, end;	end = offset + bytes;	for (;;) {		/* Loop over all inode entries and see if we find		 * A request for the page we wish to update		 */		spin_lock(&nfs_wreq_lock);		req = _nfs_find_request(inode, page);		if (req) {			if (!nfs_lock_request_dontget(req)) {				int error;				spin_unlock(&nfs_wreq_lock);				error = nfs_wait_on_request(req);				nfs_release_request(req);				if (error < 0)					return ERR_PTR(error);				continue;			}			spin_unlock(&nfs_wreq_lock);			if (new)				nfs_release_request(new);			break;		}		if (new) {			nfs_lock_request_dontget(new);			nfs_inode_add_request(inode, new);			spin_unlock(&nfs_wreq_lock);			nfs_mark_request_dirty(new);			return new;		}		spin_unlock(&nfs_wreq_lock);		new = nfs_create_request(file, inode, page, offset, bytes);		if (IS_ERR(new))			return new;		/* If the region is locked, adjust the timeout */		if (region_locked(inode, new))			new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;		else			new->wb_timeout = jiffies + NFS_WRITEBACK_DELAY;	}	/* We have a request for our page.	 * If the creds don't match, or the	 * page addresses don't match,	 * tell the caller to wait on the conflicting	 * request.	 */	rqend = req->wb_offset + req->wb_bytes;	if (req->wb_file != file	    || req->wb_page != page	    || !nfs_dirty_request(req)	    || offset > rqend || end < req->wb_offset) {		nfs_unlock_request(req);		return ERR_PTR(-EBUSY);	}	/* Okay, the request matches. Update the region */	if (offset < req->wb_offset) {		req->wb_offset = offset;		req->wb_bytes = rqend - req->wb_offset;	}	if (end > rqend)		req->wb_bytes = end - req->wb_offset;	return req;}/* * This is the strategy routine for NFS. * It is called by nfs_updatepage whenever the user wrote up to the end * of a page. * * We always try to submit a set of requests in parallel so that the * server's write code can gather writes. This is mainly for the benefit * of NFSv2. * * We never submit more requests than we think the remote can handle. * For UDP sockets, we make sure we don't exceed the congestion window; * for TCP, we limit the number of requests to 8. * * NFS_STRATEGY_PAGES gives the minimum number of requests for NFSv2 that * should be sent out in one go. This is for the benefit of NFSv2 servers * that perform write gathering. * * FIXME: Different servers may have different sweet spots. * Record the average congestion window in server struct? */#define NFS_STRATEGY_PAGES      8static voidnfs_strategy(struct inode *inode){	unsigned int	dirty, wpages;	dirty  = inode->u.nfs_i.ndirty;	wpages = NFS_SERVER(inode)->wpages;#ifdef CONFIG_NFS_V3	if (NFS_PROTO(inode)->version == 2) {		if (dirty >= NFS_STRATEGY_PAGES * wpages)			nfs_flush_file(inode, NULL, 0, 0, 0);	} else if (dirty >= wpages)		nfs_flush_file(inode, NULL, 0, 0, 0);#else	if (dirty >= NFS_STRATEGY_PAGES * wpages)		nfs_flush_file(inode, NULL, 0, 0, 0);#endif}intnfs_flush_incompatible(struct file *file, struct page *page){	struct inode	*inode = file->f_dentry->d_inode;	struct nfs_page	*req;	int		status = 0;	/*	 * Look for a request corresponding to this page. If there	 * is one, and it belongs to another file, we flush it out	 * before we try to copy anything into the page. Do this	 * due to the lack of an ACCESS-type call in NFSv2.	 * Also do the same if we find a request from an existing	 * dropped page.	 */	req = nfs_find_request(inode,page);	if (req) {		if (req->wb_file != file || req->wb_page != page)			status = nfs_wb_page(inode, page);		nfs_release_request(req);	}	return (status < 0) ? status : 0;}/* * Update and possibly write a cached page of an NFS file. * * XXX: Keep an eye on generic_file_read to make sure it doesn't do bad * things with a page scheduled for an RPC call (e.g. invalidate it). */intnfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count){	struct dentry	*dentry = file->f_dentry;	struct inode	*inode = dentry->d_inode;	struct nfs_page	*req;	loff_t		end;	int		status = 0;	dprintk("NFS:      nfs_updatepage(%s/%s %d@%Ld)\n",		dentry->d_parent->d_name.name, dentry->d_name.name,		count, (long long)(page_offset(page) +offset));	/*	 * If wsize is smaller than page size, update and write	 * page synchronously.	 */	if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE || IS_SYNC(inode))		return nfs_writepage_sync(file, inode, page, offset, count);	/*	 * Try to find an NFS request corresponding to this page	 * and update it.	 * If the existing request cannot be updated, we must flush	 * it out now.	 */	do {		req = nfs_update_request(file, inode, page, offset, count);		status = (IS_ERR(req)) ? PTR_ERR(req) : 0;		if (status != -EBUSY)			break;		/* Request could not be updated. Flush it out and try again */		status = nfs_wb_page(inode, page);	} while (status >= 0);	if (status < 0)		goto done;	status = 0;	end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count);	if (inode->i_size < end)		inode->i_size = end;	/* 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) {		SetPageUptodate(page);		nfs_unlock_request(req);		nfs_strategy(inode);	} else		nfs_unlock_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;

⌨️ 快捷键说明

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