diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2012-06-05 09:10:25 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-14 08:33:16 -0400 |
commit | 2d83bde9a16e18eafdc73a3a1f4a8eb110e49672 (patch) | |
tree | 04e2277dba94d252f4b74cf1acb728880b606c2e /fs/ceph | |
parent | 3819219b592159725069eb16a7a46f58e4ecef32 (diff) |
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>
Diffstat (limited to 'fs/ceph')
-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, | |||
594 | if (err < 0) | 594 | if (err < 0) |
595 | return ERR_PTR(err); | 595 | return ERR_PTR(err); |
596 | 596 | ||
597 | /* open (but not create!) intent? */ | ||
598 | if (nd && | ||
599 | (nd->flags & LOOKUP_OPEN) && | ||
600 | !(nd->intent.open.flags & O_CREAT)) { | ||
601 | int mode = nd->intent.open.create_mode & ~current->fs->umask; | ||
602 | return ceph_lookup_open(dir, dentry, nd, mode); | ||
603 | } | ||
604 | |||
605 | /* can we conclude ENOENT locally? */ | 597 | /* can we conclude ENOENT locally? */ |
606 | if (dentry->d_inode == NULL) { | 598 | if (dentry->d_inode == NULL) { |
607 | struct ceph_inode_info *ci = ceph_inode(dir); | 599 | struct ceph_inode_info *ci = ceph_inode(dir); |
@@ -642,6 +634,47 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, | |||
642 | return dentry; | 634 | return dentry; |
643 | } | 635 | } |
644 | 636 | ||
637 | struct file *ceph_atomic_open(struct inode *dir, struct dentry *dentry, | ||
638 | struct opendata *od, unsigned flags, umode_t mode, | ||
639 | bool *created) | ||
640 | { | ||
641 | int err; | ||
642 | struct dentry *res = NULL; | ||
643 | struct file *filp; | ||
644 | |||
645 | if (!(flags & O_CREAT)) { | ||
646 | if (dentry->d_name.len > NAME_MAX) | ||
647 | return ERR_PTR(-ENAMETOOLONG); | ||
648 | |||
649 | err = ceph_init_dentry(dentry); | ||
650 | if (err < 0) | ||
651 | return ERR_PTR(err); | ||
652 | |||
653 | return ceph_lookup_open(dir, dentry, od, flags, mode); | ||
654 | } | ||
655 | |||
656 | if (d_unhashed(dentry)) { | ||
657 | res = ceph_lookup(dir, dentry, NULL); | ||
658 | if (IS_ERR(res)) | ||
659 | return ERR_CAST(res); | ||
660 | |||
661 | if (res) | ||
662 | dentry = res; | ||
663 | } | ||
664 | |||
665 | /* We don't deal with positive dentries here */ | ||
666 | if (dentry->d_inode) { | ||
667 | finish_no_open(od, res); | ||
668 | return NULL; | ||
669 | } | ||
670 | |||
671 | *created = true; | ||
672 | filp = ceph_lookup_open(dir, dentry, od, flags, mode); | ||
673 | dput(res); | ||
674 | |||
675 | return filp; | ||
676 | } | ||
677 | |||
645 | /* | 678 | /* |
646 | * If we do a create but get no trace back from the MDS, follow up with | 679 | * If we do a create but get no trace back from the MDS, follow up with |
647 | * a lookup (the VFS expects us to link up the provided dentry). | 680 | * 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, | |||
702 | static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode, | 735 | static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode, |
703 | struct nameidata *nd) | 736 | struct nameidata *nd) |
704 | { | 737 | { |
705 | dout("create in dir %p dentry %p name '%.*s'\n", | 738 | return ceph_mknod(dir, dentry, mode, 0); |
706 | dir, dentry, dentry->d_name.len, dentry->d_name.name); | ||
707 | |||
708 | if (ceph_snap(dir) != CEPH_NOSNAP) | ||
709 | return -EROFS; | ||
710 | |||
711 | if (nd) { | ||
712 | BUG_ON((nd->flags & LOOKUP_OPEN) == 0); | ||
713 | dentry = ceph_lookup_open(dir, dentry, nd, mode); | ||
714 | /* hrm, what should i do here if we get aliased? */ | ||
715 | if (IS_ERR(dentry)) | ||
716 | return PTR_ERR(dentry); | ||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | /* fall back to mknod */ | ||
721 | return ceph_mknod(dir, dentry, (mode & ~S_IFMT) | S_IFREG, 0); | ||
722 | } | 739 | } |
723 | 740 | ||
724 | static int ceph_symlink(struct inode *dir, struct dentry *dentry, | 741 | static int ceph_symlink(struct inode *dir, struct dentry *dentry, |
@@ -1357,6 +1374,7 @@ const struct inode_operations ceph_dir_iops = { | |||
1357 | .rmdir = ceph_unlink, | 1374 | .rmdir = ceph_unlink, |
1358 | .rename = ceph_rename, | 1375 | .rename = ceph_rename, |
1359 | .create = ceph_create, | 1376 | .create = ceph_create, |
1377 | .atomic_open = ceph_atomic_open, | ||
1360 | }; | 1378 | }; |
1361 | 1379 | ||
1362 | const struct dentry_operations ceph_dentry_ops = { | 1380 | 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: | |||
213 | * may_open() fails, the struct *file gets cleaned up (i.e. | 213 | * may_open() fails, the struct *file gets cleaned up (i.e. |
214 | * ceph_release gets called). So fear not! | 214 | * ceph_release gets called). So fear not! |
215 | */ | 215 | */ |
216 | /* | 216 | struct file *ceph_lookup_open(struct inode *dir, struct dentry *dentry, |
217 | * flags | 217 | struct opendata *od, unsigned flags, umode_t mode) |
218 | * path_lookup_open -> LOOKUP_OPEN | ||
219 | * path_lookup_create -> LOOKUP_OPEN|LOOKUP_CREATE | ||
220 | */ | ||
221 | struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, | ||
222 | struct nameidata *nd, int mode) | ||
223 | { | 218 | { |
224 | struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); | 219 | struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); |
225 | struct ceph_mds_client *mdsc = fsc->mdsc; | 220 | struct ceph_mds_client *mdsc = fsc->mdsc; |
226 | struct file *file; | 221 | struct file *file = NULL; |
227 | struct ceph_mds_request *req; | 222 | struct ceph_mds_request *req; |
228 | struct dentry *ret; | 223 | struct dentry *ret; |
229 | int err; | 224 | int err; |
230 | int flags = nd->intent.open.flags; | ||
231 | 225 | ||
232 | dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n", | 226 | dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n", |
233 | dentry, dentry->d_name.len, dentry->d_name.name, flags, mode); | 227 | 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, | |||
253 | err = ceph_handle_notrace_create(dir, dentry); | 247 | err = ceph_handle_notrace_create(dir, dentry); |
254 | if (err) | 248 | if (err) |
255 | goto out; | 249 | goto out; |
256 | file = lookup_instantiate_filp(nd, req->r_dentry, ceph_open); | 250 | file = finish_open(od, req->r_dentry, ceph_open); |
257 | if (IS_ERR(file)) | 251 | if (IS_ERR(file)) |
258 | err = PTR_ERR(file); | 252 | err = PTR_ERR(file); |
259 | out: | 253 | out: |
260 | ret = ceph_finish_lookup(req, dentry, err); | 254 | ret = ceph_finish_lookup(req, dentry, err); |
261 | ceph_mdsc_put_request(req); | 255 | ceph_mdsc_put_request(req); |
262 | dout("ceph_lookup_open result=%p\n", ret); | 256 | dout("ceph_lookup_open result=%p\n", ret); |
263 | return ret; | 257 | |
258 | if (IS_ERR(ret)) | ||
259 | return ERR_CAST(ret); | ||
260 | |||
261 | dput(ret); | ||
262 | return err ? ERR_PTR(err) : file; | ||
264 | } | 263 | } |
265 | 264 | ||
266 | int ceph_release(struct inode *inode, struct file *file) | 265 | 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, | |||
806 | loff_t off, size_t len); | 806 | loff_t off, size_t len); |
807 | extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); | 807 | extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); |
808 | extern int ceph_open(struct inode *inode, struct file *file); | 808 | extern int ceph_open(struct inode *inode, struct file *file); |
809 | extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, | 809 | extern struct file *ceph_lookup_open(struct inode *dir, struct dentry *dentry, |
810 | struct nameidata *nd, int mode); | 810 | struct opendata *od, unsigned flags, |
811 | umode_t mode); | ||
811 | extern int ceph_release(struct inode *inode, struct file *filp); | 812 | extern int ceph_release(struct inode *inode, struct file *filp); |
812 | 813 | ||
813 | /* dir.c */ | 814 | /* dir.c */ |