diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2012-06-05 15:10:25 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-14 16:33:16 +0400 |
commit | 2d83bde9a16e18eafdc73a3a1f4a8eb110e49672 (patch) | |
tree | 04e2277dba94d252f4b74cf1acb728880b606c2e | |
parent | 3819219b592159725069eb16a7a46f58e4ecef32 (diff) | |
download | linux-2d83bde9a16e18eafdc73a3a1f4a8eb110e49672.tar.gz linux-2d83bde9a16e18eafdc73a3a1f4a8eb110e49672.tar.bz2 linux-2d83bde9a16e18eafdc73a3a1f4a8eb110e49672.zip |
ceph: implement i_op->atomic_open()
Add an ->atomic_open implementation which replaces the atomic lookup+open+create
operation implemented via ->lookup and ->create operations.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
CC: Sage Weil <sage@newdream.net>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/ceph/dir.c | 68 | ||||
-rw-r--r-- | fs/ceph/file.c | 21 | ||||
-rw-r--r-- | fs/ceph/super.h | 5 |
3 files changed, 56 insertions, 38 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index c4b7832c38b5..75df600ec9b4 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -594,14 +594,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, if (err < 0) return ERR_PTR(err); - /* open (but not create!) intent? */ - if (nd && - (nd->flags & LOOKUP_OPEN) && - !(nd->intent.open.flags & O_CREAT)) { - int mode = nd->intent.open.create_mode & ~current->fs->umask; - return ceph_lookup_open(dir, dentry, nd, mode); - } - /* can we conclude ENOENT locally? */ if (dentry->d_inode == NULL) { struct ceph_inode_info *ci = ceph_inode(dir); @@ -642,6 +634,47 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, return dentry; } +struct file *ceph_atomic_open(struct inode *dir, struct dentry *dentry, + struct opendata *od, unsigned flags, umode_t mode, + bool *created) +{ + int err; + struct dentry *res = NULL; + struct file *filp; + + if (!(flags & O_CREAT)) { + if (dentry->d_name.len > NAME_MAX) + return ERR_PTR(-ENAMETOOLONG); + + err = ceph_init_dentry(dentry); + if (err < 0) + return ERR_PTR(err); + + return ceph_lookup_open(dir, dentry, od, flags, mode); + } + + if (d_unhashed(dentry)) { + res = ceph_lookup(dir, dentry, NULL); + if (IS_ERR(res)) + return ERR_CAST(res); + + if (res) + dentry = res; + } + + /* We don't deal with positive dentries here */ + if (dentry->d_inode) { + finish_no_open(od, res); + return NULL; + } + + *created = true; + filp = ceph_lookup_open(dir, dentry, od, flags, mode); + dput(res); + + return filp; +} + /* * If we do a create but get no trace back from the MDS, follow up with * a lookup (the VFS expects us to link up the provided dentry). @@ -702,23 +735,7 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { - dout("create in dir %p dentry %p name '%.*s'\n", - dir, dentry, dentry->d_name.len, dentry->d_name.name); - - if (ceph_snap(dir) != CEPH_NOSNAP) - return -EROFS; - - if (nd) { - BUG_ON((nd->flags & LOOKUP_OPEN) == 0); - dentry = ceph_lookup_open(dir, dentry, nd, mode); - /* hrm, what should i do here if we get aliased? */ - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - return 0; - } - - /* fall back to mknod */ - return ceph_mknod(dir, dentry, (mode & ~S_IFMT) | S_IFREG, 0); + return ceph_mknod(dir, dentry, mode, 0); } static int ceph_symlink(struct inode *dir, struct dentry *dentry, @@ -1357,6 +1374,7 @@ const struct inode_operations ceph_dir_iops = { .rmdir = ceph_unlink, .rename = ceph_rename, .create = ceph_create, + .atomic_open = ceph_atomic_open, }; const struct dentry_operations ceph_dentry_ops = { diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 4bf9773e6a36..e34dc22e75a9 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -213,21 +213,15 @@ out: * may_open() fails, the struct *file gets cleaned up (i.e. * ceph_release gets called). So fear not! */ -/* - * flags - * path_lookup_open -> LOOKUP_OPEN - * path_lookup_create -> LOOKUP_OPEN|LOOKUP_CREATE - */ -struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, - struct nameidata *nd, int mode) +struct file *ceph_lookup_open(struct inode *dir, struct dentry *dentry, + struct opendata *od, unsigned flags, umode_t mode) { struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); struct ceph_mds_client *mdsc = fsc->mdsc; - struct file *file; + struct file *file = NULL; struct ceph_mds_request *req; struct dentry *ret; int err; - int flags = nd->intent.open.flags; dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n", dentry, dentry->d_name.len, dentry->d_name.name, flags, mode); @@ -253,14 +247,19 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, err = ceph_handle_notrace_create(dir, dentry); if (err) goto out; - file = lookup_instantiate_filp(nd, req->r_dentry, ceph_open); + file = finish_open(od, req->r_dentry, ceph_open); if (IS_ERR(file)) err = PTR_ERR(file); out: ret = ceph_finish_lookup(req, dentry, err); ceph_mdsc_put_request(req); dout("ceph_lookup_open result=%p\n", ret); - return ret; + + if (IS_ERR(ret)) + return ERR_CAST(ret); + + dput(ret); + return err ? ERR_PTR(err) : file; } int ceph_release(struct inode *inode, struct file *file) diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 8471db98b62c..e61e54673e56 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -806,8 +806,9 @@ extern int ceph_copy_from_page_vector(struct page **pages, loff_t off, size_t len); extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); extern int ceph_open(struct inode *inode, struct file *file); -extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, - struct nameidata *nd, int mode); +extern struct file *ceph_lookup_open(struct inode *dir, struct dentry *dentry, + struct opendata *od, unsigned flags, + umode_t mode); extern int ceph_release(struct inode *inode, struct file *filp); /* dir.c */ |