drivers/md/dm-delay.c

Source file repositories/reference/linux-study-clean/drivers/md/dm-delay.c

File Facts

System
Linux kernel
Corpus path
drivers/md/dm-delay.c
Extension
.c
Size
10856 bytes
Lines
471
Domain
Driver Families
Bucket
drivers/md
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct delay_class {
	struct dm_dev *dev;
	sector_t start;
	unsigned int delay;
	unsigned int ops;
};

struct delay_c {
	struct timer_list delay_timer;
	struct mutex process_bios_lock; /* hold while removing bios to be processed from list */
	spinlock_t delayed_bios_lock; /* hold on all accesses to delayed_bios list */
	struct workqueue_struct *kdelayd_wq;
	struct work_struct flush_expired_bios;
	struct list_head delayed_bios;
	struct task_struct *worker;
	unsigned int worker_sleep_us;
	bool may_delay;

	struct delay_class read;
	struct delay_class write;
	struct delay_class flush;

	int argc;
};

struct dm_delay_info {
	struct delay_c *context;
	struct delay_class *class;
	struct list_head list;
	unsigned long expires;
};

static void handle_delayed_timer(struct timer_list *t)
{
	struct delay_c *dc = timer_container_of(dc, t, delay_timer);

	queue_work(dc->kdelayd_wq, &dc->flush_expired_bios);
}

static void queue_timeout(struct delay_c *dc, unsigned long expires)
{
	timer_reduce(&dc->delay_timer, expires);
}

static inline bool delay_is_fast(struct delay_c *dc)
{
	return !!dc->worker;
}

static void flush_bios(struct bio *bio)
{
	struct bio *n;

	while (bio) {
		n = bio->bi_next;
		bio->bi_next = NULL;
		dm_submit_bio_remap(bio, NULL);
		bio = n;
	}
}

static void flush_delayed_bios(struct delay_c *dc, bool flush_all)
{
	struct dm_delay_info *delayed, *next;
	struct bio_list flush_bio_list;
	LIST_HEAD(local_list);
	unsigned long next_expires = 0;
	bool start_timer = false;
	bio_list_init(&flush_bio_list);

	mutex_lock(&dc->process_bios_lock);
	spin_lock(&dc->delayed_bios_lock);
	list_replace_init(&dc->delayed_bios, &local_list);
	spin_unlock(&dc->delayed_bios_lock);
	list_for_each_entry_safe(delayed, next, &local_list, list) {
		cond_resched();
		if (flush_all || time_after_eq(jiffies, delayed->expires)) {
			struct bio *bio = dm_bio_from_per_bio_data(delayed,
						sizeof(struct dm_delay_info));
			list_del(&delayed->list);
			bio_list_add(&flush_bio_list, bio);
			delayed->class->ops--;
			continue;
		}

		if (!delay_is_fast(dc)) {
			if (!start_timer) {
				start_timer = true;
				next_expires = delayed->expires;
			} else {

Annotation

Implementation Notes