diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index bc8f27cc4483..36c0e7af9d0f 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -642,34 +642,47 @@ static void free_bd_holder(struct bd_holder *bo) | |||
642 | } | 642 | } |
643 | 643 | ||
644 | /** | 644 | /** |
645 | * find_bd_holder - find matching struct bd_holder from the block device | ||
646 | * | ||
647 | * @bdev: struct block device to be searched | ||
648 | * @bo: target struct bd_holder | ||
649 | * | ||
650 | * Returns matching entry with @bo in @bdev->bd_holder_list. | ||
651 | * If found, increment the reference count and return the pointer. | ||
652 | * If not found, returns NULL. | ||
653 | */ | ||
654 | static struct bd_holder *find_bd_holder(struct block_device *bdev, | ||
655 | struct bd_holder *bo) | ||
656 | { | ||
657 | struct bd_holder *tmp; | ||
658 | |||
659 | list_for_each_entry(tmp, &bdev->bd_holder_list, list) | ||
660 | if (tmp->sdir == bo->sdir) { | ||
661 | tmp->count++; | ||
662 | return tmp; | ||
663 | } | ||
664 | |||
665 | return NULL; | ||
666 | } | ||
667 | |||
668 | /** | ||
645 | * add_bd_holder - create sysfs symlinks for bd_claim() relationship | 669 | * add_bd_holder - create sysfs symlinks for bd_claim() relationship |
646 | * | 670 | * |
647 | * @bdev: block device to be bd_claimed | 671 | * @bdev: block device to be bd_claimed |
648 | * @bo: preallocated and initialized by alloc_bd_holder() | 672 | * @bo: preallocated and initialized by alloc_bd_holder() |
649 | * | 673 | * |
650 | * If there is no matching entry with @bo in @bdev->bd_holder_list, | 674 | * Add @bo to @bdev->bd_holder_list, create symlinks. |
651 | * add @bo to the list, create symlinks. | ||
652 | * | 675 | * |
653 | * Returns 0 if symlinks are created or already there. | 676 | * Returns 0 if symlinks are created. |
654 | * Returns -ve if something fails and @bo can be freed. | 677 | * Returns -ve if something fails. |
655 | */ | 678 | */ |
656 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) | 679 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) |
657 | { | 680 | { |
658 | struct bd_holder *tmp; | ||
659 | int ret; | 681 | int ret; |
660 | 682 | ||
661 | if (!bo) | 683 | if (!bo) |
662 | return -EINVAL; | 684 | return -EINVAL; |
663 | 685 | ||
664 | list_for_each_entry(tmp, &bdev->bd_holder_list, list) { | ||
665 | if (tmp->sdir == bo->sdir) { | ||
666 | tmp->count++; | ||
667 | /* We've already done what we need to do here. */ | ||
668 | free_bd_holder(bo); | ||
669 | return 0; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | if (!bd_holder_grab_dirs(bdev, bo)) | 686 | if (!bd_holder_grab_dirs(bdev, bo)) |
674 | return -EBUSY; | 687 | return -EBUSY; |
675 | 688 | ||
@@ -740,7 +753,7 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder, | |||
740 | struct kobject *kobj) | 753 | struct kobject *kobj) |
741 | { | 754 | { |
742 | int res; | 755 | int res; |
743 | struct bd_holder *bo; | 756 | struct bd_holder *bo, *found; |
744 | 757 | ||
745 | if (!kobj) | 758 | if (!kobj) |
746 | return -EINVAL; | 759 | return -EINVAL; |
@@ -751,9 +764,16 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder, | |||
751 | 764 | ||
752 | mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); | 765 | mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); |
753 | res = bd_claim(bdev, holder); | 766 | res = bd_claim(bdev, holder); |
754 | if (res == 0) | 767 | if (res == 0) { |
755 | res = add_bd_holder(bdev, bo); | 768 | found = find_bd_holder(bdev, bo); |
756 | if (res) | 769 | if (found == NULL) { |
770 | res = add_bd_holder(bdev, bo); | ||
771 | if (res) | ||
772 | bd_release(bdev); | ||
773 | } | ||
774 | } | ||
775 | |||
776 | if (res || found) | ||
757 | free_bd_holder(bo); | 777 | free_bd_holder(bo); |
758 | mutex_unlock(&bdev->bd_mutex); | 778 | mutex_unlock(&bdev->bd_mutex); |
759 | 779 | ||
@@ -1131,6 +1151,8 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
1131 | filp->f_flags |= O_LARGEFILE; | 1151 | filp->f_flags |= O_LARGEFILE; |
1132 | 1152 | ||
1133 | bdev = bd_acquire(inode); | 1153 | bdev = bd_acquire(inode); |
1154 | if (bdev == NULL) | ||
1155 | return -ENOMEM; | ||
1134 | 1156 | ||
1135 | res = do_open(bdev, filp, BD_MUTEX_NORMAL); | 1157 | res = do_open(bdev, filp, BD_MUTEX_NORMAL); |
1136 | if (res) | 1158 | if (res) |