Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #include <linux/blkdev.h>
0003 #include <linux/slab.h>
0004 
0005 struct bd_holder_disk {
0006     struct list_head    list;
0007     struct block_device *bdev;
0008     int         refcnt;
0009 };
0010 
0011 static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
0012                           struct gendisk *disk)
0013 {
0014     struct bd_holder_disk *holder;
0015 
0016     list_for_each_entry(holder, &disk->slave_bdevs, list)
0017         if (holder->bdev == bdev)
0018             return holder;
0019     return NULL;
0020 }
0021 
0022 static int add_symlink(struct kobject *from, struct kobject *to)
0023 {
0024     return sysfs_create_link(from, to, kobject_name(to));
0025 }
0026 
0027 static void del_symlink(struct kobject *from, struct kobject *to)
0028 {
0029     sysfs_remove_link(from, kobject_name(to));
0030 }
0031 
0032 static int __link_disk_holder(struct block_device *bdev, struct gendisk *disk)
0033 {
0034     int ret;
0035 
0036     ret = add_symlink(disk->slave_dir, bdev_kobj(bdev));
0037     if (ret)
0038         return ret;
0039     ret = add_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
0040     if (ret)
0041         del_symlink(disk->slave_dir, bdev_kobj(bdev));
0042     return ret;
0043 }
0044 
0045 /**
0046  * bd_link_disk_holder - create symlinks between holding disk and slave bdev
0047  * @bdev: the claimed slave bdev
0048  * @disk: the holding disk
0049  *
0050  * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
0051  *
0052  * This functions creates the following sysfs symlinks.
0053  *
0054  * - from "slaves" directory of the holder @disk to the claimed @bdev
0055  * - from "holders" directory of the @bdev to the holder @disk
0056  *
0057  * For example, if /dev/dm-0 maps to /dev/sda and disk for dm-0 is
0058  * passed to bd_link_disk_holder(), then:
0059  *
0060  *   /sys/block/dm-0/slaves/sda --> /sys/block/sda
0061  *   /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
0062  *
0063  * The caller must have claimed @bdev before calling this function and
0064  * ensure that both @bdev and @disk are valid during the creation and
0065  * lifetime of these symlinks.
0066  *
0067  * CONTEXT:
0068  * Might sleep.
0069  *
0070  * RETURNS:
0071  * 0 on success, -errno on failure.
0072  */
0073 int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
0074 {
0075     struct bd_holder_disk *holder;
0076     int ret = 0;
0077 
0078     mutex_lock(&disk->open_mutex);
0079 
0080     WARN_ON_ONCE(!bdev->bd_holder);
0081 
0082     holder = bd_find_holder_disk(bdev, disk);
0083     if (holder) {
0084         holder->refcnt++;
0085         goto out_unlock;
0086     }
0087 
0088     holder = kzalloc(sizeof(*holder), GFP_KERNEL);
0089     if (!holder) {
0090         ret = -ENOMEM;
0091         goto out_unlock;
0092     }
0093 
0094     INIT_LIST_HEAD(&holder->list);
0095     holder->bdev = bdev;
0096     holder->refcnt = 1;
0097     if (disk->slave_dir) {
0098         ret = __link_disk_holder(bdev, disk);
0099         if (ret) {
0100             kfree(holder);
0101             goto out_unlock;
0102         }
0103     }
0104 
0105     list_add(&holder->list, &disk->slave_bdevs);
0106     /*
0107      * del_gendisk drops the initial reference to bd_holder_dir, so we need
0108      * to keep our own here to allow for cleanup past that point.
0109      */
0110     kobject_get(bdev->bd_holder_dir);
0111 
0112 out_unlock:
0113     mutex_unlock(&disk->open_mutex);
0114     return ret;
0115 }
0116 EXPORT_SYMBOL_GPL(bd_link_disk_holder);
0117 
0118 static void __unlink_disk_holder(struct block_device *bdev,
0119         struct gendisk *disk)
0120 {
0121     del_symlink(disk->slave_dir, bdev_kobj(bdev));
0122     del_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
0123 }
0124 
0125 /**
0126  * bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
0127  * @bdev: the calimed slave bdev
0128  * @disk: the holding disk
0129  *
0130  * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
0131  *
0132  * CONTEXT:
0133  * Might sleep.
0134  */
0135 void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
0136 {
0137     struct bd_holder_disk *holder;
0138 
0139     mutex_lock(&disk->open_mutex);
0140     holder = bd_find_holder_disk(bdev, disk);
0141     if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
0142         if (disk->slave_dir)
0143             __unlink_disk_holder(bdev, disk);
0144         kobject_put(bdev->bd_holder_dir);
0145         list_del_init(&holder->list);
0146         kfree(holder);
0147     }
0148     mutex_unlock(&disk->open_mutex);
0149 }
0150 EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
0151 
0152 int bd_register_pending_holders(struct gendisk *disk)
0153 {
0154     struct bd_holder_disk *holder;
0155     int ret;
0156 
0157     mutex_lock(&disk->open_mutex);
0158     list_for_each_entry(holder, &disk->slave_bdevs, list) {
0159         ret = __link_disk_holder(holder->bdev, disk);
0160         if (ret)
0161             goto out_undo;
0162     }
0163     mutex_unlock(&disk->open_mutex);
0164     return 0;
0165 
0166 out_undo:
0167     list_for_each_entry_continue_reverse(holder, &disk->slave_bdevs, list)
0168         __unlink_disk_holder(holder->bdev, disk);
0169     mutex_unlock(&disk->open_mutex);
0170     return ret;
0171 }