drivers/md/dm-kcopyd.c

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

File Facts

System
Linux kernel
Corpus path
drivers/md/dm-kcopyd.c
Extension
.c
Size
22097 bytes
Lines
999
Domain
Driver Families
Bucket
drivers/md
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 dm_kcopyd_client {
	struct page_list *pages;
	unsigned int nr_reserved_pages;
	unsigned int nr_free_pages;
	unsigned int sub_job_size;

	struct dm_io_client *io_client;

	wait_queue_head_t destroyq;

	mempool_t job_pool;

	struct workqueue_struct *kcopyd_wq;
	struct work_struct kcopyd_work;

	struct dm_kcopyd_throttle *throttle;

	atomic_t nr_jobs;

/*
 * We maintain four lists of jobs:
 *
 * i)   jobs waiting for pages
 * ii)  jobs that have pages, and are waiting for the io to be issued.
 * iii) jobs that don't need to do any IO and just run a callback
 * iv) jobs that have completed.
 *
 * All four of these are protected by job_lock.
 */
	spinlock_t job_lock;
	struct list_head callback_jobs;
	struct list_head complete_jobs;
	struct list_head io_jobs;
	struct list_head pages_jobs;
};

static struct page_list zero_page_list;

static DEFINE_SPINLOCK(throttle_spinlock);

/*
 * IO/IDLE accounting slowly decays after (1 << ACCOUNT_INTERVAL_SHIFT) period.
 * When total_period >= (1 << ACCOUNT_INTERVAL_SHIFT) the counters are divided
 * by 2.
 */
#define ACCOUNT_INTERVAL_SHIFT		SHIFT_HZ

/*
 * Sleep this number of milliseconds.
 *
 * The value was decided experimentally.
 * Smaller values seem to cause an increased copy rate above the limit.
 * The reason for this is unknown but possibly due to jiffies rounding errors
 * or read/write cache inside the disk.
 */
#define SLEEP_USEC			100000

/*
 * Maximum number of sleep events. There is a theoretical livelock if more
 * kcopyd clients do work simultaneously which this limit avoids.
 */
#define MAX_SLEEPS			10

static void io_job_start(struct dm_kcopyd_throttle *t)
{
	unsigned int throttle, now, difference;
	int slept = 0, skew;

	if (unlikely(!t))
		return;

try_again:
	spin_lock_irq(&throttle_spinlock);

	throttle = READ_ONCE(t->throttle);

	if (likely(throttle >= 100))
		goto skip_limit;

	now = jiffies;
	difference = now - t->last_jiffies;
	t->last_jiffies = now;
	if (t->num_io_jobs)
		t->io_period += difference;
	t->total_period += difference;

	/*
	 * Maintain sane values if we got a temporary overflow.
	 */
	if (unlikely(t->io_period > t->total_period))

Annotation

Implementation Notes