diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2013-06-14 06:17:15 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2013-06-14 06:17:15 -0400 |
commit | 6d4ade986f9c8df31e68fd30643997f79cc5a5f8 (patch) | |
tree | f0758a7a9b008d0bd3665234a5074e3cf6f4d455 /fs/gfs2/inode.c | |
parent | 5a00f3cc978be45b9d2597851bedaa40630bc597 (diff) |
GFS2: Add atomic_open support
I've restricted atomic_open to only operate on regular files, although
I still don't understand why atomic_open should not be possible also for
directories on GFS2. That can always be added in later though, if it
makes sense.
The ->atomic_open function can be passed negative dentries, which
in most cases means either ENOENT (->lookup) or a call to d_instantiate
(->create). In the GFS2 case though, we need to actually perform the
look up, since we do not know whether there has been a new inode created
on another node. The look up calls d_splice_alias which then tries to
rehash the dentry - so the solution here is to simply check for that
in d_splice_alias. The same issue is likely to affect any other cluster
filesystem implementing ->atomic_open
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: "J. Bruce Fields" <bfields fieldses org>
Cc: Jeff Layton <jlayton@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r-- | fs/gfs2/inode.c | 125 |
1 files changed, 99 insertions, 26 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index ede16ae784e2..bbb2715171cd 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -535,6 +535,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, | |||
535 | * gfs2_create_inode - Create a new inode | 535 | * gfs2_create_inode - Create a new inode |
536 | * @dir: The parent directory | 536 | * @dir: The parent directory |
537 | * @dentry: The new dentry | 537 | * @dentry: The new dentry |
538 | * @file: If non-NULL, the file which is being opened | ||
538 | * @mode: The permissions on the new inode | 539 | * @mode: The permissions on the new inode |
539 | * @dev: For device nodes, this is the device number | 540 | * @dev: For device nodes, this is the device number |
540 | * @symname: For symlinks, this is the link destination | 541 | * @symname: For symlinks, this is the link destination |
@@ -544,8 +545,9 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, | |||
544 | */ | 545 | */ |
545 | 546 | ||
546 | static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, | 547 | static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, |
548 | struct file *file, | ||
547 | umode_t mode, dev_t dev, const char *symname, | 549 | umode_t mode, dev_t dev, const char *symname, |
548 | unsigned int size, int excl) | 550 | unsigned int size, int excl, int *opened) |
549 | { | 551 | { |
550 | const struct qstr *name = &dentry->d_name; | 552 | const struct qstr *name = &dentry->d_name; |
551 | struct gfs2_holder ghs[2]; | 553 | struct gfs2_holder ghs[2]; |
@@ -553,6 +555,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, | |||
553 | struct gfs2_inode *dip = GFS2_I(dir), *ip; | 555 | struct gfs2_inode *dip = GFS2_I(dir), *ip; |
554 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 556 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
555 | struct gfs2_glock *io_gl; | 557 | struct gfs2_glock *io_gl; |
558 | struct dentry *d; | ||
556 | int error; | 559 | int error; |
557 | u32 aflags = 0; | 560 | u32 aflags = 0; |
558 | int arq; | 561 | int arq; |
@@ -579,9 +582,20 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, | |||
579 | inode = gfs2_dir_search(dir, &dentry->d_name, !S_ISREG(mode) || excl); | 582 | inode = gfs2_dir_search(dir, &dentry->d_name, !S_ISREG(mode) || excl); |
580 | error = PTR_ERR(inode); | 583 | error = PTR_ERR(inode); |
581 | if (!IS_ERR(inode)) { | 584 | if (!IS_ERR(inode)) { |
585 | d = d_splice_alias(inode, dentry); | ||
586 | error = 0; | ||
587 | if (file && !IS_ERR(d)) { | ||
588 | if (d == NULL) | ||
589 | d = dentry; | ||
590 | if (S_ISREG(inode->i_mode)) | ||
591 | error = finish_open(file, d, gfs2_open_common, opened); | ||
592 | else | ||
593 | error = finish_no_open(file, d); | ||
594 | } | ||
582 | gfs2_glock_dq_uninit(ghs); | 595 | gfs2_glock_dq_uninit(ghs); |
583 | d_instantiate(dentry, inode); | 596 | if (IS_ERR(d)) |
584 | return 0; | 597 | return PTR_RET(d); |
598 | return error; | ||
585 | } else if (error != -ENOENT) { | 599 | } else if (error != -ENOENT) { |
586 | goto fail_gunlock; | 600 | goto fail_gunlock; |
587 | } | 601 | } |
@@ -679,10 +693,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, | |||
679 | goto fail_gunlock3; | 693 | goto fail_gunlock3; |
680 | 694 | ||
681 | mark_inode_dirty(inode); | 695 | mark_inode_dirty(inode); |
696 | d_instantiate(dentry, inode); | ||
697 | if (file) | ||
698 | error = finish_open(file, dentry, gfs2_open_common, opened); | ||
682 | gfs2_glock_dq_uninit(ghs); | 699 | gfs2_glock_dq_uninit(ghs); |
683 | gfs2_glock_dq_uninit(ghs + 1); | 700 | gfs2_glock_dq_uninit(ghs + 1); |
684 | d_instantiate(dentry, inode); | 701 | return error; |
685 | return 0; | ||
686 | 702 | ||
687 | fail_gunlock3: | 703 | fail_gunlock3: |
688 | gfs2_glock_dq_uninit(ghs + 1); | 704 | gfs2_glock_dq_uninit(ghs + 1); |
@@ -722,36 +738,56 @@ fail: | |||
722 | static int gfs2_create(struct inode *dir, struct dentry *dentry, | 738 | static int gfs2_create(struct inode *dir, struct dentry *dentry, |
723 | umode_t mode, bool excl) | 739 | umode_t mode, bool excl) |
724 | { | 740 | { |
725 | return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl); | 741 | return gfs2_create_inode(dir, dentry, NULL, S_IFREG | mode, 0, NULL, 0, excl, NULL); |
726 | } | 742 | } |
727 | 743 | ||
728 | /** | 744 | /** |
729 | * gfs2_lookup - Look up a filename in a directory and return its inode | 745 | * __gfs2_lookup - Look up a filename in a directory and return its inode |
730 | * @dir: The directory inode | 746 | * @dir: The directory inode |
731 | * @dentry: The dentry of the new inode | 747 | * @dentry: The dentry of the new inode |
732 | * @nd: passed from Linux VFS, ignored by us | 748 | * @file: File to be opened |
749 | * @opened: atomic_open flags | ||
733 | * | 750 | * |
734 | * Called by the VFS layer. Lock dir and call gfs2_lookupi() | ||
735 | * | 751 | * |
736 | * Returns: errno | 752 | * Returns: errno |
737 | */ | 753 | */ |
738 | 754 | ||
739 | static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, | 755 | static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry, |
740 | unsigned int flags) | 756 | struct file *file, int *opened) |
741 | { | 757 | { |
742 | struct inode *inode = gfs2_lookupi(dir, &dentry->d_name, 0); | 758 | struct inode *inode; |
743 | if (inode && !IS_ERR(inode)) { | 759 | struct dentry *d; |
744 | struct gfs2_glock *gl = GFS2_I(inode)->i_gl; | 760 | struct gfs2_holder gh; |
745 | struct gfs2_holder gh; | 761 | struct gfs2_glock *gl; |
746 | int error; | 762 | int error; |
747 | error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); | 763 | |
748 | if (error) { | 764 | inode = gfs2_lookupi(dir, &dentry->d_name, 0); |
749 | iput(inode); | 765 | if (!inode) |
750 | return ERR_PTR(error); | 766 | return NULL; |
751 | } | 767 | if (IS_ERR(inode)) |
752 | gfs2_glock_dq_uninit(&gh); | 768 | return ERR_CAST(inode); |
769 | |||
770 | gl = GFS2_I(inode)->i_gl; | ||
771 | error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); | ||
772 | if (error) { | ||
773 | iput(inode); | ||
774 | return ERR_PTR(error); | ||
753 | } | 775 | } |
754 | return d_splice_alias(inode, dentry); | 776 | |
777 | d = d_splice_alias(inode, dentry); | ||
778 | if (file && S_ISREG(inode->i_mode)) | ||
779 | error = finish_open(file, dentry, gfs2_open_common, opened); | ||
780 | |||
781 | gfs2_glock_dq_uninit(&gh); | ||
782 | if (error) | ||
783 | return ERR_PTR(error); | ||
784 | return d; | ||
785 | } | ||
786 | |||
787 | static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, | ||
788 | unsigned flags) | ||
789 | { | ||
790 | return __gfs2_lookup(dir, dentry, NULL, NULL); | ||
755 | } | 791 | } |
756 | 792 | ||
757 | /** | 793 | /** |
@@ -1069,7 +1105,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, | |||
1069 | if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1) | 1105 | if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1) |
1070 | return -ENAMETOOLONG; | 1106 | return -ENAMETOOLONG; |
1071 | 1107 | ||
1072 | return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size, 0); | 1108 | return gfs2_create_inode(dir, dentry, NULL, S_IFLNK | S_IRWXUGO, 0, symname, size, 0, NULL); |
1073 | } | 1109 | } |
1074 | 1110 | ||
1075 | /** | 1111 | /** |
@@ -1085,7 +1121,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
1085 | { | 1121 | { |
1086 | struct gfs2_sbd *sdp = GFS2_SB(dir); | 1122 | struct gfs2_sbd *sdp = GFS2_SB(dir); |
1087 | unsigned dsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode); | 1123 | unsigned dsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode); |
1088 | return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, dsize, 0); | 1124 | return gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0, NULL); |
1089 | } | 1125 | } |
1090 | 1126 | ||
1091 | /** | 1127 | /** |
@@ -1100,7 +1136,43 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
1100 | static int gfs2_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, | 1136 | static int gfs2_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, |
1101 | dev_t dev) | 1137 | dev_t dev) |
1102 | { | 1138 | { |
1103 | return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0, 0); | 1139 | return gfs2_create_inode(dir, dentry, NULL, mode, dev, NULL, 0, 0, NULL); |
1140 | } | ||
1141 | |||
1142 | /** | ||
1143 | * gfs2_atomic_open - Atomically open a file | ||
1144 | * @dir: The directory | ||
1145 | * @dentry: The proposed new entry | ||
1146 | * @file: The proposed new struct file | ||
1147 | * @flags: open flags | ||
1148 | * @mode: File mode | ||
1149 | * @opened: Flag to say whether the file has been opened or not | ||
1150 | * | ||
1151 | * Returns: error code or 0 for success | ||
1152 | */ | ||
1153 | |||
1154 | static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry, | ||
1155 | struct file *file, unsigned flags, | ||
1156 | umode_t mode, int *opened) | ||
1157 | { | ||
1158 | struct dentry *d; | ||
1159 | bool excl = !!(flags & O_EXCL); | ||
1160 | |||
1161 | d = __gfs2_lookup(dir, dentry, file, opened); | ||
1162 | if (IS_ERR(d)) | ||
1163 | return PTR_ERR(d); | ||
1164 | if (d == NULL) | ||
1165 | d = dentry; | ||
1166 | if (d->d_inode) { | ||
1167 | if (!(*opened & FILE_OPENED)) | ||
1168 | return finish_no_open(file, d); | ||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | if (!(flags & O_CREAT)) | ||
1173 | return -ENOENT; | ||
1174 | |||
1175 | return gfs2_create_inode(dir, dentry, file, S_IFREG | mode, 0, NULL, 0, excl, opened); | ||
1104 | } | 1176 | } |
1105 | 1177 | ||
1106 | /* | 1178 | /* |
@@ -1780,6 +1852,7 @@ const struct inode_operations gfs2_dir_iops = { | |||
1780 | .removexattr = gfs2_removexattr, | 1852 | .removexattr = gfs2_removexattr, |
1781 | .fiemap = gfs2_fiemap, | 1853 | .fiemap = gfs2_fiemap, |
1782 | .get_acl = gfs2_get_acl, | 1854 | .get_acl = gfs2_get_acl, |
1855 | .atomic_open = gfs2_atomic_open, | ||
1783 | }; | 1856 | }; |
1784 | 1857 | ||
1785 | const struct inode_operations gfs2_symlink_iops = { | 1858 | const struct inode_operations gfs2_symlink_iops = { |