9p: implement i_op->atomic_open()

Add an ->atomic_open implementation which replaces the atomic open+create
operation implemented via ->create.  No functionality is changed.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
CC: Eric Van Hensbergen <ericvh@gmail.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Miklos Szeredi 2012-06-05 15:10:26 +02:00 committed by Al Viro
parent 2d83bde9a1
commit e43ae79c54
2 changed files with 137 additions and 84 deletions

View File

@ -712,11 +712,14 @@ error:
} }
/** /**
* v9fs_vfs_create - VFS hook to create files * v9fs_vfs_create - VFS hook to create a regular file
*
* open(.., O_CREAT) is handled in v9fs_vfs_atomic_open(). This is only called
* for mknod(2).
*
* @dir: directory inode that is being created * @dir: directory inode that is being created
* @dentry: dentry that is being deleted * @dentry: dentry that is being deleted
* @mode: create permissions * @mode: create permissions
* @nd: path information
* *
*/ */
@ -724,76 +727,19 @@ static int
v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
struct nameidata *nd) struct nameidata *nd)
{ {
int err; struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
u32 perm; u32 perm = unixmode2p9mode(v9ses, mode);
int flags; struct p9_fid *fid;
struct file *filp;
struct v9fs_inode *v9inode;
struct v9fs_session_info *v9ses;
struct p9_fid *fid, *inode_fid;
err = 0; /* P9_OEXCL? */
fid = NULL; fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_ORDWR);
v9ses = v9fs_inode2v9ses(dir); if (IS_ERR(fid))
perm = unixmode2p9mode(v9ses, mode); return PTR_ERR(fid);
if (nd)
flags = nd->intent.open.flags;
else
flags = O_RDWR;
fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
v9fs_uflags2omode(flags,
v9fs_proto_dotu(v9ses)));
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
fid = NULL;
goto error;
}
v9fs_invalidate_inode_attr(dir); v9fs_invalidate_inode_attr(dir);
/* if we are opening a file, assign the open fid to the file */ p9_client_clunk(fid);
if (nd) {
v9inode = V9FS_I(dentry->d_inode);
mutex_lock(&v9inode->v_mutex);
if (v9ses->cache && !v9inode->writeback_fid &&
((flags & O_ACCMODE) != O_RDONLY)) {
/*
* clone a fid and add it to writeback_fid
* we do it during open time instead of
* page dirty time via write_begin/page_mkwrite
* because we want write after unlink usecase
* to work.
*/
inode_fid = v9fs_writeback_fid(dentry);
if (IS_ERR(inode_fid)) {
err = PTR_ERR(inode_fid);
mutex_unlock(&v9inode->v_mutex);
goto error;
}
v9inode->writeback_fid = (void *) inode_fid;
}
mutex_unlock(&v9inode->v_mutex);
filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
if (IS_ERR(filp)) {
err = PTR_ERR(filp);
goto error;
}
filp->private_data = fid;
#ifdef CONFIG_9P_FSCACHE
if (v9ses->cache)
v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
#endif
} else
p9_client_clunk(fid);
return 0; return 0;
error:
if (fid)
p9_client_clunk(fid);
return err;
} }
/** /**
@ -910,6 +856,93 @@ error:
return ERR_PTR(result); return ERR_PTR(result);
} }
static struct file *
v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
struct opendata *od, unsigned flags, umode_t mode,
bool *created)
{
int err;
u32 perm;
struct file *filp;
struct v9fs_inode *v9inode;
struct v9fs_session_info *v9ses;
struct p9_fid *fid, *inode_fid;
struct dentry *res = NULL;
if (d_unhashed(dentry)) {
res = v9fs_vfs_lookup(dir, dentry, NULL);
if (IS_ERR(res))
return ERR_CAST(res);
if (res)
dentry = res;
}
/* Only creates */
if (!(flags & O_CREAT) || dentry->d_inode) {
finish_no_open(od, res);
return NULL;
}
err = 0;
fid = NULL;
v9ses = v9fs_inode2v9ses(dir);
perm = unixmode2p9mode(v9ses, mode);
fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
v9fs_uflags2omode(flags,
v9fs_proto_dotu(v9ses)));
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
fid = NULL;
goto error;
}
v9fs_invalidate_inode_attr(dir);
v9inode = V9FS_I(dentry->d_inode);
mutex_lock(&v9inode->v_mutex);
if (v9ses->cache && !v9inode->writeback_fid &&
((flags & O_ACCMODE) != O_RDONLY)) {
/*
* clone a fid and add it to writeback_fid
* we do it during open time instead of
* page dirty time via write_begin/page_mkwrite
* because we want write after unlink usecase
* to work.
*/
inode_fid = v9fs_writeback_fid(dentry);
if (IS_ERR(inode_fid)) {
err = PTR_ERR(inode_fid);
mutex_unlock(&v9inode->v_mutex);
goto error;
}
v9inode->writeback_fid = (void *) inode_fid;
}
mutex_unlock(&v9inode->v_mutex);
filp = finish_open(od, dentry, generic_file_open);
if (IS_ERR(filp)) {
err = PTR_ERR(filp);
goto error;
}
filp->private_data = fid;
#ifdef CONFIG_9P_FSCACHE
if (v9ses->cache)
v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
#endif
*created = true;
out:
dput(res);
return filp;
error:
if (fid)
p9_client_clunk(fid);
filp = ERR_PTR(err);
goto out;
}
/** /**
* v9fs_vfs_unlink - VFS unlink hook to delete an inode * v9fs_vfs_unlink - VFS unlink hook to delete an inode
* @i: inode that is being unlinked * @i: inode that is being unlinked
@ -1488,6 +1521,7 @@ out:
static const struct inode_operations v9fs_dir_inode_operations_dotu = { static const struct inode_operations v9fs_dir_inode_operations_dotu = {
.create = v9fs_vfs_create, .create = v9fs_vfs_create,
.lookup = v9fs_vfs_lookup, .lookup = v9fs_vfs_lookup,
.atomic_open = v9fs_vfs_atomic_open,
.symlink = v9fs_vfs_symlink, .symlink = v9fs_vfs_symlink,
.link = v9fs_vfs_link, .link = v9fs_vfs_link,
.unlink = v9fs_vfs_unlink, .unlink = v9fs_vfs_unlink,
@ -1502,6 +1536,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
static const struct inode_operations v9fs_dir_inode_operations = { static const struct inode_operations v9fs_dir_inode_operations = {
.create = v9fs_vfs_create, .create = v9fs_vfs_create,
.lookup = v9fs_vfs_lookup, .lookup = v9fs_vfs_lookup,
.atomic_open = v9fs_vfs_atomic_open,
.unlink = v9fs_vfs_unlink, .unlink = v9fs_vfs_unlink,
.mkdir = v9fs_vfs_mkdir, .mkdir = v9fs_vfs_mkdir,
.rmdir = v9fs_vfs_rmdir, .rmdir = v9fs_vfs_rmdir,

View File

@ -230,17 +230,23 @@ int v9fs_open_to_dotl_flags(int flags)
* @dir: directory inode that is being created * @dir: directory inode that is being created
* @dentry: dentry that is being deleted * @dentry: dentry that is being deleted
* @mode: create permissions * @mode: create permissions
* @nd: path information
* *
*/ */
static int static int
v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
struct nameidata *nd) struct nameidata *nd)
{
return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
}
static struct file *
v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
struct opendata *od, unsigned flags, umode_t omode,
bool *created)
{ {
int err = 0; int err = 0;
gid_t gid; gid_t gid;
int flags;
umode_t mode; umode_t mode;
char *name = NULL; char *name = NULL;
struct file *filp; struct file *filp;
@ -251,18 +257,24 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
struct p9_fid *dfid, *ofid, *inode_fid; struct p9_fid *dfid, *ofid, *inode_fid;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct posix_acl *pacl = NULL, *dacl = NULL; struct posix_acl *pacl = NULL, *dacl = NULL;
struct dentry *res = NULL;
if (d_unhashed(dentry)) {
res = v9fs_vfs_lookup(dir, dentry, NULL);
if (IS_ERR(res))
return ERR_CAST(res);
if (res)
dentry = res;
}
/* Only creates */
if (!(flags & O_CREAT) || dentry->d_inode) {
finish_no_open(od, res);
return NULL;
}
v9ses = v9fs_inode2v9ses(dir); v9ses = v9fs_inode2v9ses(dir);
if (nd)
flags = nd->intent.open.flags;
else {
/*
* create call without LOOKUP_OPEN is due
* to mknod of regular files. So use mknod
* operation.
*/
return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
}
name = (char *) dentry->d_name.name; name = (char *) dentry->d_name.name;
p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n", p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
@ -272,7 +284,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
if (IS_ERR(dfid)) { if (IS_ERR(dfid)) {
err = PTR_ERR(dfid); err = PTR_ERR(dfid);
p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
return err; goto err_return;
} }
/* clone a fid to use for creation */ /* clone a fid to use for creation */
@ -280,7 +292,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
if (IS_ERR(ofid)) { if (IS_ERR(ofid)) {
err = PTR_ERR(ofid); err = PTR_ERR(ofid);
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
return err; goto err_return;
} }
gid = v9fs_get_fsgid_for_create(dir); gid = v9fs_get_fsgid_for_create(dir);
@ -345,7 +357,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
} }
mutex_unlock(&v9inode->v_mutex); mutex_unlock(&v9inode->v_mutex);
/* Since we are opening a file, assign the open fid to the file */ /* Since we are opening a file, assign the open fid to the file */
filp = lookup_instantiate_filp(nd, dentry, generic_file_open); filp = finish_open(od, dentry, generic_file_open);
if (IS_ERR(filp)) { if (IS_ERR(filp)) {
err = PTR_ERR(filp); err = PTR_ERR(filp);
goto err_clunk_old_fid; goto err_clunk_old_fid;
@ -355,7 +367,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
if (v9ses->cache) if (v9ses->cache)
v9fs_cache_inode_set_cookie(inode, filp); v9fs_cache_inode_set_cookie(inode, filp);
#endif #endif
return 0; *created = true;
out:
dput(res);
return filp;
error: error:
if (fid) if (fid)
@ -364,7 +379,9 @@ err_clunk_old_fid:
if (ofid) if (ofid)
p9_client_clunk(ofid); p9_client_clunk(ofid);
v9fs_set_create_acl(NULL, &dacl, &pacl); v9fs_set_create_acl(NULL, &dacl, &pacl);
return err; err_return:
filp = ERR_PTR(err);
goto out;
} }
/** /**
@ -982,6 +999,7 @@ out:
const struct inode_operations v9fs_dir_inode_operations_dotl = { const struct inode_operations v9fs_dir_inode_operations_dotl = {
.create = v9fs_vfs_create_dotl, .create = v9fs_vfs_create_dotl,
.atomic_open = v9fs_vfs_atomic_open_dotl,
.lookup = v9fs_vfs_lookup, .lookup = v9fs_vfs_lookup,
.link = v9fs_vfs_link_dotl, .link = v9fs_vfs_link_dotl,
.symlink = v9fs_vfs_symlink_dotl, .symlink = v9fs_vfs_symlink_dotl,