diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 330 |
1 files changed, 234 insertions, 96 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 6dcee88c2e5d..26e5f5026620 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -245,37 +245,14 @@ struct super_block *freeze_bdev(struct block_device *bdev) | |||
245 | sb = get_active_super(bdev); | 245 | sb = get_active_super(bdev); |
246 | if (!sb) | 246 | if (!sb) |
247 | goto out; | 247 | goto out; |
248 | if (sb->s_flags & MS_RDONLY) { | 248 | error = freeze_super(sb); |
249 | sb->s_frozen = SB_FREEZE_TRANS; | 249 | if (error) { |
250 | up_write(&sb->s_umount); | 250 | deactivate_super(sb); |
251 | bdev->bd_fsfreeze_count--; | ||
251 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 252 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
252 | return sb; | 253 | return ERR_PTR(error); |
253 | } | ||
254 | |||
255 | sb->s_frozen = SB_FREEZE_WRITE; | ||
256 | smp_wmb(); | ||
257 | |||
258 | sync_filesystem(sb); | ||
259 | |||
260 | sb->s_frozen = SB_FREEZE_TRANS; | ||
261 | smp_wmb(); | ||
262 | |||
263 | sync_blockdev(sb->s_bdev); | ||
264 | |||
265 | if (sb->s_op->freeze_fs) { | ||
266 | error = sb->s_op->freeze_fs(sb); | ||
267 | if (error) { | ||
268 | printk(KERN_ERR | ||
269 | "VFS:Filesystem freeze failed\n"); | ||
270 | sb->s_frozen = SB_UNFROZEN; | ||
271 | deactivate_locked_super(sb); | ||
272 | bdev->bd_fsfreeze_count--; | ||
273 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
274 | return ERR_PTR(error); | ||
275 | } | ||
276 | } | 254 | } |
277 | up_write(&sb->s_umount); | 255 | deactivate_super(sb); |
278 | |||
279 | out: | 256 | out: |
280 | sync_blockdev(bdev); | 257 | sync_blockdev(bdev); |
281 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 258 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
@@ -296,40 +273,22 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb) | |||
296 | 273 | ||
297 | mutex_lock(&bdev->bd_fsfreeze_mutex); | 274 | mutex_lock(&bdev->bd_fsfreeze_mutex); |
298 | if (!bdev->bd_fsfreeze_count) | 275 | if (!bdev->bd_fsfreeze_count) |
299 | goto out_unlock; | 276 | goto out; |
300 | 277 | ||
301 | error = 0; | 278 | error = 0; |
302 | if (--bdev->bd_fsfreeze_count > 0) | 279 | if (--bdev->bd_fsfreeze_count > 0) |
303 | goto out_unlock; | 280 | goto out; |
304 | 281 | ||
305 | if (!sb) | 282 | if (!sb) |
306 | goto out_unlock; | 283 | goto out; |
307 | |||
308 | BUG_ON(sb->s_bdev != bdev); | ||
309 | down_write(&sb->s_umount); | ||
310 | if (sb->s_flags & MS_RDONLY) | ||
311 | goto out_unfrozen; | ||
312 | |||
313 | if (sb->s_op->unfreeze_fs) { | ||
314 | error = sb->s_op->unfreeze_fs(sb); | ||
315 | if (error) { | ||
316 | printk(KERN_ERR | ||
317 | "VFS:Filesystem thaw failed\n"); | ||
318 | sb->s_frozen = SB_FREEZE_TRANS; | ||
319 | bdev->bd_fsfreeze_count++; | ||
320 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
321 | return error; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | out_unfrozen: | ||
326 | sb->s_frozen = SB_UNFROZEN; | ||
327 | smp_wmb(); | ||
328 | wake_up(&sb->s_wait_unfrozen); | ||
329 | 284 | ||
330 | if (sb) | 285 | error = thaw_super(sb); |
331 | deactivate_locked_super(sb); | 286 | if (error) { |
332 | out_unlock: | 287 | bdev->bd_fsfreeze_count++; |
288 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
289 | return error; | ||
290 | } | ||
291 | out: | ||
333 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 292 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
334 | return 0; | 293 | return 0; |
335 | } | 294 | } |
@@ -417,7 +376,7 @@ int blkdev_fsync(struct file *filp, struct dentry *dentry, int datasync) | |||
417 | */ | 376 | */ |
418 | mutex_unlock(&bd_inode->i_mutex); | 377 | mutex_unlock(&bd_inode->i_mutex); |
419 | 378 | ||
420 | error = blkdev_issue_flush(bdev, NULL); | 379 | error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL, BLKDEV_IFL_WAIT); |
421 | if (error == -EOPNOTSUPP) | 380 | if (error == -EOPNOTSUPP) |
422 | error = 0; | 381 | error = 0; |
423 | 382 | ||
@@ -668,41 +627,209 @@ void bd_forget(struct inode *inode) | |||
668 | iput(bdev->bd_inode); | 627 | iput(bdev->bd_inode); |
669 | } | 628 | } |
670 | 629 | ||
671 | int bd_claim(struct block_device *bdev, void *holder) | 630 | /** |
631 | * bd_may_claim - test whether a block device can be claimed | ||
632 | * @bdev: block device of interest | ||
633 | * @whole: whole block device containing @bdev, may equal @bdev | ||
634 | * @holder: holder trying to claim @bdev | ||
635 | * | ||
636 | * Test whther @bdev can be claimed by @holder. | ||
637 | * | ||
638 | * CONTEXT: | ||
639 | * spin_lock(&bdev_lock). | ||
640 | * | ||
641 | * RETURNS: | ||
642 | * %true if @bdev can be claimed, %false otherwise. | ||
643 | */ | ||
644 | static bool bd_may_claim(struct block_device *bdev, struct block_device *whole, | ||
645 | void *holder) | ||
672 | { | 646 | { |
673 | int res; | ||
674 | spin_lock(&bdev_lock); | ||
675 | |||
676 | /* first decide result */ | ||
677 | if (bdev->bd_holder == holder) | 647 | if (bdev->bd_holder == holder) |
678 | res = 0; /* already a holder */ | 648 | return true; /* already a holder */ |
679 | else if (bdev->bd_holder != NULL) | 649 | else if (bdev->bd_holder != NULL) |
680 | res = -EBUSY; /* held by someone else */ | 650 | return false; /* held by someone else */ |
681 | else if (bdev->bd_contains == bdev) | 651 | else if (bdev->bd_contains == bdev) |
682 | res = 0; /* is a whole device which isn't held */ | 652 | return true; /* is a whole device which isn't held */ |
683 | 653 | ||
684 | else if (bdev->bd_contains->bd_holder == bd_claim) | 654 | else if (whole->bd_holder == bd_claim) |
685 | res = 0; /* is a partition of a device that is being partitioned */ | 655 | return true; /* is a partition of a device that is being partitioned */ |
686 | else if (bdev->bd_contains->bd_holder != NULL) | 656 | else if (whole->bd_holder != NULL) |
687 | res = -EBUSY; /* is a partition of a held device */ | 657 | return false; /* is a partition of a held device */ |
688 | else | 658 | else |
689 | res = 0; /* is a partition of an un-held device */ | 659 | return true; /* is a partition of an un-held device */ |
660 | } | ||
661 | |||
662 | /** | ||
663 | * bd_prepare_to_claim - prepare to claim a block device | ||
664 | * @bdev: block device of interest | ||
665 | * @whole: the whole device containing @bdev, may equal @bdev | ||
666 | * @holder: holder trying to claim @bdev | ||
667 | * | ||
668 | * Prepare to claim @bdev. This function fails if @bdev is already | ||
669 | * claimed by another holder and waits if another claiming is in | ||
670 | * progress. This function doesn't actually claim. On successful | ||
671 | * return, the caller has ownership of bd_claiming and bd_holder[s]. | ||
672 | * | ||
673 | * CONTEXT: | ||
674 | * spin_lock(&bdev_lock). Might release bdev_lock, sleep and regrab | ||
675 | * it multiple times. | ||
676 | * | ||
677 | * RETURNS: | ||
678 | * 0 if @bdev can be claimed, -EBUSY otherwise. | ||
679 | */ | ||
680 | static int bd_prepare_to_claim(struct block_device *bdev, | ||
681 | struct block_device *whole, void *holder) | ||
682 | { | ||
683 | retry: | ||
684 | /* if someone else claimed, fail */ | ||
685 | if (!bd_may_claim(bdev, whole, holder)) | ||
686 | return -EBUSY; | ||
687 | |||
688 | /* if someone else is claiming, wait for it to finish */ | ||
689 | if (whole->bd_claiming && whole->bd_claiming != holder) { | ||
690 | wait_queue_head_t *wq = bit_waitqueue(&whole->bd_claiming, 0); | ||
691 | DEFINE_WAIT(wait); | ||
692 | |||
693 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); | ||
694 | spin_unlock(&bdev_lock); | ||
695 | schedule(); | ||
696 | finish_wait(wq, &wait); | ||
697 | spin_lock(&bdev_lock); | ||
698 | goto retry; | ||
699 | } | ||
700 | |||
701 | /* yay, all mine */ | ||
702 | return 0; | ||
703 | } | ||
690 | 704 | ||
691 | /* now impose change */ | 705 | /** |
692 | if (res==0) { | 706 | * bd_start_claiming - start claiming a block device |
707 | * @bdev: block device of interest | ||
708 | * @holder: holder trying to claim @bdev | ||
709 | * | ||
710 | * @bdev is about to be opened exclusively. Check @bdev can be opened | ||
711 | * exclusively and mark that an exclusive open is in progress. Each | ||
712 | * successful call to this function must be matched with a call to | ||
713 | * either bd_claim() or bd_abort_claiming(). If this function | ||
714 | * succeeds, the matching bd_claim() is guaranteed to succeed. | ||
715 | * | ||
716 | * CONTEXT: | ||
717 | * Might sleep. | ||
718 | * | ||
719 | * RETURNS: | ||
720 | * Pointer to the block device containing @bdev on success, ERR_PTR() | ||
721 | * value on failure. | ||
722 | */ | ||
723 | static struct block_device *bd_start_claiming(struct block_device *bdev, | ||
724 | void *holder) | ||
725 | { | ||
726 | struct gendisk *disk; | ||
727 | struct block_device *whole; | ||
728 | int partno, err; | ||
729 | |||
730 | might_sleep(); | ||
731 | |||
732 | /* | ||
733 | * @bdev might not have been initialized properly yet, look up | ||
734 | * and grab the outer block device the hard way. | ||
735 | */ | ||
736 | disk = get_gendisk(bdev->bd_dev, &partno); | ||
737 | if (!disk) | ||
738 | return ERR_PTR(-ENXIO); | ||
739 | |||
740 | whole = bdget_disk(disk, 0); | ||
741 | put_disk(disk); | ||
742 | if (!whole) | ||
743 | return ERR_PTR(-ENOMEM); | ||
744 | |||
745 | /* prepare to claim, if successful, mark claiming in progress */ | ||
746 | spin_lock(&bdev_lock); | ||
747 | |||
748 | err = bd_prepare_to_claim(bdev, whole, holder); | ||
749 | if (err == 0) { | ||
750 | whole->bd_claiming = holder; | ||
751 | spin_unlock(&bdev_lock); | ||
752 | return whole; | ||
753 | } else { | ||
754 | spin_unlock(&bdev_lock); | ||
755 | bdput(whole); | ||
756 | return ERR_PTR(err); | ||
757 | } | ||
758 | } | ||
759 | |||
760 | /* releases bdev_lock */ | ||
761 | static void __bd_abort_claiming(struct block_device *whole, void *holder) | ||
762 | { | ||
763 | BUG_ON(whole->bd_claiming != holder); | ||
764 | whole->bd_claiming = NULL; | ||
765 | wake_up_bit(&whole->bd_claiming, 0); | ||
766 | |||
767 | spin_unlock(&bdev_lock); | ||
768 | bdput(whole); | ||
769 | } | ||
770 | |||
771 | /** | ||
772 | * bd_abort_claiming - abort claiming a block device | ||
773 | * @whole: whole block device returned by bd_start_claiming() | ||
774 | * @holder: holder trying to claim @bdev | ||
775 | * | ||
776 | * Abort a claiming block started by bd_start_claiming(). Note that | ||
777 | * @whole is not the block device to be claimed but the whole device | ||
778 | * returned by bd_start_claiming(). | ||
779 | * | ||
780 | * CONTEXT: | ||
781 | * Grabs and releases bdev_lock. | ||
782 | */ | ||
783 | static void bd_abort_claiming(struct block_device *whole, void *holder) | ||
784 | { | ||
785 | spin_lock(&bdev_lock); | ||
786 | __bd_abort_claiming(whole, holder); /* releases bdev_lock */ | ||
787 | } | ||
788 | |||
789 | /** | ||
790 | * bd_claim - claim a block device | ||
791 | * @bdev: block device to claim | ||
792 | * @holder: holder trying to claim @bdev | ||
793 | * | ||
794 | * Try to claim @bdev which must have been opened successfully. This | ||
795 | * function may be called with or without preceding | ||
796 | * blk_start_claiming(). In the former case, this function is always | ||
797 | * successful and terminates the claiming block. | ||
798 | * | ||
799 | * CONTEXT: | ||
800 | * Might sleep. | ||
801 | * | ||
802 | * RETURNS: | ||
803 | * 0 if successful, -EBUSY if @bdev is already claimed. | ||
804 | */ | ||
805 | int bd_claim(struct block_device *bdev, void *holder) | ||
806 | { | ||
807 | struct block_device *whole = bdev->bd_contains; | ||
808 | int res; | ||
809 | |||
810 | might_sleep(); | ||
811 | |||
812 | spin_lock(&bdev_lock); | ||
813 | |||
814 | res = bd_prepare_to_claim(bdev, whole, holder); | ||
815 | if (res == 0) { | ||
693 | /* note that for a whole device bd_holders | 816 | /* note that for a whole device bd_holders |
694 | * will be incremented twice, and bd_holder will | 817 | * will be incremented twice, and bd_holder will |
695 | * be set to bd_claim before being set to holder | 818 | * be set to bd_claim before being set to holder |
696 | */ | 819 | */ |
697 | bdev->bd_contains->bd_holders ++; | 820 | whole->bd_holders++; |
698 | bdev->bd_contains->bd_holder = bd_claim; | 821 | whole->bd_holder = bd_claim; |
699 | bdev->bd_holders++; | 822 | bdev->bd_holders++; |
700 | bdev->bd_holder = holder; | 823 | bdev->bd_holder = holder; |
701 | } | 824 | } |
702 | spin_unlock(&bdev_lock); | 825 | |
826 | if (whole->bd_claiming) | ||
827 | __bd_abort_claiming(whole, holder); /* releases bdev_lock */ | ||
828 | else | ||
829 | spin_unlock(&bdev_lock); | ||
830 | |||
703 | return res; | 831 | return res; |
704 | } | 832 | } |
705 | |||
706 | EXPORT_SYMBOL(bd_claim); | 833 | EXPORT_SYMBOL(bd_claim); |
707 | 834 | ||
708 | void bd_release(struct block_device *bdev) | 835 | void bd_release(struct block_device *bdev) |
@@ -1316,6 +1443,7 @@ EXPORT_SYMBOL(blkdev_get); | |||
1316 | 1443 | ||
1317 | static int blkdev_open(struct inode * inode, struct file * filp) | 1444 | static int blkdev_open(struct inode * inode, struct file * filp) |
1318 | { | 1445 | { |
1446 | struct block_device *whole = NULL; | ||
1319 | struct block_device *bdev; | 1447 | struct block_device *bdev; |
1320 | int res; | 1448 | int res; |
1321 | 1449 | ||
@@ -1338,22 +1466,25 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
1338 | if (bdev == NULL) | 1466 | if (bdev == NULL) |
1339 | return -ENOMEM; | 1467 | return -ENOMEM; |
1340 | 1468 | ||
1469 | if (filp->f_mode & FMODE_EXCL) { | ||
1470 | whole = bd_start_claiming(bdev, filp); | ||
1471 | if (IS_ERR(whole)) { | ||
1472 | bdput(bdev); | ||
1473 | return PTR_ERR(whole); | ||
1474 | } | ||
1475 | } | ||
1476 | |||
1341 | filp->f_mapping = bdev->bd_inode->i_mapping; | 1477 | filp->f_mapping = bdev->bd_inode->i_mapping; |
1342 | 1478 | ||
1343 | res = blkdev_get(bdev, filp->f_mode); | 1479 | res = blkdev_get(bdev, filp->f_mode); |
1344 | if (res) | ||
1345 | return res; | ||
1346 | 1480 | ||
1347 | if (filp->f_mode & FMODE_EXCL) { | 1481 | if (whole) { |
1348 | res = bd_claim(bdev, filp); | 1482 | if (res == 0) |
1349 | if (res) | 1483 | BUG_ON(bd_claim(bdev, filp) != 0); |
1350 | goto out_blkdev_put; | 1484 | else |
1485 | bd_abort_claiming(whole, filp); | ||
1351 | } | 1486 | } |
1352 | 1487 | ||
1353 | return 0; | ||
1354 | |||
1355 | out_blkdev_put: | ||
1356 | blkdev_put(bdev, filp->f_mode); | ||
1357 | return res; | 1488 | return res; |
1358 | } | 1489 | } |
1359 | 1490 | ||
@@ -1564,27 +1695,34 @@ EXPORT_SYMBOL(lookup_bdev); | |||
1564 | */ | 1695 | */ |
1565 | struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder) | 1696 | struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder) |
1566 | { | 1697 | { |
1567 | struct block_device *bdev; | 1698 | struct block_device *bdev, *whole; |
1568 | int error = 0; | 1699 | int error; |
1569 | 1700 | ||
1570 | bdev = lookup_bdev(path); | 1701 | bdev = lookup_bdev(path); |
1571 | if (IS_ERR(bdev)) | 1702 | if (IS_ERR(bdev)) |
1572 | return bdev; | 1703 | return bdev; |
1573 | 1704 | ||
1705 | whole = bd_start_claiming(bdev, holder); | ||
1706 | if (IS_ERR(whole)) { | ||
1707 | bdput(bdev); | ||
1708 | return whole; | ||
1709 | } | ||
1710 | |||
1574 | error = blkdev_get(bdev, mode); | 1711 | error = blkdev_get(bdev, mode); |
1575 | if (error) | 1712 | if (error) |
1576 | return ERR_PTR(error); | 1713 | goto out_abort_claiming; |
1714 | |||
1577 | error = -EACCES; | 1715 | error = -EACCES; |
1578 | if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) | 1716 | if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) |
1579 | goto blkdev_put; | 1717 | goto out_blkdev_put; |
1580 | error = bd_claim(bdev, holder); | ||
1581 | if (error) | ||
1582 | goto blkdev_put; | ||
1583 | 1718 | ||
1719 | BUG_ON(bd_claim(bdev, holder) != 0); | ||
1584 | return bdev; | 1720 | return bdev; |
1585 | 1721 | ||
1586 | blkdev_put: | 1722 | out_blkdev_put: |
1587 | blkdev_put(bdev, mode); | 1723 | blkdev_put(bdev, mode); |
1724 | out_abort_claiming: | ||
1725 | bd_abort_claiming(whole, holder); | ||
1588 | return ERR_PTR(error); | 1726 | return ERR_PTR(error); |
1589 | } | 1727 | } |
1590 | 1728 | ||