0001
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
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
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
0108
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
0127
0128
0129
0130
0131
0132
0133
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 }