mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	nfs: implement i_op->atomic_open()
Replace NFS4 specific ->lookup implementation with ->atomic_open impelementation and use the generic nfs_lookup for other lookups. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> CC: Trond Myklebust <Trond.Myklebust@netapp.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									d18e9008c3
								
							
						
					
					
						commit
						0dd2b474d0
					
				
					 1 changed files with 97 additions and 86 deletions
				
			
		
							
								
								
									
										183
									
								
								fs/nfs/dir.c
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								fs/nfs/dir.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -111,11 +111,15 @@ const struct inode_operations nfs3_dir_inode_operations = {
 | 
			
		|||
 | 
			
		||||
#ifdef CONFIG_NFS_V4
 | 
			
		||||
 | 
			
		||||
static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
 | 
			
		||||
static int nfs_open_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd);
 | 
			
		||||
static struct file *nfs_atomic_open(struct inode *, struct dentry *,
 | 
			
		||||
				    struct opendata *, unsigned, umode_t,
 | 
			
		||||
				    bool *);
 | 
			
		||||
static int nfs4_create(struct inode *dir, struct dentry *dentry,
 | 
			
		||||
		       umode_t mode, struct nameidata *nd);
 | 
			
		||||
const struct inode_operations nfs4_dir_inode_operations = {
 | 
			
		||||
	.create		= nfs_open_create,
 | 
			
		||||
	.lookup		= nfs_atomic_lookup,
 | 
			
		||||
	.create		= nfs4_create,
 | 
			
		||||
	.lookup		= nfs_lookup,
 | 
			
		||||
	.atomic_open	= nfs_atomic_open,
 | 
			
		||||
	.link		= nfs_link,
 | 
			
		||||
	.unlink		= nfs_unlink,
 | 
			
		||||
	.symlink	= nfs_symlink,
 | 
			
		||||
| 
						 | 
				
			
			@ -1403,120 +1407,132 @@ static int do_open(struct inode *inode, struct file *filp)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx)
 | 
			
		||||
static struct file *nfs_finish_open(struct nfs_open_context *ctx,
 | 
			
		||||
				    struct dentry *dentry,
 | 
			
		||||
				    struct opendata *od, unsigned open_flags)
 | 
			
		||||
{
 | 
			
		||||
	struct file *filp;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (ctx->dentry != dentry) {
 | 
			
		||||
		dput(ctx->dentry);
 | 
			
		||||
		ctx->dentry = dget(dentry);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If the open_intent is for execute, we have an extra check to make */
 | 
			
		||||
	if (ctx->mode & FMODE_EXEC) {
 | 
			
		||||
		ret = nfs_may_open(ctx->dentry->d_inode,
 | 
			
		||||
				ctx->cred,
 | 
			
		||||
				nd->intent.open.flags);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
		err = nfs_may_open(dentry->d_inode, ctx->cred, open_flags);
 | 
			
		||||
		if (err < 0) {
 | 
			
		||||
			filp = ERR_PTR(err);
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	filp = lookup_instantiate_filp(nd, ctx->dentry, do_open);
 | 
			
		||||
	if (IS_ERR(filp))
 | 
			
		||||
		ret = PTR_ERR(filp);
 | 
			
		||||
	else
 | 
			
		||||
 | 
			
		||||
	filp = finish_open(od, dentry, do_open);
 | 
			
		||||
	if (!IS_ERR(filp))
 | 
			
		||||
		nfs_file_set_open_context(filp, ctx);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	put_nfs_open_context(ctx);
 | 
			
		||||
	return ret;
 | 
			
		||||
	return filp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 | 
			
		||||
static struct file *nfs_atomic_open(struct inode *dir, struct dentry *dentry,
 | 
			
		||||
				    struct opendata *od, unsigned open_flags,
 | 
			
		||||
				    umode_t mode, bool *created)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs_open_context *ctx;
 | 
			
		||||
	struct iattr attr;
 | 
			
		||||
	struct dentry *res = NULL;
 | 
			
		||||
	struct dentry *res;
 | 
			
		||||
	struct iattr attr = { .ia_valid = ATTR_OPEN };
 | 
			
		||||
	struct inode *inode;
 | 
			
		||||
	int open_flags;
 | 
			
		||||
	struct file *filp;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n",
 | 
			
		||||
	/* Expect a negative dentry */
 | 
			
		||||
	BUG_ON(dentry->d_inode);
 | 
			
		||||
 | 
			
		||||
	dfprintk(VFS, "NFS: atomic_open(%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(nd))
 | 
			
		||||
	/* NFS only supports OPEN on regular files */
 | 
			
		||||
	if ((open_flags & O_DIRECTORY)) {
 | 
			
		||||
		err = -ENOENT;
 | 
			
		||||
		if (!d_unhashed(dentry)) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * Hashed negative dentry with O_DIRECTORY: dentry was
 | 
			
		||||
			 * revalidated and is fine, no need to perform lookup
 | 
			
		||||
			 * again
 | 
			
		||||
			 */
 | 
			
		||||
			goto out_err;
 | 
			
		||||
		}
 | 
			
		||||
		goto no_open;
 | 
			
		||||
 | 
			
		||||
	if (dentry->d_name.len > NFS_SERVER(dir)->namelen) {
 | 
			
		||||
		res = ERR_PTR(-ENAMETOOLONG);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
 | 
			
		||||
	 * the dentry. */
 | 
			
		||||
	if (nd->flags & LOOKUP_EXCL) {
 | 
			
		||||
		d_instantiate(dentry, NULL);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	err = -ENAMETOOLONG;
 | 
			
		||||
	if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
 | 
			
		||||
		goto out_err;
 | 
			
		||||
 | 
			
		||||
	open_flags = nd->intent.open.flags;
 | 
			
		||||
	attr.ia_valid = ATTR_OPEN;
 | 
			
		||||
 | 
			
		||||
	ctx = create_nfs_open_context(dentry, open_flags);
 | 
			
		||||
	res = ERR_CAST(ctx);
 | 
			
		||||
	if (IS_ERR(ctx))
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (nd->flags & LOOKUP_CREATE) {
 | 
			
		||||
		attr.ia_mode = nd->intent.open.create_mode;
 | 
			
		||||
	if (open_flags & O_CREAT) {
 | 
			
		||||
		attr.ia_valid |= ATTR_MODE;
 | 
			
		||||
		attr.ia_mode &= ~current_umask();
 | 
			
		||||
	} else
 | 
			
		||||
		open_flags &= ~(O_EXCL | O_CREAT);
 | 
			
		||||
 | 
			
		||||
		attr.ia_mode = mode & ~current_umask();
 | 
			
		||||
	}
 | 
			
		||||
	if (open_flags & O_TRUNC) {
 | 
			
		||||
		attr.ia_valid |= ATTR_SIZE;
 | 
			
		||||
		attr.ia_size = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Open the file on the server */
 | 
			
		||||
	ctx = create_nfs_open_context(dentry, open_flags);
 | 
			
		||||
	err = PTR_ERR(ctx);
 | 
			
		||||
	if (IS_ERR(ctx))
 | 
			
		||||
		goto out_err;
 | 
			
		||||
 | 
			
		||||
	nfs_block_sillyrename(dentry->d_parent);
 | 
			
		||||
	inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
 | 
			
		||||
	d_drop(dentry);
 | 
			
		||||
	if (IS_ERR(inode)) {
 | 
			
		||||
		nfs_unblock_sillyrename(dentry->d_parent);
 | 
			
		||||
		put_nfs_open_context(ctx);
 | 
			
		||||
		switch (PTR_ERR(inode)) {
 | 
			
		||||
			/* Make a negative dentry */
 | 
			
		||||
			case -ENOENT:
 | 
			
		||||
				d_add(dentry, NULL);
 | 
			
		||||
				res = NULL;
 | 
			
		||||
				goto out;
 | 
			
		||||
			/* This turned out not to be a regular file */
 | 
			
		||||
			case -EISDIR:
 | 
			
		||||
			case -ENOTDIR:
 | 
			
		||||
		err = PTR_ERR(inode);
 | 
			
		||||
		switch (err) {
 | 
			
		||||
		case -ENOENT:
 | 
			
		||||
			d_add(dentry, NULL);
 | 
			
		||||
			break;
 | 
			
		||||
		case -EISDIR:
 | 
			
		||||
		case -ENOTDIR:
 | 
			
		||||
			goto no_open;
 | 
			
		||||
		case -ELOOP:
 | 
			
		||||
			if (!(open_flags & O_NOFOLLOW))
 | 
			
		||||
				goto no_open;
 | 
			
		||||
			case -ELOOP:
 | 
			
		||||
				if (!(nd->intent.open.flags & O_NOFOLLOW))
 | 
			
		||||
					goto no_open;
 | 
			
		||||
			break;
 | 
			
		||||
			/* case -EINVAL: */
 | 
			
		||||
			default:
 | 
			
		||||
				res = ERR_CAST(inode);
 | 
			
		||||
				goto out;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		goto out_err;
 | 
			
		||||
	}
 | 
			
		||||
	res = d_add_unique(dentry, inode);
 | 
			
		||||
	nfs_unblock_sillyrename(dentry->d_parent);
 | 
			
		||||
	if (res != NULL) {
 | 
			
		||||
		dput(ctx->dentry);
 | 
			
		||||
		ctx->dentry = dget(res);
 | 
			
		||||
	if (res != NULL)
 | 
			
		||||
		dentry = res;
 | 
			
		||||
	}
 | 
			
		||||
	err = nfs_intent_set_file(nd, ctx);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		if (res != NULL)
 | 
			
		||||
			dput(res);
 | 
			
		||||
		return ERR_PTR(err);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
 | 
			
		||||
	nfs_unblock_sillyrename(dentry->d_parent);
 | 
			
		||||
	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 | 
			
		||||
	return res;
 | 
			
		||||
 | 
			
		||||
	filp = nfs_finish_open(ctx, dentry, od, open_flags);
 | 
			
		||||
 | 
			
		||||
	dput(res);
 | 
			
		||||
	return filp;
 | 
			
		||||
 | 
			
		||||
out_err:
 | 
			
		||||
	return ERR_PTR(err);
 | 
			
		||||
 | 
			
		||||
no_open:
 | 
			
		||||
	return nfs_lookup(dir, dentry, nd);
 | 
			
		||||
	res = nfs_lookup(dir, dentry, NULL);
 | 
			
		||||
	err = PTR_ERR(res);
 | 
			
		||||
	if (IS_ERR(res))
 | 
			
		||||
		goto out_err;
 | 
			
		||||
 | 
			
		||||
	finish_no_open(od, res);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
 | 
			
		||||
| 
						 | 
				
			
			@ -1566,8 +1582,8 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
 | 
			
		|||
	return nfs_lookup_revalidate(dentry, nd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int nfs_open_create(struct inode *dir, struct dentry *dentry,
 | 
			
		||||
		umode_t mode, struct nameidata *nd)
 | 
			
		||||
static int nfs4_create(struct inode *dir, struct dentry *dentry,
 | 
			
		||||
		       umode_t mode, struct nameidata *nd)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs_open_context *ctx = NULL;
 | 
			
		||||
	struct iattr attr;
 | 
			
		||||
| 
						 | 
				
			
			@ -1591,19 +1607,14 @@ static int nfs_open_create(struct inode *dir, struct dentry *dentry,
 | 
			
		|||
	error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx);
 | 
			
		||||
	if (error != 0)
 | 
			
		||||
		goto out_put_ctx;
 | 
			
		||||
	if (nd) {
 | 
			
		||||
		error = nfs_intent_set_file(nd, ctx);
 | 
			
		||||
		if (error < 0)
 | 
			
		||||
			goto out_err;
 | 
			
		||||
	} else {
 | 
			
		||||
		put_nfs_open_context(ctx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	put_nfs_open_context(ctx);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
out_put_ctx:
 | 
			
		||||
	put_nfs_open_context(ctx);
 | 
			
		||||
out_err_drop:
 | 
			
		||||
	d_drop(dentry);
 | 
			
		||||
out_err:
 | 
			
		||||
	return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue