Blame view

drivers/md/dm-kcopyd.c 21.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * Copyright (C) 2002 Sistina Software (UK) Limited.
373a392bd   Milan Broz   dm kcopyd: update...
3
   * Copyright (C) 2006 Red Hat GmbH
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
   *
   * This file is released under the GPL.
   *
   * Kcopyd provides a simple interface for copying an area of one
   * block-device to one or more other block-devices, with an asynchronous
   * completion notification.
   */
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
11
  #include <linux/types.h>
60063497a   Arun Sharma   atomic: use <linu...
12
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/blkdev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
22
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <linux/list.h>
  #include <linux/mempool.h>
  #include <linux/module.h>
  #include <linux/pagemap.h>
  #include <linux/slab.h>
  #include <linux/vmalloc.h>
  #include <linux/workqueue.h>
48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
23
  #include <linux/mutex.h>
df5d2e908   Mikulas Patocka   dm kcopyd: introd...
24
  #include <linux/delay.h>
586e80e6e   Mikulas Patocka   dm: remove dm hea...
25
  #include <linux/device-mapper.h>
a765e20ee   Alasdair G Kergon   dm: move include ...
26
  #include <linux/dm-kcopyd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27

4cc96131a   Mike Snitzer   dm: move request-...
28
  #include "dm-core.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
30
31
  #define SPLIT_COUNT	8
  #define MIN_JOBS	8
c663e0409   Nikos Tsironis   dm kcopyd: Increa...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  
  #define DEFAULT_SUB_JOB_SIZE_KB 512
  #define MAX_SUB_JOB_SIZE_KB     1024
  
  static unsigned kcopyd_subjob_size_kb = DEFAULT_SUB_JOB_SIZE_KB;
  
  module_param(kcopyd_subjob_size_kb, uint, S_IRUGO | S_IWUSR);
  MODULE_PARM_DESC(kcopyd_subjob_size_kb, "Sub-job size for dm-kcopyd clients");
  
  static unsigned dm_get_kcopyd_subjob_size(void)
  {
  	unsigned sub_job_size_kb;
  
  	sub_job_size_kb = __dm_get_module_param(&kcopyd_subjob_size_kb,
  						DEFAULT_SUB_JOB_SIZE_KB,
  						MAX_SUB_JOB_SIZE_KB);
  
  	return sub_job_size_kb << 1;
  }
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
51

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
  /*-----------------------------------------------------------------
   * Each kcopyd client has its own little pool of preallocated
   * pages for kcopyd io.
   *---------------------------------------------------------------*/
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
56
  struct dm_kcopyd_client {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  	struct page_list *pages;
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
58
59
  	unsigned nr_reserved_pages;
  	unsigned nr_free_pages;
c663e0409   Nikos Tsironis   dm kcopyd: Increa...
60
  	unsigned sub_job_size;
138728dc9   Alasdair G Kergon   [PATCH] dm snapsh...
61

373a392bd   Milan Broz   dm kcopyd: update...
62
  	struct dm_io_client *io_client;
138728dc9   Alasdair G Kergon   [PATCH] dm snapsh...
63
  	wait_queue_head_t destroyq;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
64

6f1c819c2   Kent Overstreet   dm: convert to bi...
65
  	mempool_t job_pool;
08d8757a4   Mikulas Patocka   dm kcopyd: privat...
66

8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
67
68
  	struct workqueue_struct *kcopyd_wq;
  	struct work_struct kcopyd_work;
df5d2e908   Mikulas Patocka   dm kcopyd: introd...
69
  	struct dm_kcopyd_throttle *throttle;
72d711c87   Mike Snitzer   dm: adjust struct...
70
  	atomic_t nr_jobs;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
71
  /*
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
72
   * We maintain four lists of jobs:
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
73
74
75
   *
   * i)   jobs waiting for pages
   * ii)  jobs that have pages, and are waiting for the io to be issued.
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
76
77
   * iii) jobs that don't need to do any IO and just run a callback
   * iv) jobs that have completed.
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
78
   *
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
79
   * All four of these are protected by job_lock.
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
80
81
   */
  	spinlock_t job_lock;
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
82
  	struct list_head callback_jobs;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
83
84
85
  	struct list_head complete_jobs;
  	struct list_head io_jobs;
  	struct list_head pages_jobs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  };
7f0696539   Mikulas Patocka   dm kcopyd: add dm...
87
  static struct page_list zero_page_list;
df5d2e908   Mikulas Patocka   dm kcopyd: introd...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  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_MSEC			100
  
  /*
   * 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 throttle, now, difference;
  	int slept = 0, skew;
  
  	if (unlikely(!t))
  		return;
  
  try_again:
  	spin_lock_irq(&throttle_spinlock);
6aa7de059   Mark Rutland   locking/atomics: ...
123
  	throttle = READ_ONCE(t->throttle);
df5d2e908   Mikulas Patocka   dm kcopyd: introd...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  
  	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))
  		t->io_period = t->total_period;
  
  	if (unlikely(t->total_period >= (1 << ACCOUNT_INTERVAL_SHIFT))) {
  		int shift = fls(t->total_period >> ACCOUNT_INTERVAL_SHIFT);
  		t->total_period >>= shift;
  		t->io_period >>= shift;
  	}
  
  	skew = t->io_period - throttle * t->total_period / 100;
  
  	if (unlikely(skew > 0) && slept < MAX_SLEEPS) {
  		slept++;
  		spin_unlock_irq(&throttle_spinlock);
  		msleep(SLEEP_MSEC);
  		goto try_again;
  	}
  
  skip_limit:
  	t->num_io_jobs++;
  
  	spin_unlock_irq(&throttle_spinlock);
  }
  
  static void io_job_finish(struct dm_kcopyd_throttle *t)
  {
  	unsigned long flags;
  
  	if (unlikely(!t))
  		return;
  
  	spin_lock_irqsave(&throttle_spinlock, flags);
  
  	t->num_io_jobs--;
6aa7de059   Mark Rutland   locking/atomics: ...
172
  	if (likely(READ_ONCE(t->throttle) >= 100))
df5d2e908   Mikulas Patocka   dm kcopyd: introd...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  		goto skip_limit;
  
  	if (!t->num_io_jobs) {
  		unsigned now, difference;
  
  		now = jiffies;
  		difference = now - t->last_jiffies;
  		t->last_jiffies = now;
  
  		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))
  			t->io_period = t->total_period;
  	}
  
  skip_limit:
  	spin_unlock_irqrestore(&throttle_spinlock, flags);
  }
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
195
196
197
198
  static void wake(struct dm_kcopyd_client *kc)
  {
  	queue_work(kc->kcopyd_wq, &kc->kcopyd_work);
  }
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
199
200
201
  /*
   * Obtain one page for the use of kcopyd.
   */
f99b55eec   Mikulas Patocka   dm kcopyd: add gf...
202
  static struct page_list *alloc_pl(gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
  {
  	struct page_list *pl;
f99b55eec   Mikulas Patocka   dm kcopyd: add gf...
205
  	pl = kmalloc(sizeof(*pl), gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
  	if (!pl)
  		return NULL;
f99b55eec   Mikulas Patocka   dm kcopyd: add gf...
208
  	pl->page = alloc_page(gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
215
216
217
218
219
220
221
  	if (!pl->page) {
  		kfree(pl);
  		return NULL;
  	}
  
  	return pl;
  }
  
  static void free_pl(struct page_list *pl)
  {
  	__free_page(pl->page);
  	kfree(pl);
  }
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
222
223
224
225
226
  /*
   * Add the provided pages to a client's free page list, releasing
   * back to the system any beyond the reserved_pages limit.
   */
  static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  {
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
228
  	struct page_list *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229

d04714580   Mikulas Patocka   dm kcopyd: alloc ...
230
231
  	do {
  		next = pl->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232

d04714580   Mikulas Patocka   dm kcopyd: alloc ...
233
234
235
236
237
238
239
  		if (kc->nr_free_pages >= kc->nr_reserved_pages)
  			free_pl(pl);
  		else {
  			pl->next = kc->pages;
  			kc->pages = pl;
  			kc->nr_free_pages++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

d04714580   Mikulas Patocka   dm kcopyd: alloc ...
241
242
  		pl = next;
  	} while (pl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
  }
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
244
245
  static int kcopyd_get_pages(struct dm_kcopyd_client *kc,
  			    unsigned int nr, struct page_list **pages)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  {
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
247
  	struct page_list *pl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

d04714580   Mikulas Patocka   dm kcopyd: alloc ...
249
250
251
  	*pages = NULL;
  
  	do {
d0164adc8   Mel Gorman   mm, page_alloc: d...
252
  		pl = alloc_pl(__GFP_NOWARN | __GFP_NORETRY | __GFP_KSWAPD_RECLAIM);
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
253
254
255
256
257
258
259
260
261
262
263
264
265
  		if (unlikely(!pl)) {
  			/* Use reserved pages */
  			pl = kc->pages;
  			if (unlikely(!pl))
  				goto out_of_memory;
  			kc->pages = pl->next;
  			kc->nr_free_pages--;
  		}
  		pl->next = *pages;
  		*pages = pl;
  	} while (--nr);
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

d04714580   Mikulas Patocka   dm kcopyd: alloc ...
267
268
269
270
  out_of_memory:
  	if (*pages)
  		kcopyd_put_pages(kc, *pages);
  	return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  }
  
  /*
   * These three functions resize the page pool.
   */
  static void drop_pages(struct page_list *pl)
  {
  	struct page_list *next;
  
  	while (pl) {
  		next = pl->next;
  		free_pl(pl);
  		pl = next;
  	}
  }
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
286
287
288
289
  /*
   * Allocate and reserve nr_pages for the use of a specific client.
   */
  static int client_reserve_pages(struct dm_kcopyd_client *kc, unsigned nr_pages)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  {
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
291
  	unsigned i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  	struct page_list *pl = NULL, *next;
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
293
  	for (i = 0; i < nr_pages; i++) {
f99b55eec   Mikulas Patocka   dm kcopyd: add gf...
294
  		next = alloc_pl(GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
301
302
  		if (!next) {
  			if (pl)
  				drop_pages(pl);
  			return -ENOMEM;
  		}
  		next->next = pl;
  		pl = next;
  	}
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
303
  	kc->nr_reserved_pages += nr_pages;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  	kcopyd_put_pages(kc, pl);
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
305

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
  	return 0;
  }
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
308
  static void client_free_pages(struct dm_kcopyd_client *kc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  {
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
310
  	BUG_ON(kc->nr_free_pages != kc->nr_reserved_pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
  	drop_pages(kc->pages);
  	kc->pages = NULL;
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
313
  	kc->nr_free_pages = kc->nr_reserved_pages = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
317
318
319
320
321
  }
  
  /*-----------------------------------------------------------------
   * kcopyd_jobs need to be allocated by the *clients* of kcopyd,
   * for this reason we use a mempool to prevent the client from
   * ever having to do io (which could cause a deadlock).
   *---------------------------------------------------------------*/
  struct kcopyd_job {
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
322
  	struct dm_kcopyd_client *kc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
327
328
329
  	struct list_head list;
  	unsigned long flags;
  
  	/*
  	 * Error state of the job.
  	 */
  	int read_err;
4cdc1d1fa   Alasdair G Kergon   dm io: write erro...
330
  	unsigned long write_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
335
  
  	/*
  	 * Either READ or WRITE
  	 */
  	int rw;
22a1ceb1e   Heinz Mauelshagen   dm io: clean inte...
336
  	struct dm_io_region source;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
341
  
  	/*
  	 * The destinations for the transfer.
  	 */
  	unsigned int num_dests;
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
342
  	struct dm_io_region dests[DM_KCOPYD_MAX_REGIONS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
  	struct page_list *pages;
  
  	/*
  	 * Set this to ensure you are notified when the job has
  	 * completed.  'context' is for callback to use.
  	 */
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
350
  	dm_kcopyd_notify_fn fn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
354
355
356
  	void *context;
  
  	/*
  	 * These fields are only used if the job has been split
  	 * into more manageable parts.
  	 */
def5b5b26   Matthias Kaehlcke   kcopyd use mutex ...
357
  	struct mutex lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
  	atomic_t sub_jobs;
  	sector_t progress;
b73c67c2c   Damien Le Moal   dm kcopyd: add se...
360
  	sector_t write_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361

c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
362
363
  	struct kcopyd_job *master_job;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364

e18b890bb   Christoph Lameter   [PATCH] slab: rem...
365
  static struct kmem_cache *_job_cache;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366

945fa4d28   Mikulas Patocka   dm kcopyd: remove...
367
  int __init dm_kcopyd_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  {
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
369
370
371
  	_job_cache = kmem_cache_create("kcopyd_job",
  				sizeof(struct kcopyd_job) * (SPLIT_COUNT + 1),
  				__alignof__(struct kcopyd_job), 0, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
  	if (!_job_cache)
  		return -ENOMEM;
7f0696539   Mikulas Patocka   dm kcopyd: add dm...
374
375
  	zero_page_list.next = &zero_page_list;
  	zero_page_list.page = ZERO_PAGE(0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
  	return 0;
  }
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
378
  void dm_kcopyd_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  	kmem_cache_destroy(_job_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
386
387
  	_job_cache = NULL;
  }
  
  /*
   * Functions to push and pop a job onto the head of a given job
   * list.
   */
b73c67c2c   Damien Le Moal   dm kcopyd: add se...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  static struct kcopyd_job *pop_io_job(struct list_head *jobs,
  				     struct dm_kcopyd_client *kc)
  {
  	struct kcopyd_job *job;
  
  	/*
  	 * For I/O jobs, pop any read, any write without sequential write
  	 * constraint and sequential writes that are at the right position.
  	 */
  	list_for_each_entry(job, jobs, list) {
  		if (job->rw == READ || !test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags)) {
  			list_del(&job->list);
  			return job;
  		}
  
  		if (job->write_offset == job->master_job->write_offset) {
  			job->master_job->write_offset += job->source.count;
  			list_del(&job->list);
  			return job;
  		}
  	}
  
  	return NULL;
  }
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
412
413
  static struct kcopyd_job *pop(struct list_head *jobs,
  			      struct dm_kcopyd_client *kc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
  {
  	struct kcopyd_job *job = NULL;
  	unsigned long flags;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
417
  	spin_lock_irqsave(&kc->job_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
  
  	if (!list_empty(jobs)) {
b73c67c2c   Damien Le Moal   dm kcopyd: add se...
420
421
422
423
424
425
  		if (jobs == &kc->io_jobs)
  			job = pop_io_job(jobs, kc);
  		else {
  			job = list_entry(jobs->next, struct kcopyd_job, list);
  			list_del(&job->list);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  	}
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
427
  	spin_unlock_irqrestore(&kc->job_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
  
  	return job;
  }
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
431
  static void push(struct list_head *jobs, struct kcopyd_job *job)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
  {
  	unsigned long flags;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
434
  	struct dm_kcopyd_client *kc = job->kc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435

8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
436
  	spin_lock_irqsave(&kc->job_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  	list_add_tail(&job->list, jobs);
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
438
  	spin_unlock_irqrestore(&kc->job_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
  }
b673c3a81   Kazuo Ito   dm kcopyd: avoid ...
440
441
442
443
444
445
446
447
448
449
  
  static void push_head(struct list_head *jobs, struct kcopyd_job *job)
  {
  	unsigned long flags;
  	struct dm_kcopyd_client *kc = job->kc;
  
  	spin_lock_irqsave(&kc->job_lock, flags);
  	list_add(&job->list, jobs);
  	spin_unlock_irqrestore(&kc->job_lock, flags);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
453
454
455
456
457
458
459
460
461
462
  /*
   * These three functions process 1 item from the corresponding
   * job list.
   *
   * They return:
   * < 0: error
   *   0: success
   * > 0: can't process yet.
   */
  static int run_complete_job(struct kcopyd_job *job)
  {
  	void *context = job->context;
  	int read_err = job->read_err;
4cdc1d1fa   Alasdair G Kergon   dm io: write erro...
463
  	unsigned long write_err = job->write_err;
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
464
465
  	dm_kcopyd_notify_fn fn = job->fn;
  	struct dm_kcopyd_client *kc = job->kc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466

7f0696539   Mikulas Patocka   dm kcopyd: add dm...
467
  	if (job->pages && job->pages != &zero_page_list)
73830857b   Mikulas Patocka   dm kcopyd: prepar...
468
  		kcopyd_put_pages(kc, job->pages);
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
469
470
471
472
  	/*
  	 * If this is the master job, the sub jobs have already
  	 * completed so we can free everything.
  	 */
d5ffebdd7   Mike Snitzer   dm: backfill miss...
473
474
  	if (job->master_job == job) {
  		mutex_destroy(&job->lock);
6f1c819c2   Kent Overstreet   dm: convert to bi...
475
  		mempool_free(job, &kc->job_pool);
d5ffebdd7   Mike Snitzer   dm: backfill miss...
476
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
  	fn(read_err, write_err, context);
138728dc9   Alasdair G Kergon   [PATCH] dm snapsh...
478
479
480
  
  	if (atomic_dec_and_test(&kc->nr_jobs))
  		wake_up(&kc->destroyq);
784c9a29e   John Pittman   dm kcopyd: avoid ...
481
  	cond_resched();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
486
487
  	return 0;
  }
  
  static void complete_io(unsigned long error, void *context)
  {
  	struct kcopyd_job *job = (struct kcopyd_job *) context;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
488
  	struct dm_kcopyd_client *kc = job->kc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489

df5d2e908   Mikulas Patocka   dm kcopyd: introd...
490
  	io_job_finish(kc->throttle);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  	if (error) {
511116669   Mike Christie   dm: use op_is_wri...
492
  		if (op_is_write(job->rw))
ce503f59a   Jonathan Brassow   [PATCH] dm kcopyd...
493
  			job->write_err |= error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
  		else
  			job->read_err = 1;
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
496
  		if (!test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) {
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
497
498
  			push(&kc->complete_jobs, job);
  			wake(kc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
  			return;
  		}
  	}
511116669   Mike Christie   dm: use op_is_wri...
502
  	if (op_is_write(job->rw))
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
503
  		push(&kc->complete_jobs, job);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
  
  	else {
  		job->rw = WRITE;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
507
  		push(&kc->io_jobs, job);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  	}
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
509
  	wake(kc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
514
515
516
517
518
  }
  
  /*
   * Request io on as many buffer heads as we can currently get for
   * a particular job.
   */
  static int run_io_job(struct kcopyd_job *job)
  {
  	int r;
373a392bd   Milan Broz   dm kcopyd: update...
519
  	struct dm_io_request io_req = {
e6047149d   Mike Christie   dm: use bio op ac...
520
521
  		.bi_op = job->rw,
  		.bi_op_flags = 0,
373a392bd   Milan Broz   dm kcopyd: update...
522
523
  		.mem.type = DM_IO_PAGE_LIST,
  		.mem.ptr.pl = job->pages,
4622afb3f   Mikulas Patocka   dm kcopyd: remove...
524
  		.mem.offset = 0,
373a392bd   Milan Broz   dm kcopyd: update...
525
526
527
528
  		.notify.fn = complete_io,
  		.notify.context = job,
  		.client = job->kc->io_client,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529

b73c67c2c   Damien Le Moal   dm kcopyd: add se...
530
531
532
533
534
  	/*
  	 * If we need to write sequentially and some reads or writes failed,
  	 * no point in continuing.
  	 */
  	if (test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags) &&
d1fef4146   Dmitry Fomichev   dm kcopyd: always...
535
536
  	    job->master_job->write_err) {
  		job->write_err = job->master_job->write_err;
b73c67c2c   Damien Le Moal   dm kcopyd: add se...
537
  		return -EIO;
d1fef4146   Dmitry Fomichev   dm kcopyd: always...
538
  	}
b73c67c2c   Damien Le Moal   dm kcopyd: add se...
539

df5d2e908   Mikulas Patocka   dm kcopyd: introd...
540
  	io_job_start(job->kc->throttle);
7eaceacca   Jens Axboe   block: remove per...
541
  	if (job->rw == READ)
373a392bd   Milan Broz   dm kcopyd: update...
542
  		r = dm_io(&io_req, 1, &job->source, NULL);
721a9602e   Jens Axboe   block: kill off R...
543
  	else
373a392bd   Milan Broz   dm kcopyd: update...
544
  		r = dm_io(&io_req, job->num_dests, job->dests, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
549
550
551
  
  	return r;
  }
  
  static int run_pages_job(struct kcopyd_job *job)
  {
  	int r;
5bf45a3dc   Mikulas Patocka   dm kcopyd: remove...
552
  	unsigned nr_pages = dm_div_up(job->dests[0].count, PAGE_SIZE >> 9);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553

5bf45a3dc   Mikulas Patocka   dm kcopyd: remove...
554
  	r = kcopyd_get_pages(job->kc, nr_pages, &job->pages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
  	if (!r) {
  		/* this job is ready for io */
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
557
  		push(&job->kc->io_jobs, job);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
561
562
563
564
565
566
567
568
569
570
571
  		return 0;
  	}
  
  	if (r == -ENOMEM)
  		/* can't complete now */
  		return 1;
  
  	return r;
  }
  
  /*
   * Run through a list for as long as possible.  Returns the count
   * of successful jobs.
   */
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
572
573
  static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
  			int (*fn) (struct kcopyd_job *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
  {
  	struct kcopyd_job *job;
  	int r, count = 0;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
577
  	while ((job = pop(jobs, kc))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
581
582
  
  		r = fn(job);
  
  		if (r < 0) {
  			/* error this rogue job */
511116669   Mike Christie   dm: use op_is_wri...
583
  			if (op_is_write(job->rw))
4cdc1d1fa   Alasdair G Kergon   dm io: write erro...
584
  				job->write_err = (unsigned long) -1L;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
  			else
  				job->read_err = 1;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
587
  			push(&kc->complete_jobs, job);
d1fef4146   Dmitry Fomichev   dm kcopyd: always...
588
  			wake(kc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
593
594
595
596
  			break;
  		}
  
  		if (r > 0) {
  			/*
  			 * We couldn't service this job ATM, so
  			 * push this job back onto the list.
  			 */
b673c3a81   Kazuo Ito   dm kcopyd: avoid ...
597
  			push_head(jobs, job);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
601
602
603
604
605
606
607
608
609
  			break;
  		}
  
  		count++;
  	}
  
  	return count;
  }
  
  /*
   * kcopyd does this every time it's woken up.
   */
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
610
  static void do_work(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  {
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
612
613
  	struct dm_kcopyd_client *kc = container_of(work,
  					struct dm_kcopyd_client, kcopyd_work);
7eaceacca   Jens Axboe   block: remove per...
614
  	struct blk_plug plug;
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
615
  	unsigned long flags;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
616

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
619
620
621
622
623
  	/*
  	 * The order that these are called is *very* important.
  	 * complete jobs can free some pages for pages jobs.
  	 * Pages jobs when successful will jump onto the io jobs
  	 * list.  io jobs call wake when they complete and it all
  	 * starts again.
  	 */
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
624
625
626
  	spin_lock_irqsave(&kc->job_lock, flags);
  	list_splice_tail_init(&kc->callback_jobs, &kc->complete_jobs);
  	spin_unlock_irqrestore(&kc->job_lock, flags);
7eaceacca   Jens Axboe   block: remove per...
627
  	blk_start_plug(&plug);
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
628
629
630
  	process_jobs(&kc->complete_jobs, kc, run_complete_job);
  	process_jobs(&kc->pages_jobs, kc, run_pages_job);
  	process_jobs(&kc->io_jobs, kc, run_io_job);
7eaceacca   Jens Axboe   block: remove per...
631
  	blk_finish_plug(&plug);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
635
636
637
638
639
640
  }
  
  /*
   * If we are copying a small region we just dispatch a single job
   * to do the copy, otherwise the io has to be split up into many
   * jobs.
   */
  static void dispatch_job(struct kcopyd_job *job)
  {
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
641
642
  	struct dm_kcopyd_client *kc = job->kc;
  	atomic_inc(&kc->nr_jobs);
9ca170a3c   Mikulas Patocka   dm kcopyd: accept...
643
  	if (unlikely(!job->source.count))
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
644
  		push(&kc->callback_jobs, job);
7f0696539   Mikulas Patocka   dm kcopyd: add dm...
645
646
  	else if (job->pages == &zero_page_list)
  		push(&kc->io_jobs, job);
9ca170a3c   Mikulas Patocka   dm kcopyd: accept...
647
648
  	else
  		push(&kc->pages_jobs, job);
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
649
  	wake(kc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  }
4cdc1d1fa   Alasdair G Kergon   dm io: write erro...
651
652
  static void segment_complete(int read_err, unsigned long write_err,
  			     void *context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
654
655
656
  {
  	/* FIXME: tidy this function */
  	sector_t progress = 0;
  	sector_t count = 0;
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
657
658
  	struct kcopyd_job *sub_job = (struct kcopyd_job *) context;
  	struct kcopyd_job *job = sub_job->master_job;
73830857b   Mikulas Patocka   dm kcopyd: prepar...
659
  	struct dm_kcopyd_client *kc = job->kc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660

def5b5b26   Matthias Kaehlcke   kcopyd use mutex ...
661
  	mutex_lock(&job->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
666
667
  
  	/* update the error */
  	if (read_err)
  		job->read_err = 1;
  
  	if (write_err)
ce503f59a   Jonathan Brassow   [PATCH] dm kcopyd...
668
  		job->write_err |= write_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
  
  	/*
  	 * Only dispatch more work if there hasn't been an error.
  	 */
  	if ((!job->read_err && !job->write_err) ||
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
674
  	    test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
678
  		/* get the next chunk of work */
  		progress = job->progress;
  		count = job->source.count - progress;
  		if (count) {
c663e0409   Nikos Tsironis   dm kcopyd: Increa...
679
680
  			if (count > kc->sub_job_size)
  				count = kc->sub_job_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
  
  			job->progress += count;
  		}
  	}
def5b5b26   Matthias Kaehlcke   kcopyd use mutex ...
685
  	mutex_unlock(&job->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
  
  	if (count) {
  		int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
  
  		*sub_job = *job;
b73c67c2c   Damien Le Moal   dm kcopyd: add se...
691
  		sub_job->write_offset = progress;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
696
697
698
699
700
  		sub_job->source.sector += progress;
  		sub_job->source.count = count;
  
  		for (i = 0; i < job->num_dests; i++) {
  			sub_job->dests[i].sector += progress;
  			sub_job->dests[i].count = count;
  		}
  
  		sub_job->fn = segment_complete;
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
701
  		sub_job->context = sub_job;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
705
706
  		dispatch_job(sub_job);
  
  	} else if (atomic_dec_and_test(&job->sub_jobs)) {
  
  		/*
340cd4445   Mikulas Patocka   dm kcopyd: fix ca...
707
708
709
710
711
712
713
  		 * Queue the completion callback to the kcopyd thread.
  		 *
  		 * Some callers assume that all the completions are called
  		 * from a single thread and don't race with each other.
  		 *
  		 * We must not call the callback directly here because this
  		 * code may not be executing in the thread.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
  		 */
340cd4445   Mikulas Patocka   dm kcopyd: fix ca...
715
716
  		push(&kc->complete_jobs, job);
  		wake(kc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
719
720
  	}
  }
  
  /*
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
721
   * Create some sub jobs to share the work between them.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
   */
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
723
  static void split_job(struct kcopyd_job *master_job)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
  {
  	int i;
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
726
  	atomic_inc(&master_job->kc->nr_jobs);
340cd4445   Mikulas Patocka   dm kcopyd: fix ca...
727

c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
728
729
730
731
732
  	atomic_set(&master_job->sub_jobs, SPLIT_COUNT);
  	for (i = 0; i < SPLIT_COUNT; i++) {
  		master_job[i + 1].master_job = master_job;
  		segment_complete(0, 0u, &master_job[i + 1]);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
  }
7209049d4   Mike Snitzer   dm kcopyd: return...
734
735
736
  void dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
  		    unsigned int num_dests, struct dm_io_region *dests,
  		    unsigned int flags, dm_kcopyd_notify_fn fn, void *context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
  {
  	struct kcopyd_job *job;
70d6c400a   Mike Snitzer   dm kcopyd: add WR...
739
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
  
  	/*
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
742
743
  	 * Allocate an array of jobs consisting of one master job
  	 * followed by SPLIT_COUNT sub jobs.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
  	 */
6f1c819c2   Kent Overstreet   dm: convert to bi...
745
  	job = mempool_alloc(&kc->job_pool, GFP_NOIO);
d5ffebdd7   Mike Snitzer   dm: backfill miss...
746
  	mutex_init(&job->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
750
751
752
753
754
  
  	/*
  	 * set up for the read.
  	 */
  	job->kc = kc;
  	job->flags = flags;
  	job->read_err = 0;
  	job->write_err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
757
  
  	job->num_dests = num_dests;
  	memcpy(&job->dests, dests, sizeof(*dests) * num_dests);
b73c67c2c   Damien Le Moal   dm kcopyd: add se...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
  	/*
  	 * If one of the destination is a host-managed zoned block device,
  	 * we need to write sequentially. If one of the destination is a
  	 * host-aware device, then leave it to the caller to choose what to do.
  	 */
  	if (!test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags)) {
  		for (i = 0; i < job->num_dests; i++) {
  			if (bdev_zoned_model(dests[i].bdev) == BLK_ZONED_HM) {
  				set_bit(DM_KCOPYD_WRITE_SEQ, &job->flags);
  				break;
  			}
  		}
  	}
  
  	/*
  	 * If we need to write sequentially, errors cannot be ignored.
  	 */
  	if (test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags) &&
  	    test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags))
  		clear_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags);
7f0696539   Mikulas Patocka   dm kcopyd: add dm...
778
779
780
781
782
783
784
785
  	if (from) {
  		job->source = *from;
  		job->pages = NULL;
  		job->rw = READ;
  	} else {
  		memset(&job->source, 0, sizeof job->source);
  		job->source.count = job->dests[0].count;
  		job->pages = &zero_page_list;
70d6c400a   Mike Snitzer   dm kcopyd: add WR...
786
787
  
  		/*
615ec946a   Christoph Hellwig   dm kcopyd: switch...
788
  		 * Use WRITE ZEROES to optimize zeroing if all dests support it.
70d6c400a   Mike Snitzer   dm kcopyd: add WR...
789
  		 */
615ec946a   Christoph Hellwig   dm kcopyd: switch...
790
  		job->rw = REQ_OP_WRITE_ZEROES;
70d6c400a   Mike Snitzer   dm kcopyd: add WR...
791
  		for (i = 0; i < job->num_dests; i++)
615ec946a   Christoph Hellwig   dm kcopyd: switch...
792
  			if (!bdev_write_zeroes_sectors(job->dests[i].bdev)) {
70d6c400a   Mike Snitzer   dm kcopyd: add WR...
793
794
795
  				job->rw = WRITE;
  				break;
  			}
7f0696539   Mikulas Patocka   dm kcopyd: add dm...
796
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
799
  
  	job->fn = fn;
  	job->context = context;
c6ea41fbb   Mikulas Patocka   dm kcopyd: preall...
800
  	job->master_job = job;
b73c67c2c   Damien Le Moal   dm kcopyd: add se...
801
  	job->write_offset = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802

c663e0409   Nikos Tsironis   dm kcopyd: Increa...
803
  	if (job->source.count <= kc->sub_job_size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  		dispatch_job(job);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
  		job->progress = 0;
  		split_job(job);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  }
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
810
  EXPORT_SYMBOL(dm_kcopyd_copy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811

7209049d4   Mike Snitzer   dm kcopyd: return...
812
813
814
  void dm_kcopyd_zero(struct dm_kcopyd_client *kc,
  		    unsigned num_dests, struct dm_io_region *dests,
  		    unsigned flags, dm_kcopyd_notify_fn fn, void *context)
7f0696539   Mikulas Patocka   dm kcopyd: add dm...
815
  {
7209049d4   Mike Snitzer   dm kcopyd: return...
816
  	dm_kcopyd_copy(kc, NULL, num_dests, dests, flags, fn, context);
7f0696539   Mikulas Patocka   dm kcopyd: add dm...
817
818
  }
  EXPORT_SYMBOL(dm_kcopyd_zero);
a6e50b409   Mikulas Patocka   dm snapshot: skip...
819
820
821
822
  void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc,
  				 dm_kcopyd_notify_fn fn, void *context)
  {
  	struct kcopyd_job *job;
6f1c819c2   Kent Overstreet   dm: convert to bi...
823
  	job = mempool_alloc(&kc->job_pool, GFP_NOIO);
a6e50b409   Mikulas Patocka   dm snapshot: skip...
824
825
826
827
828
  
  	memset(job, 0, sizeof(struct kcopyd_job));
  	job->kc = kc;
  	job->fn = fn;
  	job->context = context;
d136f2efd   Alasdair G Kergon   dm kcopyd: fix jo...
829
  	job->master_job = job;
a6e50b409   Mikulas Patocka   dm snapshot: skip...
830
831
832
833
834
835
836
837
838
839
840
841
842
843
  
  	atomic_inc(&kc->nr_jobs);
  
  	return job;
  }
  EXPORT_SYMBOL(dm_kcopyd_prepare_callback);
  
  void dm_kcopyd_do_callback(void *j, int read_err, unsigned long write_err)
  {
  	struct kcopyd_job *job = j;
  	struct dm_kcopyd_client *kc = job->kc;
  
  	job->read_err = read_err;
  	job->write_err = write_err;
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
844
  	push(&kc->callback_jobs, job);
a6e50b409   Mikulas Patocka   dm snapshot: skip...
845
846
847
  	wake(kc);
  }
  EXPORT_SYMBOL(dm_kcopyd_do_callback);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
851
  /*
   * Cancels a kcopyd job, eg. someone might be deactivating a
   * mirror.
   */
0b56306e5   Adrian Bunk   [PATCH] drivers/m...
852
  #if 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
  int kcopyd_cancel(struct kcopyd_job *job, int block)
  {
  	/* FIXME: finish */
  	return -1;
  }
0b56306e5   Adrian Bunk   [PATCH] drivers/m...
858
  #endif  /*  0  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
  
  /*-----------------------------------------------------------------
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
861
   * Client setup
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
   *---------------------------------------------------------------*/
df5d2e908   Mikulas Patocka   dm kcopyd: introd...
863
  struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *throttle)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
  {
6f1c819c2   Kent Overstreet   dm: convert to bi...
865
  	int r;
c663e0409   Nikos Tsironis   dm kcopyd: Increa...
866
  	unsigned reserve_pages;
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
867
  	struct dm_kcopyd_client *kc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868

d37753540   Kent Overstreet   dm: Use kzalloc f...
869
  	kc = kzalloc(sizeof(*kc), GFP_KERNEL);
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
870
  	if (!kc)
fa34ce730   Mikulas Patocka   dm kcopyd: return...
871
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872

8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
873
  	spin_lock_init(&kc->job_lock);
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
874
  	INIT_LIST_HEAD(&kc->callback_jobs);
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
875
876
877
  	INIT_LIST_HEAD(&kc->complete_jobs);
  	INIT_LIST_HEAD(&kc->io_jobs);
  	INIT_LIST_HEAD(&kc->pages_jobs);
df5d2e908   Mikulas Patocka   dm kcopyd: introd...
878
  	kc->throttle = throttle;
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
879

6f1c819c2   Kent Overstreet   dm: convert to bi...
880
881
  	r = mempool_init_slab_pool(&kc->job_pool, MIN_JOBS, _job_cache);
  	if (r)
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
882
  		goto bad_slab;
08d8757a4   Mikulas Patocka   dm kcopyd: privat...
883

8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
884
  	INIT_WORK(&kc->kcopyd_work, do_work);
670368a8d   Tejun Heo   dm: stop using WQ...
885
  	kc->kcopyd_wq = alloc_workqueue("kcopyd", WQ_MEM_RECLAIM, 0);
6f1c819c2   Kent Overstreet   dm: convert to bi...
886
887
  	if (!kc->kcopyd_wq) {
  		r = -ENOMEM;
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
888
  		goto bad_workqueue;
6f1c819c2   Kent Overstreet   dm: convert to bi...
889
  	}
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
890

c663e0409   Nikos Tsironis   dm kcopyd: Increa...
891
892
  	kc->sub_job_size = dm_get_kcopyd_subjob_size();
  	reserve_pages = DIV_ROUND_UP(kc->sub_job_size << SECTOR_SHIFT, PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  	kc->pages = NULL;
d04714580   Mikulas Patocka   dm kcopyd: alloc ...
894
  	kc->nr_reserved_pages = kc->nr_free_pages = 0;
c663e0409   Nikos Tsironis   dm kcopyd: Increa...
895
  	r = client_reserve_pages(kc, reserve_pages);
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
896
897
  	if (r)
  		goto bad_client_pages;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898

bda8efec5   Mikulas Patocka   dm io: use fixed ...
899
  	kc->io_client = dm_io_client_create();
373a392bd   Milan Broz   dm kcopyd: update...
900
901
  	if (IS_ERR(kc->io_client)) {
  		r = PTR_ERR(kc->io_client);
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
902
  		goto bad_io_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  	}
138728dc9   Alasdair G Kergon   [PATCH] dm snapsh...
904
905
  	init_waitqueue_head(&kc->destroyq);
  	atomic_set(&kc->nr_jobs, 0);
fa34ce730   Mikulas Patocka   dm kcopyd: return...
906
  	return kc;
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
907
908
909
910
911
912
  
  bad_io_client:
  	client_free_pages(kc);
  bad_client_pages:
  	destroy_workqueue(kc->kcopyd_wq);
  bad_workqueue:
6f1c819c2   Kent Overstreet   dm: convert to bi...
913
  	mempool_exit(&kc->job_pool);
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
914
915
  bad_slab:
  	kfree(kc);
fa34ce730   Mikulas Patocka   dm kcopyd: return...
916
  	return ERR_PTR(r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
  }
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
918
  EXPORT_SYMBOL(dm_kcopyd_client_create);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919

eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
920
  void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
  {
138728dc9   Alasdair G Kergon   [PATCH] dm snapsh...
922
923
  	/* Wait for completion of all jobs submitted by this client. */
  	wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
d7e6b8dfc   Nikos Tsironis   dm kcopyd: Fix bu...
924
  	BUG_ON(!list_empty(&kc->callback_jobs));
8c0cbc2f7   Mikulas Patocka   dm kcopyd: per de...
925
926
927
928
  	BUG_ON(!list_empty(&kc->complete_jobs));
  	BUG_ON(!list_empty(&kc->io_jobs));
  	BUG_ON(!list_empty(&kc->pages_jobs));
  	destroy_workqueue(kc->kcopyd_wq);
373a392bd   Milan Broz   dm kcopyd: update...
929
  	dm_io_client_destroy(kc->io_client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
  	client_free_pages(kc);
6f1c819c2   Kent Overstreet   dm: convert to bi...
931
  	mempool_exit(&kc->job_pool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  	kfree(kc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
  }
eb69aca5d   Heinz Mauelshagen   dm kcopyd: clean ...
934
  EXPORT_SYMBOL(dm_kcopyd_client_destroy);