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

📄 dir.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (isopen && !(server->flags & NFS_MOUNT_NOCTO))		return __nfs_revalidate_inode(server, inode);	return nfs_revalidate_inode(server, inode);}/* * We judge how long we want to trust negative * dentries by looking at the parent inode mtime. * * If parent mtime has changed, we revalidate, else we wait for a * period corresponding to the parent's attribute cache timeout value. */static inlineint nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,		       struct nameidata *nd){	int ndflags = 0;	if (nd)		ndflags = nd->flags;	/* Don't revalidate a negative dentry if we're creating a new file */	if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE))		return 0;	return !nfs_check_verifier(dir, dentry);}/* * 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 parent directory is seen to have changed, we throw out the * cached dentry and do a new lookup. */static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd){	struct inode *dir;	struct inode *inode;	struct dentry *parent;	int error;	struct nfs_fh fhandle;	struct nfs_fattr fattr;	unsigned long verifier;	int isopen = 0;	parent = dget_parent(dentry);	lock_kernel();	dir = parent->d_inode;	inode = dentry->d_inode;	if (nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_OPEN))		isopen = 1;	if (!inode) {		if (nfs_neg_need_reval(dir, dentry, nd))			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;	}	/* Revalidate parent directory attribute cache */	nfs_revalidate_inode(NFS_SERVER(dir), dir);	/* Force a full look up iff the parent directory has changed */	if (nfs_check_verifier(dir, dentry)) {		if (nfs_lookup_verify_inode(inode, isopen))			goto out_zap_parent;		goto out_valid;	}	/*	 * Note: we're not holding inode->i_sem and so may be racing with	 * operations that change the directory. We therefore save the	 * change attribute *before* we do the RPC call.	 */	verifier = nfs_save_change_attribute(dir);	error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);	if (!error) {		if (nfs_compare_fh(NFS_FH(inode), &fhandle))			goto out_bad;		if (nfs_lookup_verify_inode(inode, isopen))			goto out_zap_parent;		goto out_valid_renew;	}	if (NFS_STALE(inode))		goto out_bad;	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);	if (error)		goto out_bad;	if (nfs_compare_fh(NFS_FH(inode), &fhandle))		goto out_bad;	if ((error = nfs_refresh_inode(inode, &fattr)) != 0)		goto out_bad; out_valid_renew:	nfs_renew_times(dentry);	nfs_set_verifier(dentry, verifier); out_valid:	unlock_kernel();	dput(parent);	return 1;out_zap_parent:	nfs_zap_caches(dir); out_bad:	NFS_CACHEINV(dir);	if (inode && S_ISDIR(inode->i_mode)) {		/* Purge readdir caches. */		nfs_zap_caches(inode);		/* If we have submounts, don't unhash ! */		if (have_submounts(dentry))			goto out_valid;		shrink_dcache_parent(dentry);	}	d_drop(dentry);	unlock_kernel();	dput(parent);	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;	}	if (!(dentry->d_sb->s_flags & MS_ACTIVE)) {		/* Unhash it, so that ancestors of killed async unlink		 * files will be cleaned up during umount */		return 1;	}	return 0;}/* * Called when the dentry loses inode. * We use it to clean up silly-renamed files. */static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode){	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {		lock_kernel();		inode->i_nlink--;		nfs_complete_unlink(dentry);		unlock_kernel();	}	/* When creating a negative dentry, we want to renew d_time */	nfs_renew_times(dentry);	iput(inode);}struct dentry_operations nfs_dentry_operations = {	.d_revalidate	= nfs_lookup_revalidate,	.d_delete	= nfs_dentry_delete,	.d_iput		= nfs_dentry_iput,};static inlineint nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd){	if (NFS_PROTO(dir)->version == 2)		return 0;	if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE))		return 0;	return (nd->intent.open.flags & O_EXCL) != 0;}static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd){	struct inode *inode = NULL;	int error;	struct nfs_fh fhandle;	struct nfs_fattr fattr;	dfprintk(VFS, "NFS: lookup(%s/%s)\n",		dentry->d_parent->d_name.name, dentry->d_name.name);	error = -ENAMETOOLONG;	if (dentry->d_name.len > NFS_SERVER(dir)->namelen)		goto out;	error = -ENOMEM;	dentry->d_op = NFS_PROTO(dir)->dentry_ops;	lock_kernel();	/* Revalidate parent directory attribute cache */	nfs_revalidate_inode(NFS_SERVER(dir), dir);	/* If we're doing an exclusive create, optimize away the lookup */	if (nfs_is_exclusive_create(dir, nd))		goto no_entry;	error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);	if (error != 0) {		error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name,				&fhandle, &fattr);		if (error == -ENOENT)			goto no_entry;		if (error != 0)			goto out_unlock;	}	error = -EACCES;	inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);	if (!inode)		goto out_unlock;no_entry:	error = 0;	d_add(dentry, inode);	nfs_renew_times(dentry);	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));out_unlock:	unlock_kernel();out:	BUG_ON(error > 0);	return ERR_PTR(error);}#ifdef CONFIG_NFS_V4static int nfs_open_revalidate(struct dentry *, struct nameidata *);struct dentry_operations nfs4_dentry_operations = {	.d_revalidate	= nfs_open_revalidate,	.d_delete	= nfs_dentry_delete,	.d_iput		= nfs_dentry_iput,};static int is_atomic_open(struct inode *dir, struct nameidata *nd){	if (!nd)		return 0;	/* Check that we are indeed trying to open this file */	if ((nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_OPEN))		return 0;	/* NFS does not (yet) have a stateful open for directories */	if (nd->flags & LOOKUP_DIRECTORY)		return 0;	/* Are we trying to write to a read only partition? */	if (IS_RDONLY(dir) && (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE)))		return 0;	return 1;}static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){	struct inode *inode = NULL;	int error = 0;	/* Check that we are indeed trying to open this file */	if (!is_atomic_open(dir, nd))		goto no_open;	if (dentry->d_name.len > NFS_SERVER(dir)->namelen) {		error = -ENAMETOOLONG;		goto out;	}	dentry->d_op = NFS_PROTO(dir)->dentry_ops;	/* Let vfs_create() deal with O_EXCL */	if (nd->intent.open.flags & O_EXCL)		goto no_entry;	/* Open the file on the server */	lock_kernel();	/* Revalidate parent directory attribute cache */	nfs_revalidate_inode(NFS_SERVER(dir), dir);	if (nd->intent.open.flags & O_CREAT) {		nfs_begin_data_update(dir);		inode = nfs4_atomic_open(dir, dentry, nd);		nfs_end_data_update(dir);	} else		inode = nfs4_atomic_open(dir, dentry, nd);	unlock_kernel();	if (IS_ERR(inode)) {		error = PTR_ERR(inode);		switch (error) {			/* Make a negative dentry */			case -ENOENT:				inode = NULL;				break;			/* This turned out not to be a regular file */			case -ELOOP:				if (!(nd->intent.open.flags & O_NOFOLLOW))					goto no_open;			/* case -EISDIR: */			/* case -EINVAL: */			default:				goto out;		}	}no_entry:	d_add(dentry, inode);	nfs_renew_times(dentry);	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));out:	BUG_ON(error > 0);	return ERR_PTR(error);no_open:	return nfs_lookup(dir, dentry, nd);}static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd){	struct dentry *parent = NULL;	struct inode *inode = dentry->d_inode;	struct inode *dir;	unsigned long verifier;	int openflags, ret = 0;	parent = dget_parent(dentry);	dir = parent->d_inode;	if (!is_atomic_open(dir, nd))		goto no_open;	/* We can't create new files in nfs_open_revalidate(), so we	 * optimize away revalidation of negative dentries.	 */	if (inode == NULL)		goto out;	/* NFS only supports OPEN on regular files */	if (!S_ISREG(inode->i_mode))		goto no_open;	openflags = nd->intent.open.flags;	/* We cannot do exclusive creation on a positive dentry */	if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))		goto no_open;	/* We can't create new files, or truncate existing ones here */	openflags &= ~(O_CREAT|O_TRUNC);	/*	 * Note: we're not holding inode->i_sem and so may be racing with	 * operations that change the directory. We therefore save the	 * change attribute *before* we do the RPC call.	 */	lock_kernel();	verifier = nfs_save_change_attribute(dir);	ret = nfs4_open_revalidate(dir, dentry, openflags);	if (!ret)		nfs_set_verifier(dentry, verifier);	unlock_kernel();out:	dput(parent);	if (!ret)		d_drop(dentry);	return ret;no_open:	dput(parent);	if (inode != NULL && nfs_have_delegation(inode, FMODE_READ))		return 1;	return nfs_lookup_revalidate(dentry, nd);}#endif /* CONFIG_NFSV4 */static inlineint find_dirent_name(nfs_readdir_descriptor_t *desc, struct page *page, struct dentry *dentry){	struct nfs_entry *entry = desc->entry;	int		 status;	while((status = dir_decode(desc)) == 0) {		if (entry->len != dentry->d_name.len)			continue;		if (memcmp(entry->name, dentry->d_name.name, entry->len))			continue;		if (!(entry->fattr->valid & NFS_ATTR_FATTR))			continue;		break;	}	return status;}/* * Use the cached Readdirplus results in order to avoid a LOOKUP call * whenever we believe that the parent directory has not changed. * * We assume that any file creation/rename changes the directory mtime. * As this results in a page cache invalidation whenever it occurs, * we don't require any other tests for cache coherency. */staticint nfs_cached_lookup(struct inode *dir, struct dentry *dentry,			struct nfs_fh *fh, struct nfs_fattr *fattr){	nfs_readdir_descriptor_t desc;	struct nfs_server *server;	struct nfs_entry entry;	struct page *page;	unsigned long timestamp;	int res;	if (!NFS_USE_READDIRPLUS(dir))		return -ENOENT;	server = NFS_SERVER(dir);	/* Don't use readdirplus unless the cache is stable */	if ((server->flags & NFS_MOUNT_NOAC) != 0			|| nfs_caches_unstable(dir)			|| nfs_attribute_timeout(dir))		return -ENOENT;	if ((NFS_FLAGS(dir) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) != 0)		return -ENOENT;	timestamp = NFS_I(dir)->readdir_timestamp;	entry.fh = fh;	entry.fattr = fattr;	desc.decode = NFS_PROTO(dir)->decode_dirent;	desc.entry = &entry;	desc.page_index = 0;	desc.plus = 1;	for(;(page = find_get_page(dir->i_mapping, desc.page_index)); desc.page_index++) {		res = -EIO;		if (PageUptodate(page)) {			void * kaddr = kmap_atomic(page, KM_USER0);			desc.ptr = kaddr;			res = find_dirent_name(&desc, page, dentry);			kunmap_atomic(kaddr, KM_USER0);		}		page_cache_release(page);		if (res == 0)			goto out_found;		if (res != -EAGAIN)			break;	}	return -ENOENT; out_found:	fattr->timestamp = timestamp;	return 0;}/* * Code common to create, mkdir, and mknod. */static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,				struct nfs_fattr *fattr){	struct inode *inode;	int error = -EACCES;	/* We may have been initialized further down */	if (dentry->d_inode)		return 0;	if (fhandle->size == 0) {		struct inode *dir = dentry->d_parent->d_inode;		error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);		if (error)			goto out_err;	}	if (!(fattr->valid & NFS_ATTR_FATTR)) {		struct nfs_server *server = NFS_SB(dentry->d_sb);		error = server->rpc_ops->getattr(server, fhandle, fattr);		if (error < 0)			goto out_err;	}	inode = nfs_fhget(dentry->d_sb, fhandle, fattr);	if (inode) {		d_instantiate(dentry, inode);		nfs_renew_times(dentry);		nfs_set_verifier(dentry, nfs_save_change_attribute(dentry->d_parent->d_inode));		return 0;	}	error = -ENOMEM;out_err:	d_drop(dentry);	return error;}/* * Following a failed create operation, we drop the dentry rather * than retain a negative dentry. This avoids a problem in the event * that the operation succeeded on the server, but an error in the * reply path made it appear to have failed. */static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,		struct nameidata *nd){	struct iattr attr;	struct inode *inode;	int error;	int open_flags = 0;	dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id, 		dir->i_ino, dentry->d_name.name);	attr.ia_mode = mode;	attr.ia_valid = ATTR_MODE;	if (nd && (nd->flags & LOOKUP_CREATE))		open_flags = nd->intent.open.flags;	/*	 * The 0 argument passed into the create function should one day	 * contain the O_EXCL flag if requested. This allows NFSv3 to	 * select the appropriate create strategy. Currently open_namei	 * does not pass the create flags.	 */	lock_kernel();	nfs_begin_data_update(dir);	inode = NFS_PROTO(dir)->create(dir, &dentry->d_name, &attr, open_flags);	nfs_end_data_update(dir);	if (!IS_ERR(inode)) {		d_instantiate(dentry, inode);		nfs_renew_times(dentry);		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));		error = 0;	} else {		error = PTR_ERR(inode);		d_drop(dentry);	}	unlock_kernel();	return error;}/* * See comments for nfs_proc_create regarding failed operations. */static intnfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev){

⌨️ 快捷键说明

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