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.c330
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
325out_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) {
332out_unlock: 287 bdev->bd_fsfreeze_count++;
288 mutex_unlock(&bdev->bd_fsfreeze_mutex);
289 return error;
290 }
291out:
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
671int 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 */
644static 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 */
680static int bd_prepare_to_claim(struct block_device *bdev,
681 struct block_device *whole, void *holder)
682{
683retry:
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 */
723static 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 */
761static 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 */
783static 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 */
805int 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
706EXPORT_SYMBOL(bd_claim); 833EXPORT_SYMBOL(bd_claim);
707 834
708void bd_release(struct block_device *bdev) 835void bd_release(struct block_device *bdev)
@@ -1316,6 +1443,7 @@ EXPORT_SYMBOL(blkdev_get);
1316 1443
1317static int blkdev_open(struct inode * inode, struct file * filp) 1444static 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 */
1565struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder) 1696struct 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
1586blkdev_put: 1722out_blkdev_put:
1587 blkdev_put(bdev, mode); 1723 blkdev_put(bdev, mode);
1724out_abort_claiming:
1725 bd_abort_claiming(whole, holder);
1588 return ERR_PTR(error); 1726 return ERR_PTR(error);
1589} 1727}
1590 1728