aboutsummaryrefslogtreecommitdiffstats
path: root/fs/block_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r--fs/block_dev.c174
1 files changed, 103 insertions, 71 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 94dfda24c06e..8bed0557d88c 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}
276EXPORT_SYMBOL(freeze_bdev); 283EXPORT_SYMBOL(freeze_bdev);
277 284
@@ -284,44 +291,44 @@ EXPORT_SYMBOL(freeze_bdev);
284 */ 291 */
285int thaw_bdev(struct block_device *bdev, struct super_block *sb) 292int 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
328out_deactivate:
329 if (sb)
330 deactivate_locked_super(sb);
331out_unlock:
325 mutex_unlock(&bdev->bd_fsfreeze_mutex); 332 mutex_unlock(&bdev->bd_fsfreeze_mutex);
326 return 0; 333 return 0;
327} 334}
@@ -420,7 +427,6 @@ static void bdev_destroy_inode(struct inode *inode)
420{ 427{
421 struct bdev_inode *bdi = BDEV_I(inode); 428 struct bdev_inode *bdi = BDEV_I(inode);
422 429
423 bdi->bdev.bd_inode_backing_dev_info = NULL;
424 kmem_cache_free(bdev_cachep, bdi); 430 kmem_cache_free(bdev_cachep, bdi);
425} 431}
426 432
@@ -431,7 +437,6 @@ static void init_once(void *foo)
431 437
432 memset(bdev, 0, sizeof(*bdev)); 438 memset(bdev, 0, sizeof(*bdev));
433 mutex_init(&bdev->bd_mutex); 439 mutex_init(&bdev->bd_mutex);
434 sema_init(&bdev->bd_mount_sem, 1);
435 INIT_LIST_HEAD(&bdev->bd_inodes); 440 INIT_LIST_HEAD(&bdev->bd_inodes);
436 INIT_LIST_HEAD(&bdev->bd_list); 441 INIT_LIST_HEAD(&bdev->bd_list);
437#ifdef CONFIG_SYSFS 442#ifdef CONFIG_SYSFS
@@ -1115,7 +1120,7 @@ EXPORT_SYMBOL(revalidate_disk);
1115int check_disk_change(struct block_device *bdev) 1120int check_disk_change(struct block_device *bdev)
1116{ 1121{
1117 struct gendisk *disk = bdev->bd_disk; 1122 struct gendisk *disk = bdev->bd_disk;
1118 struct block_device_operations * bdops = disk->fops; 1123 const struct block_device_operations *bdops = disk->fops;
1119 1124
1120 if (!bdops->media_changed) 1125 if (!bdops->media_changed)
1121 return 0; 1126 return 0;
@@ -1243,8 +1248,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
1243 bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9); 1248 bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
1244 } 1249 }
1245 } else { 1250 } else {
1246 put_disk(disk);
1247 module_put(disk->fops->owner); 1251 module_put(disk->fops->owner);
1252 put_disk(disk);
1248 disk = NULL; 1253 disk = NULL;
1249 if (bdev->bd_contains == bdev) { 1254 if (bdev->bd_contains == bdev) {
1250 if (bdev->bd_disk->fops->open) { 1255 if (bdev->bd_disk->fops->open) {
@@ -1405,6 +1410,33 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
1405} 1410}
1406 1411
1407/* 1412/*
1413 * Write data to the block device. Only intended for the block device itself
1414 * and the raw driver which basically is a fake block device.
1415 *
1416 * Does not take i_mutex for the write and thus is not for general purpose
1417 * use.
1418 */
1419ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
1420 unsigned long nr_segs, loff_t pos)
1421{
1422 struct file *file = iocb->ki_filp;
1423 ssize_t ret;
1424
1425 BUG_ON(iocb->ki_pos != pos);
1426
1427 ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
1428 if (ret > 0 || ret == -EIOCBQUEUED) {
1429 ssize_t err;
1430
1431 err = generic_write_sync(file, pos, ret);
1432 if (err < 0 && ret > 0)
1433 ret = err;
1434 }
1435 return ret;
1436}
1437EXPORT_SYMBOL_GPL(blkdev_aio_write);
1438
1439/*
1408 * Try to release a page associated with block device when the system 1440 * Try to release a page associated with block device when the system
1409 * is under memory pressure. 1441 * is under memory pressure.
1410 */ 1442 */
@@ -1436,7 +1468,7 @@ const struct file_operations def_blk_fops = {
1436 .read = do_sync_read, 1468 .read = do_sync_read,
1437 .write = do_sync_write, 1469 .write = do_sync_write,
1438 .aio_read = generic_file_aio_read, 1470 .aio_read = generic_file_aio_read,
1439 .aio_write = generic_file_aio_write_nolock, 1471 .aio_write = blkdev_aio_write,
1440 .mmap = generic_file_mmap, 1472 .mmap = generic_file_mmap,
1441 .fsync = block_fsync, 1473 .fsync = block_fsync,
1442 .unlocked_ioctl = block_ioctl, 1474 .unlocked_ioctl = block_ioctl,