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/dir.c | |
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/dir.c')
-rw-r--r-- | fs/ceph/dir.c | 68 |
1 files changed, 43 insertions, 25 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 = { |