diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 140 |
1 files changed, 73 insertions, 67 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 5d1ed50bd46c..9cf4b926f8e4 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -216,8 +216,6 @@ EXPORT_SYMBOL(fsync_bdev); | |||
216 | * freeze_bdev -- lock a filesystem and force it into a consistent state | 216 | * freeze_bdev -- lock a filesystem and force it into a consistent state |
217 | * @bdev: blockdevice to lock | 217 | * @bdev: blockdevice to lock |
218 | * | 218 | * |
219 | * This takes the block device bd_mount_sem to make sure no new mounts | ||
220 | * happen on bdev until thaw_bdev() is called. | ||
221 | * If a superblock is found on this device, we take the s_umount semaphore | 219 | * If a superblock is found on this device, we take the s_umount semaphore |
222 | * on it to make sure nobody unmounts until the snapshot creation is done. | 220 | * on it to make sure nobody unmounts until the snapshot creation is done. |
223 | * The reference counter (bd_fsfreeze_count) guarantees that only the last | 221 | * The reference counter (bd_fsfreeze_count) guarantees that only the last |
@@ -232,46 +230,55 @@ struct super_block *freeze_bdev(struct block_device *bdev) | |||
232 | int error = 0; | 230 | int error = 0; |
233 | 231 | ||
234 | mutex_lock(&bdev->bd_fsfreeze_mutex); | 232 | mutex_lock(&bdev->bd_fsfreeze_mutex); |
235 | if (bdev->bd_fsfreeze_count > 0) { | 233 | if (++bdev->bd_fsfreeze_count > 1) { |
236 | 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 | */ | ||
237 | sb = get_super(bdev); | 239 | sb = get_super(bdev); |
240 | drop_super(sb); | ||
238 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 241 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
239 | return sb; | 242 | return sb; |
240 | } | 243 | } |
241 | bdev->bd_fsfreeze_count++; | 244 | |
242 | 245 | sb = get_active_super(bdev); | |
243 | down(&bdev->bd_mount_sem); | 246 | if (!sb) |
244 | sb = get_super(bdev); | 247 | goto out; |
245 | if (sb && !(sb->s_flags & MS_RDONLY)) { | 248 | if (sb->s_flags & MS_RDONLY) { |
246 | sb->s_frozen = SB_FREEZE_WRITE; | 249 | deactivate_locked_super(sb); |
247 | smp_wmb(); | 250 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
248 | 251 | return sb; | |
249 | sync_filesystem(sb); | 252 | } |
250 | 253 | ||
251 | sb->s_frozen = SB_FREEZE_TRANS; | 254 | sb->s_frozen = SB_FREEZE_WRITE; |
252 | smp_wmb(); | 255 | smp_wmb(); |
253 | 256 | ||
254 | sync_blockdev(sb->s_bdev); | 257 | sync_filesystem(sb); |
255 | 258 | ||
256 | if (sb->s_op->freeze_fs) { | 259 | sb->s_frozen = SB_FREEZE_TRANS; |
257 | error = sb->s_op->freeze_fs(sb); | 260 | smp_wmb(); |
258 | if (error) { | 261 | |
259 | printk(KERN_ERR | 262 | sync_blockdev(sb->s_bdev); |
260 | "VFS:Filesystem freeze failed\n"); | 263 | |
261 | sb->s_frozen = SB_UNFROZEN; | 264 | if (sb->s_op->freeze_fs) { |
262 | drop_super(sb); | 265 | error = sb->s_op->freeze_fs(sb); |
263 | up(&bdev->bd_mount_sem); | 266 | if (error) { |
264 | bdev->bd_fsfreeze_count--; | 267 | printk(KERN_ERR |
265 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 268 | "VFS:Filesystem freeze failed\n"); |
266 | return ERR_PTR(error); | 269 | sb->s_frozen = SB_UNFROZEN; |
267 | } | 270 | deactivate_locked_super(sb); |
271 | bdev->bd_fsfreeze_count--; | ||
272 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
273 | return ERR_PTR(error); | ||
268 | } | 274 | } |
269 | } | 275 | } |
276 | up_write(&sb->s_umount); | ||
270 | 277 | ||
278 | out: | ||
271 | sync_blockdev(bdev); | 279 | sync_blockdev(bdev); |
272 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 280 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
273 | 281 | return sb; /* thaw_bdev releases s->s_umount */ | |
274 | return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */ | ||
275 | } | 282 | } |
276 | EXPORT_SYMBOL(freeze_bdev); | 283 | EXPORT_SYMBOL(freeze_bdev); |
277 | 284 | ||
@@ -284,44 +291,44 @@ EXPORT_SYMBOL(freeze_bdev); | |||
284 | */ | 291 | */ |
285 | int thaw_bdev(struct block_device *bdev, struct super_block *sb) | 292 | int thaw_bdev(struct block_device *bdev, struct super_block *sb) |
286 | { | 293 | { |
287 | int error = 0; | 294 | int error = -EINVAL; |
288 | 295 | ||
289 | mutex_lock(&bdev->bd_fsfreeze_mutex); | 296 | mutex_lock(&bdev->bd_fsfreeze_mutex); |
290 | if (!bdev->bd_fsfreeze_count) { | 297 | if (!bdev->bd_fsfreeze_count) |
291 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 298 | goto out_unlock; |
292 | return -EINVAL; | 299 | |
293 | } | 300 | error = 0; |
294 | 301 | if (--bdev->bd_fsfreeze_count > 0) | |
295 | bdev->bd_fsfreeze_count--; | 302 | goto out_unlock; |
296 | if (bdev->bd_fsfreeze_count > 0) { | 303 | |
297 | if (sb) | 304 | if (!sb) |
298 | drop_super(sb); | 305 | goto out_unlock; |
299 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 306 | |
300 | return 0; | 307 | BUG_ON(sb->s_bdev != bdev); |
301 | } | 308 | down_write(&sb->s_umount); |
302 | 309 | if (sb->s_flags & MS_RDONLY) | |
303 | if (sb) { | 310 | goto out_deactivate; |
304 | BUG_ON(sb->s_bdev != bdev); | 311 | |
305 | if (!(sb->s_flags & MS_RDONLY)) { | 312 | if (sb->s_op->unfreeze_fs) { |
306 | if (sb->s_op->unfreeze_fs) { | 313 | error = sb->s_op->unfreeze_fs(sb); |
307 | error = sb->s_op->unfreeze_fs(sb); | 314 | if (error) { |
308 | if (error) { | 315 | printk(KERN_ERR |
309 | printk(KERN_ERR | 316 | "VFS:Filesystem thaw failed\n"); |
310 | "VFS:Filesystem thaw failed\n"); | 317 | sb->s_frozen = SB_FREEZE_TRANS; |
311 | sb->s_frozen = SB_FREEZE_TRANS; | 318 | bdev->bd_fsfreeze_count++; |
312 | bdev->bd_fsfreeze_count++; | 319 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
313 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 320 | return error; |
314 | return error; | ||
315 | } | ||
316 | } | ||
317 | sb->s_frozen = SB_UNFROZEN; | ||
318 | smp_wmb(); | ||
319 | wake_up(&sb->s_wait_unfrozen); | ||
320 | } | 321 | } |
321 | drop_super(sb); | ||
322 | } | 322 | } |
323 | 323 | ||
324 | up(&bdev->bd_mount_sem); | 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: | ||
325 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 332 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
326 | return 0; | 333 | return 0; |
327 | } | 334 | } |
@@ -430,7 +437,6 @@ static void init_once(void *foo) | |||
430 | 437 | ||
431 | memset(bdev, 0, sizeof(*bdev)); | 438 | memset(bdev, 0, sizeof(*bdev)); |
432 | mutex_init(&bdev->bd_mutex); | 439 | mutex_init(&bdev->bd_mutex); |
433 | sema_init(&bdev->bd_mount_sem, 1); | ||
434 | INIT_LIST_HEAD(&bdev->bd_inodes); | 440 | INIT_LIST_HEAD(&bdev->bd_inodes); |
435 | INIT_LIST_HEAD(&bdev->bd_list); | 441 | INIT_LIST_HEAD(&bdev->bd_list); |
436 | #ifdef CONFIG_SYSFS | 442 | #ifdef CONFIG_SYSFS |