Blame view

drivers/md/dm-table.c 36.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * Copyright (C) 2001 Sistina Software (UK) Limited.
d58168763   Mikulas Patocka   dm table: rework ...
3
   * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
   *
   * This file is released under the GPL.
   */
  
  #include "dm.h"
  
  #include <linux/module.h>
  #include <linux/vmalloc.h>
  #include <linux/blkdev.h>
  #include <linux/namei.h>
  #include <linux/ctype.h>
e7d2860b6   AndrĂ© Goddard Rosa   tree-wide: conver...
15
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
  #include <linux/slab.h>
  #include <linux/interrupt.h>
48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
18
  #include <linux/mutex.h>
d58168763   Mikulas Patocka   dm table: rework ...
19
  #include <linux/delay.h>
60063497a   Arun Sharma   atomic: use <linu...
20
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21

72d948616   Alasdair G Kergon   [PATCH] dm: impro...
22
  #define DM_MSG_PREFIX "table"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
  #define MAX_DEPTH 16
  #define NODE_SIZE L1_CACHE_BYTES
  #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
  #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
d58168763   Mikulas Patocka   dm table: rework ...
27
28
29
30
31
32
33
34
35
36
37
38
  /*
   * The table has always exactly one reference from either mapped_device->map
   * or hash_cell->new_map. This reference is not counted in table->holders.
   * A pair of dm_create_table/dm_destroy_table functions is used for table
   * creation/destruction.
   *
   * Temporary references from the other code increase table->holders. A pair
   * of dm_table_get/dm_table_put functions is used to manipulate it.
   *
   * When the table is about to be destroyed, we wait for table->holders to
   * drop to zero.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  struct dm_table {
1134e5ae7   Mike Anderson   [PATCH] dm table:...
40
  	struct mapped_device *md;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  	atomic_t holders;
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
42
  	unsigned type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
49
50
51
52
  
  	/* btree table */
  	unsigned int depth;
  	unsigned int counts[MAX_DEPTH];	/* in nodes */
  	sector_t *index[MAX_DEPTH];
  
  	unsigned int num_targets;
  	unsigned int num_allocated;
  	sector_t *highs;
  	struct dm_target *targets;
36a0456fb   Alasdair G Kergon   dm table: add imm...
53
  	struct target_type *immutable_target_type;
a91a2785b   Martin K. Petersen   block: Require su...
54
  	unsigned integrity_supported:1;
3791e2fc0   Alasdair G Kergon   dm table: add sin...
55
  	unsigned singleton:1;
5ae89a872   Mike Snitzer   dm: linear suppor...
56

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
  	/*
  	 * Indicates the rw permissions for the new logical
  	 * device.  This should be a combination of FMODE_READ
  	 * and FMODE_WRITE.
  	 */
aeb5d7270   Al Viro   [PATCH] introduce...
62
  	fmode_t mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
  
  	/* a list of devices used by this table */
  	struct list_head devices;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
  	/* events get handed up using this callback */
  	void (*event_fn)(void *);
  	void *event_context;
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
69
70
  
  	struct dm_md_mempools *mempools;
9d357b078   NeilBrown   dm: introduce tar...
71
72
  
  	struct list_head target_callbacks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  };
  
  /*
   * Similar to ceiling(log_size(n))
   */
  static unsigned int int_log(unsigned int n, unsigned int base)
  {
  	int result = 0;
  
  	while (n > 1) {
  		n = dm_div_up(n, base);
  		result++;
  	}
  
  	return result;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
   * Calculate the index of the child node of the n'th node k'th key.
   */
  static inline unsigned int get_child(unsigned int n, unsigned int k)
  {
  	return (n * CHILDREN_PER_NODE) + k;
  }
  
  /*
   * Return the n'th node of level l from table t.
   */
  static inline sector_t *get_node(struct dm_table *t,
  				 unsigned int l, unsigned int n)
  {
  	return t->index[l] + (n * KEYS_PER_NODE);
  }
  
  /*
   * Return the highest key that you could lookup from the n'th
   * node on level l of the btree.
   */
  static sector_t high(struct dm_table *t, unsigned int l, unsigned int n)
  {
  	for (; l < t->depth - 1; l++)
  		n = get_child(n, CHILDREN_PER_NODE - 1);
  
  	if (n >= t->counts[l])
  		return (sector_t) - 1;
  
  	return get_node(t, l, n)[KEYS_PER_NODE - 1];
  }
  
  /*
   * Fills in a level of the btree based on the highs of the level
   * below it.
   */
  static int setup_btree_index(unsigned int l, struct dm_table *t)
  {
  	unsigned int n, k;
  	sector_t *node;
  
  	for (n = 0U; n < t->counts[l]; n++) {
  		node = get_node(t, l, n);
  
  		for (k = 0U; k < KEYS_PER_NODE; k++)
  			node[k] = high(t, l + 1, get_child(n, k));
  	}
  
  	return 0;
  }
  
  void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size)
  {
  	unsigned long size;
  	void *addr;
  
  	/*
  	 * Check that we're not going to overflow.
  	 */
  	if (nmemb > (ULONG_MAX / elem_size))
  		return NULL;
  
  	size = nmemb * elem_size;
e29e65aac   Joe Perches   dm: use vzalloc
153
  	addr = vzalloc(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
  
  	return addr;
  }
086490125   Mike Snitzer   dm table: clean d...
157
  EXPORT_SYMBOL(dm_vcalloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
161
162
163
164
165
166
167
168
169
170
  
  /*
   * highs, and targets are managed as dynamic arrays during a
   * table load.
   */
  static int alloc_targets(struct dm_table *t, unsigned int num)
  {
  	sector_t *n_highs;
  	struct dm_target *n_targets;
  	int n = t->num_targets;
  
  	/*
  	 * Allocate both the target array and offset array at once.
512875bd9   Jun'ichi Nomura   dm: table detect ...
171
172
  	 * Append an empty entry to catch sectors beyond the end of
  	 * the device.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  	 */
512875bd9   Jun'ichi Nomura   dm: table detect ...
174
  	n_highs = (sector_t *) dm_vcalloc(num + 1, sizeof(struct dm_target) +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  					  sizeof(sector_t));
  	if (!n_highs)
  		return -ENOMEM;
  
  	n_targets = (struct dm_target *) (n_highs + num);
  
  	if (n) {
  		memcpy(n_highs, t->highs, sizeof(*n_highs) * n);
  		memcpy(n_targets, t->targets, sizeof(*n_targets) * n);
  	}
  
  	memset(n_highs + n, -1, sizeof(*n_highs) * (num - n));
  	vfree(t->highs);
  
  	t->num_allocated = num;
  	t->highs = n_highs;
  	t->targets = n_targets;
  
  	return 0;
  }
aeb5d7270   Al Viro   [PATCH] introduce...
195
  int dm_table_create(struct dm_table **result, fmode_t mode,
1134e5ae7   Mike Anderson   [PATCH] dm table:...
196
  		    unsigned num_targets, struct mapped_device *md)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
  {
094262db9   Dmitry Monakhov   dm: use kzalloc
198
  	struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
  
  	if (!t)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
  	INIT_LIST_HEAD(&t->devices);
9d357b078   NeilBrown   dm: introduce tar...
203
  	INIT_LIST_HEAD(&t->target_callbacks);
d58168763   Mikulas Patocka   dm table: rework ...
204
  	atomic_set(&t->holders, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
209
210
211
212
213
214
215
216
217
  
  	if (!num_targets)
  		num_targets = KEYS_PER_NODE;
  
  	num_targets = dm_round_up(num_targets, KEYS_PER_NODE);
  
  	if (alloc_targets(t, num_targets)) {
  		kfree(t);
  		t = NULL;
  		return -ENOMEM;
  	}
  
  	t->mode = mode;
1134e5ae7   Mike Anderson   [PATCH] dm table:...
218
  	t->md = md;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
223
224
225
  	*result = t;
  	return 0;
  }
  
  static void free_devices(struct list_head *devices)
  {
  	struct list_head *tmp, *next;
afb24528f   Paul Jimenez   dm: table use lis...
226
  	list_for_each_safe(tmp, next, devices) {
82b1519b3   Mikulas Patocka   dm: export struct...
227
228
  		struct dm_dev_internal *dd =
  		    list_entry(tmp, struct dm_dev_internal, list);
1b6da7545   Jonthan Brassow   dm table: improve...
229
230
  		DMWARN("dm_table_destroy: dm_put_device call missing for %s",
  		       dd->dm_dev.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
  		kfree(dd);
  	}
  }
d58168763   Mikulas Patocka   dm table: rework ...
234
  void dm_table_destroy(struct dm_table *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
  {
  	unsigned int i;
a79401559   Alasdair G Kergon   dm: bind new tabl...
237
238
  	if (!t)
  		return;
d58168763   Mikulas Patocka   dm table: rework ...
239
240
241
  	while (atomic_read(&t->holders))
  		msleep(1);
  	smp_mb();
26803b9f0   Will Drewry   dm ioctl: refacto...
242
  	/* free the indexes */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  	if (t->depth >= 2)
  		vfree(t->index[t->depth - 2]);
  
  	/* free the targets */
  	for (i = 0; i < t->num_targets; i++) {
  		struct dm_target *tgt = t->targets + i;
  
  		if (tgt->type->dtr)
  			tgt->type->dtr(tgt);
  
  		dm_put_target_type(tgt->type);
  	}
  
  	vfree(t->highs);
  
  	/* free the device list */
1b6da7545   Jonthan Brassow   dm table: improve...
259
  	if (t->devices.next != &t->devices)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  		free_devices(&t->devices);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261

e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
262
  	dm_free_md_mempools(t->mempools);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
268
269
  	kfree(t);
  }
  
  void dm_table_get(struct dm_table *t)
  {
  	atomic_inc(&t->holders);
  }
086490125   Mike Snitzer   dm table: clean d...
270
  EXPORT_SYMBOL(dm_table_get);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
  
  void dm_table_put(struct dm_table *t)
  {
  	if (!t)
  		return;
d58168763   Mikulas Patocka   dm table: rework ...
276
277
  	smp_mb__before_atomic_dec();
  	atomic_dec(&t->holders);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  }
086490125   Mike Snitzer   dm table: clean d...
279
  EXPORT_SYMBOL(dm_table_put);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
284
285
286
287
288
289
290
291
292
  
  /*
   * Checks to see if we need to extend highs or targets.
   */
  static inline int check_space(struct dm_table *t)
  {
  	if (t->num_targets >= t->num_allocated)
  		return alloc_targets(t, t->num_allocated * 2);
  
  	return 0;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
   * See if we've already got a device in the list.
   */
82b1519b3   Mikulas Patocka   dm: export struct...
295
  static struct dm_dev_internal *find_device(struct list_head *l, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  {
82b1519b3   Mikulas Patocka   dm: export struct...
297
  	struct dm_dev_internal *dd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
  
  	list_for_each_entry (dd, l, list)
82b1519b3   Mikulas Patocka   dm: export struct...
300
  		if (dd->dm_dev.bdev->bd_dev == dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
306
307
308
  			return dd;
  
  	return NULL;
  }
  
  /*
   * Open a device so we can use it as a map destination.
   */
82b1519b3   Mikulas Patocka   dm: export struct...
309
310
  static int open_dev(struct dm_dev_internal *d, dev_t dev,
  		    struct mapped_device *md)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
  {
  	static char *_claim_ptr = "I belong to device-mapper";
  	struct block_device *bdev;
  
  	int r;
82b1519b3   Mikulas Patocka   dm: export struct...
316
  	BUG_ON(d->dm_dev.bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317

d4d776299   Tejun Heo   block: clean up b...
318
  	bdev = blkdev_get_by_dev(dev, d->dm_dev.mode | FMODE_EXCL, _claim_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
  	if (IS_ERR(bdev))
  		return PTR_ERR(bdev);
e09b457bd   Tejun Heo   block: simplify h...
321

e09b457bd   Tejun Heo   block: simplify h...
322
323
  	r = bd_link_disk_holder(bdev, dm_disk(md));
  	if (r) {
e525fd89d   Tejun Heo   block: make blkde...
324
  		blkdev_put(bdev, d->dm_dev.mode | FMODE_EXCL);
e09b457bd   Tejun Heo   block: simplify h...
325
326
327
328
329
  		return r;
  	}
  
  	d->dm_dev.bdev = bdev;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
334
  }
  
  /*
   * Close a device that we've been using.
   */
82b1519b3   Mikulas Patocka   dm: export struct...
335
  static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  {
82b1519b3   Mikulas Patocka   dm: export struct...
337
  	if (!d->dm_dev.bdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  		return;
49731baa4   Tejun Heo   block: restore mu...
339
  	bd_unlink_disk_holder(d->dm_dev.bdev, dm_disk(md));
e525fd89d   Tejun Heo   block: make blkde...
340
  	blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL);
82b1519b3   Mikulas Patocka   dm: export struct...
341
  	d->dm_dev.bdev = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
  }
  
  /*
f6a1ed108   Mikulas Patocka   dm table: fix que...
345
   * If possible, this checks an area of a destination device is invalid.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
   */
f6a1ed108   Mikulas Patocka   dm table: fix que...
347
348
  static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev,
  				  sector_t start, sector_t len, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  {
f4808ca99   Milan Broz   dm table: reject ...
350
  	struct request_queue *q;
754c5fc7e   Mike Snitzer   dm: calculate que...
351
352
353
354
  	struct queue_limits *limits = data;
  	struct block_device *bdev = dev->bdev;
  	sector_t dev_size =
  		i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
02acc3a4f   Mike Snitzer   dm table: ensure ...
355
  	unsigned short logical_block_size_sectors =
754c5fc7e   Mike Snitzer   dm: calculate que...
356
  		limits->logical_block_size >> SECTOR_SHIFT;
02acc3a4f   Mike Snitzer   dm table: ensure ...
357
  	char b[BDEVNAME_SIZE];
2cd54d9be   Mike Anderson   dm: allow offline...
358

f4808ca99   Milan Broz   dm table: reject ...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  	/*
  	 * Some devices exist without request functions,
  	 * such as loop devices not yet bound to backing files.
  	 * Forbid the use of such devices.
  	 */
  	q = bdev_get_queue(bdev);
  	if (!q || !q->make_request_fn) {
  		DMWARN("%s: %s is not yet initialised: "
  		       "start=%llu, len=%llu, dev_size=%llu",
  		       dm_device_name(ti->table->md), bdevname(bdev, b),
  		       (unsigned long long)start,
  		       (unsigned long long)len,
  		       (unsigned long long)dev_size);
  		return 1;
  	}
2cd54d9be   Mike Anderson   dm: allow offline...
374
  	if (!dev_size)
f6a1ed108   Mikulas Patocka   dm table: fix que...
375
  		return 0;
2cd54d9be   Mike Anderson   dm: allow offline...
376

5dea271b6   Mike Snitzer   dm table: pass co...
377
  	if ((start >= dev_size) || (start + len > dev_size)) {
a963a9562   Mike Snitzer   dm table: add mor...
378
379
380
381
382
383
  		DMWARN("%s: %s too small for target: "
  		       "start=%llu, len=%llu, dev_size=%llu",
  		       dm_device_name(ti->table->md), bdevname(bdev, b),
  		       (unsigned long long)start,
  		       (unsigned long long)len,
  		       (unsigned long long)dev_size);
f6a1ed108   Mikulas Patocka   dm table: fix que...
384
  		return 1;
02acc3a4f   Mike Snitzer   dm table: ensure ...
385
386
387
  	}
  
  	if (logical_block_size_sectors <= 1)
f6a1ed108   Mikulas Patocka   dm table: fix que...
388
  		return 0;
02acc3a4f   Mike Snitzer   dm table: ensure ...
389
390
391
  
  	if (start & (logical_block_size_sectors - 1)) {
  		DMWARN("%s: start=%llu not aligned to h/w "
a963a9562   Mike Snitzer   dm table: add mor...
392
  		       "logical block size %u of %s",
02acc3a4f   Mike Snitzer   dm table: ensure ...
393
394
  		       dm_device_name(ti->table->md),
  		       (unsigned long long)start,
754c5fc7e   Mike Snitzer   dm: calculate que...
395
  		       limits->logical_block_size, bdevname(bdev, b));
f6a1ed108   Mikulas Patocka   dm table: fix que...
396
  		return 1;
02acc3a4f   Mike Snitzer   dm table: ensure ...
397
  	}
5dea271b6   Mike Snitzer   dm table: pass co...
398
  	if (len & (logical_block_size_sectors - 1)) {
02acc3a4f   Mike Snitzer   dm table: ensure ...
399
  		DMWARN("%s: len=%llu not aligned to h/w "
a963a9562   Mike Snitzer   dm table: add mor...
400
  		       "logical block size %u of %s",
02acc3a4f   Mike Snitzer   dm table: ensure ...
401
  		       dm_device_name(ti->table->md),
5dea271b6   Mike Snitzer   dm table: pass co...
402
  		       (unsigned long long)len,
754c5fc7e   Mike Snitzer   dm: calculate que...
403
  		       limits->logical_block_size, bdevname(bdev, b));
f6a1ed108   Mikulas Patocka   dm table: fix que...
404
  		return 1;
02acc3a4f   Mike Snitzer   dm table: ensure ...
405
  	}
f6a1ed108   Mikulas Patocka   dm table: fix que...
406
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
  }
  
  /*
570b9d968   Alasdair G Kergon   dm table: fix upg...
410
   * This upgrades the mode on an already open dm_dev, being
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
   * careful to leave things as they were if we fail to reopen the
570b9d968   Alasdair G Kergon   dm table: fix upg...
412
413
   * device and not to touch the existing bdev field in case
   * it is accessed concurrently inside dm_table_any_congested().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
   */
aeb5d7270   Al Viro   [PATCH] introduce...
415
  static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
82b1519b3   Mikulas Patocka   dm: export struct...
416
  			struct mapped_device *md)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
  {
  	int r;
570b9d968   Alasdair G Kergon   dm table: fix upg...
419
  	struct dm_dev_internal dd_new, dd_old;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420

570b9d968   Alasdair G Kergon   dm table: fix upg...
421
422
423
424
425
426
427
428
  	dd_new = dd_old = *dd;
  
  	dd_new.dm_dev.mode |= new_mode;
  	dd_new.dm_dev.bdev = NULL;
  
  	r = open_dev(&dd_new, dd->dm_dev.bdev->bd_dev, md);
  	if (r)
  		return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429

82b1519b3   Mikulas Patocka   dm: export struct...
430
  	dd->dm_dev.mode |= new_mode;
570b9d968   Alasdair G Kergon   dm table: fix upg...
431
  	close_dev(&dd_old, md);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432

570b9d968   Alasdair G Kergon   dm table: fix upg...
433
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
438
439
  }
  
  /*
   * Add a device to the list, or just increment the usage count if
   * it's already present.
   */
086490125   Mike Snitzer   dm table: clean d...
440
441
  int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
  		  struct dm_dev **result)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  {
  	int r;
69a2ce72a   Andrew Morton   dm: table use uni...
444
  	dev_t uninitialized_var(dev);
82b1519b3   Mikulas Patocka   dm: export struct...
445
  	struct dm_dev_internal *dd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  	unsigned int major, minor;
086490125   Mike Snitzer   dm table: clean d...
447
  	struct dm_table *t = ti->table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448

547bc9264   Eric Sesterhenn   BUG_ON() Conversi...
449
  	BUG_ON(!t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
453
454
455
456
457
  
  	if (sscanf(path, "%u:%u", &major, &minor) == 2) {
  		/* Extract the major/minor numbers */
  		dev = MKDEV(major, minor);
  		if (MAJOR(dev) != major || MINOR(dev) != minor)
  			return -EOVERFLOW;
  	} else {
  		/* convert the path to a device */
72e8264ed   Christoph Hellwig   [PATCH] dm: kill ...
458
459
460
461
462
463
  		struct block_device *bdev = lookup_bdev(path);
  
  		if (IS_ERR(bdev))
  			return PTR_ERR(bdev);
  		dev = bdev->bd_dev;
  		bdput(bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
466
467
468
469
470
  	}
  
  	dd = find_device(&t->devices, dev);
  	if (!dd) {
  		dd = kmalloc(sizeof(*dd), GFP_KERNEL);
  		if (!dd)
  			return -ENOMEM;
82b1519b3   Mikulas Patocka   dm: export struct...
471
472
  		dd->dm_dev.mode = mode;
  		dd->dm_dev.bdev = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473

f165921df   Jun'ichi Nomura   [PATCH] dm/md dep...
474
  		if ((r = open_dev(dd, dev, t->md))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
  			kfree(dd);
  			return r;
  		}
82b1519b3   Mikulas Patocka   dm: export struct...
478
  		format_dev_t(dd->dm_dev.name, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
  
  		atomic_set(&dd->count, 0);
  		list_add(&dd->list, &t->devices);
82b1519b3   Mikulas Patocka   dm: export struct...
482
  	} else if (dd->dm_dev.mode != (mode | dd->dm_dev.mode)) {
f165921df   Jun'ichi Nomura   [PATCH] dm/md dep...
483
  		r = upgrade_mode(dd, mode, t->md);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
  		if (r)
  			return r;
  	}
  	atomic_inc(&dd->count);
82b1519b3   Mikulas Patocka   dm: export struct...
488
  	*result = &dd->dm_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
  	return 0;
  }
086490125   Mike Snitzer   dm table: clean d...
491
  EXPORT_SYMBOL(dm_get_device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492

754c5fc7e   Mike Snitzer   dm: calculate que...
493
  int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
5dea271b6   Mike Snitzer   dm table: pass co...
494
  			 sector_t start, sector_t len, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  {
754c5fc7e   Mike Snitzer   dm: calculate que...
496
497
  	struct queue_limits *limits = data;
  	struct block_device *bdev = dev->bdev;
165125e1e   Jens Axboe   [BLOCK] Get rid o...
498
  	struct request_queue *q = bdev_get_queue(bdev);
0c2322e4c   Alasdair G Kergon   dm: detect lost q...
499
500
501
502
503
  	char b[BDEVNAME_SIZE];
  
  	if (unlikely(!q)) {
  		DMWARN("%s: Cannot set limits for nonexistent device %s",
  		       dm_device_name(ti->table->md), bdevname(bdev, b));
754c5fc7e   Mike Snitzer   dm: calculate que...
504
  		return 0;
0c2322e4c   Alasdair G Kergon   dm: detect lost q...
505
  	}
3cb402145   Bryn Reeves   [PATCH] dm: extra...
506

b27d7f16d   Martin K. Petersen   DM: Fix device ma...
507
508
  	if (bdev_stack_limits(limits, bdev, start) < 0)
  		DMWARN("%s: adding target device %s caused an alignment inconsistency: "
a963a9562   Mike Snitzer   dm table: add mor...
509
510
511
512
513
514
  		       "physical_block_size=%u, logical_block_size=%u, "
  		       "alignment_offset=%u, start=%llu",
  		       dm_device_name(ti->table->md), bdevname(bdev, b),
  		       q->limits.physical_block_size,
  		       q->limits.logical_block_size,
  		       q->limits.alignment_offset,
b27d7f16d   Martin K. Petersen   DM: Fix device ma...
515
  		       (unsigned long long) start << SECTOR_SHIFT);
3cb402145   Bryn Reeves   [PATCH] dm: extra...
516

9980c638a   Milan Broz   dm table: remove ...
517
518
519
520
  	/*
  	 * Check if merge fn is supported.
  	 * If not we'll force DM to use PAGE_SIZE or
  	 * smaller I/O, just to be safe.
3cb402145   Bryn Reeves   [PATCH] dm: extra...
521
  	 */
d5b9dd04b   Mikulas Patocka   dm: ignore merge_...
522
  	if (dm_queue_merge_is_compulsory(q) && !ti->type->merge)
72d4cd9f3   Mike Snitzer   block: max hardwa...
523
524
  		blk_limits_max_hw_sectors(limits,
  					  (unsigned int) (PAGE_SIZE >> 9));
754c5fc7e   Mike Snitzer   dm: calculate que...
525
  	return 0;
3cb402145   Bryn Reeves   [PATCH] dm: extra...
526
527
  }
  EXPORT_SYMBOL_GPL(dm_set_device_limits);
969429b50   NeilBrown   [PATCH] dm: make ...
528

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  /*
086490125   Mike Snitzer   dm table: clean d...
530
   * Decrement a device's use count and remove it if necessary.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
   */
82b1519b3   Mikulas Patocka   dm: export struct...
532
  void dm_put_device(struct dm_target *ti, struct dm_dev *d)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  {
82b1519b3   Mikulas Patocka   dm: export struct...
534
535
  	struct dm_dev_internal *dd = container_of(d, struct dm_dev_internal,
  						  dm_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  	if (atomic_dec_and_test(&dd->count)) {
f165921df   Jun'ichi Nomura   [PATCH] dm/md dep...
537
  		close_dev(dd, ti->table->md);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
540
541
  		list_del(&dd->list);
  		kfree(dd);
  	}
  }
086490125   Mike Snitzer   dm table: clean d...
542
  EXPORT_SYMBOL(dm_put_device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
  
  /*
   * Checks to see if the target joins onto the end of the table.
   */
  static int adjoin(struct dm_table *table, struct dm_target *ti)
  {
  	struct dm_target *prev;
  
  	if (!table->num_targets)
  		return !ti->begin;
  
  	prev = &table->targets[table->num_targets - 1];
  	return (ti->begin == (prev->begin + prev->len));
  }
  
  /*
   * Used to dynamically allocate the arg array.
   */
  static char **realloc_argv(unsigned *array_size, char **old_argv)
  {
  	char **argv;
  	unsigned new_size;
  
  	new_size = *array_size ? *array_size * 2 : 64;
  	argv = kmalloc(new_size * sizeof(*argv), GFP_KERNEL);
  	if (argv) {
  		memcpy(argv, old_argv, *array_size * sizeof(*argv));
  		*array_size = new_size;
  	}
  
  	kfree(old_argv);
  	return argv;
  }
  
  /*
   * Destructively splits up the argument list to pass to ctr.
   */
  int dm_split_args(int *argc, char ***argvp, char *input)
  {
  	char *start, *end = input, *out, **argv = NULL;
  	unsigned array_size = 0;
  
  	*argc = 0;
814d68629   David Teigland   [PATCH] dm table ...
586
587
588
589
590
  
  	if (!input) {
  		*argvp = NULL;
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
594
595
  	argv = realloc_argv(&array_size, argv);
  	if (!argv)
  		return -ENOMEM;
  
  	while (1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
  		/* Skip whitespace */
e7d2860b6   AndrĂ© Goddard Rosa   tree-wide: conver...
597
  		start = skip_spaces(end);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  
  		if (!*start)
  			break;	/* success, we hit the end */
  
  		/* 'out' is used to remove any back-quotes */
  		end = out = start;
  		while (*end) {
  			/* Everything apart from '\0' can be quoted */
  			if (*end == '\\' && *(end + 1)) {
  				*out++ = *(end + 1);
  				end += 2;
  				continue;
  			}
  
  			if (isspace(*end))
  				break;	/* end of token */
  
  			*out++ = *end++;
  		}
  
  		/* have we already filled the array ? */
  		if ((*argc + 1) > array_size) {
  			argv = realloc_argv(&array_size, argv);
  			if (!argv)
  				return -ENOMEM;
  		}
  
  		/* we know this is whitespace */
  		if (*end)
  			end++;
  
  		/* terminate the string and put it in the array */
  		*out = '\0';
  		argv[*argc] = start;
  		(*argc)++;
  	}
  
  	*argvp = argv;
  	return 0;
  }
be6d4305d   Mike Snitzer   dm table: validat...
638
639
640
641
642
643
644
  /*
   * Impose necessary and sufficient conditions on a devices's table such
   * that any incoming bio which respects its logical_block_size can be
   * processed successfully.  If it falls across the boundary between
   * two or more targets, the size of each piece it gets split into must
   * be compatible with the logical_block_size of the target processing it.
   */
754c5fc7e   Mike Snitzer   dm: calculate que...
645
646
  static int validate_hardware_logical_block_alignment(struct dm_table *table,
  						 struct queue_limits *limits)
be6d4305d   Mike Snitzer   dm table: validat...
647
648
649
650
651
652
  {
  	/*
  	 * This function uses arithmetic modulo the logical_block_size
  	 * (in units of 512-byte sectors).
  	 */
  	unsigned short device_logical_block_size_sects =
754c5fc7e   Mike Snitzer   dm: calculate que...
653
  		limits->logical_block_size >> SECTOR_SHIFT;
be6d4305d   Mike Snitzer   dm table: validat...
654
655
656
657
658
659
660
661
662
663
664
665
666
  
  	/*
  	 * Offset of the start of the next table entry, mod logical_block_size.
  	 */
  	unsigned short next_target_start = 0;
  
  	/*
  	 * Given an aligned bio that extends beyond the end of a
  	 * target, how many sectors must the next target handle?
  	 */
  	unsigned short remaining = 0;
  
  	struct dm_target *uninitialized_var(ti);
754c5fc7e   Mike Snitzer   dm: calculate que...
667
  	struct queue_limits ti_limits;
be6d4305d   Mike Snitzer   dm table: validat...
668
669
670
671
672
673
674
  	unsigned i = 0;
  
  	/*
  	 * Check each entry in the table in turn.
  	 */
  	while (i < dm_table_get_num_targets(table)) {
  		ti = dm_table_get_target(table, i++);
754c5fc7e   Mike Snitzer   dm: calculate que...
675
676
677
678
679
680
  		blk_set_default_limits(&ti_limits);
  
  		/* combine all target devices' limits */
  		if (ti->type->iterate_devices)
  			ti->type->iterate_devices(ti, dm_set_device_limits,
  						  &ti_limits);
be6d4305d   Mike Snitzer   dm table: validat...
681
682
683
684
685
  		/*
  		 * If the remaining sectors fall entirely within this
  		 * table entry are they compatible with its logical_block_size?
  		 */
  		if (remaining < ti->len &&
754c5fc7e   Mike Snitzer   dm: calculate que...
686
  		    remaining & ((ti_limits.logical_block_size >>
be6d4305d   Mike Snitzer   dm table: validat...
687
688
689
690
691
692
693
694
695
696
697
698
  				  SECTOR_SHIFT) - 1))
  			break;	/* Error */
  
  		next_target_start =
  		    (unsigned short) ((next_target_start + ti->len) &
  				      (device_logical_block_size_sects - 1));
  		remaining = next_target_start ?
  		    device_logical_block_size_sects - next_target_start : 0;
  	}
  
  	if (remaining) {
  		DMWARN("%s: table line %u (start sect %llu len %llu) "
a963a9562   Mike Snitzer   dm table: add mor...
699
  		       "not aligned to h/w logical block size %u",
be6d4305d   Mike Snitzer   dm table: validat...
700
701
702
  		       dm_device_name(table->md), i,
  		       (unsigned long long) ti->begin,
  		       (unsigned long long) ti->len,
754c5fc7e   Mike Snitzer   dm: calculate que...
703
  		       limits->logical_block_size);
be6d4305d   Mike Snitzer   dm table: validat...
704
705
706
707
708
  		return -EINVAL;
  	}
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
712
713
714
  int dm_table_add_target(struct dm_table *t, const char *type,
  			sector_t start, sector_t len, char *params)
  {
  	int r = -EINVAL, argc;
  	char **argv;
  	struct dm_target *tgt;
3791e2fc0   Alasdair G Kergon   dm table: add sin...
715
716
717
718
719
  	if (t->singleton) {
  		DMERR("%s: target type %s must appear alone in table",
  		      dm_device_name(t->md), t->targets->type->name);
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
724
725
726
  	if ((r = check_space(t)))
  		return r;
  
  	tgt = t->targets + t->num_targets;
  	memset(tgt, 0, sizeof(*tgt));
  
  	if (!len) {
72d948616   Alasdair G Kergon   [PATCH] dm: impro...
727
  		DMERR("%s: zero-length target", dm_device_name(t->md));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
730
731
732
  		return -EINVAL;
  	}
  
  	tgt->type = dm_get_target_type(type);
  	if (!tgt->type) {
72d948616   Alasdair G Kergon   [PATCH] dm: impro...
733
734
  		DMERR("%s: %s: unknown target type", dm_device_name(t->md),
  		      type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
  		return -EINVAL;
  	}
3791e2fc0   Alasdair G Kergon   dm table: add sin...
737
738
739
740
741
742
743
744
  	if (dm_target_needs_singleton(tgt->type)) {
  		if (t->num_targets) {
  			DMERR("%s: target type %s must appear alone in table",
  			      dm_device_name(t->md), type);
  			return -EINVAL;
  		}
  		t->singleton = 1;
  	}
cc6cbe141   Alasdair G Kergon   dm table: add alw...
745
746
747
748
749
  	if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) {
  		DMERR("%s: target type %s may not be included in read-only tables",
  		      dm_device_name(t->md), type);
  		return -EINVAL;
  	}
36a0456fb   Alasdair G Kergon   dm table: add imm...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  	if (t->immutable_target_type) {
  		if (t->immutable_target_type != tgt->type) {
  			DMERR("%s: immutable target type %s cannot be mixed with other target types",
  			      dm_device_name(t->md), t->immutable_target_type->name);
  			return -EINVAL;
  		}
  	} else if (dm_target_is_immutable(tgt->type)) {
  		if (t->num_targets) {
  			DMERR("%s: immutable target type %s cannot be mixed with other target types",
  			      dm_device_name(t->md), tgt->type->name);
  			return -EINVAL;
  		}
  		t->immutable_target_type = tgt->type;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  	tgt->table = t;
  	tgt->begin = start;
  	tgt->len = len;
  	tgt->error = "Unknown error";
  
  	/*
  	 * Does this target adjoin the previous one ?
  	 */
  	if (!adjoin(t, tgt)) {
  		tgt->error = "Gap in table";
  		r = -EINVAL;
  		goto bad;
  	}
  
  	r = dm_split_args(&argc, &argv, params);
  	if (r) {
  		tgt->error = "couldn't split parameters (insufficient memory)";
  		goto bad;
  	}
  
  	r = tgt->type->ctr(tgt, argc, argv);
  	kfree(argv);
  	if (r)
  		goto bad;
  
  	t->highs[t->num_targets++] = tgt->begin + tgt->len - 1;
936688d7e   Mike Snitzer   dm table: fix dis...
790
791
792
  	if (!tgt->num_discard_requests && tgt->discards_supported)
  		DMWARN("%s: %s: ignoring discards_supported because num_discard_requests is zero.",
  		       dm_device_name(t->md), type);
5ae89a872   Mike Snitzer   dm: linear suppor...
793

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
  	return 0;
  
   bad:
72d948616   Alasdair G Kergon   [PATCH] dm: impro...
797
  	DMERR("%s: %s: %s", dm_device_name(t->md), type, tgt->error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
  	dm_put_target_type(tgt->type);
  	return r;
  }
498f0103e   Mike Snitzer   dm table: share t...
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
  /*
   * Target argument parsing helpers.
   */
  static int validate_next_arg(struct dm_arg *arg, struct dm_arg_set *arg_set,
  			     unsigned *value, char **error, unsigned grouped)
  {
  	const char *arg_str = dm_shift_arg(arg_set);
  
  	if (!arg_str ||
  	    (sscanf(arg_str, "%u", value) != 1) ||
  	    (*value < arg->min) ||
  	    (*value > arg->max) ||
  	    (grouped && arg_set->argc < *value)) {
  		*error = arg->error;
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  int dm_read_arg(struct dm_arg *arg, struct dm_arg_set *arg_set,
  		unsigned *value, char **error)
  {
  	return validate_next_arg(arg, arg_set, value, error, 0);
  }
  EXPORT_SYMBOL(dm_read_arg);
  
  int dm_read_arg_group(struct dm_arg *arg, struct dm_arg_set *arg_set,
  		      unsigned *value, char **error)
  {
  	return validate_next_arg(arg, arg_set, value, error, 1);
  }
  EXPORT_SYMBOL(dm_read_arg_group);
  
  const char *dm_shift_arg(struct dm_arg_set *as)
  {
  	char *r;
  
  	if (as->argc) {
  		as->argc--;
  		r = *as->argv;
  		as->argv++;
  		return r;
  	}
  
  	return NULL;
  }
  EXPORT_SYMBOL(dm_shift_arg);
  
  void dm_consume_args(struct dm_arg_set *as, unsigned num_args)
  {
  	BUG_ON(as->argc < num_args);
  	as->argc -= num_args;
  	as->argv += num_args;
  }
  EXPORT_SYMBOL(dm_consume_args);
26803b9f0   Will Drewry   dm ioctl: refacto...
857
  static int dm_table_set_type(struct dm_table *t)
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
  {
  	unsigned i;
  	unsigned bio_based = 0, request_based = 0;
  	struct dm_target *tgt;
  	struct dm_dev_internal *dd;
  	struct list_head *devices;
  
  	for (i = 0; i < t->num_targets; i++) {
  		tgt = t->targets + i;
  		if (dm_target_request_based(tgt))
  			request_based = 1;
  		else
  			bio_based = 1;
  
  		if (bio_based && request_based) {
  			DMWARN("Inconsistent table: different target types"
  			       " can't be mixed up");
  			return -EINVAL;
  		}
  	}
  
  	if (bio_based) {
  		/* We must use this table as bio-based */
  		t->type = DM_TYPE_BIO_BASED;
  		return 0;
  	}
  
  	BUG_ON(!request_based); /* No targets in this table */
  
  	/* Non-request-stackable devices can't be used for request-based dm */
  	devices = dm_table_get_devices(t);
  	list_for_each_entry(dd, devices, list) {
  		if (!blk_queue_stackable(bdev_get_queue(dd->dm_dev.bdev))) {
  			DMWARN("table load rejected: including"
  			       " non-request-stackable devices");
  			return -EINVAL;
  		}
  	}
  
  	/*
  	 * Request-based dm supports only tables that have a single target now.
  	 * To support multiple targets, request splitting support is needed,
  	 * and that needs lots of changes in the block-layer.
  	 * (e.g. request completion process for partial completion.)
  	 */
  	if (t->num_targets > 1) {
  		DMWARN("Request-based dm doesn't support multiple targets yet");
  		return -EINVAL;
  	}
  
  	t->type = DM_TYPE_REQUEST_BASED;
  
  	return 0;
  }
  
  unsigned dm_table_get_type(struct dm_table *t)
  {
  	return t->type;
  }
36a0456fb   Alasdair G Kergon   dm table: add imm...
917
918
919
920
  struct target_type *dm_table_get_immutable_target_type(struct dm_table *t)
  {
  	return t->immutable_target_type;
  }
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
921
922
923
924
925
926
927
928
929
930
931
932
933
  bool dm_table_request_based(struct dm_table *t)
  {
  	return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED;
  }
  
  int dm_table_alloc_md_mempools(struct dm_table *t)
  {
  	unsigned type = dm_table_get_type(t);
  
  	if (unlikely(type == DM_TYPE_NONE)) {
  		DMWARN("no table type is set, can't allocate mempools");
  		return -EINVAL;
  	}
a91a2785b   Martin K. Petersen   block: Require su...
934
  	t->mempools = dm_alloc_md_mempools(type, t->integrity_supported);
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
  	if (!t->mempools)
  		return -ENOMEM;
  
  	return 0;
  }
  
  void dm_table_free_md_mempools(struct dm_table *t)
  {
  	dm_free_md_mempools(t->mempools);
  	t->mempools = NULL;
  }
  
  struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t)
  {
  	return t->mempools;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
  static int setup_indexes(struct dm_table *t)
  {
  	int i;
  	unsigned int total = 0;
  	sector_t *indexes;
  
  	/* allocate the space for *all* the indexes */
  	for (i = t->depth - 2; i >= 0; i--) {
  		t->counts[i] = dm_div_up(t->counts[i + 1], CHILDREN_PER_NODE);
  		total += t->counts[i];
  	}
  
  	indexes = (sector_t *) dm_vcalloc(total, (unsigned long) NODE_SIZE);
  	if (!indexes)
  		return -ENOMEM;
  
  	/* set up internal nodes, bottom-up */
82d601dc0   Jun'ichi Nomura   dm: table remove ...
968
  	for (i = t->depth - 2; i >= 0; i--) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
972
973
974
975
976
977
978
979
  		t->index[i] = indexes;
  		indexes += (KEYS_PER_NODE * t->counts[i]);
  		setup_btree_index(i, t);
  	}
  
  	return 0;
  }
  
  /*
   * Builds the btree to index the map.
   */
26803b9f0   Will Drewry   dm ioctl: refacto...
980
  static int dm_table_build_index(struct dm_table *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
982
983
  {
  	int r = 0;
  	unsigned int leaf_nodes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
985
986
987
988
989
990
991
992
993
994
995
996
  	/* how many indexes will the btree have ? */
  	leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE);
  	t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE);
  
  	/* leaf layer has already been set up */
  	t->counts[t->depth - 1] = leaf_nodes;
  	t->index[t->depth - 1] = t->highs;
  
  	if (t->depth >= 2)
  		r = setup_indexes(t);
  
  	return r;
  }
26803b9f0   Will Drewry   dm ioctl: refacto...
997
  /*
a63a5cf84   Mike Snitzer   dm: improve block...
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
   * Get a disk whose integrity profile reflects the table's profile.
   * If %match_all is true, all devices' profiles must match.
   * If %match_all is false, all devices must at least have an
   * allocated integrity profile; but uninitialized is ok.
   * Returns NULL if integrity support was inconsistent or unavailable.
   */
  static struct gendisk * dm_table_get_integrity_disk(struct dm_table *t,
  						    bool match_all)
  {
  	struct list_head *devices = dm_table_get_devices(t);
  	struct dm_dev_internal *dd = NULL;
  	struct gendisk *prev_disk = NULL, *template_disk = NULL;
  
  	list_for_each_entry(dd, devices, list) {
  		template_disk = dd->dm_dev.bdev->bd_disk;
  		if (!blk_get_integrity(template_disk))
  			goto no_integrity;
  		if (!match_all && !blk_integrity_is_initialized(template_disk))
  			continue; /* skip uninitialized profiles */
  		else if (prev_disk &&
  			 blk_integrity_compare(prev_disk, template_disk) < 0)
  			goto no_integrity;
  		prev_disk = template_disk;
  	}
  
  	return template_disk;
  
  no_integrity:
  	if (prev_disk)
  		DMWARN("%s: integrity not set: %s and %s profile mismatch",
  		       dm_device_name(t->md),
  		       prev_disk->disk_name,
  		       template_disk->disk_name);
  	return NULL;
  }
  
  /*
26803b9f0   Will Drewry   dm ioctl: refacto...
1035
   * Register the mapped device for blk_integrity support if
a63a5cf84   Mike Snitzer   dm: improve block...
1036
1037
1038
1039
1040
1041
1042
   * the underlying devices have an integrity profile.  But all devices
   * may not have matching profiles (checking all devices isn't reliable
   * during table load because this table may use other DM device(s) which
   * must be resumed before they will have an initialized integity profile).
   * Stacked DM devices force a 2 stage integrity profile validation:
   * 1 - during load, validate all initialized integrity profiles match
   * 2 - during resume, validate all integrity profiles match
26803b9f0   Will Drewry   dm ioctl: refacto...
1043
1044
1045
   */
  static int dm_table_prealloc_integrity(struct dm_table *t, struct mapped_device *md)
  {
a63a5cf84   Mike Snitzer   dm: improve block...
1046
  	struct gendisk *template_disk = NULL;
26803b9f0   Will Drewry   dm ioctl: refacto...
1047

a63a5cf84   Mike Snitzer   dm: improve block...
1048
1049
1050
  	template_disk = dm_table_get_integrity_disk(t, false);
  	if (!template_disk)
  		return 0;
26803b9f0   Will Drewry   dm ioctl: refacto...
1051

a63a5cf84   Mike Snitzer   dm: improve block...
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
  	if (!blk_integrity_is_initialized(dm_disk(md))) {
  		t->integrity_supported = 1;
  		return blk_integrity_register(dm_disk(md), NULL);
  	}
  
  	/*
  	 * If DM device already has an initalized integrity
  	 * profile the new profile should not conflict.
  	 */
  	if (blk_integrity_is_initialized(template_disk) &&
  	    blk_integrity_compare(dm_disk(md), template_disk) < 0) {
  		DMWARN("%s: conflict with existing integrity profile: "
  		       "%s profile mismatch",
  		       dm_device_name(t->md),
  		       template_disk->disk_name);
  		return 1;
  	}
  
  	/* Preserve existing initialized integrity profile */
  	t->integrity_supported = 1;
26803b9f0   Will Drewry   dm ioctl: refacto...
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
  	return 0;
  }
  
  /*
   * Prepares the table for use by building the indices,
   * setting the type, and allocating mempools.
   */
  int dm_table_complete(struct dm_table *t)
  {
  	int r;
  
  	r = dm_table_set_type(t);
  	if (r) {
  		DMERR("unable to set table type");
  		return r;
  	}
  
  	r = dm_table_build_index(t);
  	if (r) {
  		DMERR("unable to build btrees");
  		return r;
  	}
  
  	r = dm_table_prealloc_integrity(t, t->md);
  	if (r) {
  		DMERR("could not register integrity profile.");
  		return r;
  	}
  
  	r = dm_table_alloc_md_mempools(t);
  	if (r)
  		DMERR("unable to allocate mempools");
  
  	return r;
  }
48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
1107
  static DEFINE_MUTEX(_event_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
1109
1110
  void dm_table_event_callback(struct dm_table *t,
  			     void (*fn)(void *), void *context)
  {
48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
1111
  	mutex_lock(&_event_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
  	t->event_fn = fn;
  	t->event_context = context;
48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
1114
  	mutex_unlock(&_event_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
1116
1117
1118
1119
1120
1121
1122
1123
  }
  
  void dm_table_event(struct dm_table *t)
  {
  	/*
  	 * You can no longer call dm_table_event() from interrupt
  	 * context, use a bottom half instead.
  	 */
  	BUG_ON(in_interrupt());
48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
1124
  	mutex_lock(&_event_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125
1126
  	if (t->event_fn)
  		t->event_fn(t->event_context);
48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
1127
  	mutex_unlock(&_event_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
  }
086490125   Mike Snitzer   dm table: clean d...
1129
  EXPORT_SYMBOL(dm_table_event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
1131
1132
1133
1134
  
  sector_t dm_table_get_size(struct dm_table *t)
  {
  	return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0;
  }
086490125   Mike Snitzer   dm table: clean d...
1135
  EXPORT_SYMBOL(dm_table_get_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
1137
1138
  
  struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index)
  {
143535396   Milan Broz   [PATCH] dm table:...
1139
  	if (index >= t->num_targets)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
1142
1143
1144
1145
1146
  		return NULL;
  
  	return t->targets + index;
  }
  
  /*
   * Search the btree for the correct target.
512875bd9   Jun'ichi Nomura   dm: table detect ...
1147
1148
1149
   *
   * Caller should check returned pointer with dm_target_is_valid()
   * to trap I/O beyond end of device.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
   */
  struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector)
  {
  	unsigned int l, n = 0, k = 0;
  	sector_t *node;
  
  	for (l = 0; l < t->depth; l++) {
  		n = get_child(n, k);
  		node = get_node(t, l, n);
  
  		for (k = 0; k < KEYS_PER_NODE; k++)
  			if (node[k] >= sector)
  				break;
  	}
  
  	return &t->targets[(KEYS_PER_NODE * n) + k];
  }
9c47008d1   Martin K. Petersen   dm: add integrity...
1167
  /*
754c5fc7e   Mike Snitzer   dm: calculate que...
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
   * Establish the new table's queue_limits and validate them.
   */
  int dm_calculate_queue_limits(struct dm_table *table,
  			      struct queue_limits *limits)
  {
  	struct dm_target *uninitialized_var(ti);
  	struct queue_limits ti_limits;
  	unsigned i = 0;
  
  	blk_set_default_limits(limits);
  
  	while (i < dm_table_get_num_targets(table)) {
  		blk_set_default_limits(&ti_limits);
  
  		ti = dm_table_get_target(table, i++);
  
  		if (!ti->type->iterate_devices)
  			goto combine_limits;
  
  		/*
  		 * Combine queue limits of all the devices this target uses.
  		 */
  		ti->type->iterate_devices(ti, dm_set_device_limits,
  					  &ti_limits);
40bea4312   Mike Snitzer   dm stripe: expose...
1192
1193
1194
  		/* Set I/O hints portion of queue limits */
  		if (ti->type->io_hints)
  			ti->type->io_hints(ti, &ti_limits);
754c5fc7e   Mike Snitzer   dm: calculate que...
1195
1196
1197
1198
  		/*
  		 * Check each device area is consistent with the target's
  		 * overall queue limits.
  		 */
f6a1ed108   Mikulas Patocka   dm table: fix que...
1199
1200
  		if (ti->type->iterate_devices(ti, device_area_is_invalid,
  					      &ti_limits))
754c5fc7e   Mike Snitzer   dm: calculate que...
1201
1202
1203
1204
1205
1206
1207
1208
  			return -EINVAL;
  
  combine_limits:
  		/*
  		 * Merge this target's queue limits into the overall limits
  		 * for the table.
  		 */
  		if (blk_stack_limits(limits, &ti_limits, 0) < 0)
b27d7f16d   Martin K. Petersen   DM: Fix device ma...
1209
  			DMWARN("%s: adding target device "
754c5fc7e   Mike Snitzer   dm: calculate que...
1210
  			       "(start sect %llu len %llu) "
b27d7f16d   Martin K. Petersen   DM: Fix device ma...
1211
  			       "caused an alignment inconsistency",
754c5fc7e   Mike Snitzer   dm: calculate que...
1212
1213
1214
1215
1216
1217
1218
1219
1220
  			       dm_device_name(table->md),
  			       (unsigned long long) ti->begin,
  			       (unsigned long long) ti->len);
  	}
  
  	return validate_hardware_logical_block_alignment(table, limits);
  }
  
  /*
9c47008d1   Martin K. Petersen   dm: add integrity...
1221
   * Set the integrity profile for this device if all devices used have
a63a5cf84   Mike Snitzer   dm: improve block...
1222
1223
1224
1225
   * matching profiles.  We're quite deep in the resume path but still
   * don't know if all devices (particularly DM devices this device
   * may be stacked on) have matching profiles.  Even if the profiles
   * don't match we have no way to fail (to resume) at this point.
9c47008d1   Martin K. Petersen   dm: add integrity...
1226
1227
1228
   */
  static void dm_table_set_integrity(struct dm_table *t)
  {
a63a5cf84   Mike Snitzer   dm: improve block...
1229
  	struct gendisk *template_disk = NULL;
9c47008d1   Martin K. Petersen   dm: add integrity...
1230
1231
1232
  
  	if (!blk_get_integrity(dm_disk(t->md)))
  		return;
a63a5cf84   Mike Snitzer   dm: improve block...
1233
  	template_disk = dm_table_get_integrity_disk(t, true);
876fbba1d   Mike Snitzer   dm table: avoid c...
1234
1235
1236
1237
  	if (template_disk)
  		blk_integrity_register(dm_disk(t->md),
  				       blk_get_integrity(template_disk));
  	else if (blk_integrity_is_initialized(dm_disk(t->md)))
a63a5cf84   Mike Snitzer   dm: improve block...
1238
1239
  		DMWARN("%s: device no longer has a valid integrity profile",
  		       dm_device_name(t->md));
876fbba1d   Mike Snitzer   dm table: avoid c...
1240
1241
1242
  	else
  		DMWARN("%s: unable to establish an integrity profile",
  		       dm_device_name(t->md));
9c47008d1   Martin K. Petersen   dm: add integrity...
1243
  }
ed8b752bc   Mike Snitzer   dm table: set flu...
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
  static int device_flush_capable(struct dm_target *ti, struct dm_dev *dev,
  				sector_t start, sector_t len, void *data)
  {
  	unsigned flush = (*(unsigned *)data);
  	struct request_queue *q = bdev_get_queue(dev->bdev);
  
  	return q && (q->flush_flags & flush);
  }
  
  static bool dm_table_supports_flush(struct dm_table *t, unsigned flush)
  {
  	struct dm_target *ti;
  	unsigned i = 0;
  
  	/*
  	 * Require at least one underlying device to support flushes.
  	 * t->devices includes internal dm devices such as mirror logs
  	 * so we need to use iterate_devices here, which targets
  	 * supporting flushes must provide.
  	 */
  	while (i < dm_table_get_num_targets(t)) {
  		ti = dm_table_get_target(t, i++);
  
  		if (!ti->num_flush_requests)
  			continue;
  
  		if (ti->type->iterate_devices &&
  		    ti->type->iterate_devices(ti, device_flush_capable, &flush))
  			return 1;
  	}
  
  	return 0;
  }
983c7db34   Milan Broz   dm crypt: always ...
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  static bool dm_table_discard_zeroes_data(struct dm_table *t)
  {
  	struct dm_target *ti;
  	unsigned i = 0;
  
  	/* Ensure that all targets supports discard_zeroes_data. */
  	while (i < dm_table_get_num_targets(t)) {
  		ti = dm_table_get_target(t, i++);
  
  		if (ti->discard_zeroes_data_unsupported)
  			return 0;
  	}
  
  	return 1;
  }
4693c9668   Mandeep Singh Baines   dm table: propaga...
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
  static int device_is_nonrot(struct dm_target *ti, struct dm_dev *dev,
  			    sector_t start, sector_t len, void *data)
  {
  	struct request_queue *q = bdev_get_queue(dev->bdev);
  
  	return q && blk_queue_nonrot(q);
  }
  
  static bool dm_table_is_nonrot(struct dm_table *t)
  {
  	struct dm_target *ti;
  	unsigned i = 0;
  
  	/* Ensure that all underlying device are non-rotational. */
  	while (i < dm_table_get_num_targets(t)) {
  		ti = dm_table_get_target(t, i++);
  
  		if (!ti->type->iterate_devices ||
  		    !ti->type->iterate_devices(ti, device_is_nonrot, NULL))
  			return 0;
  	}
  
  	return 1;
  }
754c5fc7e   Mike Snitzer   dm: calculate que...
1316
1317
  void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
  			       struct queue_limits *limits)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  {
ed8b752bc   Mike Snitzer   dm table: set flu...
1319
  	unsigned flush = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
  	/*
1197764e4   Mike Snitzer   dm table: establi...
1321
  	 * Copy table's limits to the DM device's request_queue
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322
  	 */
754c5fc7e   Mike Snitzer   dm: calculate que...
1323
  	q->limits = *limits;
c9a3f6d6f   Jens Axboe   dm: use unlocked ...
1324

5ae89a872   Mike Snitzer   dm: linear suppor...
1325
1326
1327
1328
  	if (!dm_table_supports_discards(t))
  		queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
  	else
  		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
ed8b752bc   Mike Snitzer   dm table: set flu...
1329
1330
1331
1332
1333
1334
  	if (dm_table_supports_flush(t, REQ_FLUSH)) {
  		flush |= REQ_FLUSH;
  		if (dm_table_supports_flush(t, REQ_FUA))
  			flush |= REQ_FUA;
  	}
  	blk_queue_flush(q, flush);
983c7db34   Milan Broz   dm crypt: always ...
1335
1336
  	if (!dm_table_discard_zeroes_data(t))
  		q->limits.discard_zeroes_data = 0;
4693c9668   Mandeep Singh Baines   dm table: propaga...
1337
1338
1339
1340
  	if (dm_table_is_nonrot(t))
  		queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
  	else
  		queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q);
9c47008d1   Martin K. Petersen   dm: add integrity...
1341
  	dm_table_set_integrity(t);
e6ee8c0b7   Kiyoshi Ueda   dm: enable reques...
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
  
  	/*
  	 * QUEUE_FLAG_STACKABLE must be set after all queue settings are
  	 * visible to other CPUs because, once the flag is set, incoming bios
  	 * are processed by request-based dm, which refers to the queue
  	 * settings.
  	 * Until the flag set, bios are passed to bio-based dm and queued to
  	 * md->deferred where queue settings are not needed yet.
  	 * Those bios are passed to request-based dm at the resume time.
  	 */
  	smp_mb();
  	if (dm_table_request_based(t))
  		queue_flag_set_unlocked(QUEUE_FLAG_STACKABLE, q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
  }
  
  unsigned int dm_table_get_num_targets(struct dm_table *t)
  {
  	return t->num_targets;
  }
  
  struct list_head *dm_table_get_devices(struct dm_table *t)
  {
  	return &t->devices;
  }
aeb5d7270   Al Viro   [PATCH] introduce...
1366
  fmode_t dm_table_get_mode(struct dm_table *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
1368
1369
  {
  	return t->mode;
  }
086490125   Mike Snitzer   dm table: clean d...
1370
  EXPORT_SYMBOL(dm_table_get_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
  
  static void suspend_targets(struct dm_table *t, unsigned postsuspend)
  {
  	int i = t->num_targets;
  	struct dm_target *ti = t->targets;
  
  	while (i--) {
  		if (postsuspend) {
  			if (ti->type->postsuspend)
  				ti->type->postsuspend(ti);
  		} else if (ti->type->presuspend)
  			ti->type->presuspend(ti);
  
  		ti++;
  	}
  }
  
  void dm_table_presuspend_targets(struct dm_table *t)
  {
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
1390
1391
  	if (!t)
  		return;
e8488d085   Adrian Bunk   dm table: drop vo...
1392
  	suspend_targets(t, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1393
1394
1395
1396
  }
  
  void dm_table_postsuspend_targets(struct dm_table *t)
  {
cf222b376   Alasdair G Kergon   [PATCH] device-ma...
1397
1398
  	if (!t)
  		return;
e8488d085   Adrian Bunk   dm table: drop vo...
1399
  	suspend_targets(t, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
  }
8757b7764   Milan Broz   [PATCH] dm table:...
1401
  int dm_table_resume_targets(struct dm_table *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1402
  {
8757b7764   Milan Broz   [PATCH] dm table:...
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
  	int i, r = 0;
  
  	for (i = 0; i < t->num_targets; i++) {
  		struct dm_target *ti = t->targets + i;
  
  		if (!ti->type->preresume)
  			continue;
  
  		r = ti->type->preresume(ti);
  		if (r)
  			return r;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
1416
1417
1418
1419
1420
1421
  
  	for (i = 0; i < t->num_targets; i++) {
  		struct dm_target *ti = t->targets + i;
  
  		if (ti->type->resume)
  			ti->type->resume(ti);
  	}
8757b7764   Milan Broz   [PATCH] dm table:...
1422
1423
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1424
  }
9d357b078   NeilBrown   dm: introduce tar...
1425
1426
1427
1428
1429
  void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callbacks *cb)
  {
  	list_add(&cb->list, &t->target_callbacks);
  }
  EXPORT_SYMBOL_GPL(dm_table_add_target_callbacks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1430
1431
  int dm_table_any_congested(struct dm_table *t, int bdi_bits)
  {
82b1519b3   Mikulas Patocka   dm: export struct...
1432
  	struct dm_dev_internal *dd;
afb24528f   Paul Jimenez   dm: table use lis...
1433
  	struct list_head *devices = dm_table_get_devices(t);
9d357b078   NeilBrown   dm: introduce tar...
1434
  	struct dm_target_callbacks *cb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
  	int r = 0;
afb24528f   Paul Jimenez   dm: table use lis...
1436
  	list_for_each_entry(dd, devices, list) {
82b1519b3   Mikulas Patocka   dm: export struct...
1437
  		struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev);
0c2322e4c   Alasdair G Kergon   dm: detect lost q...
1438
1439
1440
1441
1442
1443
1444
1445
  		char b[BDEVNAME_SIZE];
  
  		if (likely(q))
  			r |= bdi_congested(&q->backing_dev_info, bdi_bits);
  		else
  			DMWARN_LIMIT("%s: any_congested: nonexistent device %s",
  				     dm_device_name(t->md),
  				     bdevname(dd->dm_dev.bdev, b));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
  	}
9d357b078   NeilBrown   dm: introduce tar...
1447
1448
1449
  	list_for_each_entry(cb, &t->target_callbacks, list)
  		if (cb->congested_fn)
  			r |= cb->congested_fn(cb, bdi_bits);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450
1451
  	return r;
  }
cec47e3d4   Kiyoshi Ueda   dm: prepare for r...
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
  int dm_table_any_busy_target(struct dm_table *t)
  {
  	unsigned i;
  	struct dm_target *ti;
  
  	for (i = 0; i < t->num_targets; i++) {
  		ti = t->targets + i;
  		if (ti->type->busy && ti->type->busy(ti))
  			return 1;
  	}
  
  	return 0;
  }
1134e5ae7   Mike Anderson   [PATCH] dm table:...
1465
1466
  struct mapped_device *dm_table_get_md(struct dm_table *t)
  {
1134e5ae7   Mike Anderson   [PATCH] dm table:...
1467
1468
  	return t->md;
  }
086490125   Mike Snitzer   dm table: clean d...
1469
  EXPORT_SYMBOL(dm_table_get_md);
1134e5ae7   Mike Anderson   [PATCH] dm table:...
1470

5ae89a872   Mike Snitzer   dm: linear suppor...
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
  static int device_discard_capable(struct dm_target *ti, struct dm_dev *dev,
  				  sector_t start, sector_t len, void *data)
  {
  	struct request_queue *q = bdev_get_queue(dev->bdev);
  
  	return q && blk_queue_discard(q);
  }
  
  bool dm_table_supports_discards(struct dm_table *t)
  {
  	struct dm_target *ti;
  	unsigned i = 0;
5ae89a872   Mike Snitzer   dm: linear suppor...
1483
  	/*
4c2593270   Mike Snitzer   dm table: allow t...
1484
1485
  	 * Unless any target used by the table set discards_supported,
  	 * require at least one underlying device to support discards.
5ae89a872   Mike Snitzer   dm: linear suppor...
1486
1487
  	 * t->devices includes internal dm devices such as mirror logs
  	 * so we need to use iterate_devices here, which targets
936688d7e   Mike Snitzer   dm table: fix dis...
1488
  	 * supporting discard selectively must provide.
5ae89a872   Mike Snitzer   dm: linear suppor...
1489
1490
1491
  	 */
  	while (i < dm_table_get_num_targets(t)) {
  		ti = dm_table_get_target(t, i++);
936688d7e   Mike Snitzer   dm table: fix dis...
1492
1493
  		if (!ti->num_discard_requests)
  			continue;
4c2593270   Mike Snitzer   dm table: allow t...
1494
1495
  		if (ti->discards_supported)
  			return 1;
5ae89a872   Mike Snitzer   dm: linear suppor...
1496
1497
1498
1499
1500
1501
1502
  		if (ti->type->iterate_devices &&
  		    ti->type->iterate_devices(ti, device_discard_capable, NULL))
  			return 1;
  	}
  
  	return 0;
  }