diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index b54b0a1b7c68..aaa8301f43f1 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -642,16 +642,38 @@ 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 int find_bd_holder(struct block_device *bdev, struct bd_holder *bo) | ||
655 | { | ||
656 | struct bd_holder *tmp; | ||
657 | |||
658 | list_for_each_entry(tmp, &bdev->bd_holder_list, list) | ||
659 | if (tmp->sdir == bo->sdir) { | ||
660 | tmp->count++; | ||
661 | return tmp; | ||
662 | } | ||
663 | |||
664 | return NULL; | ||
665 | } | ||
666 | |||
667 | /** | ||
645 | * add_bd_holder - create sysfs symlinks for bd_claim() relationship | 668 | * add_bd_holder - create sysfs symlinks for bd_claim() relationship |
646 | * | 669 | * |
647 | * @bdev: block device to be bd_claimed | 670 | * @bdev: block device to be bd_claimed |
648 | * @bo: preallocated and initialized by alloc_bd_holder() | 671 | * @bo: preallocated and initialized by alloc_bd_holder() |
649 | * | 672 | * |
650 | * If there is no matching entry with @bo in @bdev->bd_holder_list, | 673 | * Add @bo to @bdev->bd_holder_list, create symlinks. |
651 | * add @bo to the list, create symlinks. | ||
652 | * | 674 | * |
653 | * Returns 0 if symlinks are created or already there. | 675 | * Returns 0 if symlinks are created. |
654 | * Returns -ve if something fails and @bo can be freed. | 676 | * Returns -ve if something fails. |
655 | */ | 677 | */ |
656 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) | 678 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) |
657 | { | 679 | { |
@@ -661,15 +683,6 @@ static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) | |||
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; |
@@ -752,11 +765,15 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder, | |||
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) { |
757 | bd_release(bdev); | 770 | res = add_bd_holder(bdev, bo); |
771 | if (res) | ||
772 | bd_release(bdev); | ||
773 | } | ||
758 | } | 774 | } |
759 | if (res) | 775 | |
776 | if (res || found) | ||
760 | free_bd_holder(bo); | 777 | free_bd_holder(bo); |
761 | mutex_unlock(&bdev->bd_mutex); | 778 | mutex_unlock(&bdev->bd_mutex); |
762 | 779 | ||