cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

holder.c (4177B)


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