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

📄 dir.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/nfs/dir.c * *  Copyright (C) 1992  Rick Sladkey * *  nfs directory handling functions * * 10 Apr 1996	Added silly rename for unlink	--okir * 28 Sep 1996	Improved directory cache --okir * 23 Aug 1997  Claus Heine claus@momo.math.rwth-aachen.de  *              Re-implemented silly rename for unlink, newly implemented *              silly rename for nfs_rename() following the suggestions *              of Olaf Kirch (okir) found in this file. *              Following Linus comments on my original hack, this version *              depends only on the dcache stuff and doesn't touch the inode *              layer (iput() and friends). *  6 Jun 1999	Cache readdir lookups in the page cache. -DaveM */#include <linux/sched.h>#include <linux/errno.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/sunrpc/clnt.h>#include <linux/nfs_fs.h>#include <linux/nfs_mount.h>#include <linux/pagemap.h>#include <linux/smp_lock.h>#define NFS_PARANOIA 1/* #define NFS_DEBUG_VERBOSE 1 */static int nfs_readdir(struct file *, void *, filldir_t);static struct dentry *nfs_lookup(struct inode *, struct dentry *);static int nfs_create(struct inode *, struct dentry *, int);static int nfs_mkdir(struct inode *, struct dentry *, int);static int nfs_rmdir(struct inode *, struct dentry *);static int nfs_unlink(struct inode *, struct dentry *);static int nfs_symlink(struct inode *, struct dentry *, const char *);static int nfs_link(struct dentry *, struct inode *, struct dentry *);static int nfs_mknod(struct inode *, struct dentry *, int, int);static int nfs_rename(struct inode *, struct dentry *,		      struct inode *, struct dentry *);struct file_operations nfs_dir_operations = {	read:		generic_read_dir,	readdir:	nfs_readdir,	open:		nfs_open,	release:	nfs_release,};struct inode_operations nfs_dir_inode_operations = {	create:		nfs_create,	lookup:		nfs_lookup,	link:		nfs_link,	unlink:		nfs_unlink,	symlink:	nfs_symlink,	mkdir:		nfs_mkdir,	rmdir:		nfs_rmdir,	mknod:		nfs_mknod,	rename:		nfs_rename,	permission:	nfs_permission,	revalidate:	nfs_revalidate,	setattr:	nfs_notify_change,};typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);typedef struct {	struct file	*file;	struct page	*page;	unsigned long	page_index;	u32		*ptr;	u64		target;	struct nfs_entry *entry;	decode_dirent_t	decode;	int		plus;	int		error;} nfs_readdir_descriptor_t;/* Now we cache directories properly, by stuffing the dirent * data directly in the page cache. * * Inode invalidation due to refresh etc. takes care of * _everything_, no sloppy entry flushing logic, no extraneous * copying, network direct to page cache, the way it was meant * to be. * * NOTE: Dirent information verification is done always by the *	 page-in of the RPC reply, nowhere else, this simplies *	 things substantially. */staticint nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page){	struct file	*file = desc->file;	struct inode	*inode = file->f_dentry->d_inode;	struct rpc_cred	*cred = nfs_file_cred(file);	void		*buffer = kmap(page);	int		error;	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index); again:	error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer,					  NFS_SERVER(inode)->dtsize, desc->plus);	/* We requested READDIRPLUS, but the server doesn't grok it */	if (desc->plus && error == -ENOTSUPP) {		NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;		desc->plus = 0;		goto again;	}	if (error < 0)		goto error;	SetPageUptodate(page);	kunmap(page);	/* Ensure consistent page alignment of the data.	 * Note: assumes we have exclusive access to this mapping either	 *	 throught inode->i_sem or some other mechanism.	 */	if (page->index == 0)		invalidate_inode_pages(inode);	UnlockPage(page);	return 0; error:	SetPageError(page);	kunmap(page);	UnlockPage(page);	invalidate_inode_pages(inode);	desc->error = error;	return -EIO;}static inlineint dir_decode(nfs_readdir_descriptor_t *desc){	u32	*p = desc->ptr;	p = desc->decode(p, desc->entry, desc->plus);	if (IS_ERR(p))		return PTR_ERR(p);	desc->ptr = p;	return 0;}static inlinevoid dir_page_release(nfs_readdir_descriptor_t *desc){	kunmap(desc->page);	page_cache_release(desc->page);	desc->page = NULL;	desc->ptr = NULL;}/* * Given a pointer to a buffer that has already been filled by a call * to readdir, find the next entry. * * If the end of the buffer has been reached, return -EAGAIN, if not, * return the offset within the buffer of the next entry to be * read. */static inlineint find_dirent(nfs_readdir_descriptor_t *desc, struct page *page){	struct nfs_entry *entry = desc->entry;	int		loop_count = 0,			status;	while((status = dir_decode(desc)) == 0) {		dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie);		if (entry->prev_cookie == desc->target)			break;		if (loop_count++ > 200) {			loop_count = 0;			schedule();		}	}	dfprintk(VFS, "NFS: find_dirent() returns %d\n", status);	return status;}/* * Find the given page, and call find_dirent() in order to try to * return the next entry. */static inlineint find_dirent_page(nfs_readdir_descriptor_t *desc){	struct inode	*inode = desc->file->f_dentry->d_inode;	struct page	*page;	int		status;	dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", desc->page_index);	desc->plus = NFS_USE_READDIRPLUS(inode);	page = read_cache_page(&inode->i_data, desc->page_index,			       (filler_t *)nfs_readdir_filler, desc);	if (IS_ERR(page)) {		status = PTR_ERR(page);		goto out;	}	if (!Page_Uptodate(page))		goto read_error;	/* NOTE: Someone else may have changed the READDIRPLUS flag */	desc->page = page;	desc->ptr = kmap(page);	status = find_dirent(desc, page);	if (status < 0)		dir_page_release(desc); out:	dfprintk(VFS, "NFS: find_dirent_page() returns %d\n", status);	return status; read_error:	page_cache_release(page);	return -EIO;}/* * Recurse through the page cache pages, and return a * filled nfs_entry structure of the next directory entry if possible. * * The target for the search is 'desc->target'. */static inlineint readdir_search_pagecache(nfs_readdir_descriptor_t *desc){	int		loop_count = 0;	int		res;	dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target);	for (;;) {		res = find_dirent_page(desc);		if (res != -EAGAIN)			break;		/* Align to beginning of next page */		desc->page_index ++;		if (loop_count++ > 200) {			loop_count = 0;			schedule();		}	}	dfprintk(VFS, "NFS: readdir_search_pagecache() returned %d\n", res);	return res;}/* * Once we've found the start of the dirent within a page: fill 'er up... */static int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,		   filldir_t filldir){	struct file	*file = desc->file;	struct nfs_entry *entry = desc->entry;	unsigned long	fileid;	int		loop_count = 0,			res;	dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target);	for(;;) {		/* Note: entry->prev_cookie contains the cookie for		 *	 retrieving the current dirent on the server */		fileid = nfs_fileid_to_ino_t(entry->ino);		res = filldir(dirent, entry->name, entry->len, 			      entry->prev_cookie, fileid, DT_UNKNOWN);		if (res < 0)			break;		file->f_pos = desc->target = entry->cookie;		if (dir_decode(desc) != 0) {			desc->page_index ++;			break;		}		if (loop_count++ > 200) {			loop_count = 0;			schedule();		}	}	dir_page_release(desc);	dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res);	return res;}/* * If we cannot find a cookie in our cache, we suspect that this is * because it points to a deleted file, so we ask the server to return * whatever it thinks is the next entry. We then feed this to filldir. * If all goes well, we should then be able to find our way round the * cache on the next call to readdir_search_pagecache(); * * NOTE: we cannot add the anonymous page to the pagecache because *	 the data it contains might not be page aligned. Besides, *	 we should already have a complete representation of the *	 directory in the page cache by the time we get here. */static inlineint uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,		     filldir_t filldir){	struct file	*file = desc->file;	struct inode	*inode = file->f_dentry->d_inode;	struct rpc_cred	*cred = nfs_file_cred(file);	struct page	*page = NULL;	int		status;	dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target);	page = alloc_page(GFP_HIGHUSER);	if (!page) {		status = -ENOMEM;		goto out;	}	desc->page = page;	desc->ptr = kmap(page);	desc->error = NFS_PROTO(inode)->readdir(inode, cred, desc->target,						desc->ptr,						NFS_SERVER(inode)->dtsize,						desc->plus);	if (desc->error >= 0) {		if ((status = dir_decode(desc)) == 0)			desc->entry->prev_cookie = desc->target;	} else		status = -EIO;	if (status < 0)		goto out_release;	status = nfs_do_filldir(desc, dirent, filldir);	/* Reset read descriptor so it searches the page cache from	 * the start upon the next call to readdir_search_pagecache() */	desc->page_index = 0;	memset(desc->entry, 0, sizeof(*desc->entry)); out:	dfprintk(VFS, "NFS: uncached_readdir() returns %d\n", status);	return status; out_release:	dir_page_release(desc);	goto out;}/* The file offset position is now represented as a true offset into the * page cache as is the case in most of the other filesystems. */static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir){	struct dentry	*dentry = filp->f_dentry;	struct inode	*inode = dentry->d_inode;	nfs_readdir_descriptor_t my_desc,			*desc = &my_desc;	struct nfs_entry my_entry;	long		res;	res = nfs_revalidate(dentry);	if (res < 0)		return res;	/*	 * filp->f_pos points to the file offset in the page cache.	 * but if the cache has meanwhile been zapped, we need to	 * read from the last dirent to revalidate f_pos	 * itself.	 */	memset(desc, 0, sizeof(*desc));	memset(&my_entry, 0, sizeof(my_entry));	desc->file = filp;	desc->target = filp->f_pos;	desc->entry = &my_entry;	desc->decode = NFS_PROTO(inode)->decode_dirent;	while(!desc->entry->eof) {		res = readdir_search_pagecache(desc);		if (res == -EBADCOOKIE) {			/* This means either end of directory */			if (desc->entry->cookie != desc->target) {				/* Or that the server has 'lost' a cookie */				res = uncached_readdir(desc, dirent, filldir);				if (res >= 0)					continue;			}			res = 0;			break;		} else if (res < 0)			break;		res = nfs_do_filldir(desc, dirent, filldir);		if (res < 0) {			res = 0;			break;		}	}	if (desc->error < 0)		return desc->error;	if (res < 0)		return res;	return 0;}/* * Whenever an NFS operation succeeds, we know that the dentry * is valid, so we update the revalidation timestamp. */static inline void nfs_renew_times(struct dentry * dentry){	dentry->d_time = jiffies;}static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags){	struct inode *inode = dentry->d_inode;	unsigned long timeout = NFS_ATTRTIMEO(inode);	/*	 * If it's the last lookup in a series, we use a stricter	 * cache consistency check by looking at the parent mtime.	 *	 * If it's been modified in the last hour, be really strict.	 * (This still means that we can avoid doing unnecessary	 * work on directories like /usr/share/bin etc which basically	 * never change).	 */	if (!(flags & LOOKUP_CONTINUE)) {		long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;		if (diff < 15*60)			timeout = 0;	}		return time_after(jiffies,dentry->d_time + timeout);}/* * We judge how long we want to trust negative * dentries by looking at the parent inode mtime. * * If mtime is close to present time, we revalidate * more often. */#define NFS_REVALIDATE_NEGATIVE (1 * HZ)static inline int nfs_neg_need_reval(struct dentry *dentry){	struct inode *dir = dentry->d_parent->d_inode;	unsigned long timeout = NFS_ATTRTIMEO(dir);	long diff = CURRENT_TIME - dir->i_mtime;	if (diff < 5*60 && timeout > NFS_REVALIDATE_NEGATIVE)		timeout = NFS_REVALIDATE_NEGATIVE;	return time_after(jiffies, dentry->d_time + timeout);}/* * This is called every time the dcache has a lookup hit, * and we should check whether we can really trust that * lookup. * * NOTE! The hit can be a negative hit too, don't assume * we have an inode! * * If the dentry is older than the revalidation interval,  * we do a new lookup and verify that the dentry is still * correct. */static int nfs_lookup_revalidate(struct dentry * dentry, int flags){	struct inode *dir;	struct inode *inode;	int error;	struct nfs_fh fhandle;	struct nfs_fattr fattr;	lock_kernel();	dir = dentry->d_parent->d_inode;	inode = dentry->d_inode;	/*	 * If we don't have an inode, let's look at the parent	 * directory mtime to get a hint about how often we	 * should validate things..	 */	if (!inode) {		if (nfs_neg_need_reval(dentry))			goto out_bad;		goto out_valid;	}	if (is_bad_inode(inode)) {		dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",			dentry->d_parent->d_name.name, dentry->d_name.name);		goto out_bad;	}	if (!nfs_dentry_force_reval(dentry, flags))		goto out_valid;	if (IS_ROOT(dentry)) {		__nfs_revalidate_inode(NFS_SERVER(inode), inode);		goto out_valid_renew;	}	/*	 * Do a new lookup and check the dentry attributes.	 */	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);	if (error)		goto out_bad;	/* Inode number matches? */	if (!(fattr.valid & NFS_ATTR_FATTR) ||	    NFS_FSID(inode) != fattr.fsid ||	    NFS_FILEID(inode) != fattr.fileid)		goto out_bad;	/* Ok, remember that we successfully checked it.. */	nfs_refresh_inode(inode, &fattr);	if (nfs_inode_is_stale(inode, &fhandle, &fattr))		goto out_bad; out_valid_renew:	nfs_renew_times(dentry);out_valid:	unlock_kernel();	return 1;out_bad:	shrink_dcache_parent(dentry);	/* If we have submounts, don't unhash ! */	if (have_submounts(dentry))		goto out_valid;	d_drop(dentry);	/* Purge readdir caches. */	nfs_zap_caches(dir);	if (inode && S_ISDIR(inode->i_mode))		nfs_zap_caches(inode);	unlock_kernel();	return 0;}/* * This is called from dput() when d_count is going to 0. */static int nfs_dentry_delete(struct dentry *dentry){	dfprintk(VFS, "NFS: dentry_delete(%s/%s, %x)\n",		dentry->d_parent->d_name.name, dentry->d_name.name,		dentry->d_flags);	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {		/* Unhash it, so that ->d_iput() would be called */		return 1;	}	return 0;}

⌨️ 快捷键说明

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