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/nilfs2/segment.c | |
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/nilfs2/segment.c')
-rw-r--r-- | fs/nilfs2/segment.c | 43 |
1 files changed, 28 insertions, 15 deletions
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); |