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

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	desc->ptr = kmap(page);		/* matching kunmap in nfs_do_filldir */	if (desc->error >= 0) {		desc->timestamp = timestamp;		desc->timestamp_valid = 1;		if ((status = dir_decode(desc)) == 0)			desc->entry->prev_cookie = *desc->dir_cookie;	} 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;	desc->entry->cookie = desc->entry->prev_cookie = 0;	desc->entry->eof = 0; out:	dfprintk(DIRCACHE, "NFS: %s: returns %d\n",			__FUNCTION__, status);	return status; out_release:	dir_page_release(desc);	goto out;}/* The file offset position represents the dirent entry number.  A   last cookie cache takes care of the common case of reading the   whole directory. */static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir){	struct dentry	*dentry = filp->f_path.dentry;	struct inode	*inode = dentry->d_inode;	nfs_readdir_descriptor_t my_desc,			*desc = &my_desc;	struct nfs_entry my_entry;	struct nfs_fh	 fh;	struct nfs_fattr fattr;	long		res;	dfprintk(VFS, "NFS: readdir(%s/%s) starting at cookie %Lu\n",			dentry->d_parent->d_name.name, dentry->d_name.name,			(long long)filp->f_pos);	nfs_inc_stats(inode, NFSIOS_VFSGETDENTS);	lock_kernel();	res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping);	if (res < 0) {		unlock_kernel();		return res;	}	/*	 * filp->f_pos points to the dirent entry number.	 * *desc->dir_cookie has the cookie for the next entry. We have	 * to either find the entry with the appropriate number or	 * revalidate the cookie.	 */	memset(desc, 0, sizeof(*desc));	desc->file = filp;	desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie;	desc->decode = NFS_PROTO(inode)->decode_dirent;	desc->plus = NFS_USE_READDIRPLUS(inode);	my_entry.cookie = my_entry.prev_cookie = 0;	my_entry.eof = 0;	my_entry.fh = &fh;	my_entry.fattr = &fattr;	nfs_fattr_init(&fattr);	desc->entry = &my_entry;	nfs_block_sillyrename(dentry);	while(!desc->entry->eof) {		res = readdir_search_pagecache(desc);		if (res == -EBADCOOKIE) {			/* This means either end of directory */			if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) {				/* Or that the server has 'lost' a cookie */				res = uncached_readdir(desc, dirent, filldir);				if (res >= 0)					continue;			}			res = 0;			break;		}		if (res == -ETOOSMALL && desc->plus) {			clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));			nfs_zap_caches(inode);			desc->plus = 0;			desc->entry->eof = 0;			continue;		}		if (res < 0)			break;		res = nfs_do_filldir(desc, dirent, filldir);		if (res < 0) {			res = 0;			break;		}	}	nfs_unblock_sillyrename(dentry);	unlock_kernel();	if (res > 0)		res = 0;	dfprintk(VFS, "NFS: readdir(%s/%s) returns %ld\n",			dentry->d_parent->d_name.name, dentry->d_name.name,			res);	return res;}static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin){	mutex_lock(&filp->f_path.dentry->d_inode->i_mutex);	switch (origin) {		case 1:			offset += filp->f_pos;		case 0:			if (offset >= 0)				break;		default:			offset = -EINVAL;			goto out;	}	if (offset != filp->f_pos) {		filp->f_pos = offset;		nfs_file_open_context(filp)->dir_cookie = 0;	}out:	mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);	return offset;}/* * All directory operations under NFS are synchronous, so fsync() * is a dummy operation. */static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync){	dfprintk(VFS, "NFS: fsync_dir(%s/%s) datasync %d\n",			dentry->d_parent->d_name.name, dentry->d_name.name,			datasync);	return 0;}/* * A check for whether or not the parent directory has changed. * In the case it has, we assume that the dentries are untrustworthy * and may need to be looked up again. */static int nfs_check_verifier(struct inode *dir, struct dentry *dentry){	if (IS_ROOT(dentry))		return 1;	if (!nfs_verify_change_attribute(dir, dentry->d_time))		return 0;	/* Revalidate nfsi->cache_change_attribute before we declare a match */	if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)		return 0;	if (!nfs_verify_change_attribute(dir, dentry->d_time))		return 0;	return 1;}/* * Return the intent data that applies to this particular path component * * Note that the current set of intents only apply to the very last * component of the path. * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT. */static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask){	if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))		return 0;	return nd->flags & mask;}/* * Use intent information to check whether or not we're going to do * an O_EXCL create using this path component. */static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd){	if (NFS_PROTO(dir)->version == 2)		return 0;	if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)		return 0;	return (nd->intent.open.flags & O_EXCL) != 0;}/* * Inode and filehandle revalidation for lookups. * * We force revalidation in the cases where the VFS sets LOOKUP_REVAL, * or if the intent information indicates that we're about to open this * particular file and the "nocto" mount flag is not set. * */static inlineint nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd){	struct nfs_server *server = NFS_SERVER(inode);	if (nd != NULL) {		/* VFS wants an on-the-wire revalidation */		if (nd->flags & LOOKUP_REVAL)			goto out_force;		/* This is an open(2) */		if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&				!(server->flags & NFS_MOUNT_NOCTO) &&				(S_ISREG(inode->i_mode) ||				 S_ISDIR(inode->i_mode)))			goto out_force;		return 0;	}	return nfs_revalidate_inode(server, inode);out_force:	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){	/* Don't revalidate a negative dentry if we're creating a new file */	if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0)		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;	parent = dget_parent(dentry);	lock_kernel();	dir = parent->d_inode;	nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);	inode = dentry->d_inode;	if (!inode) {		if (nfs_neg_need_reval(dir, dentry, nd))			goto out_bad;		goto out_valid;	}	if (is_bad_inode(inode)) {		dfprintk(LOOKUPCACHE, "%s: %s/%s has dud inode\n",				__FUNCTION__, dentry->d_parent->d_name.name,				dentry->d_name.name);		goto out_bad;	}	/* Force a full look up iff the parent directory has changed */	if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {		if (nfs_lookup_verify_inode(inode, nd))			goto out_zap_parent;		goto out_valid;	}	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;	nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out_valid:	unlock_kernel();	dput(parent);	dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n",			__FUNCTION__, dentry->d_parent->d_name.name,			dentry->d_name.name);	return 1;out_zap_parent:	nfs_zap_caches(dir); out_bad:	nfs_mark_for_revalidate(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);	dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",			__FUNCTION__, dentry->d_parent->d_name.name,			dentry->d_name.name);	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){	nfs_inode_return_delegation(inode);	if (S_ISDIR(inode->i_mode))		/* drop any readdir cache as it could easily be old */		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {		lock_kernel();		drop_nlink(inode);		nfs_complete_unlink(dentry, inode);		unlock_kernel();	}	iput(inode);}struct dentry_operations nfs_dentry_operations = {	.d_revalidate	= nfs_lookup_revalidate,	.d_delete	= nfs_dentry_delete,	.d_iput		= nfs_dentry_iput,};static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd){	struct dentry *res;	struct dentry *parent;	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);	nfs_inc_stats(dir, NFSIOS_VFSLOOKUP);	res = ERR_PTR(-ENAMETOOLONG);	if (dentry->d_name.len > NFS_SERVER(dir)->namelen)		goto out;	res = ERR_PTR(-ENOMEM);	dentry->d_op = NFS_PROTO(dir)->dentry_ops;	lock_kernel();	/*	 * If we're doing an exclusive create, optimize away the lookup	 * but don't hash the dentry.	 */	if (nfs_is_exclusive_create(dir, nd)) {		d_instantiate(dentry, NULL);		res = NULL;		goto out_unlock;	}	parent = dentry->d_parent;	/* Protect against concurrent sillydeletes */	nfs_block_sillyrename(parent);	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);	if (error == -ENOENT)		goto no_entry;	if (error < 0) {		res = ERR_PTR(error);		goto out_unblock_sillyrename;	}	inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);	res = (struct dentry *)inode;	if (IS_ERR(res))		goto out_unblock_sillyrename;no_entry:	res = d_materialise_unique(dentry, inode);	if (res != NULL) {		if (IS_ERR(res))			goto out_unblock_sillyrename;		dentry = res;	}	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));out_unblock_sillyrename:	nfs_unblock_sillyrename(parent);out_unlock:	unlock_kernel();out:	return res;}#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,};/* * Use intent information to determine whether we need to substitute * the NFSv4-style stateful OPEN for the LOOKUP call */static int is_atomic_open(struct inode *dir, struct nameidata *nd){	if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0)		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 dentry *res = NULL;	int error;	dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n",			dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);	/* 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) {		res = ERR_PTR(-ENAMETOOLONG);		goto out;	}	dentry->d_op = NFS_PROTO(dir)->dentry_ops;	/* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash	 * the dentry. */	if (nd->intent.open.flags & O_EXCL) {		d_instantiate(dentry, NULL);		goto out;

⌨️ 快捷键说明

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