Blame view

drivers/md/dm.c 59.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
784aae735   Milan Broz   dm: add name and ...
3
   * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
   *
   * This file is released under the GPL.
   */
  
  #include "dm.h"
51e5b2bd3   Mike Anderson   dm: add uevent to...
9
  #include "dm-uevent.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
  
  #include <linux/init.h>
  #include <linux/module.h>
48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
13
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
  #include <linux/moduleparam.h>
  #include <linux/blkpg.h>
  #include <linux/bio.h>
  #include <linux/buffer_head.h>
  #include <linux/mempool.h>
  #include <linux/slab.h>
  #include <linux/idr.h>
3ac51e741   Darrick J. Wong   [PATCH] dm store ...
21
  #include <linux/hdreg.h>
55782138e   Li Zefan   tracing/events: c...
22
23
  
  #include <trace/events/block.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

72d948616   Alasdair G Kergon   [PATCH] dm: impro...
25
  #define DM_MSG_PREFIX "core"
60935eb21   Milan Broz   dm ioctl: support...
26
27
28
29
30
31
  /*
   * Cookies are numeric values sent with CHANGE and REMOVE
   * uevents while resuming, removing or renaming the device.
   */
  #define DM_COOKIE_ENV_VAR_NAME "DM_COOKIE"
  #define DM_COOKIE_LENGTH 24
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
  static const char *_name = DM_NAME;
  
  static unsigned int major = 0;
  static unsigned int _major = 0;
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
36
  static DEFINE_SPINLOCK(_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  /*
8fbf26ad5   Kiyoshi Ueda   dm request: add c...
38
   * For bio-based dm.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
   * One of these is allocated per bio.
   */
  struct dm_io {
  	struct mapped_device *md;
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  	atomic_t io_count;
6ae2fa671   Richard Kennedy   dm io: remove str...
45
  	struct bio *bio;
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
46
  	unsigned long start_time;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
  };
  
  /*
8fbf26ad5   Kiyoshi Ueda   dm request: add c...
50
   * For bio-based dm.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
   * One of these is allocated per target within a bio.  Hopefully
   * this will be simplified out one day.
   */
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
54
  struct dm_target_io {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
  	struct dm_io *io;
  	struct dm_target *ti;
  	union map_info info;
  };
8fbf26ad5   Kiyoshi Ueda   dm request: add c...
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  /*
   * For request-based dm.
   * One of these is allocated per request.
   */
  struct dm_rq_target_io {
  	struct mapped_device *md;
  	struct dm_target *ti;
  	struct request *orig, clone;
  	int error;
  	union map_info info;
  };
  
  /*
   * For request-based dm.
   * One of these is allocated per bio.
   */
  struct dm_rq_clone_bio_info {
  	struct bio *orig;
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
77
  	struct dm_rq_target_io *tio;
8fbf26ad5   Kiyoshi Ueda   dm request: add c...
78
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
  union map_info *dm_get_mapinfo(struct bio *bio)
  {
17b2f66f2   Alasdair G Kergon   [PATCH] dm: add e...
81
  	if (bio && bio->bi_private)
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
82
  		return &((struct dm_target_io *)bio->bi_private)->info;
17b2f66f2   Alasdair G Kergon   [PATCH] dm: add e...
83
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  }
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
85
86
87
88
89
90
91
  union map_info *dm_get_rq_mapinfo(struct request *rq)
  {
  	if (rq && rq->end_io_data)
  		return &((struct dm_rq_target_io *)rq->end_io_data)->info;
  	return NULL;
  }
  EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
ba61fdd17   Jeff Mahoney   [PATCH] dm: fix i...
92
  #define MINOR_ALLOCED ((void *)-1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
  /*
   * Bits for the md->flags field.
   */
1eb787ec1   Alasdair G Kergon   dm: split DMF_BLO...
96
  #define DMF_BLOCK_IO_FOR_SUSPEND 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  #define DMF_SUSPENDED 1
aa8d7c2fb   Alasdair G Kergon   [PATCH] device-ma...
98
  #define DMF_FROZEN 2
fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
99
  #define DMF_FREEING 3
5c6bd75d0   Alasdair G Kergon   [PATCH] dm: preve...
100
  #define DMF_DELETING 4
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
101
  #define DMF_NOFLUSH_SUSPENDING 5
1eb787ec1   Alasdair G Kergon   dm: split DMF_BLO...
102
  #define DMF_QUEUE_IO_TO_THREAD 6
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103

304f3f6a5   Milan Broz   dm: move deferred...
104
105
106
  /*
   * Work processed by per-device workqueue.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
  struct mapped_device {
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
108
  	struct rw_semaphore io_lock;
e61290a4a   Daniel Walker   dm: convert suspe...
109
  	struct mutex suspend_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
  	rwlock_t map_lock;
  	atomic_t holders;
5c6bd75d0   Alasdair G Kergon   [PATCH] dm: preve...
112
  	atomic_t open_count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  
  	unsigned long flags;
165125e1e   Jens Axboe   [BLOCK] Get rid o...
115
  	struct request_queue *queue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  	struct gendisk *disk;
7e51f257e   Mike Anderson   [PATCH] dm: store...
117
  	char name[16];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
122
123
124
125
  
  	void *interface_ptr;
  
  	/*
  	 * A list of ios that arrived while we were suspended.
  	 */
  	atomic_t pending;
  	wait_queue_head_t wait;
53d5914f2   Mikulas Patocka   dm: remove unnece...
126
  	struct work_struct work;
748593646   Kiyoshi Ueda   [PATCH] dm: tidy ...
127
  	struct bio_list deferred;
022c26110   Mikulas Patocka   dm: merge pushbac...
128
  	spinlock_t deferred_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
  
  	/*
af7e466a1   Mikulas Patocka   dm: implement bas...
131
132
133
134
135
  	 * An error from the barrier request currently being processed.
  	 */
  	int barrier_error;
  
  	/*
304f3f6a5   Milan Broz   dm: move deferred...
136
137
138
139
140
  	 * Processing queue (flush/barriers)
  	 */
  	struct workqueue_struct *wq;
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
147
148
149
  	 * The current mapping.
  	 */
  	struct dm_table *map;
  
  	/*
  	 * io objects are allocated from here.
  	 */
  	mempool_t *io_pool;
  	mempool_t *tio_pool;
9faf400f7   Stefan Bader   [PATCH] dm: use p...
150
  	struct bio_set *bs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
155
  	/*
  	 * Event handling.
  	 */
  	atomic_t event_nr;
  	wait_queue_head_t eventq;
7a8c3d3b9   Mike Anderson   dm: uevent genera...
156
157
158
  	atomic_t uevent_seq;
  	struct list_head uevent_list;
  	spinlock_t uevent_lock; /* Protect access to uevent_list */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
162
163
  
  	/*
  	 * freeze/thaw support require holding onto a super block
  	 */
  	struct super_block *frozen_sb;
db8fef4fa   Mikulas Patocka   dm: rename suspen...
164
  	struct block_device *bdev;
3ac51e741   Darrick J. Wong   [PATCH] dm store ...
165
166
167
  
  	/* forced geometry settings */
  	struct hd_geometry geometry;
784aae735   Milan Broz   dm: add name and ...
168

cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
169
170
171
172
173
  	/* marker of flush suspend for request-based dm */
  	struct request suspend_rq;
  
  	/* For saving the address of __make_request for request based dm */
  	make_request_fn *saved_make_request_fn;
784aae735   Milan Broz   dm: add name and ...
174
175
  	/* sysfs handle */
  	struct kobject kobj;
52b1fd5a2   Mikulas Patocka   dm: send empty ba...
176
177
178
  
  	/* zero-length barrier that will be cloned and submitted to targets */
  	struct bio barrier_bio;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  };
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
180
181
182
183
184
185
186
187
  /*
   * For mempools pre-allocation at the table loading time.
   */
  struct dm_md_mempools {
  	mempool_t *io_pool;
  	mempool_t *tio_pool;
  	struct bio_set *bs;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  #define MIN_IOS 256
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
189
190
  static struct kmem_cache *_io_cache;
  static struct kmem_cache *_tio_cache;
8fbf26ad5   Kiyoshi Ueda   dm request: add c...
191
192
  static struct kmem_cache *_rq_tio_cache;
  static struct kmem_cache *_rq_bio_info_cache;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
  static int __init local_init(void)
  {
51157b4ab   Kiyoshi Ueda   dm: tidy local_init
196
  	int r = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  	/* allocate a slab for the dm_ios */
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
199
  	_io_cache = KMEM_CACHE(dm_io, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  	if (!_io_cache)
51157b4ab   Kiyoshi Ueda   dm: tidy local_init
201
  		return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
  
  	/* allocate a slab for the target ios */
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
204
  	_tio_cache = KMEM_CACHE(dm_target_io, 0);
51157b4ab   Kiyoshi Ueda   dm: tidy local_init
205
206
  	if (!_tio_cache)
  		goto out_free_io_cache;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

8fbf26ad5   Kiyoshi Ueda   dm request: add c...
208
209
210
211
212
213
214
  	_rq_tio_cache = KMEM_CACHE(dm_rq_target_io, 0);
  	if (!_rq_tio_cache)
  		goto out_free_tio_cache;
  
  	_rq_bio_info_cache = KMEM_CACHE(dm_rq_clone_bio_info, 0);
  	if (!_rq_bio_info_cache)
  		goto out_free_rq_tio_cache;
51e5b2bd3   Mike Anderson   dm: add uevent to...
215
  	r = dm_uevent_init();
51157b4ab   Kiyoshi Ueda   dm: tidy local_init
216
  	if (r)
8fbf26ad5   Kiyoshi Ueda   dm request: add c...
217
  		goto out_free_rq_bio_info_cache;
51e5b2bd3   Mike Anderson   dm: add uevent to...
218

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
  	_major = major;
  	r = register_blkdev(_major, _name);
51157b4ab   Kiyoshi Ueda   dm: tidy local_init
221
222
  	if (r < 0)
  		goto out_uevent_exit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
226
227
  
  	if (!_major)
  		_major = r;
  
  	return 0;
51157b4ab   Kiyoshi Ueda   dm: tidy local_init
228
229
230
  
  out_uevent_exit:
  	dm_uevent_exit();
8fbf26ad5   Kiyoshi Ueda   dm request: add c...
231
232
233
234
  out_free_rq_bio_info_cache:
  	kmem_cache_destroy(_rq_bio_info_cache);
  out_free_rq_tio_cache:
  	kmem_cache_destroy(_rq_tio_cache);
51157b4ab   Kiyoshi Ueda   dm: tidy local_init
235
236
237
238
239
240
  out_free_tio_cache:
  	kmem_cache_destroy(_tio_cache);
  out_free_io_cache:
  	kmem_cache_destroy(_io_cache);
  
  	return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
  }
  
  static void local_exit(void)
  {
8fbf26ad5   Kiyoshi Ueda   dm request: add c...
245
246
  	kmem_cache_destroy(_rq_bio_info_cache);
  	kmem_cache_destroy(_rq_tio_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
  	kmem_cache_destroy(_tio_cache);
  	kmem_cache_destroy(_io_cache);
00d59405c   Akinobu Mita   unregister_blkdev...
249
  	unregister_blkdev(_major, _name);
51e5b2bd3   Mike Anderson   dm: add uevent to...
250
  	dm_uevent_exit();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
  
  	_major = 0;
  
  	DMINFO("cleaned up");
  }
b9249e556   Alasdair G Kergon   dm: mark function...
256
  static int (*_inits[])(void) __initdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
  	local_init,
  	dm_target_init,
  	dm_linear_init,
  	dm_stripe_init,
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
261
  	dm_kcopyd_init,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
  	dm_interface_init,
  };
b9249e556   Alasdair G Kergon   dm: mark function...
264
  static void (*_exits[])(void) = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
  	local_exit,
  	dm_target_exit,
  	dm_linear_exit,
  	dm_stripe_exit,
945fa4d28   Mikulas Patocka   dm kcopyd: remove...
269
  	dm_kcopyd_exit,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  	dm_interface_exit,
  };
  
  static int __init dm_init(void)
  {
  	const int count = ARRAY_SIZE(_inits);
  
  	int r, i;
  
  	for (i = 0; i < count; i++) {
  		r = _inits[i]();
  		if (r)
  			goto bad;
  	}
  
  	return 0;
  
        bad:
  	while (i--)
  		_exits[i]();
  
  	return r;
  }
  
  static void __exit dm_exit(void)
  {
  	int i = ARRAY_SIZE(_exits);
  
  	while (i--)
  		_exits[i]();
  }
  
  /*
   * Block device functions
   */
fe5f9f2cd   Al Viro   [PATCH] switch dm
305
  static int dm_blk_open(struct block_device *bdev, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
  {
  	struct mapped_device *md;
fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
308
  	spin_lock(&_minor_lock);
fe5f9f2cd   Al Viro   [PATCH] switch dm
309
  	md = bdev->bd_disk->private_data;
fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
310
311
  	if (!md)
  		goto out;
5c6bd75d0   Alasdair G Kergon   [PATCH] dm: preve...
312
313
  	if (test_bit(DMF_FREEING, &md->flags) ||
  	    test_bit(DMF_DELETING, &md->flags)) {
fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
314
315
316
  		md = NULL;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  	dm_get(md);
5c6bd75d0   Alasdair G Kergon   [PATCH] dm: preve...
318
  	atomic_inc(&md->open_count);
fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
319
320
321
322
323
  
  out:
  	spin_unlock(&_minor_lock);
  
  	return md ? 0 : -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  }
fe5f9f2cd   Al Viro   [PATCH] switch dm
325
  static int dm_blk_close(struct gendisk *disk, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
  {
fe5f9f2cd   Al Viro   [PATCH] switch dm
327
  	struct mapped_device *md = disk->private_data;
5c6bd75d0   Alasdair G Kergon   [PATCH] dm: preve...
328
  	atomic_dec(&md->open_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
  	dm_put(md);
  	return 0;
  }
5c6bd75d0   Alasdair G Kergon   [PATCH] dm: preve...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  int dm_open_count(struct mapped_device *md)
  {
  	return atomic_read(&md->open_count);
  }
  
  /*
   * Guarantees nothing is using the device before it's deleted.
   */
  int dm_lock_for_deletion(struct mapped_device *md)
  {
  	int r = 0;
  
  	spin_lock(&_minor_lock);
  
  	if (dm_open_count(md))
  		r = -EBUSY;
  	else
  		set_bit(DMF_DELETING, &md->flags);
  
  	spin_unlock(&_minor_lock);
  
  	return r;
  }
3ac51e741   Darrick J. Wong   [PATCH] dm store ...
355
356
357
358
359
360
  static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
  {
  	struct mapped_device *md = bdev->bd_disk->private_data;
  
  	return dm_get_geometry(md, geo);
  }
fe5f9f2cd   Al Viro   [PATCH] switch dm
361
  static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
aa129a224   Milan Broz   [PATCH] dm: suppo...
362
363
  			unsigned int cmd, unsigned long arg)
  {
fe5f9f2cd   Al Viro   [PATCH] switch dm
364
365
  	struct mapped_device *md = bdev->bd_disk->private_data;
  	struct dm_table *map = dm_get_table(md);
aa129a224   Milan Broz   [PATCH] dm: suppo...
366
367
  	struct dm_target *tgt;
  	int r = -ENOTTY;
aa129a224   Milan Broz   [PATCH] dm: suppo...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  	if (!map || !dm_table_get_size(map))
  		goto out;
  
  	/* We only support devices that have a single target */
  	if (dm_table_get_num_targets(map) != 1)
  		goto out;
  
  	tgt = dm_table_get_target(map, 0);
  
  	if (dm_suspended(md)) {
  		r = -EAGAIN;
  		goto out;
  	}
  
  	if (tgt->type->ioctl)
647b3d008   Al Viro   [PATCH] lose unus...
383
  		r = tgt->type->ioctl(tgt, cmd, arg);
aa129a224   Milan Broz   [PATCH] dm: suppo...
384
385
386
  
  out:
  	dm_table_put(map);
aa129a224   Milan Broz   [PATCH] dm: suppo...
387
388
  	return r;
  }
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
389
  static struct dm_io *alloc_io(struct mapped_device *md)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
  {
  	return mempool_alloc(md->io_pool, GFP_NOIO);
  }
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
393
  static void free_io(struct mapped_device *md, struct dm_io *io)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
  {
  	mempool_free(io, md->io_pool);
  }
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
397
  static void free_tio(struct mapped_device *md, struct dm_target_io *tio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
  {
  	mempool_free(tio, md->tio_pool);
  }
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  static struct dm_rq_target_io *alloc_rq_tio(struct mapped_device *md)
  {
  	return mempool_alloc(md->tio_pool, GFP_ATOMIC);
  }
  
  static void free_rq_tio(struct dm_rq_target_io *tio)
  {
  	mempool_free(tio, tio->md->tio_pool);
  }
  
  static struct dm_rq_clone_bio_info *alloc_bio_info(struct mapped_device *md)
  {
  	return mempool_alloc(md->io_pool, GFP_ATOMIC);
  }
  
  static void free_bio_info(struct dm_rq_clone_bio_info *info)
  {
  	mempool_free(info, info->tio->md->io_pool);
  }
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
420
421
422
  static void start_io_acct(struct dm_io *io)
  {
  	struct mapped_device *md = io->md;
c99590591   Tejun Heo   block: fix diskst...
423
  	int cpu;
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
424
425
  
  	io->start_time = jiffies;
074a7aca7   Tejun Heo   block: move stats...
426
427
428
429
  	cpu = part_stat_lock();
  	part_round_stats(cpu, &dm_disk(md)->part0);
  	part_stat_unlock();
  	dm_disk(md)->part0.in_flight = atomic_inc_return(&md->pending);
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
430
  }
d221d2e77   Mikulas Patocka   dm: move pending ...
431
  static void end_io_acct(struct dm_io *io)
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
432
433
434
435
  {
  	struct mapped_device *md = io->md;
  	struct bio *bio = io->bio;
  	unsigned long duration = jiffies - io->start_time;
c99590591   Tejun Heo   block: fix diskst...
436
  	int pending, cpu;
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
437
  	int rw = bio_data_dir(bio);
074a7aca7   Tejun Heo   block: move stats...
438
439
440
441
  	cpu = part_stat_lock();
  	part_round_stats(cpu, &dm_disk(md)->part0);
  	part_stat_add(cpu, &dm_disk(md)->part0, ticks[rw], duration);
  	part_stat_unlock();
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
442

af7e466a1   Mikulas Patocka   dm: implement bas...
443
444
445
446
  	/*
  	 * After this is decremented the bio must not be touched if it is
  	 * a barrier.
  	 */
074a7aca7   Tejun Heo   block: move stats...
447
448
  	dm_disk(md)->part0.in_flight = pending =
  		atomic_dec_return(&md->pending);
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
449

d221d2e77   Mikulas Patocka   dm: move pending ...
450
451
452
  	/* nudge anyone waiting on suspend queue */
  	if (!pending)
  		wake_up(&md->wait);
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
453
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
  /*
   * Add the bio to the list of deferred io.
   */
92c639021   Mikulas Patocka   dm: remove dm_req...
457
  static void queue_io(struct mapped_device *md, struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  {
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
459
  	down_write(&md->io_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460

022c26110   Mikulas Patocka   dm: merge pushbac...
461
  	spin_lock_irq(&md->deferred_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  	bio_list_add(&md->deferred, bio);
022c26110   Mikulas Patocka   dm: merge pushbac...
463
  	spin_unlock_irq(&md->deferred_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464

92c639021   Mikulas Patocka   dm: remove dm_req...
465
466
  	if (!test_and_set_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags))
  		queue_work(md->wq, &md->work);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
467
  	up_write(&md->io_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
471
472
473
474
475
476
477
  }
  
  /*
   * Everyone (including functions in this file), should use this
   * function to access the md->map field, and make sure they call
   * dm_table_put() when finished.
   */
  struct dm_table *dm_get_table(struct mapped_device *md)
  {
  	struct dm_table *t;
523d9297d   Kiyoshi Ueda   dm: disable inter...
478
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479

523d9297d   Kiyoshi Ueda   dm: disable inter...
480
  	read_lock_irqsave(&md->map_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
  	t = md->map;
  	if (t)
  		dm_table_get(t);
523d9297d   Kiyoshi Ueda   dm: disable inter...
484
  	read_unlock_irqrestore(&md->map_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
  
  	return t;
  }
3ac51e741   Darrick J. Wong   [PATCH] dm store ...
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  /*
   * Get the geometry associated with a dm device
   */
  int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo)
  {
  	*geo = md->geometry;
  
  	return 0;
  }
  
  /*
   * Set the geometry of a device.
   */
  int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo)
  {
  	sector_t sz = (sector_t)geo->cylinders * geo->heads * geo->sectors;
  
  	if (geo->start > sz) {
  		DMWARN("Start sector is beyond the geometry limits.");
  		return -EINVAL;
  	}
  
  	md->geometry = *geo;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
519
520
521
  /*-----------------------------------------------------------------
   * CRUD START:
   *   A more elegant soln is in the works that uses the queue
   *   merge fn, unfortunately there are a couple of changes to
   *   the block layer that I want to make for this.  So in the
   *   interests of getting something for people to use I give
   *   you this clearly demarcated crap.
   *---------------------------------------------------------------*/
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
522
523
524
525
  static int __noflush_suspending(struct mapped_device *md)
  {
  	return test_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
  /*
   * Decrements the number of outstanding ios that a bio has been
   * cloned into, completing the original io if necc.
   */
858119e15   Arjan van de Ven   [PATCH] Unlinline...
530
  static void dec_pending(struct dm_io *io, int error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  {
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
532
  	unsigned long flags;
b35f8caa0   Milan Broz   dm crypt: wait fo...
533
534
535
  	int io_error;
  	struct bio *bio;
  	struct mapped_device *md = io->md;
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
536
537
  
  	/* Push-back supersedes any I/O errors */
b35f8caa0   Milan Broz   dm crypt: wait fo...
538
  	if (error && !(io->error > 0 && __noflush_suspending(md)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
  		io->error = error;
  
  	if (atomic_dec_and_test(&io->io_count)) {
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
542
543
544
  		if (io->error == DM_ENDIO_REQUEUE) {
  			/*
  			 * Target requested pushing back the I/O.
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
545
  			 */
022c26110   Mikulas Patocka   dm: merge pushbac...
546
  			spin_lock_irqsave(&md->deferred_lock, flags);
2761e95fe   Mikulas Patocka   dm: process reque...
547
548
549
550
551
  			if (__noflush_suspending(md)) {
  				if (!bio_barrier(io->bio))
  					bio_list_add_head(&md->deferred,
  							  io->bio);
  			} else
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
552
553
  				/* noflush suspend was interrupted. */
  				io->error = -EIO;
022c26110   Mikulas Patocka   dm: merge pushbac...
554
  			spin_unlock_irqrestore(&md->deferred_lock, flags);
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
555
  		}
b35f8caa0   Milan Broz   dm crypt: wait fo...
556
557
  		io_error = io->error;
  		bio = io->bio;
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
558

af7e466a1   Mikulas Patocka   dm: implement bas...
559
560
561
562
563
564
  		if (bio_barrier(bio)) {
  			/*
  			 * There can be just one barrier request so we use
  			 * a per-device variable for error reporting.
  			 * Note that you can't touch the bio after end_io_acct
  			 */
fdb9572b7   Mikulas Patocka   dm: remove EOPNOT...
565
  			if (!md->barrier_error && io_error != -EOPNOTSUPP)
5aa2781d9   Mikulas Patocka   dm: store only fi...
566
  				md->barrier_error = io_error;
af7e466a1   Mikulas Patocka   dm: implement bas...
567
568
569
  			end_io_acct(io);
  		} else {
  			end_io_acct(io);
b35f8caa0   Milan Broz   dm crypt: wait fo...
570

af7e466a1   Mikulas Patocka   dm: implement bas...
571
572
  			if (io_error != DM_ENDIO_REQUEUE) {
  				trace_block_bio_complete(md->queue, bio);
2056a782f   Jens Axboe   [PATCH] Block que...
573

af7e466a1   Mikulas Patocka   dm: implement bas...
574
575
  				bio_endio(bio, io_error);
  			}
b35f8caa0   Milan Broz   dm crypt: wait fo...
576
  		}
af7e466a1   Mikulas Patocka   dm: implement bas...
577
578
  
  		free_io(md, io);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
  	}
  }
6712ecf8f   NeilBrown   Drop 'size' argum...
581
  static void clone_endio(struct bio *bio, int error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
  {
  	int r = 0;
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
584
  	struct dm_target_io *tio = bio->bi_private;
b35f8caa0   Milan Broz   dm crypt: wait fo...
585
  	struct dm_io *io = tio->io;
9faf400f7   Stefan Bader   [PATCH] dm: use p...
586
  	struct mapped_device *md = tio->io->md;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  	dm_endio_fn endio = tio->ti->type->end_io;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
591
592
  	if (!bio_flagged(bio, BIO_UPTODATE) && !error)
  		error = -EIO;
  
  	if (endio) {
  		r = endio(tio->ti, bio, error, &tio->info);
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
593
594
595
596
597
  		if (r < 0 || r == DM_ENDIO_REQUEUE)
  			/*
  			 * error and requeue request are handled
  			 * in dec_pending().
  			 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  			error = r;
45cbcd798   Kiyoshi Ueda   [PATCH] dm: map a...
599
600
  		else if (r == DM_ENDIO_INCOMPLETE)
  			/* The target will handle the io */
6712ecf8f   NeilBrown   Drop 'size' argum...
601
  			return;
45cbcd798   Kiyoshi Ueda   [PATCH] dm: map a...
602
603
604
605
  		else if (r) {
  			DMWARN("unimplemented target endio return value: %d", r);
  			BUG();
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  	}
9faf400f7   Stefan Bader   [PATCH] dm: use p...
607
608
609
610
  	/*
  	 * Store md for cleanup instead of tio which is about to get freed.
  	 */
  	bio->bi_private = md->bs;
9faf400f7   Stefan Bader   [PATCH] dm: use p...
611
  	free_tio(md, tio);
b35f8caa0   Milan Broz   dm crypt: wait fo...
612
613
  	bio_put(bio);
  	dec_pending(io, error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
  }
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
  /*
   * Partial completion handling for request-based dm
   */
  static void end_clone_bio(struct bio *clone, int error)
  {
  	struct dm_rq_clone_bio_info *info = clone->bi_private;
  	struct dm_rq_target_io *tio = info->tio;
  	struct bio *bio = info->orig;
  	unsigned int nr_bytes = info->orig->bi_size;
  
  	bio_put(clone);
  
  	if (tio->error)
  		/*
  		 * An error has already been detected on the request.
  		 * Once error occurred, just let clone->end_io() handle
  		 * the remainder.
  		 */
  		return;
  	else if (error) {
  		/*
  		 * Don't notice the error to the upper layer yet.
  		 * The error handling decision is made by the target driver,
  		 * when the request is completed.
  		 */
  		tio->error = error;
  		return;
  	}
  
  	/*
  	 * I/O for the bio successfully completed.
  	 * Notice the data completion to the upper layer.
  	 */
  
  	/*
  	 * bios are processed from the head of the list.
  	 * So the completing bio should always be rq->bio.
  	 * If it's not, something wrong is happening.
  	 */
  	if (tio->orig->bio != bio)
  		DMERR("bio completion is going in the middle of the request");
  
  	/*
  	 * Update the original request.
  	 * Do not use blk_end_request() here, because it may complete
  	 * the original request before the clone, and break the ordering.
  	 */
  	blk_update_request(tio->orig, 0, nr_bytes);
  }
  
  /*
   * Don't touch any member of the md after calling this function because
   * the md may be freed in dm_put() at the end of this function.
   * Or do dm_get() before calling this function and dm_put() later.
   */
  static void rq_completed(struct mapped_device *md, int run_queue)
  {
  	int wakeup_waiters = 0;
  	struct request_queue *q = md->queue;
  	unsigned long flags;
  
  	spin_lock_irqsave(q->queue_lock, flags);
  	if (!queue_in_flight(q))
  		wakeup_waiters = 1;
  	spin_unlock_irqrestore(q->queue_lock, flags);
  
  	/* nudge anyone waiting on suspend queue */
  	if (wakeup_waiters)
  		wake_up(&md->wait);
  
  	if (run_queue)
  		blk_run_queue(q);
  
  	/*
  	 * dm_put() must be at the end of this function. See the comment above
  	 */
  	dm_put(md);
  }
  
  static void dm_unprep_request(struct request *rq)
  {
  	struct request *clone = rq->special;
  	struct dm_rq_target_io *tio = clone->end_io_data;
  
  	rq->special = NULL;
  	rq->cmd_flags &= ~REQ_DONTPREP;
  
  	blk_rq_unprep_clone(clone);
  	free_rq_tio(tio);
  }
  
  /*
   * Requeue the original request of a clone.
   */
  void dm_requeue_unmapped_request(struct request *clone)
  {
  	struct dm_rq_target_io *tio = clone->end_io_data;
  	struct mapped_device *md = tio->md;
  	struct request *rq = tio->orig;
  	struct request_queue *q = rq->q;
  	unsigned long flags;
  
  	dm_unprep_request(rq);
  
  	spin_lock_irqsave(q->queue_lock, flags);
  	if (elv_queue_empty(q))
  		blk_plug_device(q);
  	blk_requeue_request(q, rq);
  	spin_unlock_irqrestore(q->queue_lock, flags);
  
  	rq_completed(md, 0);
  }
  EXPORT_SYMBOL_GPL(dm_requeue_unmapped_request);
  
  static void __stop_queue(struct request_queue *q)
  {
  	blk_stop_queue(q);
  }
  
  static void stop_queue(struct request_queue *q)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(q->queue_lock, flags);
  	__stop_queue(q);
  	spin_unlock_irqrestore(q->queue_lock, flags);
  }
  
  static void __start_queue(struct request_queue *q)
  {
  	if (blk_queue_stopped(q))
  		blk_start_queue(q);
  }
  
  static void start_queue(struct request_queue *q)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(q->queue_lock, flags);
  	__start_queue(q);
  	spin_unlock_irqrestore(q->queue_lock, flags);
  }
  
  /*
   * Complete the clone and the original request.
   * Must be called without queue lock.
   */
  static void dm_end_request(struct request *clone, int error)
  {
  	struct dm_rq_target_io *tio = clone->end_io_data;
  	struct mapped_device *md = tio->md;
  	struct request *rq = tio->orig;
  
  	if (blk_pc_request(rq)) {
  		rq->errors = clone->errors;
  		rq->resid_len = clone->resid_len;
  
  		if (rq->sense)
  			/*
  			 * We are using the sense buffer of the original
  			 * request.
  			 * So setting the length of the sense data is enough.
  			 */
  			rq->sense_len = clone->sense_len;
  	}
  
  	BUG_ON(clone->bio);
  	free_rq_tio(tio);
  
  	blk_end_request_all(rq, error);
  
  	rq_completed(md, 1);
  }
  
  /*
   * Request completion handler for request-based dm
   */
  static void dm_softirq_done(struct request *rq)
  {
  	struct request *clone = rq->completion_data;
  	struct dm_rq_target_io *tio = clone->end_io_data;
  	dm_request_endio_fn rq_end_io = tio->ti->type->rq_end_io;
  	int error = tio->error;
  
  	if (!(rq->cmd_flags & REQ_FAILED) && rq_end_io)
  		error = rq_end_io(tio->ti, clone, error, &tio->info);
  
  	if (error <= 0)
  		/* The target wants to complete the I/O */
  		dm_end_request(clone, error);
  	else if (error == DM_ENDIO_INCOMPLETE)
  		/* The target will handle the I/O */
  		return;
  	else if (error == DM_ENDIO_REQUEUE)
  		/* The target wants to requeue the I/O */
  		dm_requeue_unmapped_request(clone);
  	else {
  		DMWARN("unimplemented target endio return value: %d", error);
  		BUG();
  	}
  }
  
  /*
   * Complete the clone and the original request with the error status
   * through softirq context.
   */
  static void dm_complete_request(struct request *clone, int error)
  {
  	struct dm_rq_target_io *tio = clone->end_io_data;
  	struct request *rq = tio->orig;
  
  	tio->error = error;
  	rq->completion_data = clone;
  	blk_complete_request(rq);
  }
  
  /*
   * Complete the not-mapped clone and the original request with the error status
   * through softirq context.
   * Target's rq_end_io() function isn't called.
   * This may be used when the target's map_rq() function fails.
   */
  void dm_kill_unmapped_request(struct request *clone, int error)
  {
  	struct dm_rq_target_io *tio = clone->end_io_data;
  	struct request *rq = tio->orig;
  
  	rq->cmd_flags |= REQ_FAILED;
  	dm_complete_request(clone, error);
  }
  EXPORT_SYMBOL_GPL(dm_kill_unmapped_request);
  
  /*
   * Called with the queue lock held
   */
  static void end_clone_request(struct request *clone, int error)
  {
  	/*
  	 * For just cleaning up the information of the queue in which
  	 * the clone was dispatched.
  	 * The clone is *NOT* freed actually here because it is alloced from
  	 * dm own mempool and REQ_ALLOCED isn't set in clone->cmd_flags.
  	 */
  	__blk_put_request(clone->q, clone);
  
  	/*
  	 * Actual request completion is done in a softirq context which doesn't
  	 * hold the queue lock.  Otherwise, deadlock could occur because:
  	 *     - another request may be submitted by the upper level driver
  	 *       of the stacking during the completion
  	 *     - the submission which requires queue lock may be done
  	 *       against this queue
  	 */
  	dm_complete_request(clone, error);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
  static sector_t max_io_len(struct mapped_device *md,
  			   sector_t sector, struct dm_target *ti)
  {
  	sector_t offset = sector - ti->begin;
  	sector_t len = ti->len - offset;
  
  	/*
  	 * Does the target need to split even further ?
  	 */
  	if (ti->split_io) {
  		sector_t boundary;
  		boundary = ((offset + ti->split_io) & ~(ti->split_io - 1))
  			   - offset;
  		if (len > boundary)
  			len = boundary;
  	}
  
  	return len;
  }
  
  static void __map_bio(struct dm_target *ti, struct bio *clone,
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
891
  		      struct dm_target_io *tio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
893
  {
  	int r;
2056a782f   Jens Axboe   [PATCH] Block que...
894
  	sector_t sector;
9faf400f7   Stefan Bader   [PATCH] dm: use p...
895
  	struct mapped_device *md;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
901
902
903
904
905
  	clone->bi_end_io = clone_endio;
  	clone->bi_private = tio;
  
  	/*
  	 * Map the clone.  If r == 0 we don't need to do
  	 * anything, the target has assumed ownership of
  	 * this io.
  	 */
  	atomic_inc(&tio->io->io_count);
2056a782f   Jens Axboe   [PATCH] Block que...
906
  	sector = clone->bi_sector;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
  	r = ti->type->map(ti, clone, &tio->info);
45cbcd798   Kiyoshi Ueda   [PATCH] dm: map a...
908
  	if (r == DM_MAPIO_REMAPPED) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
  		/* the bio has been remapped so dispatch it */
2056a782f   Jens Axboe   [PATCH] Block que...
910

5f3ea37c7   Arnaldo Carvalho de Melo   blktrace: port to...
911
  		trace_block_remap(bdev_get_queue(clone->bi_bdev), clone,
22a7c31a9   Alan D. Brunelle   blktrace: from-se...
912
  				    tio->io->bio->bi_bdev->bd_dev, sector);
2056a782f   Jens Axboe   [PATCH] Block que...
913

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
  		generic_make_request(clone);
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
915
916
  	} else if (r < 0 || r == DM_MAPIO_REQUEUE) {
  		/* error the io and bail out, or requeue it if needed */
9faf400f7   Stefan Bader   [PATCH] dm: use p...
917
918
919
920
921
922
  		md = tio->io->md;
  		dec_pending(tio->io, r);
  		/*
  		 * Store bio_set for cleanup.
  		 */
  		clone->bi_private = md->bs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
  		bio_put(clone);
9faf400f7   Stefan Bader   [PATCH] dm: use p...
924
  		free_tio(md, tio);
45cbcd798   Kiyoshi Ueda   [PATCH] dm: map a...
925
926
927
  	} else if (r) {
  		DMWARN("unimplemented target map return value: %d", r);
  		BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
930
931
932
933
934
935
936
937
938
939
  	}
  }
  
  struct clone_info {
  	struct mapped_device *md;
  	struct dm_table *map;
  	struct bio *bio;
  	struct dm_io *io;
  	sector_t sector;
  	sector_t sector_count;
  	unsigned short idx;
  };
3676347a5   Peter Osterlund   [PATCH] kill bio-...
940
941
  static void dm_bio_destructor(struct bio *bio)
  {
9faf400f7   Stefan Bader   [PATCH] dm: use p...
942
943
944
  	struct bio_set *bs = bio->bi_private;
  
  	bio_free(bio, bs);
3676347a5   Peter Osterlund   [PATCH] kill bio-...
945
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
949
950
  /*
   * Creates a little bio that is just does part of a bvec.
   */
  static struct bio *split_bvec(struct bio *bio, sector_t sector,
  			      unsigned short idx, unsigned int offset,
9faf400f7   Stefan Bader   [PATCH] dm: use p...
951
  			      unsigned int len, struct bio_set *bs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
954
  {
  	struct bio *clone;
  	struct bio_vec *bv = bio->bi_io_vec + idx;
9faf400f7   Stefan Bader   [PATCH] dm: use p...
955
  	clone = bio_alloc_bioset(GFP_NOIO, 1, bs);
3676347a5   Peter Osterlund   [PATCH] kill bio-...
956
  	clone->bi_destructor = dm_bio_destructor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
959
960
  	*clone->bi_io_vec = *bv;
  
  	clone->bi_sector = sector;
  	clone->bi_bdev = bio->bi_bdev;
af7e466a1   Mikulas Patocka   dm: implement bas...
961
  	clone->bi_rw = bio->bi_rw & ~(1 << BIO_RW_BARRIER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
964
965
  	clone->bi_vcnt = 1;
  	clone->bi_size = to_bytes(len);
  	clone->bi_io_vec->bv_offset = offset;
  	clone->bi_io_vec->bv_len = clone->bi_size;
f3e1d26ed   Martin K. Petersen   dm: mark split bi...
966
  	clone->bi_flags |= 1 << BIO_CLONED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967

9c47008d1   Martin K. Petersen   dm: add integrity...
968
  	if (bio_integrity(bio)) {
7878cba9f   Martin K. Petersen   block: Create bip...
969
  		bio_integrity_clone(clone, bio, GFP_NOIO, bs);
9c47008d1   Martin K. Petersen   dm: add integrity...
970
971
972
  		bio_integrity_trim(clone,
  				   bio_sector_offset(bio, idx, offset), len);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973
974
975
976
977
978
979
980
  	return clone;
  }
  
  /*
   * Creates a bio that consists of range of complete bvecs.
   */
  static struct bio *clone_bio(struct bio *bio, sector_t sector,
  			     unsigned short idx, unsigned short bv_count,
9faf400f7   Stefan Bader   [PATCH] dm: use p...
981
  			     unsigned int len, struct bio_set *bs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
  {
  	struct bio *clone;
9faf400f7   Stefan Bader   [PATCH] dm: use p...
984
985
  	clone = bio_alloc_bioset(GFP_NOIO, bio->bi_max_vecs, bs);
  	__bio_clone(clone, bio);
af7e466a1   Mikulas Patocka   dm: implement bas...
986
  	clone->bi_rw &= ~(1 << BIO_RW_BARRIER);
9faf400f7   Stefan Bader   [PATCH] dm: use p...
987
  	clone->bi_destructor = dm_bio_destructor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
990
991
992
  	clone->bi_sector = sector;
  	clone->bi_idx = idx;
  	clone->bi_vcnt = idx + bv_count;
  	clone->bi_size = to_bytes(len);
  	clone->bi_flags &= ~(1 << BIO_SEG_VALID);
9c47008d1   Martin K. Petersen   dm: add integrity...
993
  	if (bio_integrity(bio)) {
7878cba9f   Martin K. Petersen   block: Create bip...
994
  		bio_integrity_clone(clone, bio, GFP_NOIO, bs);
9c47008d1   Martin K. Petersen   dm: add integrity...
995
996
997
998
999
  
  		if (idx != bio->bi_idx || clone->bi_size < bio->bi_size)
  			bio_integrity_trim(clone,
  					   bio_sector_offset(bio, idx, 0), len);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
  	return clone;
  }
9015df24a   Alasdair G Kergon   dm: initialise ti...
1002
1003
  static struct dm_target_io *alloc_tio(struct clone_info *ci,
  				      struct dm_target *ti)
f9ab94cee   Mikulas Patocka   dm: introduce num...
1004
  {
9015df24a   Alasdair G Kergon   dm: initialise ti...
1005
  	struct dm_target_io *tio = mempool_alloc(ci->md->tio_pool, GFP_NOIO);
f9ab94cee   Mikulas Patocka   dm: introduce num...
1006
1007
1008
  
  	tio->io = ci->io;
  	tio->ti = ti;
f9ab94cee   Mikulas Patocka   dm: introduce num...
1009
  	memset(&tio->info, 0, sizeof(tio->info));
9015df24a   Alasdair G Kergon   dm: initialise ti...
1010
1011
1012
1013
1014
1015
1016
1017
1018
  
  	return tio;
  }
  
  static void __flush_target(struct clone_info *ci, struct dm_target *ti,
  			  unsigned flush_nr)
  {
  	struct dm_target_io *tio = alloc_tio(ci, ti);
  	struct bio *clone;
f9ab94cee   Mikulas Patocka   dm: introduce num...
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
  	tio->info.flush_request = flush_nr;
  
  	clone = bio_alloc_bioset(GFP_NOIO, 0, ci->md->bs);
  	__bio_clone(clone, ci->bio);
  	clone->bi_destructor = dm_bio_destructor;
  
  	__map_bio(ti, clone, tio);
  }
  
  static int __clone_and_map_empty_barrier(struct clone_info *ci)
  {
  	unsigned target_nr = 0, flush_nr;
  	struct dm_target *ti;
  
  	while ((ti = dm_table_get_target(ci->map, target_nr++)))
  		for (flush_nr = 0; flush_nr < ti->num_flush_requests;
  		     flush_nr++)
  			__flush_target(ci, ti, flush_nr);
  
  	ci->sector_count = 0;
  
  	return 0;
  }
512875bd9   Jun'ichi Nomura   dm: table detect ...
1042
  static int __clone_and_map(struct clone_info *ci)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
  {
  	struct bio *clone, *bio = ci->bio;
512875bd9   Jun'ichi Nomura   dm: table detect ...
1045
1046
  	struct dm_target *ti;
  	sector_t len = 0, max;
028867ac2   Alasdair G Kergon   dm: use kmem_cach...
1047
  	struct dm_target_io *tio;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048

f9ab94cee   Mikulas Patocka   dm: introduce num...
1049
1050
  	if (unlikely(bio_empty_barrier(bio)))
  		return __clone_and_map_empty_barrier(ci);
512875bd9   Jun'ichi Nomura   dm: table detect ...
1051
1052
1053
1054
1055
  	ti = dm_table_find_target(ci->map, ci->sector);
  	if (!dm_target_is_valid(ti))
  		return -EIO;
  
  	max = max_io_len(ci->md, ci->sector, ti);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
1057
1058
  	/*
  	 * Allocate a target io object.
  	 */
9015df24a   Alasdair G Kergon   dm: initialise ti...
1059
  	tio = alloc_tio(ci, ti);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
1062
1063
1064
1065
1066
  
  	if (ci->sector_count <= max) {
  		/*
  		 * Optimise for the simple case where we can do all of
  		 * the remaining io with a single clone.
  		 */
  		clone = clone_bio(bio, ci->sector, ci->idx,
9faf400f7   Stefan Bader   [PATCH] dm: use p...
1067
1068
  				  bio->bi_vcnt - ci->idx, ci->sector_count,
  				  ci->md->bs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
  		__map_bio(ti, clone, tio);
  		ci->sector_count = 0;
  
  	} else if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) {
  		/*
  		 * There are some bvecs that don't span targets.
  		 * Do as many of these as possible.
  		 */
  		int i;
  		sector_t remaining = max;
  		sector_t bv_len;
  
  		for (i = ci->idx; remaining && (i < bio->bi_vcnt); i++) {
  			bv_len = to_sector(bio->bi_io_vec[i].bv_len);
  
  			if (bv_len > remaining)
  				break;
  
  			remaining -= bv_len;
  			len += bv_len;
  		}
9faf400f7   Stefan Bader   [PATCH] dm: use p...
1090
1091
  		clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len,
  				  ci->md->bs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
1093
1094
1095
1096
1097
1098
1099
  		__map_bio(ti, clone, tio);
  
  		ci->sector += len;
  		ci->sector_count -= len;
  		ci->idx = i;
  
  	} else {
  		/*
d2044a94e   Alasdair G Kergon   [PATCH] dm: bio s...
1100
  		 * Handle a bvec that must be split between two or more targets.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
  		 */
  		struct bio_vec *bv = bio->bi_io_vec + ci->idx;
d2044a94e   Alasdair G Kergon   [PATCH] dm: bio s...
1103
1104
  		sector_t remaining = to_sector(bv->bv_len);
  		unsigned int offset = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105

d2044a94e   Alasdair G Kergon   [PATCH] dm: bio s...
1106
1107
1108
  		do {
  			if (offset) {
  				ti = dm_table_find_target(ci->map, ci->sector);
512875bd9   Jun'ichi Nomura   dm: table detect ...
1109
1110
  				if (!dm_target_is_valid(ti))
  					return -EIO;
d2044a94e   Alasdair G Kergon   [PATCH] dm: bio s...
1111
  				max = max_io_len(ci->md, ci->sector, ti);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112

9015df24a   Alasdair G Kergon   dm: initialise ti...
1113
  				tio = alloc_tio(ci, ti);
d2044a94e   Alasdair G Kergon   [PATCH] dm: bio s...
1114
1115
1116
1117
1118
  			}
  
  			len = min(remaining, max);
  
  			clone = split_bvec(bio, ci->sector, ci->idx,
9faf400f7   Stefan Bader   [PATCH] dm: use p...
1119
1120
  					   bv->bv_offset + offset, len,
  					   ci->md->bs);
d2044a94e   Alasdair G Kergon   [PATCH] dm: bio s...
1121
1122
1123
1124
1125
1126
1127
  
  			__map_bio(ti, clone, tio);
  
  			ci->sector += len;
  			ci->sector_count -= len;
  			offset += to_bytes(len);
  		} while (remaining -= len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
  		ci->idx++;
  	}
512875bd9   Jun'ichi Nomura   dm: table detect ...
1131
1132
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
1134
1135
  }
  
  /*
8a53c28db   Mikulas Patocka   dm: rename __spli...
1136
   * Split the bio into several clones and submit it to targets.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
   */
f0b9a4502   Mikulas Patocka   dm: move bio_io_e...
1138
  static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
  {
  	struct clone_info ci;
512875bd9   Jun'ichi Nomura   dm: table detect ...
1141
  	int error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
1143
  
  	ci.map = dm_get_table(md);
f0b9a4502   Mikulas Patocka   dm: move bio_io_e...
1144
  	if (unlikely(!ci.map)) {
af7e466a1   Mikulas Patocka   dm: implement bas...
1145
1146
1147
  		if (!bio_barrier(bio))
  			bio_io_error(bio);
  		else
5aa2781d9   Mikulas Patocka   dm: store only fi...
1148
1149
  			if (!md->barrier_error)
  				md->barrier_error = -EIO;
f0b9a4502   Mikulas Patocka   dm: move bio_io_e...
1150
1151
  		return;
  	}
692d0eb9e   Mikulas Patocka   dm: remove limite...
1152

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
1155
1156
1157
1158
1159
1160
1161
  	ci.md = md;
  	ci.bio = bio;
  	ci.io = alloc_io(md);
  	ci.io->error = 0;
  	atomic_set(&ci.io->io_count, 1);
  	ci.io->bio = bio;
  	ci.io->md = md;
  	ci.sector = bio->bi_sector;
  	ci.sector_count = bio_sectors(bio);
f9ab94cee   Mikulas Patocka   dm: introduce num...
1162
1163
  	if (unlikely(bio_empty_barrier(bio)))
  		ci.sector_count = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
  	ci.idx = bio->bi_idx;
3eaf840e0   Jun'ichi "Nick" Nomura   [PATCH] device-ma...
1165
  	start_io_acct(ci.io);
512875bd9   Jun'ichi Nomura   dm: table detect ...
1166
1167
  	while (ci.sector_count && !error)
  		error = __clone_and_map(&ci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
1169
  
  	/* drop the extra reference count */
512875bd9   Jun'ichi Nomura   dm: table detect ...
1170
  	dec_pending(ci.io, error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
1173
1174
1175
  	dm_table_put(ci.map);
  }
  /*-----------------------------------------------------------------
   * CRUD END
   *---------------------------------------------------------------*/
f6fccb121   Milan Broz   dm: introduce mer...
1176
1177
1178
1179
1180
1181
1182
1183
  static int dm_merge_bvec(struct request_queue *q,
  			 struct bvec_merge_data *bvm,
  			 struct bio_vec *biovec)
  {
  	struct mapped_device *md = q->queuedata;
  	struct dm_table *map = dm_get_table(md);
  	struct dm_target *ti;
  	sector_t max_sectors;
5037108ac   Mikulas Patocka   dm: always allow ...
1184
  	int max_size = 0;
f6fccb121   Milan Broz   dm: introduce mer...
1185
1186
  
  	if (unlikely(!map))
5037108ac   Mikulas Patocka   dm: always allow ...
1187
  		goto out;
f6fccb121   Milan Broz   dm: introduce mer...
1188
1189
  
  	ti = dm_table_find_target(map, bvm->bi_sector);
b01cd5ac4   Mikulas Patocka   dm: cope with acc...
1190
1191
  	if (!dm_target_is_valid(ti))
  		goto out_table;
f6fccb121   Milan Broz   dm: introduce mer...
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
  
  	/*
  	 * Find maximum amount of I/O that won't need splitting
  	 */
  	max_sectors = min(max_io_len(md, bvm->bi_sector, ti),
  			  (sector_t) BIO_MAX_SECTORS);
  	max_size = (max_sectors << SECTOR_SHIFT) - bvm->bi_size;
  	if (max_size < 0)
  		max_size = 0;
  
  	/*
  	 * merge_bvec_fn() returns number of bytes
  	 * it can accept at this offset
  	 * max is precomputed maximal io size
  	 */
  	if (max_size && ti->type->merge)
  		max_size = ti->type->merge(ti, bvm, biovec, max_size);
8cbeb67ad   Mikulas Patocka   dm: avoid unsuppo...
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
  	/*
  	 * If the target doesn't support merge method and some of the devices
  	 * provided their merge_bvec method (we know this by looking at
  	 * queue_max_hw_sectors), then we can't allow bios with multiple vector
  	 * entries.  So always set max_size to 0, and the code below allows
  	 * just one page.
  	 */
  	else if (queue_max_hw_sectors(q) <= PAGE_SIZE >> 9)
  
  		max_size = 0;
f6fccb121   Milan Broz   dm: introduce mer...
1219

b01cd5ac4   Mikulas Patocka   dm: cope with acc...
1220
  out_table:
5037108ac   Mikulas Patocka   dm: always allow ...
1221
1222
1223
  	dm_table_put(map);
  
  out:
f6fccb121   Milan Broz   dm: introduce mer...
1224
1225
1226
1227
1228
  	/*
  	 * Always allow an entire first page
  	 */
  	if (max_size <= biovec->bv_len && !(bvm->bi_size >> SECTOR_SHIFT))
  		max_size = biovec->bv_len;
f6fccb121   Milan Broz   dm: introduce mer...
1229
1230
  	return max_size;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
1232
1233
1234
  /*
   * The request function that just remaps the bio built up by
   * dm_merge_bvec.
   */
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
1235
  static int _dm_request(struct request_queue *q, struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
  {
12f03a49c   Kevin Corry   [PATCH] device-ma...
1237
  	int rw = bio_data_dir(bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
  	struct mapped_device *md = q->queuedata;
c99590591   Tejun Heo   block: fix diskst...
1239
  	int cpu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1240

2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
1241
  	down_read(&md->io_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242

074a7aca7   Tejun Heo   block: move stats...
1243
1244
1245
1246
  	cpu = part_stat_lock();
  	part_stat_inc(cpu, &dm_disk(md)->part0, ios[rw]);
  	part_stat_add(cpu, &dm_disk(md)->part0, sectors[rw], bio_sectors(bio));
  	part_stat_unlock();
12f03a49c   Kevin Corry   [PATCH] device-ma...
1247

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1248
  	/*
1eb787ec1   Alasdair G Kergon   dm: split DMF_BLO...
1249
1250
  	 * If we're suspended or the thread is processing barriers
  	 * we have to queue this io for later.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
  	 */
af7e466a1   Mikulas Patocka   dm: implement bas...
1252
1253
  	if (unlikely(test_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags)) ||
  	    unlikely(bio_barrier(bio))) {
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
1254
  		up_read(&md->io_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1255

54d9a1b45   Alasdair G Kergon   dm: simplify dm_r...
1256
1257
1258
1259
1260
  		if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) &&
  		    bio_rw(bio) == READA) {
  			bio_io_error(bio);
  			return 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261

92c639021   Mikulas Patocka   dm: remove dm_req...
1262
  		queue_io(md, bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1263

92c639021   Mikulas Patocka   dm: remove dm_req...
1264
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1265
  	}
f0b9a4502   Mikulas Patocka   dm: move bio_io_e...
1266
  	__split_and_process_bio(md, bio);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
1267
  	up_read(&md->io_lock);
f0b9a4502   Mikulas Patocka   dm: move bio_io_e...
1268
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
  }
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
  static int dm_make_request(struct request_queue *q, struct bio *bio)
  {
  	struct mapped_device *md = q->queuedata;
  
  	if (unlikely(bio_barrier(bio))) {
  		bio_endio(bio, -EOPNOTSUPP);
  		return 0;
  	}
  
  	return md->saved_make_request_fn(q, bio); /* call __make_request() */
  }
  
  static int dm_request_based(struct mapped_device *md)
  {
  	return blk_queue_stackable(md->queue);
  }
  
  static int dm_request(struct request_queue *q, struct bio *bio)
  {
  	struct mapped_device *md = q->queuedata;
  
  	if (dm_request_based(md))
  		return dm_make_request(q, bio);
  
  	return _dm_request(q, bio);
  }
  
  void dm_dispatch_request(struct request *rq)
  {
  	int r;
  
  	if (blk_queue_io_stat(rq->q))
  		rq->cmd_flags |= REQ_IO_STAT;
  
  	rq->start_time = jiffies;
  	r = blk_insert_cloned_request(rq->q, rq);
  	if (r)
  		dm_complete_request(rq, r);
  }
  EXPORT_SYMBOL_GPL(dm_dispatch_request);
  
  static void dm_rq_bio_destructor(struct bio *bio)
  {
  	struct dm_rq_clone_bio_info *info = bio->bi_private;
  	struct mapped_device *md = info->tio->md;
  
  	free_bio_info(info);
  	bio_free(bio, md->bs);
  }
  
  static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig,
  				 void *data)
  {
  	struct dm_rq_target_io *tio = data;
  	struct mapped_device *md = tio->md;
  	struct dm_rq_clone_bio_info *info = alloc_bio_info(md);
  
  	if (!info)
  		return -ENOMEM;
  
  	info->orig = bio_orig;
  	info->tio = tio;
  	bio->bi_end_io = end_clone_bio;
  	bio->bi_private = info;
  	bio->bi_destructor = dm_rq_bio_destructor;
  
  	return 0;
  }
  
  static int setup_clone(struct request *clone, struct request *rq,
  		       struct dm_rq_target_io *tio)
  {
  	int r = blk_rq_prep_clone(clone, rq, tio->md->bs, GFP_ATOMIC,
  				  dm_rq_bio_constructor, tio);
  
  	if (r)
  		return r;
  
  	clone->cmd = rq->cmd;
  	clone->cmd_len = rq->cmd_len;
  	clone->sense = rq->sense;
  	clone->buffer = rq->buffer;
  	clone->end_io = end_clone_request;
  	clone->end_io_data = tio;
  
  	return 0;
  }
  
  static int dm_rq_flush_suspending(struct mapped_device *md)
  {
  	return !md->suspend_rq.special;
  }
  
  /*
   * Called with the queue lock held.
   */
  static int dm_prep_fn(struct request_queue *q, struct request *rq)
  {
  	struct mapped_device *md = q->queuedata;
  	struct dm_rq_target_io *tio;
  	struct request *clone;
  
  	if (unlikely(rq == &md->suspend_rq)) {
  		if (dm_rq_flush_suspending(md))
  			return BLKPREP_OK;
  		else
  			/* The flush suspend was interrupted */
  			return BLKPREP_KILL;
  	}
  
  	if (unlikely(rq->special)) {
  		DMWARN("Already has something in rq->special.");
  		return BLKPREP_KILL;
  	}
  
  	tio = alloc_rq_tio(md); /* Only one for each original request */
  	if (!tio)
  		/* -ENOMEM */
  		return BLKPREP_DEFER;
  
  	tio->md = md;
  	tio->ti = NULL;
  	tio->orig = rq;
  	tio->error = 0;
  	memset(&tio->info, 0, sizeof(tio->info));
  
  	clone = &tio->clone;
  	if (setup_clone(clone, rq, tio)) {
  		/* -ENOMEM */
  		free_rq_tio(tio);
  		return BLKPREP_DEFER;
  	}
  
  	rq->special = clone;
  	rq->cmd_flags |= REQ_DONTPREP;
  
  	return BLKPREP_OK;
  }
  
  static void map_request(struct dm_target *ti, struct request *rq,
  			struct mapped_device *md)
  {
  	int r;
  	struct request *clone = rq->special;
  	struct dm_rq_target_io *tio = clone->end_io_data;
  
  	/*
  	 * Hold the md reference here for the in-flight I/O.
  	 * We can't rely on the reference count by device opener,
  	 * because the device may be closed during the request completion
  	 * when all bios are completed.
  	 * See the comment in rq_completed() too.
  	 */
  	dm_get(md);
  
  	tio->ti = ti;
  	r = ti->type->map_rq(ti, clone, &tio->info);
  	switch (r) {
  	case DM_MAPIO_SUBMITTED:
  		/* The target has taken the I/O to submit by itself later */
  		break;
  	case DM_MAPIO_REMAPPED:
  		/* The target has remapped the I/O so dispatch it */
  		dm_dispatch_request(clone);
  		break;
  	case DM_MAPIO_REQUEUE:
  		/* The target wants to requeue the I/O */
  		dm_requeue_unmapped_request(clone);
  		break;
  	default:
  		if (r > 0) {
  			DMWARN("unimplemented target map return value: %d", r);
  			BUG();
  		}
  
  		/* The target wants to complete the I/O */
  		dm_kill_unmapped_request(clone, r);
  		break;
  	}
  }
  
  /*
   * q->request_fn for request-based dm.
   * Called with the queue lock held.
   */
  static void dm_request_fn(struct request_queue *q)
  {
  	struct mapped_device *md = q->queuedata;
  	struct dm_table *map = dm_get_table(md);
  	struct dm_target *ti;
  	struct request *rq;
  
  	/*
  	 * For noflush suspend, check blk_queue_stopped() to immediately
  	 * quit I/O dispatching.
  	 */
  	while (!blk_queue_plugged(q) && !blk_queue_stopped(q)) {
  		rq = blk_peek_request(q);
  		if (!rq)
  			goto plug_and_out;
  
  		if (unlikely(rq == &md->suspend_rq)) { /* Flush suspend maker */
  			if (queue_in_flight(q))
  				/* Not quiet yet.  Wait more */
  				goto plug_and_out;
  
  			/* This device should be quiet now */
  			__stop_queue(q);
  			blk_start_request(rq);
  			__blk_end_request_all(rq, 0);
  			wake_up(&md->wait);
  			goto out;
  		}
  
  		ti = dm_table_find_target(map, blk_rq_pos(rq));
  		if (ti->type->busy && ti->type->busy(ti))
  			goto plug_and_out;
  
  		blk_start_request(rq);
  		spin_unlock(q->queue_lock);
  		map_request(ti, rq, md);
  		spin_lock_irq(q->queue_lock);
  	}
  
  	goto out;
  
  plug_and_out:
  	if (!elv_queue_empty(q))
  		/* Some requests still remain, retry later */
  		blk_plug_device(q);
  
  out:
  	dm_table_put(map);
  
  	return;
  }
  
  int dm_underlying_device_busy(struct request_queue *q)
  {
  	return blk_lld_busy(q);
  }
  EXPORT_SYMBOL_GPL(dm_underlying_device_busy);
  
  static int dm_lld_busy(struct request_queue *q)
  {
  	int r;
  	struct mapped_device *md = q->queuedata;
  	struct dm_table *map = dm_get_table(md);
  
  	if (!map || test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))
  		r = 1;
  	else
  		r = dm_table_any_busy_target(map);
  
  	dm_table_put(map);
  
  	return r;
  }
165125e1e   Jens Axboe   [BLOCK] Get rid o...
1528
  static void dm_unplug_all(struct request_queue *q)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529
1530
1531
1532
1533
  {
  	struct mapped_device *md = q->queuedata;
  	struct dm_table *map = dm_get_table(md);
  
  	if (map) {
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
1534
1535
  		if (dm_request_based(md))
  			generic_unplug_device(q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1536
1537
1538
1539
1540
1541
1542
  		dm_table_unplug_all(map);
  		dm_table_put(map);
  	}
  }
  
  static int dm_any_congested(void *congested_data, int bdi_bits)
  {
8a57dfc6f   Chandra Seetharaman   dm: avoid destroy...
1543
1544
1545
  	int r = bdi_bits;
  	struct mapped_device *md = congested_data;
  	struct dm_table *map;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1546

1eb787ec1   Alasdair G Kergon   dm: split DMF_BLO...
1547
  	if (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
8a57dfc6f   Chandra Seetharaman   dm: avoid destroy...
1548
1549
  		map = dm_get_table(md);
  		if (map) {
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
1550
1551
1552
1553
1554
1555
1556
1557
1558
  			/*
  			 * Request-based dm cares about only own queue for
  			 * the query about congestion status of request_queue
  			 */
  			if (dm_request_based(md))
  				r = md->queue->backing_dev_info.state &
  				    bdi_bits;
  			else
  				r = dm_table_any_congested(map, bdi_bits);
8a57dfc6f   Chandra Seetharaman   dm: avoid destroy...
1559
1560
1561
  			dm_table_put(map);
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1562
1563
1564
1565
1566
1567
  	return r;
  }
  
  /*-----------------------------------------------------------------
   * An IDR is used to keep track of allocated minor numbers.
   *---------------------------------------------------------------*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1568
  static DEFINE_IDR(_minor_idr);
2b06cfff1   Alasdair G Kergon   [PATCH] dm: conso...
1569
  static void free_minor(int minor)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
  {
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1571
  	spin_lock(&_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
  	idr_remove(&_minor_idr, minor);
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1573
  	spin_unlock(&_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1574
1575
1576
1577
1578
  }
  
  /*
   * See if the device with a specific minor # is free.
   */
cf13ab8e0   Frederik Deweerdt   dm: remove md arg...
1579
  static int specific_minor(int minor)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1580
1581
1582
1583
1584
  {
  	int r, m;
  
  	if (minor >= (1 << MINORBITS))
  		return -EINVAL;
62f75c2f3   Jeff Mahoney   [PATCH] dm: move ...
1585
1586
1587
  	r = idr_pre_get(&_minor_idr, GFP_KERNEL);
  	if (!r)
  		return -ENOMEM;
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1588
  	spin_lock(&_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
1590
1591
1592
1593
  
  	if (idr_find(&_minor_idr, minor)) {
  		r = -EBUSY;
  		goto out;
  	}
ba61fdd17   Jeff Mahoney   [PATCH] dm: fix i...
1594
  	r = idr_get_new_above(&_minor_idr, MINOR_ALLOCED, minor, &m);
62f75c2f3   Jeff Mahoney   [PATCH] dm: move ...
1595
  	if (r)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1596
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
1598
1599
1600
1601
1602
1603
1604
  
  	if (m != minor) {
  		idr_remove(&_minor_idr, m);
  		r = -EBUSY;
  		goto out;
  	}
  
  out:
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1605
  	spin_unlock(&_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606
1607
  	return r;
  }
cf13ab8e0   Frederik Deweerdt   dm: remove md arg...
1608
  static int next_free_minor(int *minor)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1609
  {
2b06cfff1   Alasdair G Kergon   [PATCH] dm: conso...
1610
  	int r, m;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1612
  	r = idr_pre_get(&_minor_idr, GFP_KERNEL);
62f75c2f3   Jeff Mahoney   [PATCH] dm: move ...
1613
1614
  	if (!r)
  		return -ENOMEM;
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1615
  	spin_lock(&_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1616

ba61fdd17   Jeff Mahoney   [PATCH] dm: fix i...
1617
  	r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m);
cf13ab8e0   Frederik Deweerdt   dm: remove md arg...
1618
  	if (r)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
  
  	if (m >= (1 << MINORBITS)) {
  		idr_remove(&_minor_idr, m);
  		r = -ENOSPC;
  		goto out;
  	}
  
  	*minor = m;
  
  out:
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1630
  	spin_unlock(&_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1631
1632
1633
1634
  	return r;
  }
  
  static struct block_device_operations dm_blk_dops;
53d5914f2   Mikulas Patocka   dm: remove unnece...
1635
  static void dm_wq_work(struct work_struct *work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1636
1637
1638
  /*
   * Allocate and initialise a blank device with a given minor.
   */
2b06cfff1   Alasdair G Kergon   [PATCH] dm: conso...
1639
  static struct mapped_device *alloc_dev(int minor)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1640
1641
  {
  	int r;
cf13ab8e0   Frederik Deweerdt   dm: remove md arg...
1642
  	struct mapped_device *md = kzalloc(sizeof(*md), GFP_KERNEL);
ba61fdd17   Jeff Mahoney   [PATCH] dm: fix i...
1643
  	void *old_md;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644
1645
1646
1647
1648
  
  	if (!md) {
  		DMWARN("unable to allocate device, out of memory.");
  		return NULL;
  	}
10da4f795   Jeff Mahoney   [PATCH] dm: add m...
1649
  	if (!try_module_get(THIS_MODULE))
6ed7ade89   Milan Broz   dm: tidy alloc_de...
1650
  		goto bad_module_get;
10da4f795   Jeff Mahoney   [PATCH] dm: add m...
1651

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1652
  	/* get a minor number for the dev */
2b06cfff1   Alasdair G Kergon   [PATCH] dm: conso...
1653
  	if (minor == DM_ANY_MINOR)
cf13ab8e0   Frederik Deweerdt   dm: remove md arg...
1654
  		r = next_free_minor(&minor);
2b06cfff1   Alasdair G Kergon   [PATCH] dm: conso...
1655
  	else
cf13ab8e0   Frederik Deweerdt   dm: remove md arg...
1656
  		r = specific_minor(minor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1657
  	if (r < 0)
6ed7ade89   Milan Broz   dm: tidy alloc_de...
1658
  		goto bad_minor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1659

2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
1660
  	init_rwsem(&md->io_lock);
e61290a4a   Daniel Walker   dm: convert suspe...
1661
  	mutex_init(&md->suspend_lock);
022c26110   Mikulas Patocka   dm: merge pushbac...
1662
  	spin_lock_init(&md->deferred_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663
1664
  	rwlock_init(&md->map_lock);
  	atomic_set(&md->holders, 1);
5c6bd75d0   Alasdair G Kergon   [PATCH] dm: preve...
1665
  	atomic_set(&md->open_count, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666
  	atomic_set(&md->event_nr, 0);
7a8c3d3b9   Mike Anderson   dm: uevent genera...
1667
1668
1669
  	atomic_set(&md->uevent_seq, 0);
  	INIT_LIST_HEAD(&md->uevent_list);
  	spin_lock_init(&md->uevent_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1670

e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
1671
  	md->queue = blk_init_queue(dm_request_fn, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1672
  	if (!md->queue)
6ed7ade89   Milan Broz   dm: tidy alloc_de...
1673
  		goto bad_queue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1674

e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
  	/*
  	 * Request-based dm devices cannot be stacked on top of bio-based dm
  	 * devices.  The type of this dm device has not been decided yet,
  	 * although we initialized the queue using blk_init_queue().
  	 * The type is decided at the first table loading time.
  	 * To prevent problematic device stacking, clear the queue flag
  	 * for request stacking support until then.
  	 *
  	 * This queue is new, so no concurrency on the queue_flags.
  	 */
  	queue_flag_clear_unlocked(QUEUE_FLAG_STACKABLE, md->queue);
  	md->saved_make_request_fn = md->queue->make_request_fn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1687
1688
1689
1690
  	md->queue->queuedata = md;
  	md->queue->backing_dev_info.congested_fn = dm_any_congested;
  	md->queue->backing_dev_info.congested_data = md;
  	blk_queue_make_request(md->queue, dm_request);
daef265f1   Jens Axboe   [PATCH] dm: don't...
1691
  	blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1692
  	md->queue->unplug_fn = dm_unplug_all;
f6fccb121   Milan Broz   dm: introduce mer...
1693
  	blk_queue_merge_bvec(md->queue, dm_merge_bvec);
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
1694
1695
1696
  	blk_queue_softirq_done(md->queue, dm_softirq_done);
  	blk_queue_prep_rq(md->queue, dm_prep_fn);
  	blk_queue_lld_busy(md->queue, dm_lld_busy);
9faf400f7   Stefan Bader   [PATCH] dm: use p...
1697

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1698
1699
  	md->disk = alloc_disk(1);
  	if (!md->disk)
6ed7ade89   Milan Broz   dm: tidy alloc_de...
1700
  		goto bad_disk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1701

f0b041153   Jeff Mahoney   [PATCH] dm: fix b...
1702
1703
  	atomic_set(&md->pending, 0);
  	init_waitqueue_head(&md->wait);
53d5914f2   Mikulas Patocka   dm: remove unnece...
1704
  	INIT_WORK(&md->work, dm_wq_work);
f0b041153   Jeff Mahoney   [PATCH] dm: fix b...
1705
  	init_waitqueue_head(&md->eventq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1706
1707
1708
1709
1710
1711
1712
  	md->disk->major = _major;
  	md->disk->first_minor = minor;
  	md->disk->fops = &dm_blk_dops;
  	md->disk->queue = md->queue;
  	md->disk->private_data = md;
  	sprintf(md->disk->disk_name, "dm-%d", minor);
  	add_disk(md->disk);
7e51f257e   Mike Anderson   [PATCH] dm: store...
1713
  	format_dev_t(md->name, MKDEV(_major, minor));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1714

304f3f6a5   Milan Broz   dm: move deferred...
1715
1716
1717
  	md->wq = create_singlethread_workqueue("kdmflush");
  	if (!md->wq)
  		goto bad_thread;
32a926da5   Mikulas Patocka   dm: always hold b...
1718
1719
1720
  	md->bdev = bdget_disk(md->disk, 0);
  	if (!md->bdev)
  		goto bad_bdev;
ba61fdd17   Jeff Mahoney   [PATCH] dm: fix i...
1721
  	/* Populate the mapping, nobody knows we exist yet */
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1722
  	spin_lock(&_minor_lock);
ba61fdd17   Jeff Mahoney   [PATCH] dm: fix i...
1723
  	old_md = idr_replace(&_minor_idr, md, minor);
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1724
  	spin_unlock(&_minor_lock);
ba61fdd17   Jeff Mahoney   [PATCH] dm: fix i...
1725
1726
  
  	BUG_ON(old_md != MINOR_ALLOCED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1727
  	return md;
32a926da5   Mikulas Patocka   dm: always hold b...
1728
1729
  bad_bdev:
  	destroy_workqueue(md->wq);
304f3f6a5   Milan Broz   dm: move deferred...
1730
1731
  bad_thread:
  	put_disk(md->disk);
6ed7ade89   Milan Broz   dm: tidy alloc_de...
1732
  bad_disk:
1312f40e1   Al Viro   [PATCH] regulariz...
1733
  	blk_cleanup_queue(md->queue);
6ed7ade89   Milan Broz   dm: tidy alloc_de...
1734
  bad_queue:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1735
  	free_minor(minor);
6ed7ade89   Milan Broz   dm: tidy alloc_de...
1736
  bad_minor:
10da4f795   Jeff Mahoney   [PATCH] dm: add m...
1737
  	module_put(THIS_MODULE);
6ed7ade89   Milan Broz   dm: tidy alloc_de...
1738
  bad_module_get:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1739
1740
1741
  	kfree(md);
  	return NULL;
  }
ae9da83f6   Jun'ichi Nomura   dm: fix thaw_bdev
1742
  static void unlock_fs(struct mapped_device *md);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1743
1744
  static void free_dev(struct mapped_device *md)
  {
f331c0296   Tejun Heo   block: don't depe...
1745
  	int minor = MINOR(disk_devt(md->disk));
63d94e482   Jun'ichi Nomura   [PATCH] dm: free ...
1746

32a926da5   Mikulas Patocka   dm: always hold b...
1747
1748
  	unlock_fs(md);
  	bdput(md->bdev);
304f3f6a5   Milan Broz   dm: move deferred...
1749
  	destroy_workqueue(md->wq);
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
1750
1751
1752
1753
1754
1755
  	if (md->tio_pool)
  		mempool_destroy(md->tio_pool);
  	if (md->io_pool)
  		mempool_destroy(md->io_pool);
  	if (md->bs)
  		bioset_free(md->bs);
9c47008d1   Martin K. Petersen   dm: add integrity...
1756
  	blk_integrity_unregister(md->disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1757
  	del_gendisk(md->disk);
63d94e482   Jun'ichi Nomura   [PATCH] dm: free ...
1758
  	free_minor(minor);
fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
1759
1760
1761
1762
  
  	spin_lock(&_minor_lock);
  	md->disk->private_data = NULL;
  	spin_unlock(&_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1763
  	put_disk(md->disk);
1312f40e1   Al Viro   [PATCH] regulariz...
1764
  	blk_cleanup_queue(md->queue);
10da4f795   Jeff Mahoney   [PATCH] dm: add m...
1765
  	module_put(THIS_MODULE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1766
1767
  	kfree(md);
  }
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
  static void __bind_mempools(struct mapped_device *md, struct dm_table *t)
  {
  	struct dm_md_mempools *p;
  
  	if (md->io_pool && md->tio_pool && md->bs)
  		/* the md already has necessary mempools */
  		goto out;
  
  	p = dm_table_get_md_mempools(t);
  	BUG_ON(!p || md->io_pool || md->tio_pool || md->bs);
  
  	md->io_pool = p->io_pool;
  	p->io_pool = NULL;
  	md->tio_pool = p->tio_pool;
  	p->tio_pool = NULL;
  	md->bs = p->bs;
  	p->bs = NULL;
  
  out:
  	/* mempool bind completed, now no need any mempools in the table */
  	dm_table_free_md_mempools(t);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1790
1791
1792
1793
1794
  /*
   * Bind a table to the device.
   */
  static void event_callback(void *context)
  {
7a8c3d3b9   Mike Anderson   dm: uevent genera...
1795
1796
  	unsigned long flags;
  	LIST_HEAD(uevents);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
  	struct mapped_device *md = (struct mapped_device *) context;
7a8c3d3b9   Mike Anderson   dm: uevent genera...
1798
1799
1800
  	spin_lock_irqsave(&md->uevent_lock, flags);
  	list_splice_init(&md->uevent_list, &uevents);
  	spin_unlock_irqrestore(&md->uevent_lock, flags);
ed9e19823   Tejun Heo   block: implement ...
1801
  	dm_send_uevents(&uevents, &disk_to_dev(md->disk)->kobj);
7a8c3d3b9   Mike Anderson   dm: uevent genera...
1802

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
1804
1805
  	atomic_inc(&md->event_nr);
  	wake_up(&md->eventq);
  }
4e90188be   Alasdair G Kergon   [PATCH] device-ma...
1806
  static void __set_size(struct mapped_device *md, sector_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1807
  {
4e90188be   Alasdair G Kergon   [PATCH] device-ma...
1808
  	set_capacity(md->disk, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1809

db8fef4fa   Mikulas Patocka   dm: rename suspen...
1810
1811
1812
  	mutex_lock(&md->bdev->bd_inode->i_mutex);
  	i_size_write(md->bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
  	mutex_unlock(&md->bdev->bd_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1813
  }
754c5fc7e   Mike Snitzer   dm: calculate que...
1814
1815
  static int __bind(struct mapped_device *md, struct dm_table *t,
  		  struct queue_limits *limits)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1816
  {
165125e1e   Jens Axboe   [BLOCK] Get rid o...
1817
  	struct request_queue *q = md->queue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1818
  	sector_t size;
523d9297d   Kiyoshi Ueda   dm: disable inter...
1819
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1820
1821
  
  	size = dm_table_get_size(t);
3ac51e741   Darrick J. Wong   [PATCH] dm store ...
1822
1823
1824
1825
1826
1827
  
  	/*
  	 * Wipe any geometry if the size of the table changed.
  	 */
  	if (size != get_capacity(md->disk))
  		memset(&md->geometry, 0, sizeof(md->geometry));
32a926da5   Mikulas Patocka   dm: always hold b...
1828
  	__set_size(md, size);
d58168763   Mikulas Patocka   dm table: rework ...
1829
1830
1831
  
  	if (!size) {
  		dm_table_destroy(t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1832
  		return 0;
d58168763   Mikulas Patocka   dm table: rework ...
1833
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834

2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
1835
  	dm_table_event_callback(t, event_callback, md);
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
  	/*
  	 * The queue hasn't been stopped yet, if the old table type wasn't
  	 * for request-based during suspension.  So stop it to prevent
  	 * I/O mapping before resume.
  	 * This must be done before setting the queue restrictions,
  	 * because request-based dm may be run just after the setting.
  	 */
  	if (dm_table_request_based(t) && !blk_queue_stopped(q))
  		stop_queue(q);
  
  	__bind_mempools(md, t);
523d9297d   Kiyoshi Ueda   dm: disable inter...
1847
  	write_lock_irqsave(&md->map_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1848
  	md->map = t;
754c5fc7e   Mike Snitzer   dm: calculate que...
1849
  	dm_table_set_restrictions(t, q, limits);
523d9297d   Kiyoshi Ueda   dm: disable inter...
1850
  	write_unlock_irqrestore(&md->map_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1851

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1852
1853
1854
1855
1856
1857
  	return 0;
  }
  
  static void __unbind(struct mapped_device *md)
  {
  	struct dm_table *map = md->map;
523d9297d   Kiyoshi Ueda   dm: disable inter...
1858
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859
1860
1861
1862
1863
  
  	if (!map)
  		return;
  
  	dm_table_event_callback(map, NULL, NULL);
523d9297d   Kiyoshi Ueda   dm: disable inter...
1864
  	write_lock_irqsave(&md->map_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1865
  	md->map = NULL;
523d9297d   Kiyoshi Ueda   dm: disable inter...
1866
  	write_unlock_irqrestore(&md->map_lock, flags);
d58168763   Mikulas Patocka   dm table: rework ...
1867
  	dm_table_destroy(map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1868
1869
1870
1871
1872
  }
  
  /*
   * Constructor for a new device.
   */
2b06cfff1   Alasdair G Kergon   [PATCH] dm: conso...
1873
  int dm_create(int minor, struct mapped_device **result)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1874
1875
  {
  	struct mapped_device *md;
2b06cfff1   Alasdair G Kergon   [PATCH] dm: conso...
1876
  	md = alloc_dev(minor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1877
1878
  	if (!md)
  		return -ENXIO;
784aae735   Milan Broz   dm: add name and ...
1879
  	dm_sysfs_init(md);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1880
1881
1882
  	*result = md;
  	return 0;
  }
637842cfd   David Teigland   [PATCH] device-ma...
1883
  static struct mapped_device *dm_find_md(dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1884
1885
  {
  	struct mapped_device *md;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1886
1887
1888
1889
  	unsigned minor = MINOR(dev);
  
  	if (MAJOR(dev) != _major || minor >= (1 << MINORBITS))
  		return NULL;
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1890
  	spin_lock(&_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1891
1892
  
  	md = idr_find(&_minor_idr, minor);
fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
1893
  	if (md && (md == MINOR_ALLOCED ||
f331c0296   Tejun Heo   block: don't depe...
1894
  		   (MINOR(disk_devt(dm_disk(md))) != minor) ||
17b2f66f2   Alasdair G Kergon   [PATCH] dm: add e...
1895
  		   test_bit(DMF_FREEING, &md->flags))) {
637842cfd   David Teigland   [PATCH] device-ma...
1896
  		md = NULL;
fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
1897
1898
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899

fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
1900
  out:
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1901
  	spin_unlock(&_minor_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1902

637842cfd   David Teigland   [PATCH] device-ma...
1903
1904
  	return md;
  }
d229a9589   David Teigland   [PATCH] device-ma...
1905
1906
1907
1908
1909
1910
1911
1912
1913
  struct mapped_device *dm_get_md(dev_t dev)
  {
  	struct mapped_device *md = dm_find_md(dev);
  
  	if (md)
  		dm_get(md);
  
  	return md;
  }
9ade92a9a   Alasdair G Kergon   [PATCH] dm: tidy ...
1914
  void *dm_get_mdptr(struct mapped_device *md)
637842cfd   David Teigland   [PATCH] device-ma...
1915
  {
9ade92a9a   Alasdair G Kergon   [PATCH] dm: tidy ...
1916
  	return md->interface_ptr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
  }
  
  void dm_set_mdptr(struct mapped_device *md, void *ptr)
  {
  	md->interface_ptr = ptr;
  }
  
  void dm_get(struct mapped_device *md)
  {
  	atomic_inc(&md->holders);
  }
72d948616   Alasdair G Kergon   [PATCH] dm: impro...
1928
1929
1930
1931
1932
  const char *dm_device_name(struct mapped_device *md)
  {
  	return md->name;
  }
  EXPORT_SYMBOL_GPL(dm_device_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1933
1934
  void dm_put(struct mapped_device *md)
  {
1134e5ae7   Mike Anderson   [PATCH] dm table:...
1935
  	struct dm_table *map;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1936

fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
1937
  	BUG_ON(test_bit(DMF_FREEING, &md->flags));
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1938
  	if (atomic_dec_and_lock(&md->holders, &_minor_lock)) {
1134e5ae7   Mike Anderson   [PATCH] dm table:...
1939
  		map = dm_get_table(md);
f331c0296   Tejun Heo   block: don't depe...
1940
1941
  		idr_replace(&_minor_idr, MINOR_ALLOCED,
  			    MINOR(disk_devt(dm_disk(md))));
fba9f90e5   Jeff Mahoney   [PATCH] dm: add D...
1942
  		set_bit(DMF_FREEING, &md->flags);
f32c10b09   Jeff Mahoney   [PATCH] dm: chang...
1943
  		spin_unlock(&_minor_lock);
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
1944
  		if (!dm_suspended(md)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1945
1946
1947
  			dm_table_presuspend_targets(map);
  			dm_table_postsuspend_targets(map);
  		}
784aae735   Milan Broz   dm: add name and ...
1948
  		dm_sysfs_exit(md);
1134e5ae7   Mike Anderson   [PATCH] dm table:...
1949
  		dm_table_put(map);
a1b51e986   Mikulas Patocka   dm table: drop re...
1950
  		__unbind(md);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1951
1952
  		free_dev(md);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1953
  }
79eb885c9   Edward Goggin   dm mpath: log dev...
1954
  EXPORT_SYMBOL_GPL(dm_put);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1955

401600dfd   Mikulas Patocka   dm: allow uninter...
1956
  static int dm_wait_for_completion(struct mapped_device *md, int interruptible)
46125c1c9   Milan Broz   dm: refactor dm_s...
1957
1958
  {
  	int r = 0;
b44ebeb01   Mikulas Patocka   dm: move wait que...
1959
  	DECLARE_WAITQUEUE(wait, current);
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
1960
1961
  	struct request_queue *q = md->queue;
  	unsigned long flags;
b44ebeb01   Mikulas Patocka   dm: move wait que...
1962
1963
1964
1965
  
  	dm_unplug_all(md->queue);
  
  	add_wait_queue(&md->wait, &wait);
46125c1c9   Milan Broz   dm: refactor dm_s...
1966
1967
  
  	while (1) {
401600dfd   Mikulas Patocka   dm: allow uninter...
1968
  		set_current_state(interruptible);
46125c1c9   Milan Broz   dm: refactor dm_s...
1969
1970
  
  		smp_mb();
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
1971
1972
1973
1974
1975
1976
1977
1978
  		if (dm_request_based(md)) {
  			spin_lock_irqsave(q->queue_lock, flags);
  			if (!queue_in_flight(q) && blk_queue_stopped(q)) {
  				spin_unlock_irqrestore(q->queue_lock, flags);
  				break;
  			}
  			spin_unlock_irqrestore(q->queue_lock, flags);
  		} else if (!atomic_read(&md->pending))
46125c1c9   Milan Broz   dm: refactor dm_s...
1979
  			break;
401600dfd   Mikulas Patocka   dm: allow uninter...
1980
1981
  		if (interruptible == TASK_INTERRUPTIBLE &&
  		    signal_pending(current)) {
46125c1c9   Milan Broz   dm: refactor dm_s...
1982
1983
1984
1985
1986
1987
1988
  			r = -EINTR;
  			break;
  		}
  
  		io_schedule();
  	}
  	set_current_state(TASK_RUNNING);
b44ebeb01   Mikulas Patocka   dm: move wait que...
1989
  	remove_wait_queue(&md->wait, &wait);
46125c1c9   Milan Broz   dm: refactor dm_s...
1990
1991
  	return r;
  }
531fe9636   Mikulas Patocka   dm: make dm_flush...
1992
  static void dm_flush(struct mapped_device *md)
af7e466a1   Mikulas Patocka   dm: implement bas...
1993
1994
  {
  	dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
52b1fd5a2   Mikulas Patocka   dm: send empty ba...
1995
1996
1997
1998
1999
2000
2001
  
  	bio_init(&md->barrier_bio);
  	md->barrier_bio.bi_bdev = md->bdev;
  	md->barrier_bio.bi_rw = WRITE_BARRIER;
  	__split_and_process_bio(md, &md->barrier_bio);
  
  	dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
af7e466a1   Mikulas Patocka   dm: implement bas...
2002
2003
2004
2005
  }
  
  static void process_barrier(struct mapped_device *md, struct bio *bio)
  {
5aa2781d9   Mikulas Patocka   dm: store only fi...
2006
  	md->barrier_error = 0;
531fe9636   Mikulas Patocka   dm: make dm_flush...
2007
  	dm_flush(md);
af7e466a1   Mikulas Patocka   dm: implement bas...
2008

5aa2781d9   Mikulas Patocka   dm: store only fi...
2009
2010
2011
  	if (!bio_empty_barrier(bio)) {
  		__split_and_process_bio(md, bio);
  		dm_flush(md);
af7e466a1   Mikulas Patocka   dm: implement bas...
2012
  	}
af7e466a1   Mikulas Patocka   dm: implement bas...
2013
  	if (md->barrier_error != DM_ENDIO_REQUEUE)
531fe9636   Mikulas Patocka   dm: make dm_flush...
2014
  		bio_endio(bio, md->barrier_error);
2761e95fe   Mikulas Patocka   dm: process reque...
2015
2016
2017
2018
2019
  	else {
  		spin_lock_irq(&md->deferred_lock);
  		bio_list_add_head(&md->deferred, bio);
  		spin_unlock_irq(&md->deferred_lock);
  	}
af7e466a1   Mikulas Patocka   dm: implement bas...
2020
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2021
2022
2023
  /*
   * Process the deferred bios
   */
ef2085870   Mikulas Patocka   dm: merge __flush...
2024
  static void dm_wq_work(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2025
  {
ef2085870   Mikulas Patocka   dm: merge __flush...
2026
2027
  	struct mapped_device *md = container_of(work, struct mapped_device,
  						work);
6d6f10df8   Milan Broz   dm: refactor defe...
2028
  	struct bio *c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029

ef2085870   Mikulas Patocka   dm: merge __flush...
2030
  	down_write(&md->io_lock);
3b00b2036   Mikulas Patocka   dm: rework queuei...
2031
  	while (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
df12ee996   Alasdair G Kergon   dm: rearrange dm_...
2032
2033
2034
2035
2036
  		spin_lock_irq(&md->deferred_lock);
  		c = bio_list_pop(&md->deferred);
  		spin_unlock_irq(&md->deferred_lock);
  
  		if (!c) {
1eb787ec1   Alasdair G Kergon   dm: split DMF_BLO...
2037
  			clear_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags);
df12ee996   Alasdair G Kergon   dm: rearrange dm_...
2038
2039
  			break;
  		}
022c26110   Mikulas Patocka   dm: merge pushbac...
2040

3b00b2036   Mikulas Patocka   dm: rework queuei...
2041
  		up_write(&md->io_lock);
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
2042
2043
2044
2045
2046
2047
2048
2049
  		if (dm_request_based(md))
  			generic_make_request(c);
  		else {
  			if (bio_barrier(c))
  				process_barrier(md, c);
  			else
  				__split_and_process_bio(md, c);
  		}
3b00b2036   Mikulas Patocka   dm: rework queuei...
2050
2051
  
  		down_write(&md->io_lock);
022c26110   Mikulas Patocka   dm: merge pushbac...
2052
  	}
73d410c01   Milan Broz   dm: tidy dm_suspend
2053

ef2085870   Mikulas Patocka   dm: merge __flush...
2054
  	up_write(&md->io_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2055
  }
9a1fb4644   Mikulas Patocka   dm: remove unnece...
2056
  static void dm_queue_flush(struct mapped_device *md)
304f3f6a5   Milan Broz   dm: move deferred...
2057
  {
3b00b2036   Mikulas Patocka   dm: rework queuei...
2058
2059
  	clear_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags);
  	smp_mb__after_clear_bit();
53d5914f2   Mikulas Patocka   dm: remove unnece...
2060
  	queue_work(md->wq, &md->work);
304f3f6a5   Milan Broz   dm: move deferred...
2061
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2062
2063
2064
2065
2066
  /*
   * Swap in a new table (destroying old one).
   */
  int dm_swap_table(struct mapped_device *md, struct dm_table *table)
  {
754c5fc7e   Mike Snitzer   dm: calculate que...
2067
  	struct queue_limits limits;
93c534aef   Alasdair G Kergon   [PATCH] device-ma...
2068
  	int r = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069

e61290a4a   Daniel Walker   dm: convert suspe...
2070
  	mutex_lock(&md->suspend_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2071
2072
  
  	/* device must be suspended */
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2073
  	if (!dm_suspended(md))
93c534aef   Alasdair G Kergon   [PATCH] device-ma...
2074
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2075

754c5fc7e   Mike Snitzer   dm: calculate que...
2076
2077
2078
  	r = dm_calculate_queue_limits(table, &limits);
  	if (r)
  		goto out;
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
2079
2080
2081
2082
2083
2084
  	/* cannot change the device type, once a table is bound */
  	if (md->map &&
  	    (dm_table_get_type(md->map) != dm_table_get_type(table))) {
  		DMWARN("can't change the device type after a table is bound");
  		goto out;
  	}
5d67aa236   Kiyoshi Ueda   dm: do not set QU...
2085
2086
2087
2088
2089
2090
2091
2092
2093
  	/*
  	 * It is enought that blk_queue_ordered() is called only once when
  	 * the first bio-based table is bound.
  	 *
  	 * This setting should be moved to alloc_dev() when request-based dm
  	 * supports barrier.
  	 */
  	if (!md->map && dm_table_bio_based(table))
  		blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2094
  	__unbind(md);
754c5fc7e   Mike Snitzer   dm: calculate que...
2095
  	r = __bind(md, table, &limits);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2096

93c534aef   Alasdair G Kergon   [PATCH] device-ma...
2097
  out:
e61290a4a   Daniel Walker   dm: convert suspe...
2098
  	mutex_unlock(&md->suspend_lock);
93c534aef   Alasdair G Kergon   [PATCH] device-ma...
2099
  	return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100
  }
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
  static void dm_rq_invalidate_suspend_marker(struct mapped_device *md)
  {
  	md->suspend_rq.special = (void *)0x1;
  }
  
  static void dm_rq_abort_suspend(struct mapped_device *md, int noflush)
  {
  	struct request_queue *q = md->queue;
  	unsigned long flags;
  
  	spin_lock_irqsave(q->queue_lock, flags);
  	if (!noflush)
  		dm_rq_invalidate_suspend_marker(md);
  	__start_queue(q);
  	spin_unlock_irqrestore(q->queue_lock, flags);
  }
  
  static void dm_rq_start_suspend(struct mapped_device *md, int noflush)
  {
  	struct request *rq = &md->suspend_rq;
  	struct request_queue *q = md->queue;
  
  	if (noflush)
  		stop_queue(q);
  	else {
  		blk_rq_init(q, rq);
  		blk_insert_request(q, rq, 0, NULL);
  	}
  }
  
  static int dm_rq_suspend_available(struct mapped_device *md, int noflush)
  {
  	int r = 1;
  	struct request *rq = &md->suspend_rq;
  	struct request_queue *q = md->queue;
  	unsigned long flags;
  
  	if (noflush)
  		return r;
  
  	/* The marker must be protected by queue lock if it is in use */
  	spin_lock_irqsave(q->queue_lock, flags);
  	if (unlikely(rq->ref_count)) {
  		/*
  		 * This can happen, when the previous flush suspend was
  		 * interrupted, the marker is still in the queue and
  		 * this flush suspend has been invoked, because we don't
  		 * remove the marker at the time of suspend interruption.
  		 * We have only one marker per mapped_device, so we can't
  		 * start another flush suspend while it is in use.
  		 */
  		BUG_ON(!rq->special); /* The marker should be invalidated */
  		DMWARN("Invalidating the previous flush suspend is still in"
  		       " progress.  Please retry later.");
  		r = 0;
  	}
  	spin_unlock_irqrestore(q->queue_lock, flags);
  
  	return r;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2161
2162
2163
2164
  /*
   * Functions to lock and unlock any filesystem running on the
   * device.
   */
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2165
  static int lock_fs(struct mapped_device *md)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
  {
e39e2e95e   Alasdair G Kergon   [PATCH] device-ma...
2167
  	int r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2168
2169
  
  	WARN_ON(md->frozen_sb);
dfbe03f6d   Alasdair G Kergon   [PATCH] device-ma...
2170

db8fef4fa   Mikulas Patocka   dm: rename suspen...
2171
  	md->frozen_sb = freeze_bdev(md->bdev);
dfbe03f6d   Alasdair G Kergon   [PATCH] device-ma...
2172
  	if (IS_ERR(md->frozen_sb)) {
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2173
  		r = PTR_ERR(md->frozen_sb);
e39e2e95e   Alasdair G Kergon   [PATCH] device-ma...
2174
2175
  		md->frozen_sb = NULL;
  		return r;
dfbe03f6d   Alasdair G Kergon   [PATCH] device-ma...
2176
  	}
aa8d7c2fb   Alasdair G Kergon   [PATCH] device-ma...
2177
  	set_bit(DMF_FROZEN, &md->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2178
2179
  	return 0;
  }
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2180
  static void unlock_fs(struct mapped_device *md)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2181
  {
aa8d7c2fb   Alasdair G Kergon   [PATCH] device-ma...
2182
2183
  	if (!test_bit(DMF_FROZEN, &md->flags))
  		return;
db8fef4fa   Mikulas Patocka   dm: rename suspen...
2184
  	thaw_bdev(md->bdev, md->frozen_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2185
  	md->frozen_sb = NULL;
aa8d7c2fb   Alasdair G Kergon   [PATCH] device-ma...
2186
  	clear_bit(DMF_FROZEN, &md->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2187
2188
2189
2190
2191
2192
2193
2194
2195
  }
  
  /*
   * We need to be able to change a mapping table under a mounted
   * filesystem.  For example we might want to move some data in
   * the background.  Before the table can be swapped with
   * dm_bind_table, dm_suspend must be called to flush any in
   * flight bios and ensure that any further io gets deferred.
   */
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
  /*
   * Suspend mechanism in request-based dm.
   *
   * After the suspend starts, further incoming requests are kept in
   * the request_queue and deferred.
   * Remaining requests in the request_queue at the start of suspend are flushed
   * if it is flush suspend.
   * The suspend completes when the following conditions have been satisfied,
   * so wait for it:
   *    1. q->in_flight is 0 (which means no in_flight request)
   *    2. queue has been stopped (which means no request dispatching)
   *
   *
   * Noflush suspend
   * ---------------
   * Noflush suspend doesn't need to dispatch remaining requests.
   * So stop the queue immediately.  Then, wait for all in_flight requests
   * to be completed or requeued.
   *
   * To abort noflush suspend, start the queue.
   *
   *
   * Flush suspend
   * -------------
   * Flush suspend needs to dispatch remaining requests.  So stop the queue
   * after the remaining requests are completed. (Requeued request must be also
   * re-dispatched and completed.  Until then, we can't stop the queue.)
   *
   * During flushing the remaining requests, further incoming requests are also
   * inserted to the same queue.  To distinguish which requests are to be
   * flushed, we insert a marker request to the queue at the time of starting
   * flush suspend, like a barrier.
   * The dispatching is blocked when the marker is found on the top of the queue.
   * And the queue is stopped when all in_flight requests are completed, since
   * that means the remaining requests are completely flushed.
   * Then, the marker is removed from the queue.
   *
   * To abort flush suspend, we also need to take care of the marker, not only
   * starting the queue.
   * We don't remove the marker forcibly from the queue since it's against
   * the block-layer manner.  Instead, we put a invalidated mark on the marker.
   * When the invalidated marker is found on the top of the queue, it is
   * immediately removed from the queue, so it doesn't block dispatching.
   * Because we have only one marker per mapped_device, we can't start another
   * flush suspend until the invalidated marker is removed from the queue.
   * So fail and return with -EBUSY in such a case.
   */
a3d77d35b   Kiyoshi Ueda   [PATCH] dm: suspe...
2243
  int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2244
  {
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2245
  	struct dm_table *map = NULL;
46125c1c9   Milan Broz   dm: refactor dm_s...
2246
  	int r = 0;
a3d77d35b   Kiyoshi Ueda   [PATCH] dm: suspe...
2247
  	int do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG ? 1 : 0;
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
2248
  	int noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2249

e61290a4a   Daniel Walker   dm: convert suspe...
2250
  	mutex_lock(&md->suspend_lock);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2251

73d410c01   Milan Broz   dm: tidy dm_suspend
2252
2253
  	if (dm_suspended(md)) {
  		r = -EINVAL;
d287483d6   Alasdair G Kergon   [PATCH] dm: suspe...
2254
  		goto out_unlock;
73d410c01   Milan Broz   dm: tidy dm_suspend
2255
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2256

cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
2257
2258
2259
2260
  	if (dm_request_based(md) && !dm_rq_suspend_available(md, noflush)) {
  		r = -EBUSY;
  		goto out_unlock;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2261
  	map = dm_get_table(md);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2262

2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
2263
2264
2265
2266
2267
2268
  	/*
  	 * DMF_NOFLUSH_SUSPENDING must be set before presuspend.
  	 * This flag is cleared before dm_suspend returns.
  	 */
  	if (noflush)
  		set_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2269
2270
  	/* This does not get reverted if there's an error later. */
  	dm_table_presuspend_targets(map);
32a926da5   Mikulas Patocka   dm: always hold b...
2271
2272
2273
2274
2275
2276
2277
  	/*
  	 * Flush I/O to the device. noflush supersedes do_lockfs,
  	 * because lock_fs() needs to flush I/Os.
  	 */
  	if (!noflush && do_lockfs) {
  		r = lock_fs(md);
  		if (r)
f431d9666   Kiyoshi Ueda   dm: remove unused...
2278
  			goto out;
aa8d7c2fb   Alasdair G Kergon   [PATCH] device-ma...
2279
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2280
2281
  
  	/*
3b00b2036   Mikulas Patocka   dm: rework queuei...
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
  	 * Here we must make sure that no processes are submitting requests
  	 * to target drivers i.e. no one may be executing
  	 * __split_and_process_bio. This is called from dm_request and
  	 * dm_wq_work.
  	 *
  	 * To get all processes out of __split_and_process_bio in dm_request,
  	 * we take the write lock. To prevent any process from reentering
  	 * __split_and_process_bio from dm_request, we set
  	 * DMF_QUEUE_IO_TO_THREAD.
  	 *
  	 * To quiesce the thread (dm_wq_work), we set DMF_BLOCK_IO_FOR_SUSPEND
  	 * and call flush_workqueue(md->wq). flush_workqueue will wait until
  	 * dm_wq_work exits and DMF_BLOCK_IO_FOR_SUSPEND will prevent any
  	 * further calls to __split_and_process_bio from dm_wq_work.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2296
  	 */
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2297
  	down_write(&md->io_lock);
1eb787ec1   Alasdair G Kergon   dm: split DMF_BLO...
2298
2299
  	set_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags);
  	set_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2300
  	up_write(&md->io_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301

3b00b2036   Mikulas Patocka   dm: rework queuei...
2302
  	flush_workqueue(md->wq);
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
2303
2304
  	if (dm_request_based(md))
  		dm_rq_start_suspend(md, noflush);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2305
  	/*
3b00b2036   Mikulas Patocka   dm: rework queuei...
2306
2307
2308
  	 * At this point no more requests are entering target request routines.
  	 * We call dm_wait_for_completion to wait for all existing requests
  	 * to finish.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2309
  	 */
401600dfd   Mikulas Patocka   dm: allow uninter...
2310
  	r = dm_wait_for_completion(md, TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311

2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2312
  	down_write(&md->io_lock);
6d6f10df8   Milan Broz   dm: refactor defe...
2313
  	if (noflush)
022c26110   Mikulas Patocka   dm: merge pushbac...
2314
  		clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
94d6351e1   Milan Broz   dm: split dm_susp...
2315
  	up_write(&md->io_lock);
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
2316

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2317
  	/* were we interrupted ? */
46125c1c9   Milan Broz   dm: refactor dm_s...
2318
  	if (r < 0) {
9a1fb4644   Mikulas Patocka   dm: remove unnece...
2319
  		dm_queue_flush(md);
73d410c01   Milan Broz   dm: tidy dm_suspend
2320

cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
2321
2322
  		if (dm_request_based(md))
  			dm_rq_abort_suspend(md, noflush);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2323
  		unlock_fs(md);
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
2324
  		goto out; /* pushback list is already flushed, so skip flush */
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2325
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326

3b00b2036   Mikulas Patocka   dm: rework queuei...
2327
2328
2329
2330
2331
  	/*
  	 * If dm_wait_for_completion returned 0, the device is completely
  	 * quiescent now. There is no request-processing activity. All new
  	 * requests are being added to md->deferred list.
  	 */
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2332
  	dm_table_postsuspend_targets(map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2333

2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2334
  	set_bit(DMF_SUSPENDED, &md->flags);
b84b0287a   Alasdair G Kergon   [PATCH] device-ma...
2335

2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2336
2337
  out:
  	dm_table_put(map);
d287483d6   Alasdair G Kergon   [PATCH] dm: suspe...
2338
2339
  
  out_unlock:
e61290a4a   Daniel Walker   dm: convert suspe...
2340
  	mutex_unlock(&md->suspend_lock);
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2341
  	return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2342
2343
2344
2345
  }
  
  int dm_resume(struct mapped_device *md)
  {
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2346
  	int r = -EINVAL;
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2347
  	struct dm_table *map = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2348

e61290a4a   Daniel Walker   dm: convert suspe...
2349
  	mutex_lock(&md->suspend_lock);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2350
  	if (!dm_suspended(md))
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2351
  		goto out;
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2352
2353
  
  	map = dm_get_table(md);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2354
  	if (!map || !dm_table_get_size(map))
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2355
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2356

8757b7764   Milan Broz   [PATCH] dm table:...
2357
2358
2359
  	r = dm_table_resume_targets(map);
  	if (r)
  		goto out;
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2360

9a1fb4644   Mikulas Patocka   dm: remove unnece...
2361
  	dm_queue_flush(md);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2362

cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
2363
2364
2365
2366
2367
2368
2369
  	/*
  	 * Flushing deferred I/Os must be done after targets are resumed
  	 * so that mapping of targets can work correctly.
  	 * Request-based dm is queueing the deferred I/Os in its request_queue.
  	 */
  	if (dm_request_based(md))
  		start_queue(md->queue);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2370
2371
2372
  	unlock_fs(md);
  
  	clear_bit(DMF_SUSPENDED, &md->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2373
  	dm_table_unplug_all(map);
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2374
2375
2376
  	r = 0;
  out:
  	dm_table_put(map);
e61290a4a   Daniel Walker   dm: convert suspe...
2377
  	mutex_unlock(&md->suspend_lock);
2ca3310e7   Alasdair G Kergon   [PATCH] device-ma...
2378

cf222b376   Alasdair G Kergon   [PATCH] device-ma...
2379
  	return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2380
2381
2382
2383
2384
  }
  
  /*-----------------------------------------------------------------
   * Event notification.
   *---------------------------------------------------------------*/
60935eb21   Milan Broz   dm ioctl: support...
2385
2386
  void dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
  		       unsigned cookie)
69267a30b   Alasdair G Kergon   dm: trigger chang...
2387
  {
60935eb21   Milan Broz   dm ioctl: support...
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
  	char udev_cookie[DM_COOKIE_LENGTH];
  	char *envp[] = { udev_cookie, NULL };
  
  	if (!cookie)
  		kobject_uevent(&disk_to_dev(md->disk)->kobj, action);
  	else {
  		snprintf(udev_cookie, DM_COOKIE_LENGTH, "%s=%u",
  			 DM_COOKIE_ENV_VAR_NAME, cookie);
  		kobject_uevent_env(&disk_to_dev(md->disk)->kobj, action, envp);
  	}
69267a30b   Alasdair G Kergon   dm: trigger chang...
2398
  }
7a8c3d3b9   Mike Anderson   dm: uevent genera...
2399
2400
2401
2402
  uint32_t dm_next_uevent_seq(struct mapped_device *md)
  {
  	return atomic_add_return(1, &md->uevent_seq);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
  uint32_t dm_get_event_nr(struct mapped_device *md)
  {
  	return atomic_read(&md->event_nr);
  }
  
  int dm_wait_event(struct mapped_device *md, int event_nr)
  {
  	return wait_event_interruptible(md->eventq,
  			(event_nr != atomic_read(&md->event_nr)));
  }
7a8c3d3b9   Mike Anderson   dm: uevent genera...
2413
2414
2415
2416
2417
2418
2419
2420
  void dm_uevent_add(struct mapped_device *md, struct list_head *elist)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&md->uevent_lock, flags);
  	list_add(elist, &md->uevent_list);
  	spin_unlock_irqrestore(&md->uevent_lock, flags);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2421
2422
2423
2424
2425
2426
2427
2428
  /*
   * The gendisk is only valid as long as you have a reference
   * count on 'md'.
   */
  struct gendisk *dm_disk(struct mapped_device *md)
  {
  	return md->disk;
  }
784aae735   Milan Broz   dm: add name and ...
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
  struct kobject *dm_kobject(struct mapped_device *md)
  {
  	return &md->kobj;
  }
  
  /*
   * struct mapped_device should not be exported outside of dm.c
   * so use this check to verify that kobj is part of md structure
   */
  struct mapped_device *dm_get_from_kobject(struct kobject *kobj)
  {
  	struct mapped_device *md;
  
  	md = container_of(kobj, struct mapped_device, kobj);
  	if (&md->kobj != kobj)
  		return NULL;
4d89b7b4e   Milan Broz   dm: sysfs skip ou...
2445
2446
2447
  	if (test_bit(DMF_FREEING, &md->flags) ||
  	    test_bit(DMF_DELETING, &md->flags))
  		return NULL;
784aae735   Milan Broz   dm: add name and ...
2448
2449
2450
  	dm_get(md);
  	return md;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2451
2452
2453
2454
  int dm_suspended(struct mapped_device *md)
  {
  	return test_bit(DMF_SUSPENDED, &md->flags);
  }
2e93ccc19   Kiyoshi Ueda   [PATCH] dm: suspe...
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
  int dm_noflush_suspending(struct dm_target *ti)
  {
  	struct mapped_device *md = dm_table_get_md(ti->table);
  	int r = __noflush_suspending(md);
  
  	dm_put(md);
  
  	return r;
  }
  EXPORT_SYMBOL_GPL(dm_noflush_suspending);
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
  struct dm_md_mempools *dm_alloc_md_mempools(unsigned type)
  {
  	struct dm_md_mempools *pools = kmalloc(sizeof(*pools), GFP_KERNEL);
  
  	if (!pools)
  		return NULL;
  
  	pools->io_pool = (type == DM_TYPE_BIO_BASED) ?
  			 mempool_create_slab_pool(MIN_IOS, _io_cache) :
  			 mempool_create_slab_pool(MIN_IOS, _rq_bio_info_cache);
  	if (!pools->io_pool)
  		goto free_pools_and_out;
  
  	pools->tio_pool = (type == DM_TYPE_BIO_BASED) ?
  			  mempool_create_slab_pool(MIN_IOS, _tio_cache) :
  			  mempool_create_slab_pool(MIN_IOS, _rq_tio_cache);
  	if (!pools->tio_pool)
  		goto free_io_pool_and_out;
  
  	pools->bs = (type == DM_TYPE_BIO_BASED) ?
  		    bioset_create(16, 0) : bioset_create(MIN_IOS, 0);
  	if (!pools->bs)
  		goto free_tio_pool_and_out;
  
  	return pools;
  
  free_tio_pool_and_out:
  	mempool_destroy(pools->tio_pool);
  
  free_io_pool_and_out:
  	mempool_destroy(pools->io_pool);
  
  free_pools_and_out:
  	kfree(pools);
  
  	return NULL;
  }
  
  void dm_free_md_mempools(struct dm_md_mempools *pools)
  {
  	if (!pools)
  		return;
  
  	if (pools->io_pool)
  		mempool_destroy(pools->io_pool);
  
  	if (pools->tio_pool)
  		mempool_destroy(pools->tio_pool);
  
  	if (pools->bs)
  		bioset_free(pools->bs);
  
  	kfree(pools);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2519
2520
2521
  static struct block_device_operations dm_blk_dops = {
  	.open = dm_blk_open,
  	.release = dm_blk_close,
aa129a224   Milan Broz   [PATCH] dm: suppo...
2522
  	.ioctl = dm_blk_ioctl,
3ac51e741   Darrick J. Wong   [PATCH] dm store ...
2523
  	.getgeo = dm_blk_getgeo,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
  	.owner = THIS_MODULE
  };
  
  EXPORT_SYMBOL(dm_get_mapinfo);
  
  /*
   * module hooks
   */
  module_init(dm_init);
  module_exit(dm_exit);
  
  module_param(major, uint, 0);
  MODULE_PARM_DESC(major, "The major number of the device mapper");
  MODULE_DESCRIPTION(DM_NAME " driver");
  MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
  MODULE_LICENSE("GPL");