[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Y5rsvibCBNGMwnn+@infradead.org>
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