diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2009-04-06 22:01:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-07 11:31:17 -0400 |
commit | 47420c799830d4676e544dbec56b2a7f787528f5 (patch) | |
tree | dd61f6c96942b07f762129c893d9cbbbeff60735 /fs | |
parent | a2e7d2df82cafb76f76809ddf6e2caa8afe4f75e (diff) |
nilfs2: avoid double error caused by nilfs_transaction_end
Pekka Enberg pointed out that double error handlings found after
nilfs_transaction_end() can be avoided by separating abort operation:
OK, I don't understand this. The only way nilfs_transaction_end() can
fail is if we have NILFS_TI_SYNC set and we fail to construct the
segment. But why do we want to construct a segment if we don't commit?
I guess what I'm asking is why don't we have a separate
nilfs_transaction_abort() function that can't fail for the erroneous
case to avoid this double error value tracking thing?
This does the separation and renames nilfs_transaction_end() to
nilfs_transaction_commit() for clarification.
Since, some calls of these functions were used just for exclusion control
against the segment constructor, they are replaced with semaphore
operations.
Acked-by: Pekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nilfs2/inode.c | 23 | ||||
-rw-r--r-- | fs/nilfs2/ioctl.c | 58 | ||||
-rw-r--r-- | fs/nilfs2/mdt.c | 5 | ||||
-rw-r--r-- | fs/nilfs2/namei.c | 74 | ||||
-rw-r--r-- | fs/nilfs2/nilfs.h | 3 | ||||
-rw-r--r-- | fs/nilfs2/segment.c | 43 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.h | 4 |
7 files changed, 135 insertions, 75 deletions
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 289d1798decb..4bf1e2c5bac6 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
@@ -77,7 +77,6 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, | |||
77 | goto out; | 77 | goto out; |
78 | err = nilfs_bmap_insert(ii->i_bmap, (unsigned long)blkoff, | 78 | err = nilfs_bmap_insert(ii->i_bmap, (unsigned long)blkoff, |
79 | (unsigned long)bh_result); | 79 | (unsigned long)bh_result); |
80 | nilfs_transaction_end(inode->i_sb, !err); | ||
81 | if (unlikely(err != 0)) { | 80 | if (unlikely(err != 0)) { |
82 | if (err == -EEXIST) { | 81 | if (err == -EEXIST) { |
83 | /* | 82 | /* |
@@ -100,8 +99,10 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, | |||
100 | inode->i_ino); | 99 | inode->i_ino); |
101 | err = -EIO; | 100 | err = -EIO; |
102 | } | 101 | } |
102 | nilfs_transaction_abort(inode->i_sb); | ||
103 | goto out; | 103 | goto out; |
104 | } | 104 | } |
105 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | ||
105 | /* Error handling should be detailed */ | 106 | /* Error handling should be detailed */ |
106 | set_buffer_new(bh_result); | 107 | set_buffer_new(bh_result); |
107 | map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed | 108 | map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed |
@@ -203,7 +204,7 @@ static int nilfs_write_begin(struct file *file, struct address_space *mapping, | |||
203 | err = block_write_begin(file, mapping, pos, len, flags, pagep, | 204 | err = block_write_begin(file, mapping, pos, len, flags, pagep, |
204 | fsdata, nilfs_get_block); | 205 | fsdata, nilfs_get_block); |
205 | if (unlikely(err)) | 206 | if (unlikely(err)) |
206 | nilfs_transaction_end(inode->i_sb, 0); | 207 | nilfs_transaction_abort(inode->i_sb); |
207 | return err; | 208 | return err; |
208 | } | 209 | } |
209 | 210 | ||
@@ -221,7 +222,7 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping, | |||
221 | copied = generic_write_end(file, mapping, pos, len, copied, page, | 222 | copied = generic_write_end(file, mapping, pos, len, copied, page, |
222 | fsdata); | 223 | fsdata); |
223 | nilfs_set_file_dirty(NILFS_SB(inode->i_sb), inode, nr_dirty); | 224 | nilfs_set_file_dirty(NILFS_SB(inode->i_sb), inode, nr_dirty); |
224 | err = nilfs_transaction_end(inode->i_sb, 1); | 225 | err = nilfs_transaction_commit(inode->i_sb); |
225 | return err ? : copied; | 226 | return err ? : copied; |
226 | } | 227 | } |
227 | 228 | ||
@@ -641,7 +642,7 @@ void nilfs_truncate(struct inode *inode) | |||
641 | nilfs_set_transaction_flag(NILFS_TI_SYNC); | 642 | nilfs_set_transaction_flag(NILFS_TI_SYNC); |
642 | 643 | ||
643 | nilfs_set_file_dirty(NILFS_SB(sb), inode, 0); | 644 | nilfs_set_file_dirty(NILFS_SB(sb), inode, 0); |
644 | nilfs_transaction_end(sb, 1); | 645 | nilfs_transaction_commit(sb); |
645 | /* May construct a logical segment and may fail in sync mode. | 646 | /* May construct a logical segment and may fail in sync mode. |
646 | But truncate has no return value. */ | 647 | But truncate has no return value. */ |
647 | } | 648 | } |
@@ -669,7 +670,7 @@ void nilfs_delete_inode(struct inode *inode) | |||
669 | /* nilfs_free_inode() marks inode buffer dirty */ | 670 | /* nilfs_free_inode() marks inode buffer dirty */ |
670 | if (IS_SYNC(inode)) | 671 | if (IS_SYNC(inode)) |
671 | nilfs_set_transaction_flag(NILFS_TI_SYNC); | 672 | nilfs_set_transaction_flag(NILFS_TI_SYNC); |
672 | nilfs_transaction_end(sb, 1); | 673 | nilfs_transaction_commit(sb); |
673 | /* May construct a logical segment and may fail in sync mode. | 674 | /* May construct a logical segment and may fail in sync mode. |
674 | But delete_inode has no return value. */ | 675 | But delete_inode has no return value. */ |
675 | } | 676 | } |
@@ -679,7 +680,7 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
679 | struct nilfs_transaction_info ti; | 680 | struct nilfs_transaction_info ti; |
680 | struct inode *inode = dentry->d_inode; | 681 | struct inode *inode = dentry->d_inode; |
681 | struct super_block *sb = inode->i_sb; | 682 | struct super_block *sb = inode->i_sb; |
682 | int err, err2; | 683 | int err; |
683 | 684 | ||
684 | err = inode_change_ok(inode, iattr); | 685 | err = inode_change_ok(inode, iattr); |
685 | if (err) | 686 | if (err) |
@@ -691,8 +692,12 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
691 | err = inode_setattr(inode, iattr); | 692 | err = inode_setattr(inode, iattr); |
692 | if (!err && (iattr->ia_valid & ATTR_MODE)) | 693 | if (!err && (iattr->ia_valid & ATTR_MODE)) |
693 | err = nilfs_acl_chmod(inode); | 694 | err = nilfs_acl_chmod(inode); |
694 | err2 = nilfs_transaction_end(sb, 1); | 695 | if (likely(!err)) |
695 | return err ? : err2; | 696 | err = nilfs_transaction_commit(sb); |
697 | else | ||
698 | nilfs_transaction_abort(sb); | ||
699 | |||
700 | return err; | ||
696 | } | 701 | } |
697 | 702 | ||
698 | int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode, | 703 | int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode, |
@@ -817,5 +822,5 @@ void nilfs_dirty_inode(struct inode *inode) | |||
817 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 822 | nilfs_transaction_begin(inode->i_sb, &ti, 0); |
818 | if (likely(inode->i_ino != NILFS_SKETCH_INO)) | 823 | if (likely(inode->i_ino != NILFS_SKETCH_INO)) |
819 | nilfs_mark_inode_dirty(inode); | 824 | nilfs_mark_inode_dirty(inode); |
820 | nilfs_transaction_end(inode->i_sb, 1); /* never fails */ | 825 | nilfs_transaction_commit(inode->i_sb); /* never fails */ |
821 | } | 826 | } |
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 02e91e167ca2..5ce06a01c7ec 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
@@ -105,7 +105,11 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, | |||
105 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 105 | nilfs_transaction_begin(inode->i_sb, &ti, 0); |
106 | ret = nilfs_cpfile_change_cpmode( | 106 | ret = nilfs_cpfile_change_cpmode( |
107 | cpfile, cpmode.cm_cno, cpmode.cm_mode); | 107 | cpfile, cpmode.cm_cno, cpmode.cm_mode); |
108 | nilfs_transaction_end(inode->i_sb, !ret); | 108 | if (unlikely(ret < 0)) { |
109 | nilfs_transaction_abort(inode->i_sb); | ||
110 | return ret; | ||
111 | } | ||
112 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | ||
109 | return ret; | 113 | return ret; |
110 | } | 114 | } |
111 | 115 | ||
@@ -125,7 +129,11 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, | |||
125 | 129 | ||
126 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 130 | nilfs_transaction_begin(inode->i_sb, &ti, 0); |
127 | ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); | 131 | ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); |
128 | nilfs_transaction_end(inode->i_sb, !ret); | 132 | if (unlikely(ret < 0)) { |
133 | nilfs_transaction_abort(inode->i_sb); | ||
134 | return ret; | ||
135 | } | ||
136 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | ||
129 | return ret; | 137 | return ret; |
130 | } | 138 | } |
131 | 139 | ||
@@ -142,16 +150,17 @@ static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp, | |||
142 | { | 150 | { |
143 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | 151 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
144 | struct nilfs_argv argv; | 152 | struct nilfs_argv argv; |
145 | struct nilfs_transaction_info ti; | ||
146 | int ret; | 153 | int ret; |
147 | 154 | ||
148 | if (copy_from_user(&argv, argp, sizeof(argv))) | 155 | if (copy_from_user(&argv, argp, sizeof(argv))) |
149 | return -EFAULT; | 156 | return -EFAULT; |
150 | 157 | ||
151 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 158 | down_read(&nilfs->ns_segctor_sem); |
152 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), | 159 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), |
153 | nilfs_ioctl_do_get_cpinfo); | 160 | nilfs_ioctl_do_get_cpinfo); |
154 | nilfs_transaction_end(inode->i_sb, 0); | 161 | up_read(&nilfs->ns_segctor_sem); |
162 | if (ret < 0) | ||
163 | return ret; | ||
155 | 164 | ||
156 | if (copy_to_user(argp, &argv, sizeof(argv))) | 165 | if (copy_to_user(argp, &argv, sizeof(argv))) |
157 | ret = -EFAULT; | 166 | ret = -EFAULT; |
@@ -161,14 +170,13 @@ static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp, | |||
161 | static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp, | 170 | static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp, |
162 | unsigned int cmd, void __user *argp) | 171 | unsigned int cmd, void __user *argp) |
163 | { | 172 | { |
164 | struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile; | 173 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
165 | struct nilfs_cpstat cpstat; | 174 | struct nilfs_cpstat cpstat; |
166 | struct nilfs_transaction_info ti; | ||
167 | int ret; | 175 | int ret; |
168 | 176 | ||
169 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 177 | down_read(&nilfs->ns_segctor_sem); |
170 | ret = nilfs_cpfile_get_stat(cpfile, &cpstat); | 178 | ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat); |
171 | nilfs_transaction_end(inode->i_sb, 0); | 179 | up_read(&nilfs->ns_segctor_sem); |
172 | if (ret < 0) | 180 | if (ret < 0) |
173 | return ret; | 181 | return ret; |
174 | 182 | ||
@@ -189,16 +197,17 @@ static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp, | |||
189 | { | 197 | { |
190 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | 198 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
191 | struct nilfs_argv argv; | 199 | struct nilfs_argv argv; |
192 | struct nilfs_transaction_info ti; | ||
193 | int ret; | 200 | int ret; |
194 | 201 | ||
195 | if (copy_from_user(&argv, argp, sizeof(argv))) | 202 | if (copy_from_user(&argv, argp, sizeof(argv))) |
196 | return -EFAULT; | 203 | return -EFAULT; |
197 | 204 | ||
198 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 205 | down_read(&nilfs->ns_segctor_sem); |
199 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), | 206 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), |
200 | nilfs_ioctl_do_get_suinfo); | 207 | nilfs_ioctl_do_get_suinfo); |
201 | nilfs_transaction_end(inode->i_sb, 0); | 208 | up_read(&nilfs->ns_segctor_sem); |
209 | if (ret < 0) | ||
210 | return ret; | ||
202 | 211 | ||
203 | if (copy_to_user(argp, &argv, sizeof(argv))) | 212 | if (copy_to_user(argp, &argv, sizeof(argv))) |
204 | ret = -EFAULT; | 213 | ret = -EFAULT; |
@@ -208,14 +217,13 @@ static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp, | |||
208 | static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp, | 217 | static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp, |
209 | unsigned int cmd, void __user *argp) | 218 | unsigned int cmd, void __user *argp) |
210 | { | 219 | { |
211 | struct inode *sufile = NILFS_SB(inode->i_sb)->s_nilfs->ns_sufile; | 220 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
212 | struct nilfs_sustat sustat; | 221 | struct nilfs_sustat sustat; |
213 | struct nilfs_transaction_info ti; | ||
214 | int ret; | 222 | int ret; |
215 | 223 | ||
216 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 224 | down_read(&nilfs->ns_segctor_sem); |
217 | ret = nilfs_sufile_get_stat(sufile, &sustat); | 225 | ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat); |
218 | nilfs_transaction_end(inode->i_sb, 0); | 226 | up_read(&nilfs->ns_segctor_sem); |
219 | if (ret < 0) | 227 | if (ret < 0) |
220 | return ret; | 228 | return ret; |
221 | 229 | ||
@@ -236,16 +244,17 @@ static int nilfs_ioctl_get_vinfo(struct inode *inode, struct file *filp, | |||
236 | { | 244 | { |
237 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | 245 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
238 | struct nilfs_argv argv; | 246 | struct nilfs_argv argv; |
239 | struct nilfs_transaction_info ti; | ||
240 | int ret; | 247 | int ret; |
241 | 248 | ||
242 | if (copy_from_user(&argv, argp, sizeof(argv))) | 249 | if (copy_from_user(&argv, argp, sizeof(argv))) |
243 | return -EFAULT; | 250 | return -EFAULT; |
244 | 251 | ||
245 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 252 | down_read(&nilfs->ns_segctor_sem); |
246 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), | 253 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), |
247 | nilfs_ioctl_do_get_vinfo); | 254 | nilfs_ioctl_do_get_vinfo); |
248 | nilfs_transaction_end(inode->i_sb, 0); | 255 | up_read(&nilfs->ns_segctor_sem); |
256 | if (ret < 0) | ||
257 | return ret; | ||
249 | 258 | ||
250 | if (copy_to_user(argp, &argv, sizeof(argv))) | 259 | if (copy_to_user(argp, &argv, sizeof(argv))) |
251 | ret = -EFAULT; | 260 | ret = -EFAULT; |
@@ -280,16 +289,17 @@ static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp, | |||
280 | { | 289 | { |
281 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | 290 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
282 | struct nilfs_argv argv; | 291 | struct nilfs_argv argv; |
283 | struct nilfs_transaction_info ti; | ||
284 | int ret; | 292 | int ret; |
285 | 293 | ||
286 | if (copy_from_user(&argv, argp, sizeof(argv))) | 294 | if (copy_from_user(&argv, argp, sizeof(argv))) |
287 | return -EFAULT; | 295 | return -EFAULT; |
288 | 296 | ||
289 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 297 | down_read(&nilfs->ns_segctor_sem); |
290 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), | 298 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), |
291 | nilfs_ioctl_do_get_bdescs); | 299 | nilfs_ioctl_do_get_bdescs); |
292 | nilfs_transaction_end(inode->i_sb, 0); | 300 | up_read(&nilfs->ns_segctor_sem); |
301 | if (ret < 0) | ||
302 | return ret; | ||
293 | 303 | ||
294 | if (copy_to_user(argp, &argv, sizeof(argv))) | 304 | if (copy_to_user(argp, &argv, sizeof(argv))) |
295 | ret = -EFAULT; | 305 | ret = -EFAULT; |
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 6ab847578615..e0a632b86feb 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c | |||
@@ -123,7 +123,10 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, | |||
123 | brelse(bh); | 123 | brelse(bh); |
124 | 124 | ||
125 | failed_unlock: | 125 | failed_unlock: |
126 | nilfs_transaction_end(sb, !err); | 126 | if (likely(!err)) |
127 | err = nilfs_transaction_commit(sb); | ||
128 | else | ||
129 | nilfs_transaction_abort(sb); | ||
127 | if (writer) | 130 | if (writer) |
128 | nilfs_put_writer(nilfs); | 131 | nilfs_put_writer(nilfs); |
129 | out: | 132 | out: |
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 95d1b29bff3c..df70dadb336f 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c | |||
@@ -109,7 +109,7 @@ static int nilfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
109 | { | 109 | { |
110 | struct inode *inode; | 110 | struct inode *inode; |
111 | struct nilfs_transaction_info ti; | 111 | struct nilfs_transaction_info ti; |
112 | int err, err2; | 112 | int err; |
113 | 113 | ||
114 | err = nilfs_transaction_begin(dir->i_sb, &ti, 1); | 114 | err = nilfs_transaction_begin(dir->i_sb, &ti, 1); |
115 | if (err) | 115 | if (err) |
@@ -123,8 +123,12 @@ static int nilfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
123 | mark_inode_dirty(inode); | 123 | mark_inode_dirty(inode); |
124 | err = nilfs_add_nondir(dentry, inode); | 124 | err = nilfs_add_nondir(dentry, inode); |
125 | } | 125 | } |
126 | err2 = nilfs_transaction_end(dir->i_sb, !err); | 126 | if (!err) |
127 | return err ? : err2; | 127 | err = nilfs_transaction_commit(dir->i_sb); |
128 | else | ||
129 | nilfs_transaction_abort(dir->i_sb); | ||
130 | |||
131 | return err; | ||
128 | } | 132 | } |
129 | 133 | ||
130 | static int | 134 | static int |
@@ -132,7 +136,7 @@ nilfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |||
132 | { | 136 | { |
133 | struct inode *inode; | 137 | struct inode *inode; |
134 | struct nilfs_transaction_info ti; | 138 | struct nilfs_transaction_info ti; |
135 | int err, err2; | 139 | int err; |
136 | 140 | ||
137 | if (!new_valid_dev(rdev)) | 141 | if (!new_valid_dev(rdev)) |
138 | return -EINVAL; | 142 | return -EINVAL; |
@@ -147,8 +151,12 @@ nilfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |||
147 | mark_inode_dirty(inode); | 151 | mark_inode_dirty(inode); |
148 | err = nilfs_add_nondir(dentry, inode); | 152 | err = nilfs_add_nondir(dentry, inode); |
149 | } | 153 | } |
150 | err2 = nilfs_transaction_end(dir->i_sb, !err); | 154 | if (!err) |
151 | return err ? : err2; | 155 | err = nilfs_transaction_commit(dir->i_sb); |
156 | else | ||
157 | nilfs_transaction_abort(dir->i_sb); | ||
158 | |||
159 | return err; | ||
152 | } | 160 | } |
153 | 161 | ||
154 | static int nilfs_symlink(struct inode *dir, struct dentry *dentry, | 162 | static int nilfs_symlink(struct inode *dir, struct dentry *dentry, |
@@ -158,7 +166,7 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry, | |||
158 | struct super_block *sb = dir->i_sb; | 166 | struct super_block *sb = dir->i_sb; |
159 | unsigned l = strlen(symname)+1; | 167 | unsigned l = strlen(symname)+1; |
160 | struct inode *inode; | 168 | struct inode *inode; |
161 | int err, err2; | 169 | int err; |
162 | 170 | ||
163 | if (l > sb->s_blocksize) | 171 | if (l > sb->s_blocksize) |
164 | return -ENAMETOOLONG; | 172 | return -ENAMETOOLONG; |
@@ -184,8 +192,12 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry, | |||
184 | 192 | ||
185 | err = nilfs_add_nondir(dentry, inode); | 193 | err = nilfs_add_nondir(dentry, inode); |
186 | out: | 194 | out: |
187 | err2 = nilfs_transaction_end(dir->i_sb, !err); | 195 | if (!err) |
188 | return err ? : err2; | 196 | err = nilfs_transaction_commit(dir->i_sb); |
197 | else | ||
198 | nilfs_transaction_abort(dir->i_sb); | ||
199 | |||
200 | return err; | ||
189 | 201 | ||
190 | out_fail: | 202 | out_fail: |
191 | inode_dec_link_count(inode); | 203 | inode_dec_link_count(inode); |
@@ -198,7 +210,7 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, | |||
198 | { | 210 | { |
199 | struct inode *inode = old_dentry->d_inode; | 211 | struct inode *inode = old_dentry->d_inode; |
200 | struct nilfs_transaction_info ti; | 212 | struct nilfs_transaction_info ti; |
201 | int err, err2; | 213 | int err; |
202 | 214 | ||
203 | if (inode->i_nlink >= NILFS_LINK_MAX) | 215 | if (inode->i_nlink >= NILFS_LINK_MAX) |
204 | return -EMLINK; | 216 | return -EMLINK; |
@@ -212,15 +224,19 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, | |||
212 | atomic_inc(&inode->i_count); | 224 | atomic_inc(&inode->i_count); |
213 | 225 | ||
214 | err = nilfs_add_nondir(dentry, inode); | 226 | err = nilfs_add_nondir(dentry, inode); |
215 | err2 = nilfs_transaction_end(dir->i_sb, !err); | 227 | if (!err) |
216 | return err ? : err2; | 228 | err = nilfs_transaction_commit(dir->i_sb); |
229 | else | ||
230 | nilfs_transaction_abort(dir->i_sb); | ||
231 | |||
232 | return err; | ||
217 | } | 233 | } |
218 | 234 | ||
219 | static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 235 | static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
220 | { | 236 | { |
221 | struct inode *inode; | 237 | struct inode *inode; |
222 | struct nilfs_transaction_info ti; | 238 | struct nilfs_transaction_info ti; |
223 | int err, err2; | 239 | int err; |
224 | 240 | ||
225 | if (dir->i_nlink >= NILFS_LINK_MAX) | 241 | if (dir->i_nlink >= NILFS_LINK_MAX) |
226 | return -EMLINK; | 242 | return -EMLINK; |
@@ -252,8 +268,12 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
252 | 268 | ||
253 | d_instantiate(dentry, inode); | 269 | d_instantiate(dentry, inode); |
254 | out: | 270 | out: |
255 | err2 = nilfs_transaction_end(dir->i_sb, !err); | 271 | if (!err) |
256 | return err ? : err2; | 272 | err = nilfs_transaction_commit(dir->i_sb); |
273 | else | ||
274 | nilfs_transaction_abort(dir->i_sb); | ||
275 | |||
276 | return err; | ||
257 | 277 | ||
258 | out_fail: | 278 | out_fail: |
259 | inode_dec_link_count(inode); | 279 | inode_dec_link_count(inode); |
@@ -270,7 +290,7 @@ static int nilfs_unlink(struct inode *dir, struct dentry *dentry) | |||
270 | struct nilfs_dir_entry *de; | 290 | struct nilfs_dir_entry *de; |
271 | struct page *page; | 291 | struct page *page; |
272 | struct nilfs_transaction_info ti; | 292 | struct nilfs_transaction_info ti; |
273 | int err, err2; | 293 | int err; |
274 | 294 | ||
275 | err = nilfs_transaction_begin(dir->i_sb, &ti, 0); | 295 | err = nilfs_transaction_begin(dir->i_sb, &ti, 0); |
276 | if (err) | 296 | if (err) |
@@ -300,15 +320,19 @@ static int nilfs_unlink(struct inode *dir, struct dentry *dentry) | |||
300 | inode_dec_link_count(inode); | 320 | inode_dec_link_count(inode); |
301 | err = 0; | 321 | err = 0; |
302 | out: | 322 | out: |
303 | err2 = nilfs_transaction_end(dir->i_sb, !err); | 323 | if (!err) |
304 | return err ? : err2; | 324 | err = nilfs_transaction_commit(dir->i_sb); |
325 | else | ||
326 | nilfs_transaction_abort(dir->i_sb); | ||
327 | |||
328 | return err; | ||
305 | } | 329 | } |
306 | 330 | ||
307 | static int nilfs_rmdir(struct inode *dir, struct dentry *dentry) | 331 | static int nilfs_rmdir(struct inode *dir, struct dentry *dentry) |
308 | { | 332 | { |
309 | struct inode *inode = dentry->d_inode; | 333 | struct inode *inode = dentry->d_inode; |
310 | struct nilfs_transaction_info ti; | 334 | struct nilfs_transaction_info ti; |
311 | int err, err2; | 335 | int err; |
312 | 336 | ||
313 | err = nilfs_transaction_begin(dir->i_sb, &ti, 0); | 337 | err = nilfs_transaction_begin(dir->i_sb, &ti, 0); |
314 | if (err) | 338 | if (err) |
@@ -323,8 +347,12 @@ static int nilfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
323 | inode_dec_link_count(dir); | 347 | inode_dec_link_count(dir); |
324 | } | 348 | } |
325 | } | 349 | } |
326 | err2 = nilfs_transaction_end(dir->i_sb, !err); | 350 | if (!err) |
327 | return err ? : err2; | 351 | err = nilfs_transaction_commit(dir->i_sb); |
352 | else | ||
353 | nilfs_transaction_abort(dir->i_sb); | ||
354 | |||
355 | return err; | ||
328 | } | 356 | } |
329 | 357 | ||
330 | static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 358 | static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
@@ -404,7 +432,7 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
404 | inode_dec_link_count(old_dir); | 432 | inode_dec_link_count(old_dir); |
405 | } | 433 | } |
406 | 434 | ||
407 | err = nilfs_transaction_end(old_dir->i_sb, 1); | 435 | err = nilfs_transaction_commit(old_dir->i_sb); |
408 | return err; | 436 | return err; |
409 | 437 | ||
410 | out_dir: | 438 | out_dir: |
@@ -416,7 +444,7 @@ out_old: | |||
416 | kunmap(old_page); | 444 | kunmap(old_page); |
417 | page_cache_release(old_page); | 445 | page_cache_release(old_page); |
418 | out: | 446 | out: |
419 | nilfs_transaction_end(old_dir->i_sb, 0); | 447 | nilfs_transaction_abort(old_dir->i_sb); |
420 | return err; | 448 | return err; |
421 | } | 449 | } |
422 | 450 | ||
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 17458ad4a809..48c070676cc5 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -166,7 +166,8 @@ struct nilfs_transaction_info { | |||
166 | 166 | ||
167 | int nilfs_transaction_begin(struct super_block *, | 167 | int nilfs_transaction_begin(struct super_block *, |
168 | struct nilfs_transaction_info *, int); | 168 | struct nilfs_transaction_info *, int); |
169 | int nilfs_transaction_end(struct super_block *, int); | 169 | int nilfs_transaction_commit(struct super_block *); |
170 | void nilfs_transaction_abort(struct super_block *); | ||
170 | 171 | ||
171 | static inline void nilfs_set_transaction_flag(unsigned int flag) | 172 | static inline void nilfs_set_transaction_flag(unsigned int flag) |
172 | { | 173 | { |
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index ad65a737aff4..6d66c5cb7b51 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
@@ -163,8 +163,8 @@ static int nilfs_prepare_segment_lock(struct nilfs_transaction_info *ti) | |||
163 | else { | 163 | else { |
164 | /* | 164 | /* |
165 | * If journal_info field is occupied by other FS, | 165 | * If journal_info field is occupied by other FS, |
166 | * we save it and restore on nilfs_transaction_end(). | 166 | * it is saved and will be restored on |
167 | * But this should never happen. | 167 | * nilfs_transaction_commit(). |
168 | */ | 168 | */ |
169 | printk(KERN_WARNING | 169 | printk(KERN_WARNING |
170 | "NILFS warning: journal info from a different " | 170 | "NILFS warning: journal info from a different " |
@@ -195,7 +195,7 @@ static int nilfs_prepare_segment_lock(struct nilfs_transaction_info *ti) | |||
195 | * | 195 | * |
196 | * nilfs_transaction_begin() acquires a reader/writer semaphore, called | 196 | * nilfs_transaction_begin() acquires a reader/writer semaphore, called |
197 | * the segment semaphore, to make a segment construction and write tasks | 197 | * the segment semaphore, to make a segment construction and write tasks |
198 | * exclusive. The function is used with nilfs_transaction_end() in pairs. | 198 | * exclusive. The function is used with nilfs_transaction_commit() in pairs. |
199 | * The region enclosed by these two functions can be nested. To avoid a | 199 | * The region enclosed by these two functions can be nested. To avoid a |
200 | * deadlock, the semaphore is only acquired or released in the outermost call. | 200 | * deadlock, the semaphore is only acquired or released in the outermost call. |
201 | * | 201 | * |
@@ -212,8 +212,6 @@ static int nilfs_prepare_segment_lock(struct nilfs_transaction_info *ti) | |||
212 | * | 212 | * |
213 | * %-ENOMEM - Insufficient memory available. | 213 | * %-ENOMEM - Insufficient memory available. |
214 | * | 214 | * |
215 | * %-ERESTARTSYS - Interrupted | ||
216 | * | ||
217 | * %-ENOSPC - No space left on device | 215 | * %-ENOSPC - No space left on device |
218 | */ | 216 | */ |
219 | int nilfs_transaction_begin(struct super_block *sb, | 217 | int nilfs_transaction_begin(struct super_block *sb, |
@@ -248,16 +246,17 @@ int nilfs_transaction_begin(struct super_block *sb, | |||
248 | } | 246 | } |
249 | 247 | ||
250 | /** | 248 | /** |
251 | * nilfs_transaction_end - end indivisible file operations. | 249 | * nilfs_transaction_commit - commit indivisible file operations. |
252 | * @sb: super block | 250 | * @sb: super block |
253 | * @commit: commit flag (0 for no change) | ||
254 | * | 251 | * |
255 | * nilfs_transaction_end() releases the read semaphore which is | 252 | * nilfs_transaction_commit() releases the read semaphore which is |
256 | * acquired by nilfs_transaction_begin(). Its releasing is only done | 253 | * acquired by nilfs_transaction_begin(). This is only performed |
257 | * in outermost call of this function. If the nilfs_transaction_info | 254 | * in outermost call of this function. If a commit flag is set, |
258 | * was allocated dynamically, it is given back to a slab cache. | 255 | * nilfs_transaction_commit() sets a timer to start the segment |
256 | * constructor. If a sync flag is set, it starts construction | ||
257 | * directly. | ||
259 | */ | 258 | */ |
260 | int nilfs_transaction_end(struct super_block *sb, int commit) | 259 | int nilfs_transaction_commit(struct super_block *sb) |
261 | { | 260 | { |
262 | struct nilfs_transaction_info *ti = current->journal_info; | 261 | struct nilfs_transaction_info *ti = current->journal_info; |
263 | struct nilfs_sb_info *sbi; | 262 | struct nilfs_sb_info *sbi; |
@@ -265,9 +264,7 @@ int nilfs_transaction_end(struct super_block *sb, int commit) | |||
265 | int err = 0; | 264 | int err = 0; |
266 | 265 | ||
267 | BUG_ON(ti == NULL || ti->ti_magic != NILFS_TI_MAGIC); | 266 | BUG_ON(ti == NULL || ti->ti_magic != NILFS_TI_MAGIC); |
268 | 267 | ti->ti_flags |= NILFS_TI_COMMIT; | |
269 | if (commit) | ||
270 | ti->ti_flags |= NILFS_TI_COMMIT; | ||
271 | if (ti->ti_count > 0) { | 268 | if (ti->ti_count > 0) { |
272 | ti->ti_count--; | 269 | ti->ti_count--; |
273 | return 0; | 270 | return 0; |
@@ -291,6 +288,22 @@ int nilfs_transaction_end(struct super_block *sb, int commit) | |||
291 | return err; | 288 | return err; |
292 | } | 289 | } |
293 | 290 | ||
291 | void nilfs_transaction_abort(struct super_block *sb) | ||
292 | { | ||
293 | struct nilfs_transaction_info *ti = current->journal_info; | ||
294 | |||
295 | BUG_ON(ti == NULL || ti->ti_magic != NILFS_TI_MAGIC); | ||
296 | if (ti->ti_count > 0) { | ||
297 | ti->ti_count--; | ||
298 | return; | ||
299 | } | ||
300 | up_read(&NILFS_SB(sb)->s_nilfs->ns_segctor_sem); | ||
301 | |||
302 | current->journal_info = ti->ti_save; | ||
303 | if (ti->ti_flags & NILFS_TI_DYNAMIC_ALLOC) | ||
304 | kmem_cache_free(nilfs_transaction_cachep, ti); | ||
305 | } | ||
306 | |||
294 | void nilfs_relax_pressure_in_lock(struct super_block *sb) | 307 | void nilfs_relax_pressure_in_lock(struct super_block *sb) |
295 | { | 308 | { |
296 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 309 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index dee8d83e0549..9cd3c113f052 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
@@ -112,8 +112,8 @@ struct the_nilfs { | |||
112 | /* | 112 | /* |
113 | * Following fields are dedicated to a writable FS-instance. | 113 | * Following fields are dedicated to a writable FS-instance. |
114 | * Except for the period seeking checkpoint, code outside the segment | 114 | * Except for the period seeking checkpoint, code outside the segment |
115 | * constructor must lock a segment semaphore with transaction_begin() | 115 | * constructor must lock a segment semaphore while accessing these |
116 | * and transaction_end(), when accessing these fields. | 116 | * fields. |
117 | * The writable FS-instance is sole during a lifetime of the_nilfs. | 117 | * The writable FS-instance is sole during a lifetime of the_nilfs. |
118 | */ | 118 | */ |
119 | u64 ns_seg_seq; | 119 | u64 ns_seg_seq; |