Commit 2cf429b5 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

loop: de-duplicate the idle worker freeing code



Use a common helper for both timer based and uncoditional freeing of idle
workers.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Tested-by: default avatarDarrick J. Wong <djwong@kernel.org>
Link: https://lore.kernel.org/r/20220330052917.2566582-7-hch@lst.de


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 9acf381f
Loading
Loading
Loading
Loading
+35 −38
Original line number Diff line number Diff line
@@ -804,7 +804,6 @@ struct loop_worker {

static void loop_workfn(struct work_struct *work);
static void loop_rootcg_workfn(struct work_struct *work);
static void loop_free_idle_workers(struct timer_list *timer);

#ifdef CONFIG_BLK_CGROUP
static inline int queue_on_root_worker(struct cgroup_subsys_state *css)
@@ -888,6 +887,39 @@ static void loop_queue_work(struct loop_device *lo, struct loop_cmd *cmd)
	spin_unlock_irq(&lo->lo_work_lock);
}

static void loop_set_timer(struct loop_device *lo)
{
	timer_reduce(&lo->timer, jiffies + LOOP_IDLE_WORKER_TIMEOUT);
}

static void loop_free_idle_workers(struct loop_device *lo, bool delete_all)
{
	struct loop_worker *pos, *worker;

	spin_lock_irq(&lo->lo_work_lock);
	list_for_each_entry_safe(worker, pos, &lo->idle_worker_list,
				idle_list) {
		if (!delete_all &&
		    time_is_after_jiffies(worker->last_ran_at +
					  LOOP_IDLE_WORKER_TIMEOUT))
			break;
		list_del(&worker->idle_list);
		rb_erase(&worker->rb_node, &lo->worker_tree);
		css_put(worker->blkcg_css);
		kfree(worker);
	}
	if (!list_empty(&lo->idle_worker_list))
		loop_set_timer(lo);
	spin_unlock_irq(&lo->lo_work_lock);
}

static void loop_free_idle_workers_timer(struct timer_list *timer)
{
	struct loop_device *lo = container_of(timer, struct loop_device, timer);

	return loop_free_idle_workers(lo, false);
}

static void loop_update_rotational(struct loop_device *lo)
{
	struct file *file = lo->lo_backing_file;
@@ -1022,7 +1054,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
	INIT_LIST_HEAD(&lo->rootcg_cmd_list);
	INIT_LIST_HEAD(&lo->idle_worker_list);
	lo->worker_tree = RB_ROOT;
	timer_setup(&lo->timer, loop_free_idle_workers,
	timer_setup(&lo->timer, loop_free_idle_workers_timer,
		TIMER_DEFERRABLE);
	lo->use_dio = lo->lo_flags & LO_FLAGS_DIRECT_IO;
	lo->lo_device = bdev;
@@ -1086,7 +1118,6 @@ static void __loop_clr_fd(struct loop_device *lo, bool release)
{
	struct file *filp;
	gfp_t gfp = lo->old_gfp_mask;
	struct loop_worker *pos, *worker;

	/*
	 * Flush loop_configure() and loop_change_fd(). It is acceptable for
@@ -1116,15 +1147,7 @@ static void __loop_clr_fd(struct loop_device *lo, bool release)
	blk_mq_freeze_queue(lo->lo_queue);

	destroy_workqueue(lo->workqueue);
	spin_lock_irq(&lo->lo_work_lock);
	list_for_each_entry_safe(worker, pos, &lo->idle_worker_list,
				idle_list) {
		list_del(&worker->idle_list);
		rb_erase(&worker->rb_node, &lo->worker_tree);
		css_put(worker->blkcg_css);
		kfree(worker);
	}
	spin_unlock_irq(&lo->lo_work_lock);
	loop_free_idle_workers(lo, true);
	del_timer_sync(&lo->timer);

	spin_lock_irq(&lo->lo_lock);
@@ -1883,11 +1906,6 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
	}
}

static void loop_set_timer(struct loop_device *lo)
{
	timer_reduce(&lo->timer, jiffies + LOOP_IDLE_WORKER_TIMEOUT);
}

static void loop_process_work(struct loop_worker *worker,
			struct list_head *cmd_list, struct loop_device *lo)
{
@@ -1936,27 +1954,6 @@ static void loop_rootcg_workfn(struct work_struct *work)
	loop_process_work(NULL, &lo->rootcg_cmd_list, lo);
}

static void loop_free_idle_workers(struct timer_list *timer)
{
	struct loop_device *lo = container_of(timer, struct loop_device, timer);
	struct loop_worker *pos, *worker;

	spin_lock_irq(&lo->lo_work_lock);
	list_for_each_entry_safe(worker, pos, &lo->idle_worker_list,
				idle_list) {
		if (time_is_after_jiffies(worker->last_ran_at +
						LOOP_IDLE_WORKER_TIMEOUT))
			break;
		list_del(&worker->idle_list);
		rb_erase(&worker->rb_node, &lo->worker_tree);
		css_put(worker->blkcg_css);
		kfree(worker);
	}
	if (!list_empty(&lo->idle_worker_list))
		loop_set_timer(lo);
	spin_unlock_irq(&lo->lo_work_lock);
}

static const struct blk_mq_ops loop_mq_ops = {
	.queue_rq       = loop_queue_rq,
	.complete	= lo_complete_rq,