lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 15 Dec 2022 01:45:34 -0800
From:   Christoph Hellwig <hch@...radead.org>
To:     Sergei Shtepa <sergei.shtepa@...am.com>
Cc:     axboe@...nel.dk, corbet@....net, linux-block@...r.kernel.org,
        linux-doc@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v2 17/21] block, blksnap: snapshot image block device

On Fri, Dec 09, 2022 at 03:23:27PM +0100, Sergei Shtepa wrote:
> +static int snapimage_kthread_worker_fn(void *param);

Any chance to order th code so that you can avoid forward declarations
wherever possible.

> +static inline int snapimage_start_worker(struct snapimage *snapimage)
> +{
> +	struct task_struct *task;
> +
> +	spin_lock_init(&snapimage->queue_lock);
> +	bio_list_init(&snapimage->queue);
> +
> +	task = kthread_create(snapimage_kthread_worker_fn,
> +			      snapimage,
> +			      BLK_SNAP_IMAGE_NAME "%d",
> +			      MINOR(snapimage->image_dev_id));
> +	if (IS_ERR(task))
> +		return -ENOMEM;
> +
> +	snapimage->worker = get_task_struct(task);

There's not need to grab and put an extra reference to the task_struct,
the kthread code already holds one.

> +	while (!kthread_should_stop()) {
> +		bio = get_bio_from_queue(snapimage);
> +		if (!bio) {
> +			schedule_timeout_interruptible(HZ / 100);

Do you need a timeout sleep here?  All new arrivals should properly
wake the thread.

> +			continue;
> +		}
> +
> +		snapimage_process_bio(snapimage, bio);
> +	}
> +
> +	while ((bio = get_bio_from_queue(snapimage)))
> +		snapimage_process_bio(snapimage, bio);

It seems like the loop could be simplified to:

	for (;; {
		while ((bio = get_bio_from_queue(snapimage)))
			snapimage_process_bio(snapimage, bio);
		if (kthread_should_stop())
			break;
		schedule();
	}

	return 0;


> +static void snapimage_submit_bio(struct bio *bio)
> +{
> +	struct snapimage *snapimage = bio->bi_bdev->bd_disk->private_data;
> +	gfp_t gfp = GFP_NOIO;
> +
> +	if (bio->bi_opf & REQ_NOWAIT)
> +		gfp |= GFP_NOWAIT;

gfp isn't actually used anywhere.

> +	if (snapimage->is_ready) {
> +		spin_lock(&snapimage->queue_lock);
> +		bio_list_add(&snapimage->queue, bio);
> +		spin_unlock(&snapimage->queue_lock);
> +
> +		wake_up_process(snapimage->worker);
> +	} else
> +		bio_io_error(bio);
> +}

I think you can do away with the is_ready flag entirely by just
calling del_gendisk early enough.  See below.

> +void snapimage_free(struct snapimage *snapimage)
> +{
> +	pr_info("Snapshot image disk [%u:%u] delete\n",
> +		MAJOR(snapimage->image_dev_id), MINOR(snapimage->image_dev_id));
> +
> +	blk_mq_freeze_queue(snapimage->disk->queue);
> +	snapimage->is_ready = false;
> +	blk_mq_unfreeze_queue(snapimage->disk->queue);
> +
> +	snapimage_stop_worker(snapimage);
> +
> +	del_gendisk(snapimage->disk);

Just move the snapimage_stop_worker after del_gendisk here, and
you should be fine.

> +	put_disk(snapimage->disk);
> +
> +	diff_area_put(snapimage->diff_area);
> +	cbt_map_put(snapimage->cbt_map);
> +
> +	ida_free(&snapimage_devt_ida, MINOR(snapimage->image_dev_id));
> +	kfree(snapimage);

.. and then implement the free_disk block_device operation, and
move all code after the put_disk into it, which means all your
data structures are alive until the very last gendisk reference goes
away.

> +#ifdef GENHD_FL_NO_PART_SCAN
> +	disk->flags |= GENHD_FL_NO_PART_SCAN;
> +#else
> +	disk->flags |= GENHD_FL_NO_PART;
> +#endif

GENHD_FL_NO_PART_SCAN is gone, so this ifdef goes away.

> +	disk->major = _major;
> +	disk->first_minor = minor;
> +	disk->minors = 1; /* One disk has only one partition */

No new driver should manage the major/minor numbers manually, as
the block layer just assigns a dev_t by default if you don't se these.

> +	wake_up_process(snapimage->worker);

I don't think this wake_up is needed - the first queue bio should
wake the helper thread up.

> +int snapimage_init(void)
> +{
> +	int ret = 0;
> +
> +	ret = register_blkdev(0, BLK_SNAP_IMAGE_NAME);
> +	if (ret < 0) {
> +		pr_err("Failed to register snapshot image block device\n");
> +		return ret;
> +	}
> +
> +	_major = ret;
> +	pr_info("Snapshot image block device major %d was registered\n",
> +		_major);
> +
> +	return 0;
> +}
> +
> +void snapimage_done(void)
> +{
> +	unregister_blkdev(_major, BLK_SNAP_IMAGE_NAME);
> +	pr_info("Snapshot image block device [%d] was unregistered\n", _major);
> +}

And with block layer managed dev_t all this boilerplate can go away
as well.

> +#include <linux/blk_types.h>
> +#include <linux/blkdev.h>
> +#include <linux/blk-mq.h>

If you already include blk-mq.h, there is no need for the other two
headers as they are already implictly included.

Powered by blists - more mailing lists