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 | |
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')
-rw-r--r-- | fs/gfs2/file.c | 69 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 125 | ||||
-rw-r--r-- | fs/gfs2/inode.h | 1 |
3 files changed, 146 insertions, 49 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index ad0dc38d87ab..4ed6a03e565b 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
@@ -538,21 +538,30 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma) | |||
538 | } | 538 | } |
539 | 539 | ||
540 | /** | 540 | /** |
541 | * gfs2_open - open a file | 541 | * gfs2_open_common - This is common to open and atomic_open |
542 | * @inode: the inode to open | 542 | * @inode: The inode being opened |
543 | * @file: the struct file for this opening | 543 | * @file: The file being opened |
544 | * | 544 | * |
545 | * Returns: errno | 545 | * This maybe called under a glock or not depending upon how it has |
546 | * been called. We must always be called under a glock for regular | ||
547 | * files, however. For other file types, it does not matter whether | ||
548 | * we hold the glock or not. | ||
549 | * | ||
550 | * Returns: Error code or 0 for success | ||
546 | */ | 551 | */ |
547 | 552 | ||
548 | static int gfs2_open(struct inode *inode, struct file *file) | 553 | int gfs2_open_common(struct inode *inode, struct file *file) |
549 | { | 554 | { |
550 | struct gfs2_inode *ip = GFS2_I(inode); | ||
551 | struct gfs2_holder i_gh; | ||
552 | struct gfs2_file *fp; | 555 | struct gfs2_file *fp; |
553 | int error; | 556 | int ret; |
554 | 557 | ||
555 | fp = kzalloc(sizeof(struct gfs2_file), GFP_KERNEL); | 558 | if (S_ISREG(inode->i_mode)) { |
559 | ret = generic_file_open(inode, file); | ||
560 | if (ret) | ||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | fp = kzalloc(sizeof(struct gfs2_file), GFP_NOFS); | ||
556 | if (!fp) | 565 | if (!fp) |
557 | return -ENOMEM; | 566 | return -ENOMEM; |
558 | 567 | ||
@@ -560,29 +569,43 @@ static int gfs2_open(struct inode *inode, struct file *file) | |||
560 | 569 | ||
561 | gfs2_assert_warn(GFS2_SB(inode), !file->private_data); | 570 | gfs2_assert_warn(GFS2_SB(inode), !file->private_data); |
562 | file->private_data = fp; | 571 | file->private_data = fp; |
572 | return 0; | ||
573 | } | ||
574 | |||
575 | /** | ||
576 | * gfs2_open - open a file | ||
577 | * @inode: the inode to open | ||
578 | * @file: the struct file for this opening | ||
579 | * | ||
580 | * After atomic_open, this function is only used for opening files | ||
581 | * which are already cached. We must still get the glock for regular | ||
582 | * files to ensure that we have the file size uptodate for the large | ||
583 | * file check which is in the common code. That is only an issue for | ||
584 | * regular files though. | ||
585 | * | ||
586 | * Returns: errno | ||
587 | */ | ||
588 | |||
589 | static int gfs2_open(struct inode *inode, struct file *file) | ||
590 | { | ||
591 | struct gfs2_inode *ip = GFS2_I(inode); | ||
592 | struct gfs2_holder i_gh; | ||
593 | int error; | ||
594 | bool need_unlock = false; | ||
563 | 595 | ||
564 | if (S_ISREG(ip->i_inode.i_mode)) { | 596 | if (S_ISREG(ip->i_inode.i_mode)) { |
565 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, | 597 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, |
566 | &i_gh); | 598 | &i_gh); |
567 | if (error) | 599 | if (error) |
568 | goto fail; | 600 | return error; |
601 | need_unlock = true; | ||
602 | } | ||
569 | 603 | ||
570 | if (!(file->f_flags & O_LARGEFILE) && | 604 | error = gfs2_open_common(inode, file); |
571 | i_size_read(inode) > MAX_NON_LFS) { | ||
572 | error = -EOVERFLOW; | ||
573 | goto fail_gunlock; | ||
574 | } | ||
575 | 605 | ||
606 | if (need_unlock) | ||
576 | gfs2_glock_dq_uninit(&i_gh); | 607 | gfs2_glock_dq_uninit(&i_gh); |
577 | } | ||
578 | |||
579 | return 0; | ||
580 | 608 | ||
581 | fail_gunlock: | ||
582 | gfs2_glock_dq_uninit(&i_gh); | ||
583 | fail: | ||
584 | file->private_data = NULL; | ||
585 | kfree(fp); | ||
586 | return error; | 609 | return error; |
587 | } | 610 | } |
588 | 611 | ||
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 = { |
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index c53c7477f6da..ba4d9492d422 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h | |||
@@ -109,6 +109,7 @@ extern int gfs2_permission(struct inode *inode, int mask); | |||
109 | extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr); | 109 | extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr); |
110 | extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); | 110 | extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); |
111 | extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); | 111 | extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); |
112 | extern int gfs2_open_common(struct inode *inode, struct file *file); | ||
112 | 113 | ||
113 | extern const struct inode_operations gfs2_file_iops; | 114 | extern const struct inode_operations gfs2_file_iops; |
114 | extern const struct inode_operations gfs2_dir_iops; | 115 | extern const struct inode_operations gfs2_dir_iops; |