holder.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/blkdev.h>
  3. #include <linux/slab.h>
  4. struct bd_holder_disk {
  5. struct list_head list;
  6. struct kobject *holder_dir;
  7. int refcnt;
  8. };
  9. static DEFINE_MUTEX(blk_holder_mutex);
  10. static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
  11. struct gendisk *disk)
  12. {
  13. struct bd_holder_disk *holder;
  14. list_for_each_entry(holder, &disk->slave_bdevs, list)
  15. if (holder->holder_dir == bdev->bd_holder_dir)
  16. return holder;
  17. return NULL;
  18. }
  19. static int add_symlink(struct kobject *from, struct kobject *to)
  20. {
  21. return sysfs_create_link(from, to, kobject_name(to));
  22. }
  23. static void del_symlink(struct kobject *from, struct kobject *to)
  24. {
  25. sysfs_remove_link(from, kobject_name(to));
  26. }
  27. /**
  28. * bd_link_disk_holder - create symlinks between holding disk and slave bdev
  29. * @bdev: the claimed slave bdev
  30. * @disk: the holding disk
  31. *
  32. * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
  33. *
  34. * This functions creates the following sysfs symlinks.
  35. *
  36. * - from "slaves" directory of the holder @disk to the claimed @bdev
  37. * - from "holders" directory of the @bdev to the holder @disk
  38. *
  39. * For example, if /dev/dm-0 maps to /dev/sda and disk for dm-0 is
  40. * passed to bd_link_disk_holder(), then:
  41. *
  42. * /sys/block/dm-0/slaves/sda --> /sys/block/sda
  43. * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
  44. *
  45. * The caller must have claimed @bdev before calling this function and
  46. * ensure that both @bdev and @disk are valid during the creation and
  47. * lifetime of these symlinks.
  48. *
  49. * CONTEXT:
  50. * Might sleep.
  51. *
  52. * RETURNS:
  53. * 0 on success, -errno on failure.
  54. */
  55. int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
  56. {
  57. struct bd_holder_disk *holder;
  58. int ret = 0;
  59. if (WARN_ON_ONCE(!disk->slave_dir))
  60. return -EINVAL;
  61. if (bdev->bd_disk == disk)
  62. return -EINVAL;
  63. /*
  64. * del_gendisk drops the initial reference to bd_holder_dir, so we
  65. * need to keep our own here to allow for cleanup past that point.
  66. */
  67. mutex_lock(&bdev->bd_disk->open_mutex);
  68. if (!disk_live(bdev->bd_disk)) {
  69. mutex_unlock(&bdev->bd_disk->open_mutex);
  70. return -ENODEV;
  71. }
  72. kobject_get(bdev->bd_holder_dir);
  73. mutex_unlock(&bdev->bd_disk->open_mutex);
  74. mutex_lock(&blk_holder_mutex);
  75. WARN_ON_ONCE(!bdev->bd_holder);
  76. holder = bd_find_holder_disk(bdev, disk);
  77. if (holder) {
  78. kobject_put(bdev->bd_holder_dir);
  79. holder->refcnt++;
  80. goto out_unlock;
  81. }
  82. holder = kzalloc(sizeof(*holder), GFP_KERNEL);
  83. if (!holder) {
  84. ret = -ENOMEM;
  85. goto out_unlock;
  86. }
  87. INIT_LIST_HEAD(&holder->list);
  88. holder->refcnt = 1;
  89. holder->holder_dir = bdev->bd_holder_dir;
  90. ret = add_symlink(disk->slave_dir, bdev_kobj(bdev));
  91. if (ret)
  92. goto out_free_holder;
  93. ret = add_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
  94. if (ret)
  95. goto out_del_symlink;
  96. list_add(&holder->list, &disk->slave_bdevs);
  97. mutex_unlock(&blk_holder_mutex);
  98. return 0;
  99. out_del_symlink:
  100. del_symlink(disk->slave_dir, bdev_kobj(bdev));
  101. out_free_holder:
  102. kfree(holder);
  103. out_unlock:
  104. mutex_unlock(&blk_holder_mutex);
  105. if (ret)
  106. kobject_put(bdev->bd_holder_dir);
  107. return ret;
  108. }
  109. EXPORT_SYMBOL_GPL(bd_link_disk_holder);
  110. /**
  111. * bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
  112. * @bdev: the calimed slave bdev
  113. * @disk: the holding disk
  114. *
  115. * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
  116. *
  117. * CONTEXT:
  118. * Might sleep.
  119. */
  120. void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
  121. {
  122. struct bd_holder_disk *holder;
  123. if (WARN_ON_ONCE(!disk->slave_dir))
  124. return;
  125. mutex_lock(&blk_holder_mutex);
  126. holder = bd_find_holder_disk(bdev, disk);
  127. if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
  128. del_symlink(disk->slave_dir, bdev_kobj(bdev));
  129. del_symlink(holder->holder_dir, &disk_to_dev(disk)->kobj);
  130. kobject_put(holder->holder_dir);
  131. list_del_init(&holder->list);
  132. kfree(holder);
  133. }
  134. mutex_unlock(&blk_holder_mutex);
  135. }
  136. EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);