diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 132 |
1 files changed, 72 insertions, 60 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 22506eb4a58e..9cf4b926f8e4 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -230,43 +230,54 @@ struct super_block *freeze_bdev(struct block_device *bdev) | |||
230 | int error = 0; | 230 | int error = 0; |
231 | 231 | ||
232 | mutex_lock(&bdev->bd_fsfreeze_mutex); | 232 | mutex_lock(&bdev->bd_fsfreeze_mutex); |
233 | if (bdev->bd_fsfreeze_count > 0) { | 233 | if (++bdev->bd_fsfreeze_count > 1) { |
234 | bdev->bd_fsfreeze_count++; | 234 | /* |
235 | * We don't even need to grab a reference - the first call | ||
236 | * to freeze_bdev grab an active reference and only the last | ||
237 | * thaw_bdev drops it. | ||
238 | */ | ||
235 | sb = get_super(bdev); | 239 | sb = get_super(bdev); |
240 | drop_super(sb); | ||
236 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 241 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
237 | return sb; | 242 | return sb; |
238 | } | 243 | } |
239 | bdev->bd_fsfreeze_count++; | 244 | |
240 | 245 | sb = get_active_super(bdev); | |
241 | sb = get_super(bdev); | 246 | if (!sb) |
242 | if (sb && !(sb->s_flags & MS_RDONLY)) { | 247 | goto out; |
243 | sb->s_frozen = SB_FREEZE_WRITE; | 248 | if (sb->s_flags & MS_RDONLY) { |
244 | smp_wmb(); | 249 | deactivate_locked_super(sb); |
245 | 250 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | |
246 | sync_filesystem(sb); | 251 | return sb; |
247 | 252 | } | |
248 | sb->s_frozen = SB_FREEZE_TRANS; | 253 | |
249 | smp_wmb(); | 254 | sb->s_frozen = SB_FREEZE_WRITE; |
250 | 255 | smp_wmb(); | |
251 | sync_blockdev(sb->s_bdev); | 256 | |
252 | 257 | sync_filesystem(sb); | |
253 | if (sb->s_op->freeze_fs) { | 258 | |
254 | error = sb->s_op->freeze_fs(sb); | 259 | sb->s_frozen = SB_FREEZE_TRANS; |
255 | if (error) { | 260 | smp_wmb(); |
256 | printk(KERN_ERR | 261 | |
257 | "VFS:Filesystem freeze failed\n"); | 262 | sync_blockdev(sb->s_bdev); |
258 | sb->s_frozen = SB_UNFROZEN; | 263 | |
259 | drop_super(sb); | 264 | if (sb->s_op->freeze_fs) { |
260 | bdev->bd_fsfreeze_count--; | 265 | error = sb->s_op->freeze_fs(sb); |
261 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 266 | if (error) { |
262 | return ERR_PTR(error); | 267 | printk(KERN_ERR |
263 | } | 268 | "VFS:Filesystem freeze failed\n"); |
269 | sb->s_frozen = SB_UNFROZEN; | ||
270 | deactivate_locked_super(sb); | ||
271 | bdev->bd_fsfreeze_count--; | ||
272 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
273 | return ERR_PTR(error); | ||
264 | } | 274 | } |
265 | } | 275 | } |
276 | up_write(&sb->s_umount); | ||
266 | 277 | ||
278 | out: | ||
267 | sync_blockdev(bdev); | 279 | sync_blockdev(bdev); |
268 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 280 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
269 | |||
270 | return sb; /* thaw_bdev releases s->s_umount */ | 281 | return sb; /* thaw_bdev releases s->s_umount */ |
271 | } | 282 | } |
272 | EXPORT_SYMBOL(freeze_bdev); | 283 | EXPORT_SYMBOL(freeze_bdev); |
@@ -280,43 +291,44 @@ EXPORT_SYMBOL(freeze_bdev); | |||
280 | */ | 291 | */ |
281 | int thaw_bdev(struct block_device *bdev, struct super_block *sb) | 292 | int thaw_bdev(struct block_device *bdev, struct super_block *sb) |
282 | { | 293 | { |
283 | int error = 0; | 294 | int error = -EINVAL; |
284 | 295 | ||
285 | mutex_lock(&bdev->bd_fsfreeze_mutex); | 296 | mutex_lock(&bdev->bd_fsfreeze_mutex); |
286 | if (!bdev->bd_fsfreeze_count) { | 297 | if (!bdev->bd_fsfreeze_count) |
287 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 298 | goto out_unlock; |
288 | return -EINVAL; | 299 | |
289 | } | 300 | error = 0; |
290 | 301 | if (--bdev->bd_fsfreeze_count > 0) | |
291 | bdev->bd_fsfreeze_count--; | 302 | goto out_unlock; |
292 | if (bdev->bd_fsfreeze_count > 0) { | 303 | |
293 | if (sb) | 304 | if (!sb) |
294 | drop_super(sb); | 305 | goto out_unlock; |
295 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 306 | |
296 | return 0; | 307 | BUG_ON(sb->s_bdev != bdev); |
297 | } | 308 | down_write(&sb->s_umount); |
298 | 309 | if (sb->s_flags & MS_RDONLY) | |
299 | if (sb) { | 310 | goto out_deactivate; |
300 | BUG_ON(sb->s_bdev != bdev); | 311 | |
301 | if (!(sb->s_flags & MS_RDONLY)) { | 312 | if (sb->s_op->unfreeze_fs) { |
302 | if (sb->s_op->unfreeze_fs) { | 313 | error = sb->s_op->unfreeze_fs(sb); |
303 | error = sb->s_op->unfreeze_fs(sb); | 314 | if (error) { |
304 | if (error) { | 315 | printk(KERN_ERR |
305 | printk(KERN_ERR | 316 | "VFS:Filesystem thaw failed\n"); |
306 | "VFS:Filesystem thaw failed\n"); | 317 | sb->s_frozen = SB_FREEZE_TRANS; |
307 | sb->s_frozen = SB_FREEZE_TRANS; | 318 | bdev->bd_fsfreeze_count++; |
308 | bdev->bd_fsfreeze_count++; | 319 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
309 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 320 | return error; |
310 | return error; | ||
311 | } | ||
312 | } | ||
313 | sb->s_frozen = SB_UNFROZEN; | ||
314 | smp_wmb(); | ||
315 | wake_up(&sb->s_wait_unfrozen); | ||
316 | } | 321 | } |
317 | drop_super(sb); | ||
318 | } | 322 | } |
319 | 323 | ||
324 | sb->s_frozen = SB_UNFROZEN; | ||
325 | smp_wmb(); | ||
326 | wake_up(&sb->s_wait_unfrozen); | ||
327 | |||
328 | out_deactivate: | ||
329 | if (sb) | ||
330 | deactivate_locked_super(sb); | ||
331 | out_unlock: | ||
320 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 332 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
321 | return 0; | 333 | return 0; |
322 | } | 334 | } |