Blame view

drivers/md/dm-thin-metadata.c 45.5 KB
991d9fa02   Joe Thornber   dm: add thin prov...
1
  /*
da105ed5f   Joe Thornber   dm thin metadata:...
2
   * Copyright (C) 2011-2012 Red Hat, Inc.
991d9fa02   Joe Thornber   dm: add thin prov...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
   *
   * This file is released under the GPL.
   */
  
  #include "dm-thin-metadata.h"
  #include "persistent-data/dm-btree.h"
  #include "persistent-data/dm-space-map.h"
  #include "persistent-data/dm-space-map-disk.h"
  #include "persistent-data/dm-transaction-manager.h"
  
  #include <linux/list.h>
  #include <linux/device-mapper.h>
  #include <linux/workqueue.h>
  
  /*--------------------------------------------------------------------------
   * As far as the metadata goes, there is:
   *
   * - A superblock in block zero, taking up fewer than 512 bytes for
   *   atomic writes.
   *
   * - A space map managing the metadata blocks.
   *
   * - A space map managing the data blocks.
   *
   * - A btree mapping our internal thin dev ids onto struct disk_device_details.
   *
   * - A hierarchical btree, with 2 levels which effectively maps (thin
   *   dev id, virtual block) -> block_time.  Block time is a 64-bit
   *   field holding the time in the low 24 bits, and block in the top 48
   *   bits.
   *
   * BTrees consist solely of btree_nodes, that fill a block.  Some are
   * internal nodes, as such their values are a __le64 pointing to other
   * nodes.  Leaf nodes can store data of any reasonable size (ie. much
   * smaller than the block size).  The nodes consist of the header,
   * followed by an array of keys, followed by an array of values.  We have
   * to binary search on the keys so they're all held together to help the
   * cpu cache.
   *
   * Space maps have 2 btrees:
   *
   * - One maps a uint64_t onto a struct index_entry.  Which points to a
   *   bitmap block, and has some details about how many free entries there
   *   are etc.
   *
   * - The bitmap blocks have a header (for the checksum).  Then the rest
   *   of the block is pairs of bits.  With the meaning being:
   *
   *   0 - ref count is 0
   *   1 - ref count is 1
   *   2 - ref count is 2
   *   3 - ref count is higher than 2
   *
   * - If the count is higher than 2 then the ref count is entered in a
   *   second btree that directly maps the block_address to a uint32_t ref
   *   count.
   *
   * The space map metadata variant doesn't have a bitmaps btree.  Instead
   * it has one single blocks worth of index_entries.  This avoids
   * recursive issues with the bitmap btree needing to allocate space in
   * order to insert.  With a small data block size such as 64k the
   * metadata support data devices that are hundreds of terrabytes.
   *
   * The space maps allocate space linearly from front to back.  Space that
   * is freed in a transaction is never recycled within that transaction.
   * To try and avoid fragmenting _free_ space the allocator always goes
   * back and fills in gaps.
   *
   * All metadata io is in THIN_METADATA_BLOCK_SIZE sized/aligned chunks
   * from the block manager.
   *--------------------------------------------------------------------------*/
  
  #define DM_MSG_PREFIX   "thin metadata"
  
  #define THIN_SUPERBLOCK_MAGIC 27022010
  #define THIN_SUPERBLOCK_LOCATION 0
07f2b6e03   Mike Snitzer   dm thin: ensure u...
79
  #define THIN_VERSION 2
991d9fa02   Joe Thornber   dm: add thin prov...
80
  #define SECTOR_TO_BLOCK_SHIFT 3
8c971178a   Joe Thornber   dm thin metadata:...
81
  /*
5f12c3384   Dennis Yang   dm thin metadata:...
82
   * For btree insert:
8c971178a   Joe Thornber   dm thin metadata:...
83
84
   *  3 for btree insert +
   *  2 for btree lookup used within space map
5f12c3384   Dennis Yang   dm thin metadata:...
85
86
87
   * For btree remove:
   *  2 for shadow spine +
   *  4 for rebalance 3 child node
8c971178a   Joe Thornber   dm thin metadata:...
88
   */
5f12c3384   Dennis Yang   dm thin metadata:...
89
  #define THIN_MAX_CONCURRENT_LOCKS 6
8c971178a   Joe Thornber   dm thin metadata:...
90

991d9fa02   Joe Thornber   dm: add thin prov...
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  /* This should be plenty */
  #define SPACE_MAP_ROOT_SIZE 128
  
  /*
   * Little endian on-disk superblock and device details.
   */
  struct thin_disk_superblock {
  	__le32 csum;	/* Checksum of superblock except for this field. */
  	__le32 flags;
  	__le64 blocknr;	/* This block number, dm_block_t. */
  
  	__u8 uuid[16];
  	__le64 magic;
  	__le32 version;
  	__le32 time;
  
  	__le64 trans_id;
  
  	/*
  	 * Root held by userspace transactions.
  	 */
  	__le64 held_root;
  
  	__u8 data_space_map_root[SPACE_MAP_ROOT_SIZE];
  	__u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE];
  
  	/*
  	 * 2-level btree mapping (dev_id, (dev block, time)) -> data block
  	 */
  	__le64 data_mapping_root;
  
  	/*
  	 * Device detail root mapping dev_id -> device_details
  	 */
  	__le64 device_details_root;
  
  	__le32 data_block_size;		/* In 512-byte sectors. */
  
  	__le32 metadata_block_size;	/* In 512-byte sectors. */
  	__le64 metadata_nr_blocks;
  
  	__le32 compat_flags;
  	__le32 compat_ro_flags;
  	__le32 incompat_flags;
  } __packed;
  
  struct disk_device_details {
  	__le64 mapped_blocks;
  	__le64 transaction_id;		/* When created. */
  	__le32 creation_time;
  	__le32 snapshotted_time;
  } __packed;
  
  struct dm_pool_metadata {
  	struct hlist_node hash;
  
  	struct block_device *bdev;
  	struct dm_block_manager *bm;
  	struct dm_space_map *metadata_sm;
  	struct dm_space_map *data_sm;
  	struct dm_transaction_manager *tm;
  	struct dm_transaction_manager *nb_tm;
  
  	/*
  	 * Two-level btree.
  	 * First level holds thin_dev_t.
  	 * Second level holds mappings.
  	 */
  	struct dm_btree_info info;
  
  	/*
  	 * Non-blocking version of the above.
  	 */
  	struct dm_btree_info nb_info;
  
  	/*
  	 * Just the top level for deleting whole devices.
  	 */
  	struct dm_btree_info tl_info;
  
  	/*
  	 * Just the bottom level for creating new devices.
  	 */
  	struct dm_btree_info bl_info;
  
  	/*
  	 * Describes the device details btree.
  	 */
  	struct dm_btree_info details_info;
  
  	struct rw_semaphore root_lock;
  	uint32_t time;
991d9fa02   Joe Thornber   dm: add thin prov...
183
184
185
186
187
188
  	dm_block_t root;
  	dm_block_t details_root;
  	struct list_head thin_devices;
  	uint64_t trans_id;
  	unsigned long flags;
  	sector_t data_block_size;
da105ed5f   Joe Thornber   dm thin metadata:...
189
190
  
  	/*
1484d4ff2   Joe Thornber   dm thin metadata:...
191
192
193
194
195
196
  	 * We reserve a section of the metadata for commit overhead.
  	 * All reported space does *not* include this.
  	 */
  	dm_block_t metadata_reserve;
  
  	/*
da105ed5f   Joe Thornber   dm thin metadata:...
197
198
199
200
201
  	 * Set if a transaction has to be aborted but the attempt to roll back
  	 * to the previous (good) transaction failed.  The only pool metadata
  	 * operation possible in this state is the closing of the device.
  	 */
  	bool fail_io:1;
5a32083d0   Joe Thornber   dm: take care to ...
202
203
204
205
206
207
208
  
  	/*
  	 * Reading the space map roots can fail, so we read it into these
  	 * buffers before the superblock is locked and updated.
  	 */
  	__u8 data_space_map_root[SPACE_MAP_ROOT_SIZE];
  	__u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE];
991d9fa02   Joe Thornber   dm: add thin prov...
209
210
211
212
213
214
215
216
  };
  
  struct dm_thin_device {
  	struct list_head list;
  	struct dm_pool_metadata *pmd;
  	dm_thin_id id;
  
  	int open_count;
da105ed5f   Joe Thornber   dm thin metadata:...
217
218
  	bool changed:1;
  	bool aborted_with_changes:1;
991d9fa02   Joe Thornber   dm: add thin prov...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
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
  	uint64_t mapped_blocks;
  	uint64_t transaction_id;
  	uint32_t creation_time;
  	uint32_t snapshotted_time;
  };
  
  /*----------------------------------------------------------------
   * superblock validator
   *--------------------------------------------------------------*/
  
  #define SUPERBLOCK_CSUM_XOR 160774
  
  static void sb_prepare_for_write(struct dm_block_validator *v,
  				 struct dm_block *b,
  				 size_t block_size)
  {
  	struct thin_disk_superblock *disk_super = dm_block_data(b);
  
  	disk_super->blocknr = cpu_to_le64(dm_block_location(b));
  	disk_super->csum = cpu_to_le32(dm_bm_checksum(&disk_super->flags,
  						      block_size - sizeof(__le32),
  						      SUPERBLOCK_CSUM_XOR));
  }
  
  static int sb_check(struct dm_block_validator *v,
  		    struct dm_block *b,
  		    size_t block_size)
  {
  	struct thin_disk_superblock *disk_super = dm_block_data(b);
  	__le32 csum_le;
  
  	if (dm_block_location(b) != le64_to_cpu(disk_super->blocknr)) {
  		DMERR("sb_check failed: blocknr %llu: "
  		      "wanted %llu", le64_to_cpu(disk_super->blocknr),
  		      (unsigned long long)dm_block_location(b));
  		return -ENOTBLK;
  	}
  
  	if (le64_to_cpu(disk_super->magic) != THIN_SUPERBLOCK_MAGIC) {
  		DMERR("sb_check failed: magic %llu: "
  		      "wanted %llu", le64_to_cpu(disk_super->magic),
  		      (unsigned long long)THIN_SUPERBLOCK_MAGIC);
  		return -EILSEQ;
  	}
  
  	csum_le = cpu_to_le32(dm_bm_checksum(&disk_super->flags,
  					     block_size - sizeof(__le32),
  					     SUPERBLOCK_CSUM_XOR));
  	if (csum_le != disk_super->csum) {
  		DMERR("sb_check failed: csum %u: wanted %u",
  		      le32_to_cpu(csum_le), le32_to_cpu(disk_super->csum));
  		return -EILSEQ;
  	}
  
  	return 0;
  }
  
  static struct dm_block_validator sb_validator = {
  	.name = "superblock",
  	.prepare_for_write = sb_prepare_for_write,
  	.check = sb_check
  };
  
  /*----------------------------------------------------------------
   * Methods for the btree value types
   *--------------------------------------------------------------*/
  
  static uint64_t pack_block_time(dm_block_t b, uint32_t t)
  {
  	return (b << 24) | t;
  }
  
  static void unpack_block_time(uint64_t v, dm_block_t *b, uint32_t *t)
  {
  	*b = v >> 24;
  	*t = v & ((1 << 24) - 1);
  }
018cede93   Mike Snitzer   dm persistent dat...
296
  static void data_block_inc(void *context, const void *value_le)
991d9fa02   Joe Thornber   dm: add thin prov...
297
298
299
300
301
302
303
304
305
306
  {
  	struct dm_space_map *sm = context;
  	__le64 v_le;
  	uint64_t b;
  	uint32_t t;
  
  	memcpy(&v_le, value_le, sizeof(v_le));
  	unpack_block_time(le64_to_cpu(v_le), &b, &t);
  	dm_sm_inc_block(sm, b);
  }
018cede93   Mike Snitzer   dm persistent dat...
307
  static void data_block_dec(void *context, const void *value_le)
991d9fa02   Joe Thornber   dm: add thin prov...
308
309
310
311
312
313
314
315
316
317
  {
  	struct dm_space_map *sm = context;
  	__le64 v_le;
  	uint64_t b;
  	uint32_t t;
  
  	memcpy(&v_le, value_le, sizeof(v_le));
  	unpack_block_time(le64_to_cpu(v_le), &b, &t);
  	dm_sm_dec_block(sm, b);
  }
018cede93   Mike Snitzer   dm persistent dat...
318
  static int data_block_equal(void *context, const void *value1_le, const void *value2_le)
991d9fa02   Joe Thornber   dm: add thin prov...
319
320
321
322
323
324
325
326
327
328
329
330
  {
  	__le64 v1_le, v2_le;
  	uint64_t b1, b2;
  	uint32_t t;
  
  	memcpy(&v1_le, value1_le, sizeof(v1_le));
  	memcpy(&v2_le, value2_le, sizeof(v2_le));
  	unpack_block_time(le64_to_cpu(v1_le), &b1, &t);
  	unpack_block_time(le64_to_cpu(v2_le), &b2, &t);
  
  	return b1 == b2;
  }
018cede93   Mike Snitzer   dm persistent dat...
331
  static void subtree_inc(void *context, const void *value)
991d9fa02   Joe Thornber   dm: add thin prov...
332
333
334
335
336
337
338
339
340
  {
  	struct dm_btree_info *info = context;
  	__le64 root_le;
  	uint64_t root;
  
  	memcpy(&root_le, value, sizeof(root_le));
  	root = le64_to_cpu(root_le);
  	dm_tm_inc(info->tm, root);
  }
018cede93   Mike Snitzer   dm persistent dat...
341
  static void subtree_dec(void *context, const void *value)
991d9fa02   Joe Thornber   dm: add thin prov...
342
343
344
345
346
347
348
349
  {
  	struct dm_btree_info *info = context;
  	__le64 root_le;
  	uint64_t root;
  
  	memcpy(&root_le, value, sizeof(root_le));
  	root = le64_to_cpu(root_le);
  	if (dm_btree_del(info, root))
29f929b52   Mike Snitzer   dm thin metadata:...
350
  		DMERR("btree delete failed");
991d9fa02   Joe Thornber   dm: add thin prov...
351
  }
018cede93   Mike Snitzer   dm persistent dat...
352
  static int subtree_equal(void *context, const void *value1_le, const void *value2_le)
991d9fa02   Joe Thornber   dm: add thin prov...
353
354
355
356
357
358
359
360
361
  {
  	__le64 v1_le, v2_le;
  	memcpy(&v1_le, value1_le, sizeof(v1_le));
  	memcpy(&v2_le, value2_le, sizeof(v2_le));
  
  	return v1_le == v2_le;
  }
  
  /*----------------------------------------------------------------*/
259711920   Joe Thornber   dm thin metadata:...
362
363
364
365
366
367
368
369
370
371
372
373
374
  static int superblock_lock_zero(struct dm_pool_metadata *pmd,
  				struct dm_block **sblock)
  {
  	return dm_bm_write_lock_zero(pmd->bm, THIN_SUPERBLOCK_LOCATION,
  				     &sb_validator, sblock);
  }
  
  static int superblock_lock(struct dm_pool_metadata *pmd,
  			   struct dm_block **sblock)
  {
  	return dm_bm_write_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
  				&sb_validator, sblock);
  }
332627db0   Joe Thornber   dm thin metadata:...
375
  static int __superblock_all_zeroes(struct dm_block_manager *bm, int *result)
991d9fa02   Joe Thornber   dm: add thin prov...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  {
  	int r;
  	unsigned i;
  	struct dm_block *b;
  	__le64 *data_le, zero = cpu_to_le64(0);
  	unsigned block_size = dm_bm_block_size(bm) / sizeof(__le64);
  
  	/*
  	 * We can't use a validator here - it may be all zeroes.
  	 */
  	r = dm_bm_read_lock(bm, THIN_SUPERBLOCK_LOCATION, NULL, &b);
  	if (r)
  		return r;
  
  	data_le = dm_block_data(b);
  	*result = 1;
  	for (i = 0; i < block_size; i++) {
  		if (data_le[i] != zero) {
  			*result = 0;
  			break;
  		}
  	}
4c7da06f5   Mikulas Patocka   dm persistent dat...
398
399
400
  	dm_bm_unlock(b);
  
  	return 0;
991d9fa02   Joe Thornber   dm: add thin prov...
401
  }
41675aea3   Joe Thornber   dm thin metadata:...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  static void __setup_btree_details(struct dm_pool_metadata *pmd)
  {
  	pmd->info.tm = pmd->tm;
  	pmd->info.levels = 2;
  	pmd->info.value_type.context = pmd->data_sm;
  	pmd->info.value_type.size = sizeof(__le64);
  	pmd->info.value_type.inc = data_block_inc;
  	pmd->info.value_type.dec = data_block_dec;
  	pmd->info.value_type.equal = data_block_equal;
  
  	memcpy(&pmd->nb_info, &pmd->info, sizeof(pmd->nb_info));
  	pmd->nb_info.tm = pmd->nb_tm;
  
  	pmd->tl_info.tm = pmd->tm;
  	pmd->tl_info.levels = 1;
e3cbf9451   Joe Thornber   dm persistent dat...
417
  	pmd->tl_info.value_type.context = &pmd->bl_info;
41675aea3   Joe Thornber   dm thin metadata:...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  	pmd->tl_info.value_type.size = sizeof(__le64);
  	pmd->tl_info.value_type.inc = subtree_inc;
  	pmd->tl_info.value_type.dec = subtree_dec;
  	pmd->tl_info.value_type.equal = subtree_equal;
  
  	pmd->bl_info.tm = pmd->tm;
  	pmd->bl_info.levels = 1;
  	pmd->bl_info.value_type.context = pmd->data_sm;
  	pmd->bl_info.value_type.size = sizeof(__le64);
  	pmd->bl_info.value_type.inc = data_block_inc;
  	pmd->bl_info.value_type.dec = data_block_dec;
  	pmd->bl_info.value_type.equal = data_block_equal;
  
  	pmd->details_info.tm = pmd->tm;
  	pmd->details_info.levels = 1;
  	pmd->details_info.value_type.context = NULL;
  	pmd->details_info.value_type.size = sizeof(struct disk_device_details);
  	pmd->details_info.value_type.inc = NULL;
  	pmd->details_info.value_type.dec = NULL;
  	pmd->details_info.value_type.equal = NULL;
  }
5a32083d0   Joe Thornber   dm: take care to ...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
  static int save_sm_roots(struct dm_pool_metadata *pmd)
  {
  	int r;
  	size_t len;
  
  	r = dm_sm_root_size(pmd->metadata_sm, &len);
  	if (r < 0)
  		return r;
  
  	r = dm_sm_copy_root(pmd->metadata_sm, &pmd->metadata_space_map_root, len);
  	if (r < 0)
  		return r;
  
  	r = dm_sm_root_size(pmd->data_sm, &len);
  	if (r < 0)
  		return r;
  
  	return dm_sm_copy_root(pmd->data_sm, &pmd->data_space_map_root, len);
  }
  
  static void copy_sm_roots(struct dm_pool_metadata *pmd,
  			  struct thin_disk_superblock *disk)
  {
  	memcpy(&disk->metadata_space_map_root,
  	       &pmd->metadata_space_map_root,
  	       sizeof(pmd->metadata_space_map_root));
  
  	memcpy(&disk->data_space_map_root,
  	       &pmd->data_space_map_root,
  	       sizeof(pmd->data_space_map_root));
  }
9cb6653f9   Joe Thornber   dm thin metadata:...
470
471
472
473
474
475
476
477
478
  static int __write_initial_superblock(struct dm_pool_metadata *pmd)
  {
  	int r;
  	struct dm_block *sblock;
  	struct thin_disk_superblock *disk_super;
  	sector_t bdev_size = i_size_read(pmd->bdev->bd_inode) >> SECTOR_SHIFT;
  
  	if (bdev_size > THIN_METADATA_MAX_SECTORS)
  		bdev_size = THIN_METADATA_MAX_SECTORS;
5a32083d0   Joe Thornber   dm: take care to ...
479
  	r = dm_sm_commit(pmd->data_sm);
10d2a9ff7   Joe Thornber   dm thin metadata:...
480
481
  	if (r < 0)
  		return r;
91bcdb92d   Joe Thornber   dm thin metadata:...
482
  	r = dm_tm_pre_commit(pmd->tm);
10d2a9ff7   Joe Thornber   dm thin metadata:...
483
484
  	if (r < 0)
  		return r;
91bcdb92d   Joe Thornber   dm thin metadata:...
485
  	r = save_sm_roots(pmd);
10d2a9ff7   Joe Thornber   dm thin metadata:...
486
487
  	if (r < 0)
  		return r;
9cb6653f9   Joe Thornber   dm thin metadata:...
488
489
490
491
492
  	r = superblock_lock_zero(pmd, &sblock);
  	if (r)
  		return r;
  
  	disk_super = dm_block_data(sblock);
10d2a9ff7   Joe Thornber   dm thin metadata:...
493
  	disk_super->flags = 0;
583ceee2e   Joe Thornber   dm thin metadata:...
494
  	memset(disk_super->uuid, 0, sizeof(disk_super->uuid));
9cb6653f9   Joe Thornber   dm thin metadata:...
495
496
497
  	disk_super->magic = cpu_to_le64(THIN_SUPERBLOCK_MAGIC);
  	disk_super->version = cpu_to_le32(THIN_VERSION);
  	disk_super->time = 0;
10d2a9ff7   Joe Thornber   dm thin metadata:...
498
499
  	disk_super->trans_id = 0;
  	disk_super->held_root = 0;
5a32083d0   Joe Thornber   dm: take care to ...
500
  	copy_sm_roots(pmd, disk_super);
10d2a9ff7   Joe Thornber   dm thin metadata:...
501
502
503
  
  	disk_super->data_mapping_root = cpu_to_le64(pmd->root);
  	disk_super->device_details_root = cpu_to_le64(pmd->details_root);
7d48935ef   Mike Snitzer   dm thin: allow me...
504
  	disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE);
9cb6653f9   Joe Thornber   dm thin metadata:...
505
506
  	disk_super->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT);
  	disk_super->data_block_size = cpu_to_le32(pmd->data_block_size);
270938bac   Joe Thornber   dm thin metadata:...
507
  	return dm_tm_commit(pmd->tm, sblock);
9cb6653f9   Joe Thornber   dm thin metadata:...
508
  }
a97e5e6fd   Joe Thornber   dm thin metadata:...
509
  static int __format_metadata(struct dm_pool_metadata *pmd)
991d9fa02   Joe Thornber   dm: add thin prov...
510
511
  {
  	int r;
384ef0e62   Joe Thornber   dm persistent dat...
512

e4d2205cd   Joe Thornber   dm thin metadata:...
513
514
515
516
517
518
  	r = dm_tm_create_with_sm(pmd->bm, THIN_SUPERBLOCK_LOCATION,
  				 &pmd->tm, &pmd->metadata_sm);
  	if (r < 0) {
  		DMERR("tm_create_with_sm failed");
  		return r;
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
519

a97e5e6fd   Joe Thornber   dm thin metadata:...
520
  	pmd->data_sm = dm_sm_disk_create(pmd->tm, 0);
e4d2205cd   Joe Thornber   dm thin metadata:...
521
522
523
  	if (IS_ERR(pmd->data_sm)) {
  		DMERR("sm_disk_create failed");
  		r = PTR_ERR(pmd->data_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
524
  		goto bad_cleanup_tm;
991d9fa02   Joe Thornber   dm: add thin prov...
525
  	}
d6332814e   Joe Thornber   dm thin metadata:...
526
  	pmd->nb_tm = dm_tm_create_non_blocking_clone(pmd->tm);
991d9fa02   Joe Thornber   dm: add thin prov...
527
  	if (!pmd->nb_tm) {
0fa5b17b0   Joe Thornber   dm thin metadata:...
528
  		DMERR("could not create non-blocking clone tm");
991d9fa02   Joe Thornber   dm: add thin prov...
529
  		r = -ENOMEM;
0fa5b17b0   Joe Thornber   dm thin metadata:...
530
  		goto bad_cleanup_data_sm;
991d9fa02   Joe Thornber   dm: add thin prov...
531
  	}
41675aea3   Joe Thornber   dm thin metadata:...
532
  	__setup_btree_details(pmd);
991d9fa02   Joe Thornber   dm: add thin prov...
533

9cb6653f9   Joe Thornber   dm thin metadata:...
534
535
  	r = dm_btree_empty(&pmd->info, &pmd->root);
  	if (r < 0)
0fa5b17b0   Joe Thornber   dm thin metadata:...
536
  		goto bad_cleanup_nb_tm;
9cb6653f9   Joe Thornber   dm thin metadata:...
537
538
539
540
  
  	r = dm_btree_empty(&pmd->details_info, &pmd->details_root);
  	if (r < 0) {
  		DMERR("couldn't create devices root");
0fa5b17b0   Joe Thornber   dm thin metadata:...
541
  		goto bad_cleanup_nb_tm;
9cb6653f9   Joe Thornber   dm thin metadata:...
542
543
544
545
  	}
  
  	r = __write_initial_superblock(pmd);
  	if (r)
0fa5b17b0   Joe Thornber   dm thin metadata:...
546
  		goto bad_cleanup_nb_tm;
9cb6653f9   Joe Thornber   dm thin metadata:...
547

991d9fa02   Joe Thornber   dm: add thin prov...
548
  	return 0;
0fa5b17b0   Joe Thornber   dm thin metadata:...
549
550
551
  bad_cleanup_nb_tm:
  	dm_tm_destroy(pmd->nb_tm);
  bad_cleanup_data_sm:
d6332814e   Joe Thornber   dm thin metadata:...
552
  	dm_sm_destroy(pmd->data_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
553
  bad_cleanup_tm:
d6332814e   Joe Thornber   dm thin metadata:...
554
555
  	dm_tm_destroy(pmd->tm);
  	dm_sm_destroy(pmd->metadata_sm);
991d9fa02   Joe Thornber   dm: add thin prov...
556
557
558
  
  	return r;
  }
d73ec5253   Mike Snitzer   dm thin metadata:...
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
  static int __check_incompat_features(struct thin_disk_superblock *disk_super,
  				     struct dm_pool_metadata *pmd)
  {
  	uint32_t features;
  
  	features = le32_to_cpu(disk_super->incompat_flags) & ~THIN_FEATURE_INCOMPAT_SUPP;
  	if (features) {
  		DMERR("could not access metadata due to unsupported optional features (%lx).",
  		      (unsigned long)features);
  		return -EINVAL;
  	}
  
  	/*
  	 * Check for read-only metadata to skip the following RDWR checks.
  	 */
  	if (get_disk_ro(pmd->bdev->bd_disk))
  		return 0;
  
  	features = le32_to_cpu(disk_super->compat_ro_flags) & ~THIN_FEATURE_COMPAT_RO_SUPP;
  	if (features) {
  		DMERR("could not access metadata RDWR due to unsupported optional features (%lx).",
  		      (unsigned long)features);
  		return -EINVAL;
  	}
  
  	return 0;
  }
e4d2205cd   Joe Thornber   dm thin metadata:...
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  static int __open_metadata(struct dm_pool_metadata *pmd)
  {
  	int r;
  	struct dm_block *sblock;
  	struct thin_disk_superblock *disk_super;
  
  	r = dm_bm_read_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
  			    &sb_validator, &sblock);
  	if (r < 0) {
  		DMERR("couldn't read superblock");
  		return r;
  	}
  
  	disk_super = dm_block_data(sblock);
d73ec5253   Mike Snitzer   dm thin metadata:...
600

9aec8629e   Mike Snitzer   dm thin metadata:...
601
602
603
604
605
606
607
608
  	/* Verify the data block size hasn't changed */
  	if (le32_to_cpu(disk_super->data_block_size) != pmd->data_block_size) {
  		DMERR("changing the data block size (from %u to %llu) is not supported",
  		      le32_to_cpu(disk_super->data_block_size),
  		      (unsigned long long)pmd->data_block_size);
  		r = -EINVAL;
  		goto bad_unlock_sblock;
  	}
d73ec5253   Mike Snitzer   dm thin metadata:...
609
  	r = __check_incompat_features(disk_super, pmd);
0fa5b17b0   Joe Thornber   dm thin metadata:...
610
611
  	if (r < 0)
  		goto bad_unlock_sblock;
d73ec5253   Mike Snitzer   dm thin metadata:...
612

e4d2205cd   Joe Thornber   dm thin metadata:...
613
614
615
616
617
618
  	r = dm_tm_open_with_sm(pmd->bm, THIN_SUPERBLOCK_LOCATION,
  			       disk_super->metadata_space_map_root,
  			       sizeof(disk_super->metadata_space_map_root),
  			       &pmd->tm, &pmd->metadata_sm);
  	if (r < 0) {
  		DMERR("tm_open_with_sm failed");
0fa5b17b0   Joe Thornber   dm thin metadata:...
619
  		goto bad_unlock_sblock;
e4d2205cd   Joe Thornber   dm thin metadata:...
620
621
622
623
624
625
  	}
  
  	pmd->data_sm = dm_sm_disk_open(pmd->tm, disk_super->data_space_map_root,
  				       sizeof(disk_super->data_space_map_root));
  	if (IS_ERR(pmd->data_sm)) {
  		DMERR("sm_disk_open failed");
e4d2205cd   Joe Thornber   dm thin metadata:...
626
  		r = PTR_ERR(pmd->data_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
627
  		goto bad_cleanup_tm;
e4d2205cd   Joe Thornber   dm thin metadata:...
628
  	}
e4d2205cd   Joe Thornber   dm thin metadata:...
629
630
  	pmd->nb_tm = dm_tm_create_non_blocking_clone(pmd->tm);
  	if (!pmd->nb_tm) {
0fa5b17b0   Joe Thornber   dm thin metadata:...
631
  		DMERR("could not create non-blocking clone tm");
e4d2205cd   Joe Thornber   dm thin metadata:...
632
  		r = -ENOMEM;
0fa5b17b0   Joe Thornber   dm thin metadata:...
633
  		goto bad_cleanup_data_sm;
e4d2205cd   Joe Thornber   dm thin metadata:...
634
635
636
  	}
  
  	__setup_btree_details(pmd);
4c7da06f5   Mikulas Patocka   dm persistent dat...
637
638
639
  	dm_bm_unlock(sblock);
  
  	return 0;
e4d2205cd   Joe Thornber   dm thin metadata:...
640

0fa5b17b0   Joe Thornber   dm thin metadata:...
641
  bad_cleanup_data_sm:
e4d2205cd   Joe Thornber   dm thin metadata:...
642
  	dm_sm_destroy(pmd->data_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
643
  bad_cleanup_tm:
e4d2205cd   Joe Thornber   dm thin metadata:...
644
645
  	dm_tm_destroy(pmd->tm);
  	dm_sm_destroy(pmd->metadata_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
646
647
  bad_unlock_sblock:
  	dm_bm_unlock(sblock);
e4d2205cd   Joe Thornber   dm thin metadata:...
648
649
650
  
  	return r;
  }
66b1edc05   Joe Thornber   dm thin metadata:...
651
  static int __open_or_format_metadata(struct dm_pool_metadata *pmd, bool format_device)
e4d2205cd   Joe Thornber   dm thin metadata:...
652
  {
8801e0694   Joe Thornber   dm thin metadata:...
653
  	int r, unformatted;
237074c0a   Joe Thornber   dm thin metadata:...
654

8801e0694   Joe Thornber   dm thin metadata:...
655
  	r = __superblock_all_zeroes(pmd->bm, &unformatted);
237074c0a   Joe Thornber   dm thin metadata:...
656
657
  	if (r)
  		return r;
8801e0694   Joe Thornber   dm thin metadata:...
658
  	if (unformatted)
66b1edc05   Joe Thornber   dm thin metadata:...
659
660
661
  		return format_device ? __format_metadata(pmd) : -EPERM;
  
  	return __open_metadata(pmd);
e4d2205cd   Joe Thornber   dm thin metadata:...
662
  }
66b1edc05   Joe Thornber   dm thin metadata:...
663
  static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool format_device)
332627db0   Joe Thornber   dm thin metadata:...
664
665
  {
  	int r;
7d48935ef   Mike Snitzer   dm thin: allow me...
666
  	pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
332627db0   Joe Thornber   dm thin metadata:...
667
668
669
670
671
  					  THIN_MAX_CONCURRENT_LOCKS);
  	if (IS_ERR(pmd->bm)) {
  		DMERR("could not create block manager");
  		return PTR_ERR(pmd->bm);
  	}
66b1edc05   Joe Thornber   dm thin metadata:...
672
  	r = __open_or_format_metadata(pmd, format_device);
332627db0   Joe Thornber   dm thin metadata:...
673
674
675
676
677
  	if (r)
  		dm_block_manager_destroy(pmd->bm);
  
  	return r;
  }
f9dd9352b   Joe Thornber   dm thin metadata:...
678
679
680
681
682
683
684
685
  static void __destroy_persistent_data_objects(struct dm_pool_metadata *pmd)
  {
  	dm_sm_destroy(pmd->data_sm);
  	dm_sm_destroy(pmd->metadata_sm);
  	dm_tm_destroy(pmd->nb_tm);
  	dm_tm_destroy(pmd->tm);
  	dm_block_manager_destroy(pmd->bm);
  }
991d9fa02   Joe Thornber   dm: add thin prov...
686
687
688
  static int __begin_transaction(struct dm_pool_metadata *pmd)
  {
  	int r;
991d9fa02   Joe Thornber   dm: add thin prov...
689
690
691
692
  	struct thin_disk_superblock *disk_super;
  	struct dm_block *sblock;
  
  	/*
991d9fa02   Joe Thornber   dm: add thin prov...
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
  	 * We re-read the superblock every time.  Shouldn't need to do this
  	 * really.
  	 */
  	r = dm_bm_read_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
  			    &sb_validator, &sblock);
  	if (r)
  		return r;
  
  	disk_super = dm_block_data(sblock);
  	pmd->time = le32_to_cpu(disk_super->time);
  	pmd->root = le64_to_cpu(disk_super->data_mapping_root);
  	pmd->details_root = le64_to_cpu(disk_super->device_details_root);
  	pmd->trans_id = le64_to_cpu(disk_super->trans_id);
  	pmd->flags = le32_to_cpu(disk_super->flags);
  	pmd->data_block_size = le32_to_cpu(disk_super->data_block_size);
991d9fa02   Joe Thornber   dm: add thin prov...
708
  	dm_bm_unlock(sblock);
d73ec5253   Mike Snitzer   dm thin metadata:...
709
  	return 0;
991d9fa02   Joe Thornber   dm: add thin prov...
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
  }
  
  static int __write_changed_details(struct dm_pool_metadata *pmd)
  {
  	int r;
  	struct dm_thin_device *td, *tmp;
  	struct disk_device_details details;
  	uint64_t key;
  
  	list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) {
  		if (!td->changed)
  			continue;
  
  		key = td->id;
  
  		details.mapped_blocks = cpu_to_le64(td->mapped_blocks);
  		details.transaction_id = cpu_to_le64(td->transaction_id);
  		details.creation_time = cpu_to_le32(td->creation_time);
  		details.snapshotted_time = cpu_to_le32(td->snapshotted_time);
  		__dm_bless_for_disk(&details);
  
  		r = dm_btree_insert(&pmd->details_info, pmd->details_root,
  				    &key, &details, &pmd->details_root);
  		if (r)
  			return r;
  
  		if (td->open_count)
  			td->changed = 0;
  		else {
  			list_del(&td->list);
  			kfree(td);
  		}
991d9fa02   Joe Thornber   dm: add thin prov...
742
743
744
745
746
747
748
  	}
  
  	return 0;
  }
  
  static int __commit_transaction(struct dm_pool_metadata *pmd)
  {
991d9fa02   Joe Thornber   dm: add thin prov...
749
750
751
752
753
754
755
756
757
758
759
760
  	int r;
  	size_t metadata_len, data_len;
  	struct thin_disk_superblock *disk_super;
  	struct dm_block *sblock;
  
  	/*
  	 * We need to know if the thin_disk_superblock exceeds a 512-byte sector.
  	 */
  	BUILD_BUG_ON(sizeof(struct thin_disk_superblock) > 512);
  
  	r = __write_changed_details(pmd);
  	if (r < 0)
d973ac196   Joe Thornber   dm thin metadata:...
761
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
762

991d9fa02   Joe Thornber   dm: add thin prov...
763
764
  	r = dm_sm_commit(pmd->data_sm);
  	if (r < 0)
d973ac196   Joe Thornber   dm thin metadata:...
765
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
766
767
768
  
  	r = dm_tm_pre_commit(pmd->tm);
  	if (r < 0)
d973ac196   Joe Thornber   dm thin metadata:...
769
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
770
771
772
  
  	r = dm_sm_root_size(pmd->metadata_sm, &metadata_len);
  	if (r < 0)
d973ac196   Joe Thornber   dm thin metadata:...
773
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
774

fef838cc1   Joe Thornber   dm thin metadata:...
775
  	r = dm_sm_root_size(pmd->data_sm, &data_len);
991d9fa02   Joe Thornber   dm: add thin prov...
776
  	if (r < 0)
d973ac196   Joe Thornber   dm thin metadata:...
777
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
778

5a32083d0   Joe Thornber   dm: take care to ...
779
780
781
  	r = save_sm_roots(pmd);
  	if (r < 0)
  		return r;
259711920   Joe Thornber   dm thin metadata:...
782
  	r = superblock_lock(pmd, &sblock);
991d9fa02   Joe Thornber   dm: add thin prov...
783
  	if (r)
d973ac196   Joe Thornber   dm thin metadata:...
784
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
785
786
787
788
789
790
791
  
  	disk_super = dm_block_data(sblock);
  	disk_super->time = cpu_to_le32(pmd->time);
  	disk_super->data_mapping_root = cpu_to_le64(pmd->root);
  	disk_super->device_details_root = cpu_to_le64(pmd->details_root);
  	disk_super->trans_id = cpu_to_le64(pmd->trans_id);
  	disk_super->flags = cpu_to_le32(pmd->flags);
5a32083d0   Joe Thornber   dm: take care to ...
792
  	copy_sm_roots(pmd, disk_super);
991d9fa02   Joe Thornber   dm: add thin prov...
793

eb04cf634   Joe Thornber   dm thin metadata:...
794
  	return dm_tm_commit(pmd->tm, sblock);
991d9fa02   Joe Thornber   dm: add thin prov...
795
  }
1484d4ff2   Joe Thornber   dm thin metadata:...
796
797
798
799
800
801
802
803
804
805
  static void __set_metadata_reserve(struct dm_pool_metadata *pmd)
  {
  	int r;
  	dm_block_t total;
  	dm_block_t max_blocks = 4096; /* 16M */
  
  	r = dm_sm_get_nr_blocks(pmd->metadata_sm, &total);
  	if (r) {
  		DMERR("could not get size of metadata device");
  		pmd->metadata_reserve = max_blocks;
4e7ea6512   Mike Snitzer   dm thin metadata:...
806
807
  	} else
  		pmd->metadata_reserve = min(max_blocks, div_u64(total, 10));
1484d4ff2   Joe Thornber   dm thin metadata:...
808
  }
991d9fa02   Joe Thornber   dm: add thin prov...
809
  struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
66b1edc05   Joe Thornber   dm thin metadata:...
810
811
  					       sector_t data_block_size,
  					       bool format_device)
991d9fa02   Joe Thornber   dm: add thin prov...
812
813
  {
  	int r;
991d9fa02   Joe Thornber   dm: add thin prov...
814
  	struct dm_pool_metadata *pmd;
991d9fa02   Joe Thornber   dm: add thin prov...
815
816
817
818
819
820
  
  	pmd = kmalloc(sizeof(*pmd), GFP_KERNEL);
  	if (!pmd) {
  		DMERR("could not allocate metadata struct");
  		return ERR_PTR(-ENOMEM);
  	}
6a0ebd31b   Joe Thornber   dm thin metadata:...
821
822
823
  	init_rwsem(&pmd->root_lock);
  	pmd->time = 0;
  	INIT_LIST_HEAD(&pmd->thin_devices);
da105ed5f   Joe Thornber   dm thin metadata:...
824
  	pmd->fail_io = false;
332627db0   Joe Thornber   dm thin metadata:...
825
  	pmd->bdev = bdev;
9cb6653f9   Joe Thornber   dm thin metadata:...
826
  	pmd->data_block_size = data_block_size;
991d9fa02   Joe Thornber   dm: add thin prov...
827

66b1edc05   Joe Thornber   dm thin metadata:...
828
  	r = __create_persistent_data_objects(pmd, format_device);
991d9fa02   Joe Thornber   dm: add thin prov...
829
  	if (r) {
991d9fa02   Joe Thornber   dm: add thin prov...
830
831
832
  		kfree(pmd);
  		return ERR_PTR(r);
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
833

270938bac   Joe Thornber   dm thin metadata:...
834
835
836
837
838
  	r = __begin_transaction(pmd);
  	if (r < 0) {
  		if (dm_pool_metadata_close(pmd) < 0)
  			DMWARN("%s: dm_pool_metadata_close() failed.", __func__);
  		return ERR_PTR(r);
991d9fa02   Joe Thornber   dm: add thin prov...
839
  	}
1484d4ff2   Joe Thornber   dm thin metadata:...
840
  	__set_metadata_reserve(pmd);
991d9fa02   Joe Thornber   dm: add thin prov...
841
  	return pmd;
991d9fa02   Joe Thornber   dm: add thin prov...
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
  }
  
  int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
  {
  	int r;
  	unsigned open_devices = 0;
  	struct dm_thin_device *td, *tmp;
  
  	down_read(&pmd->root_lock);
  	list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) {
  		if (td->open_count)
  			open_devices++;
  		else {
  			list_del(&td->list);
  			kfree(td);
  		}
  	}
  	up_read(&pmd->root_lock);
  
  	if (open_devices) {
  		DMERR("attempt to close pmd when %u device(s) are still open",
  		       open_devices);
  		return -EBUSY;
  	}
49f154c73   Mike Snitzer   dm thin metadata:...
866
  	if (!dm_bm_is_read_only(pmd->bm) && !pmd->fail_io) {
12ba58af4   Joe Thornber   dm thin metadata:...
867
868
869
870
871
  		r = __commit_transaction(pmd);
  		if (r < 0)
  			DMWARN("%s: __commit_transaction() failed, error = %d",
  			       __func__, r);
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
872

da105ed5f   Joe Thornber   dm thin metadata:...
873
874
  	if (!pmd->fail_io)
  		__destroy_persistent_data_objects(pmd);
991d9fa02   Joe Thornber   dm: add thin prov...
875

da105ed5f   Joe Thornber   dm thin metadata:...
876
  	kfree(pmd);
991d9fa02   Joe Thornber   dm: add thin prov...
877
878
  	return 0;
  }
1f3db25d8   Mike Snitzer   dm thin metadata:...
879
880
881
882
883
  /*
   * __open_device: Returns @td corresponding to device with id @dev,
   * creating it if @create is set and incrementing @td->open_count.
   * On failure, @td is undefined.
   */
991d9fa02   Joe Thornber   dm: add thin prov...
884
885
886
887
888
889
890
891
892
893
  static int __open_device(struct dm_pool_metadata *pmd,
  			 dm_thin_id dev, int create,
  			 struct dm_thin_device **td)
  {
  	int r, changed = 0;
  	struct dm_thin_device *td2;
  	uint64_t key = dev;
  	struct disk_device_details details_le;
  
  	/*
1f3db25d8   Mike Snitzer   dm thin metadata:...
894
  	 * If the device is already open, return it.
991d9fa02   Joe Thornber   dm: add thin prov...
895
896
897
  	 */
  	list_for_each_entry(td2, &pmd->thin_devices, list)
  		if (td2->id == dev) {
1f3db25d8   Mike Snitzer   dm thin metadata:...
898
899
900
901
902
  			/*
  			 * May not create an already-open device.
  			 */
  			if (create)
  				return -EEXIST;
991d9fa02   Joe Thornber   dm: add thin prov...
903
904
905
906
907
908
909
910
911
912
913
914
915
  			td2->open_count++;
  			*td = td2;
  			return 0;
  		}
  
  	/*
  	 * Check the device exists.
  	 */
  	r = dm_btree_lookup(&pmd->details_info, pmd->details_root,
  			    &key, &details_le);
  	if (r) {
  		if (r != -ENODATA || !create)
  			return r;
1f3db25d8   Mike Snitzer   dm thin metadata:...
916
917
918
  		/*
  		 * Create new device.
  		 */
991d9fa02   Joe Thornber   dm: add thin prov...
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
  		changed = 1;
  		details_le.mapped_blocks = 0;
  		details_le.transaction_id = cpu_to_le64(pmd->trans_id);
  		details_le.creation_time = cpu_to_le32(pmd->time);
  		details_le.snapshotted_time = cpu_to_le32(pmd->time);
  	}
  
  	*td = kmalloc(sizeof(**td), GFP_NOIO);
  	if (!*td)
  		return -ENOMEM;
  
  	(*td)->pmd = pmd;
  	(*td)->id = dev;
  	(*td)->open_count = 1;
  	(*td)->changed = changed;
da105ed5f   Joe Thornber   dm thin metadata:...
934
  	(*td)->aborted_with_changes = false;
991d9fa02   Joe Thornber   dm: add thin prov...
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
  	(*td)->mapped_blocks = le64_to_cpu(details_le.mapped_blocks);
  	(*td)->transaction_id = le64_to_cpu(details_le.transaction_id);
  	(*td)->creation_time = le32_to_cpu(details_le.creation_time);
  	(*td)->snapshotted_time = le32_to_cpu(details_le.snapshotted_time);
  
  	list_add(&(*td)->list, &pmd->thin_devices);
  
  	return 0;
  }
  
  static void __close_device(struct dm_thin_device *td)
  {
  	--td->open_count;
  }
  
  static int __create_thin(struct dm_pool_metadata *pmd,
  			 dm_thin_id dev)
  {
  	int r;
  	dm_block_t dev_root;
  	uint64_t key = dev;
  	struct disk_device_details details_le;
  	struct dm_thin_device *td;
  	__le64 value;
  
  	r = dm_btree_lookup(&pmd->details_info, pmd->details_root,
  			    &key, &details_le);
  	if (!r)
  		return -EEXIST;
  
  	/*
  	 * Create an empty btree for the mappings.
  	 */
  	r = dm_btree_empty(&pmd->bl_info, &dev_root);
  	if (r)
  		return r;
  
  	/*
  	 * Insert it into the main mapping tree.
  	 */
  	value = cpu_to_le64(dev_root);
  	__dm_bless_for_disk(&value);
  	r = dm_btree_insert(&pmd->tl_info, pmd->root, &key, &value, &pmd->root);
  	if (r) {
  		dm_btree_del(&pmd->bl_info, dev_root);
  		return r;
  	}
  
  	r = __open_device(pmd, dev, 1, &td);
  	if (r) {
991d9fa02   Joe Thornber   dm: add thin prov...
985
986
987
988
  		dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
  		dm_btree_del(&pmd->bl_info, dev_root);
  		return r;
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
989
990
991
992
993
994
995
  	__close_device(td);
  
  	return r;
  }
  
  int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
996
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
997
998
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
999
1000
  	if (!pmd->fail_io)
  		r = __create_thin(pmd, dev);
991d9fa02   Joe Thornber   dm: add thin prov...
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
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  static int __set_snapshot_details(struct dm_pool_metadata *pmd,
  				  struct dm_thin_device *snap,
  				  dm_thin_id origin, uint32_t time)
  {
  	int r;
  	struct dm_thin_device *td;
  
  	r = __open_device(pmd, origin, 0, &td);
  	if (r)
  		return r;
  
  	td->changed = 1;
  	td->snapshotted_time = time;
  
  	snap->mapped_blocks = td->mapped_blocks;
  	snap->snapshotted_time = time;
  	__close_device(td);
  
  	return 0;
  }
  
  static int __create_snap(struct dm_pool_metadata *pmd,
  			 dm_thin_id dev, dm_thin_id origin)
  {
  	int r;
  	dm_block_t origin_root;
  	uint64_t key = origin, dev_key = dev;
  	struct dm_thin_device *td;
  	struct disk_device_details details_le;
  	__le64 value;
  
  	/* check this device is unused */
  	r = dm_btree_lookup(&pmd->details_info, pmd->details_root,
  			    &dev_key, &details_le);
  	if (!r)
  		return -EEXIST;
  
  	/* find the mapping tree for the origin */
  	r = dm_btree_lookup(&pmd->tl_info, pmd->root, &key, &value);
  	if (r)
  		return r;
  	origin_root = le64_to_cpu(value);
  
  	/* clone the origin, an inc will do */
  	dm_tm_inc(pmd->tm, origin_root);
  
  	/* insert into the main mapping tree */
  	value = cpu_to_le64(origin_root);
  	__dm_bless_for_disk(&value);
  	key = dev;
  	r = dm_btree_insert(&pmd->tl_info, pmd->root, &key, &value, &pmd->root);
  	if (r) {
  		dm_tm_dec(pmd->tm, origin_root);
  		return r;
  	}
  
  	pmd->time++;
  
  	r = __open_device(pmd, dev, 1, &td);
  	if (r)
  		goto bad;
  
  	r = __set_snapshot_details(pmd, td, origin, pmd->time);
1f3db25d8   Mike Snitzer   dm thin metadata:...
1069
  	__close_device(td);
991d9fa02   Joe Thornber   dm: add thin prov...
1070
1071
  	if (r)
  		goto bad;
991d9fa02   Joe Thornber   dm: add thin prov...
1072
1073
1074
  	return 0;
  
  bad:
991d9fa02   Joe Thornber   dm: add thin prov...
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
  	dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
  	dm_btree_remove(&pmd->details_info, pmd->details_root,
  			&key, &pmd->details_root);
  	return r;
  }
  
  int dm_pool_create_snap(struct dm_pool_metadata *pmd,
  				 dm_thin_id dev,
  				 dm_thin_id origin)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1085
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1086
1087
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1088
1089
  	if (!pmd->fail_io)
  		r = __create_snap(pmd, dev, origin);
991d9fa02   Joe Thornber   dm: add thin prov...
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  static int __delete_device(struct dm_pool_metadata *pmd, dm_thin_id dev)
  {
  	int r;
  	uint64_t key = dev;
  	struct dm_thin_device *td;
  
  	/* TODO: failure should mark the transaction invalid */
  	r = __open_device(pmd, dev, 0, &td);
  	if (r)
  		return r;
  
  	if (td->open_count > 1) {
  		__close_device(td);
  		return -EBUSY;
  	}
  
  	list_del(&td->list);
  	kfree(td);
  	r = dm_btree_remove(&pmd->details_info, pmd->details_root,
  			    &key, &pmd->details_root);
  	if (r)
  		return r;
  
  	r = dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
  	if (r)
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
1121
1122
1123
1124
1125
1126
  	return 0;
  }
  
  int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd,
  			       dm_thin_id dev)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1127
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1128
1129
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1130
1131
  	if (!pmd->fail_io)
  		r = __delete_device(pmd, dev);
991d9fa02   Joe Thornber   dm: add thin prov...
1132
1133
1134
1135
1136
1137
1138
1139
1140
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd,
  					uint64_t current_id,
  					uint64_t new_id)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1141
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1142
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1143
1144
1145
  
  	if (pmd->fail_io)
  		goto out;
991d9fa02   Joe Thornber   dm: add thin prov...
1146
  	if (pmd->trans_id != current_id) {
991d9fa02   Joe Thornber   dm: add thin prov...
1147
  		DMERR("mismatched transaction id");
da105ed5f   Joe Thornber   dm thin metadata:...
1148
  		goto out;
991d9fa02   Joe Thornber   dm: add thin prov...
1149
1150
1151
  	}
  
  	pmd->trans_id = new_id;
da105ed5f   Joe Thornber   dm thin metadata:...
1152
1153
1154
  	r = 0;
  
  out:
991d9fa02   Joe Thornber   dm: add thin prov...
1155
  	up_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1156
  	return r;
991d9fa02   Joe Thornber   dm: add thin prov...
1157
1158
1159
1160
1161
  }
  
  int dm_pool_get_metadata_transaction_id(struct dm_pool_metadata *pmd,
  					uint64_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1162
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1163
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1164
1165
1166
1167
  	if (!pmd->fail_io) {
  		*result = pmd->trans_id;
  		r = 0;
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
1168
  	up_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1169
  	return r;
991d9fa02   Joe Thornber   dm: add thin prov...
1170
  }
cc8394d86   Joe Thornber   dm thin: provide ...
1171
1172
1173
1174
1175
1176
1177
1178
  static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
  {
  	int r, inc;
  	struct thin_disk_superblock *disk_super;
  	struct dm_block *copy, *sblock;
  	dm_block_t held_root;
  
  	/*
49e99fc71   Joe Thornber   dm thin metadata:...
1179
1180
1181
1182
1183
1184
  	 * We commit to ensure the btree roots which we increment in a
  	 * moment are up to date.
  	 */
  	__commit_transaction(pmd);
  
  	/*
cc8394d86   Joe Thornber   dm thin: provide ...
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
  	 * Copy the superblock.
  	 */
  	dm_sm_inc_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION);
  	r = dm_tm_shadow_block(pmd->tm, THIN_SUPERBLOCK_LOCATION,
  			       &sb_validator, &copy, &inc);
  	if (r)
  		return r;
  
  	BUG_ON(!inc);
  
  	held_root = dm_block_location(copy);
  	disk_super = dm_block_data(copy);
  
  	if (le64_to_cpu(disk_super->held_root)) {
  		DMWARN("Pool metadata snapshot already exists: release this before taking another.");
  
  		dm_tm_dec(pmd->tm, held_root);
  		dm_tm_unlock(pmd->tm, copy);
cc8394d86   Joe Thornber   dm thin: provide ...
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
  		return -EBUSY;
  	}
  
  	/*
  	 * Wipe the spacemap since we're not publishing this.
  	 */
  	memset(&disk_super->data_space_map_root, 0,
  	       sizeof(disk_super->data_space_map_root));
  	memset(&disk_super->metadata_space_map_root, 0,
  	       sizeof(disk_super->metadata_space_map_root));
  
  	/*
  	 * Increment the data structures that need to be preserved.
  	 */
  	dm_tm_inc(pmd->tm, le64_to_cpu(disk_super->data_mapping_root));
  	dm_tm_inc(pmd->tm, le64_to_cpu(disk_super->device_details_root));
  	dm_tm_unlock(pmd->tm, copy);
  
  	/*
  	 * Write the held root into the superblock.
  	 */
259711920   Joe Thornber   dm thin metadata:...
1224
  	r = superblock_lock(pmd, &sblock);
cc8394d86   Joe Thornber   dm thin: provide ...
1225
1226
  	if (r) {
  		dm_tm_dec(pmd->tm, held_root);
cc8394d86   Joe Thornber   dm thin: provide ...
1227
1228
1229
1230
1231
1232
  		return r;
  	}
  
  	disk_super = dm_block_data(sblock);
  	disk_super->held_root = cpu_to_le64(held_root);
  	dm_bm_unlock(sblock);
cc8394d86   Joe Thornber   dm thin: provide ...
1233
1234
1235
1236
1237
  	return 0;
  }
  
  int dm_pool_reserve_metadata_snap(struct dm_pool_metadata *pmd)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1238
  	int r = -EINVAL;
cc8394d86   Joe Thornber   dm thin: provide ...
1239
1240
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1241
1242
  	if (!pmd->fail_io)
  		r = __reserve_metadata_snap(pmd);
cc8394d86   Joe Thornber   dm thin: provide ...
1243
1244
1245
1246
1247
1248
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  static int __release_metadata_snap(struct dm_pool_metadata *pmd)
991d9fa02   Joe Thornber   dm: add thin prov...
1249
1250
1251
  {
  	int r;
  	struct thin_disk_superblock *disk_super;
cc8394d86   Joe Thornber   dm thin: provide ...
1252
1253
  	struct dm_block *sblock, *copy;
  	dm_block_t held_root;
991d9fa02   Joe Thornber   dm: add thin prov...
1254

259711920   Joe Thornber   dm thin metadata:...
1255
  	r = superblock_lock(pmd, &sblock);
991d9fa02   Joe Thornber   dm: add thin prov...
1256
1257
1258
1259
  	if (r)
  		return r;
  
  	disk_super = dm_block_data(sblock);
cc8394d86   Joe Thornber   dm thin: provide ...
1260
1261
  	held_root = le64_to_cpu(disk_super->held_root);
  	disk_super->held_root = cpu_to_le64(0);
cc8394d86   Joe Thornber   dm thin: provide ...
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
  
  	dm_bm_unlock(sblock);
  
  	if (!held_root) {
  		DMWARN("No pool metadata snapshot found: nothing to release.");
  		return -EINVAL;
  	}
  
  	r = dm_tm_read_lock(pmd->tm, held_root, &sb_validator, &copy);
  	if (r)
  		return r;
  
  	disk_super = dm_block_data(copy);
7f518ad0a   Joe Thornber   dm thin metadata:...
1275
1276
  	dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root));
  	dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root));
cc8394d86   Joe Thornber   dm thin: provide ...
1277
  	dm_sm_dec_block(pmd->metadata_sm, held_root);
4c7da06f5   Mikulas Patocka   dm persistent dat...
1278
1279
1280
  	dm_tm_unlock(pmd->tm, copy);
  
  	return 0;
cc8394d86   Joe Thornber   dm thin: provide ...
1281
1282
1283
1284
  }
  
  int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1285
  	int r = -EINVAL;
cc8394d86   Joe Thornber   dm thin: provide ...
1286
1287
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1288
1289
  	if (!pmd->fail_io)
  		r = __release_metadata_snap(pmd);
cc8394d86   Joe Thornber   dm thin: provide ...
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  static int __get_metadata_snap(struct dm_pool_metadata *pmd,
  			       dm_block_t *result)
  {
  	int r;
  	struct thin_disk_superblock *disk_super;
  	struct dm_block *sblock;
  
  	r = dm_bm_read_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
  			    &sb_validator, &sblock);
  	if (r)
  		return r;
  
  	disk_super = dm_block_data(sblock);
991d9fa02   Joe Thornber   dm: add thin prov...
1308
  	*result = le64_to_cpu(disk_super->held_root);
4c7da06f5   Mikulas Patocka   dm persistent dat...
1309
1310
1311
  	dm_bm_unlock(sblock);
  
  	return 0;
991d9fa02   Joe Thornber   dm: add thin prov...
1312
  }
cc8394d86   Joe Thornber   dm thin: provide ...
1313
1314
  int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd,
  			      dm_block_t *result)
991d9fa02   Joe Thornber   dm: add thin prov...
1315
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1316
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1317
1318
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1319
1320
  	if (!pmd->fail_io)
  		r = __get_metadata_snap(pmd, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1321
1322
1323
1324
1325
1326
1327
1328
  	up_read(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_thin_id dev,
  			     struct dm_thin_device **td)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1329
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1330
1331
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1332
1333
  	if (!pmd->fail_io)
  		r = __open_device(pmd, dev, 0, td);
991d9fa02   Joe Thornber   dm: add thin prov...
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_pool_close_thin_device(struct dm_thin_device *td)
  {
  	down_write(&td->pmd->root_lock);
  	__close_device(td);
  	up_write(&td->pmd->root_lock);
  
  	return 0;
  }
  
  dm_thin_id dm_thin_dev_id(struct dm_thin_device *td)
  {
  	return td->id;
  }
19fa1a675   Joe Thornber   dm thin: fix disc...
1352
1353
1354
1355
1356
1357
  /*
   * Check whether @time (of block creation) is older than @td's last snapshot.
   * If so then the associated block is shared with the last snapshot device.
   * Any block on a device created *after* the device last got snapshotted is
   * necessarily not shared.
   */
17b7d63f7   Mike Snitzer   dm thin: clean up...
1358
  static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time)
991d9fa02   Joe Thornber   dm: add thin prov...
1359
1360
1361
  {
  	return td->snapshotted_time > time;
  }
3d5f67332   Joe Thornber   dm thin metadata:...
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
  static void unpack_lookup_result(struct dm_thin_device *td, __le64 value,
  				 struct dm_thin_lookup_result *result)
  {
  	uint64_t block_time = 0;
  	dm_block_t exception_block;
  	uint32_t exception_time;
  
  	block_time = le64_to_cpu(value);
  	unpack_block_time(block_time, &exception_block, &exception_time);
  	result->block = exception_block;
  	result->shared = __snapshotted_since(td, exception_time);
  }
086fbbbda   Joe Thornber   dm thin metadata:...
1374
1375
  static int __find_block(struct dm_thin_device *td, dm_block_t block,
  			int can_issue_io, struct dm_thin_lookup_result *result)
991d9fa02   Joe Thornber   dm: add thin prov...
1376
  {
e5cfc69a5   Joe Thornber   dm thin metadata:...
1377
  	int r;
991d9fa02   Joe Thornber   dm: add thin prov...
1378
1379
1380
  	__le64 value;
  	struct dm_pool_metadata *pmd = td->pmd;
  	dm_block_t keys[2] = { td->id, block };
da105ed5f   Joe Thornber   dm thin metadata:...
1381
  	struct dm_btree_info *info;
991d9fa02   Joe Thornber   dm: add thin prov...
1382

e5cfc69a5   Joe Thornber   dm thin metadata:...
1383
1384
1385
1386
  	if (can_issue_io) {
  		info = &pmd->info;
  	} else
  		info = &pmd->nb_info;
da105ed5f   Joe Thornber   dm thin metadata:...
1387

e5cfc69a5   Joe Thornber   dm thin metadata:...
1388
  	r = dm_btree_lookup(info, pmd->root, keys, &value);
3d5f67332   Joe Thornber   dm thin metadata:...
1389
1390
  	if (!r)
  		unpack_lookup_result(td, value, result);
3d5f67332   Joe Thornber   dm thin metadata:...
1391
1392
  	return r;
  }
086fbbbda   Joe Thornber   dm thin metadata:...
1393
1394
  int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
  		       int can_issue_io, struct dm_thin_lookup_result *result)
3d5f67332   Joe Thornber   dm thin metadata:...
1395
1396
  {
  	int r;
3d5f67332   Joe Thornber   dm thin metadata:...
1397
  	struct dm_pool_metadata *pmd = td->pmd;
3d5f67332   Joe Thornber   dm thin metadata:...
1398
1399
1400
1401
1402
  
  	down_read(&pmd->root_lock);
  	if (pmd->fail_io) {
  		up_read(&pmd->root_lock);
  		return -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1403
  	}
086fbbbda   Joe Thornber   dm thin metadata:...
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
  	r = __find_block(td, block, can_issue_io, result);
  
  	up_read(&pmd->root_lock);
  	return r;
  }
  
  static int __find_next_mapped_block(struct dm_thin_device *td, dm_block_t block,
  					  dm_block_t *vblock,
  					  struct dm_thin_lookup_result *result)
  {
  	int r;
  	__le64 value;
  	struct dm_pool_metadata *pmd = td->pmd;
  	dm_block_t keys[2] = { td->id, block };
3d5f67332   Joe Thornber   dm thin metadata:...
1418
1419
1420
  	r = dm_btree_lookup_next(&pmd->info, pmd->root, keys, vblock, &value);
  	if (!r)
  		unpack_lookup_result(td, value, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1421
1422
  	return r;
  }
086fbbbda   Joe Thornber   dm thin metadata:...
1423
1424
1425
1426
  static int __find_mapped_range(struct dm_thin_device *td,
  			       dm_block_t begin, dm_block_t end,
  			       dm_block_t *thin_begin, dm_block_t *thin_end,
  			       dm_block_t *pool_begin, bool *maybe_shared)
a5d895a90   Joe Thornber   dm thin metadata:...
1427
1428
1429
1430
1431
1432
1433
  {
  	int r;
  	dm_block_t pool_end;
  	struct dm_thin_lookup_result lookup;
  
  	if (end < begin)
  		return -ENODATA;
086fbbbda   Joe Thornber   dm thin metadata:...
1434
  	r = __find_next_mapped_block(td, begin, &begin, &lookup);
3d5f67332   Joe Thornber   dm thin metadata:...
1435
1436
  	if (r)
  		return r;
a5d895a90   Joe Thornber   dm thin metadata:...
1437

3d5f67332   Joe Thornber   dm thin metadata:...
1438
  	if (begin >= end)
a5d895a90   Joe Thornber   dm thin metadata:...
1439
1440
1441
1442
1443
1444
1445
1446
1447
  		return -ENODATA;
  
  	*thin_begin = begin;
  	*pool_begin = lookup.block;
  	*maybe_shared = lookup.shared;
  
  	begin++;
  	pool_end = *pool_begin + 1;
  	while (begin != end) {
086fbbbda   Joe Thornber   dm thin metadata:...
1448
  		r = __find_block(td, begin, true, &lookup);
a5d895a90   Joe Thornber   dm thin metadata:...
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
  		if (r) {
  			if (r == -ENODATA)
  				break;
  			else
  				return r;
  		}
  
  		if ((lookup.block != pool_end) ||
  		    (lookup.shared != *maybe_shared))
  			break;
  
  		pool_end++;
  		begin++;
  	}
  
  	*thin_end = begin;
  	return 0;
  }
086fbbbda   Joe Thornber   dm thin metadata:...
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
  int dm_thin_find_mapped_range(struct dm_thin_device *td,
  			      dm_block_t begin, dm_block_t end,
  			      dm_block_t *thin_begin, dm_block_t *thin_end,
  			      dm_block_t *pool_begin, bool *maybe_shared)
  {
  	int r = -EINVAL;
  	struct dm_pool_metadata *pmd = td->pmd;
  
  	down_read(&pmd->root_lock);
  	if (!pmd->fail_io) {
  		r = __find_mapped_range(td, begin, end, thin_begin, thin_end,
  					pool_begin, maybe_shared);
  	}
  	up_read(&pmd->root_lock);
  
  	return r;
  }
991d9fa02   Joe Thornber   dm: add thin prov...
1484
1485
1486
1487
1488
1489
1490
  static int __insert(struct dm_thin_device *td, dm_block_t block,
  		    dm_block_t data_block)
  {
  	int r, inserted;
  	__le64 value;
  	struct dm_pool_metadata *pmd = td->pmd;
  	dm_block_t keys[2] = { td->id, block };
991d9fa02   Joe Thornber   dm: add thin prov...
1491
1492
1493
1494
1495
1496
1497
  	value = cpu_to_le64(pack_block_time(data_block, pmd->time));
  	__dm_bless_for_disk(&value);
  
  	r = dm_btree_insert_notify(&pmd->info, pmd->root, keys, &value,
  				   &pmd->root, &inserted);
  	if (r)
  		return r;
40db5a537   Joe Thornber   dm thin metadata:...
1498
1499
  	td->changed = 1;
  	if (inserted)
991d9fa02   Joe Thornber   dm: add thin prov...
1500
  		td->mapped_blocks++;
991d9fa02   Joe Thornber   dm: add thin prov...
1501
1502
1503
1504
1505
1506
1507
  
  	return 0;
  }
  
  int dm_thin_insert_block(struct dm_thin_device *td, dm_block_t block,
  			 dm_block_t data_block)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1508
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1509
1510
  
  	down_write(&td->pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1511
1512
  	if (!td->pmd->fail_io)
  		r = __insert(td, block, data_block);
991d9fa02   Joe Thornber   dm: add thin prov...
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
  	up_write(&td->pmd->root_lock);
  
  	return r;
  }
  
  static int __remove(struct dm_thin_device *td, dm_block_t block)
  {
  	int r;
  	struct dm_pool_metadata *pmd = td->pmd;
  	dm_block_t keys[2] = { td->id, block };
  
  	r = dm_btree_remove(&pmd->info, pmd->root, keys, &pmd->root);
  	if (r)
  		return r;
af63bcb81   Joe Thornber   dm thin metadata:...
1527
1528
  	td->mapped_blocks--;
  	td->changed = 1;
991d9fa02   Joe Thornber   dm: add thin prov...
1529
1530
1531
  
  	return 0;
  }
6550f075f   Joe Thornber   dm thin metadata:...
1532
1533
1534
  static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_t end)
  {
  	int r;
993ceab91   Joe Thornber   dm thin metadata:...
1535
  	unsigned count, total_count = 0;
6550f075f   Joe Thornber   dm thin metadata:...
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
  	struct dm_pool_metadata *pmd = td->pmd;
  	dm_block_t keys[1] = { td->id };
  	__le64 value;
  	dm_block_t mapping_root;
  
  	/*
  	 * Find the mapping tree
  	 */
  	r = dm_btree_lookup(&pmd->tl_info, pmd->root, keys, &value);
  	if (r)
  		return r;
  
  	/*
  	 * Remove from the mapping tree, taking care to inc the
  	 * ref count so it doesn't get deleted.
  	 */
  	mapping_root = le64_to_cpu(value);
  	dm_tm_inc(pmd->tm, mapping_root);
  	r = dm_btree_remove(&pmd->tl_info, pmd->root, keys, &pmd->root);
  	if (r)
  		return r;
993ceab91   Joe Thornber   dm thin metadata:...
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
  	/*
  	 * Remove leaves stops at the first unmapped entry, so we have to
  	 * loop round finding mapped ranges.
  	 */
  	while (begin < end) {
  		r = dm_btree_lookup_next(&pmd->bl_info, mapping_root, &begin, &begin, &value);
  		if (r == -ENODATA)
  			break;
  
  		if (r)
  			return r;
  
  		if (begin >= end)
  			break;
  
  		r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count);
  		if (r)
  			return r;
  
  		total_count += count;
  	}
6550f075f   Joe Thornber   dm thin metadata:...
1578

993ceab91   Joe Thornber   dm thin metadata:...
1579
  	td->mapped_blocks -= total_count;
6550f075f   Joe Thornber   dm thin metadata:...
1580
1581
1582
1583
1584
1585
1586
1587
1588
  	td->changed = 1;
  
  	/*
  	 * Reinsert the mapping tree.
  	 */
  	value = cpu_to_le64(mapping_root);
  	__dm_bless_for_disk(&value);
  	return dm_btree_insert(&pmd->tl_info, pmd->root, keys, &value, &pmd->root);
  }
991d9fa02   Joe Thornber   dm: add thin prov...
1589
1590
  int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1591
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1592
1593
  
  	down_write(&td->pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1594
1595
  	if (!td->pmd->fail_io)
  		r = __remove(td, block);
991d9fa02   Joe Thornber   dm: add thin prov...
1596
  	up_write(&td->pmd->root_lock);
19fa1a675   Joe Thornber   dm thin: fix disc...
1597
1598
1599
  
  	return r;
  }
6550f075f   Joe Thornber   dm thin metadata:...
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
  int dm_thin_remove_range(struct dm_thin_device *td,
  			 dm_block_t begin, dm_block_t end)
  {
  	int r = -EINVAL;
  
  	down_write(&td->pmd->root_lock);
  	if (!td->pmd->fail_io)
  		r = __remove_range(td, begin, end);
  	up_write(&td->pmd->root_lock);
  
  	return r;
  }
294710ddf   Joe Thornber   dm thin: fix pass...
1612
  int dm_pool_block_is_shared(struct dm_pool_metadata *pmd, dm_block_t b, bool *result)
19fa1a675   Joe Thornber   dm thin: fix disc...
1613
1614
1615
1616
1617
1618
1619
  {
  	int r;
  	uint32_t ref_count;
  
  	down_read(&pmd->root_lock);
  	r = dm_sm_get_count(pmd->data_sm, b, &ref_count);
  	if (!r)
294710ddf   Joe Thornber   dm thin: fix pass...
1620
  		*result = (ref_count > 1);
19fa1a675   Joe Thornber   dm thin: fix disc...
1621
  	up_read(&pmd->root_lock);
991d9fa02   Joe Thornber   dm: add thin prov...
1622
1623
1624
  
  	return r;
  }
2a0fbffb1   Joe Thornber   dm thin: fix a ra...
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
  int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e)
  {
  	int r = 0;
  
  	down_write(&pmd->root_lock);
  	for (; b != e; b++) {
  		r = dm_sm_inc_block(pmd->data_sm, b);
  		if (r)
  			break;
  	}
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_pool_dec_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e)
  {
  	int r = 0;
  
  	down_write(&pmd->root_lock);
  	for (; b != e; b++) {
  		r = dm_sm_dec_block(pmd->data_sm, b);
  		if (r)
  			break;
  	}
  	up_write(&pmd->root_lock);
  
  	return r;
  }
40db5a537   Joe Thornber   dm thin metadata:...
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
  bool dm_thin_changed_this_transaction(struct dm_thin_device *td)
  {
  	int r;
  
  	down_read(&td->pmd->root_lock);
  	r = td->changed;
  	up_read(&td->pmd->root_lock);
  
  	return r;
  }
4d1662a30   Mike Snitzer   dm thin: avoid me...
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
  bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd)
  {
  	bool r = false;
  	struct dm_thin_device *td, *tmp;
  
  	down_read(&pmd->root_lock);
  	list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) {
  		if (td->changed) {
  			r = td->changed;
  			break;
  		}
  	}
  	up_read(&pmd->root_lock);
  
  	return r;
  }
da105ed5f   Joe Thornber   dm thin metadata:...
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
  bool dm_thin_aborted_changes(struct dm_thin_device *td)
  {
  	bool r;
  
  	down_read(&td->pmd->root_lock);
  	r = td->aborted_with_changes;
  	up_read(&td->pmd->root_lock);
  
  	return r;
  }
991d9fa02   Joe Thornber   dm: add thin prov...
1690
1691
  int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1692
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1693
1694
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1695
1696
  	if (!pmd->fail_io)
  		r = dm_sm_new_block(pmd->data_sm, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1697
1698
1699
1700
1701
1702
1703
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_pool_commit_metadata(struct dm_pool_metadata *pmd)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1704
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1705
1706
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1707
1708
  	if (pmd->fail_io)
  		goto out;
991d9fa02   Joe Thornber   dm: add thin prov...
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
  
  	r = __commit_transaction(pmd);
  	if (r <= 0)
  		goto out;
  
  	/*
  	 * Open the next transaction.
  	 */
  	r = __begin_transaction(pmd);
  out:
  	up_write(&pmd->root_lock);
  	return r;
  }
da105ed5f   Joe Thornber   dm thin metadata:...
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
  static void __set_abort_with_changes_flags(struct dm_pool_metadata *pmd)
  {
  	struct dm_thin_device *td;
  
  	list_for_each_entry(td, &pmd->thin_devices, list)
  		td->aborted_with_changes = td->changed;
  }
  
  int dm_pool_abort_metadata(struct dm_pool_metadata *pmd)
  {
  	int r = -EINVAL;
  
  	down_write(&pmd->root_lock);
  	if (pmd->fail_io)
  		goto out;
  
  	__set_abort_with_changes_flags(pmd);
  	__destroy_persistent_data_objects(pmd);
  	r = __create_persistent_data_objects(pmd, false);
  	if (r)
  		pmd->fail_io = true;
  
  out:
  	up_write(&pmd->root_lock);
  
  	return r;
  }
991d9fa02   Joe Thornber   dm: add thin prov...
1749
1750
  int dm_pool_get_free_block_count(struct dm_pool_metadata *pmd, dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1751
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1752
1753
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1754
1755
  	if (!pmd->fail_io)
  		r = dm_sm_get_nr_free(pmd->data_sm, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1756
1757
1758
1759
1760
1761
1762
1763
  	up_read(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd,
  					  dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1764
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1765
1766
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1767
1768
  	if (!pmd->fail_io)
  		r = dm_sm_get_nr_free(pmd->metadata_sm, result);
1484d4ff2   Joe Thornber   dm thin metadata:...
1769
1770
1771
1772
1773
1774
1775
  
  	if (!r) {
  		if (*result < pmd->metadata_reserve)
  			*result = 0;
  		else
  			*result -= pmd->metadata_reserve;
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
1776
1777
1778
1779
1780
1781
1782
1783
  	up_read(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd,
  				  dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1784
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1785
1786
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1787
1788
  	if (!pmd->fail_io)
  		r = dm_sm_get_nr_blocks(pmd->metadata_sm, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1789
1790
1791
1792
  	up_read(&pmd->root_lock);
  
  	return r;
  }
991d9fa02   Joe Thornber   dm: add thin prov...
1793
1794
  int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1795
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1796
1797
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1798
1799
  	if (!pmd->fail_io)
  		r = dm_sm_get_nr_blocks(pmd->data_sm, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1800
1801
1802
1803
1804
1805
1806
  	up_read(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_thin_get_mapped_count(struct dm_thin_device *td, dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1807
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1808
1809
1810
  	struct dm_pool_metadata *pmd = td->pmd;
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1811
1812
1813
1814
  	if (!pmd->fail_io) {
  		*result = td->mapped_blocks;
  		r = 0;
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
1815
  	up_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1816
  	return r;
991d9fa02   Joe Thornber   dm: add thin prov...
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
  }
  
  static int __highest_block(struct dm_thin_device *td, dm_block_t *result)
  {
  	int r;
  	__le64 value_le;
  	dm_block_t thin_root;
  	struct dm_pool_metadata *pmd = td->pmd;
  
  	r = dm_btree_lookup(&pmd->tl_info, pmd->root, &td->id, &value_le);
  	if (r)
  		return r;
  
  	thin_root = le64_to_cpu(value_le);
  
  	return dm_btree_find_highest_key(&pmd->bl_info, thin_root, result);
  }
  
  int dm_thin_get_highest_mapped_block(struct dm_thin_device *td,
  				     dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1838
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1839
1840
1841
  	struct dm_pool_metadata *pmd = td->pmd;
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1842
1843
  	if (!pmd->fail_io)
  		r = __highest_block(td, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1844
1845
1846
1847
  	up_read(&pmd->root_lock);
  
  	return r;
  }
b17446df2   Joe Thornber   dm thin: refactor...
1848
  static int __resize_space_map(struct dm_space_map *sm, dm_block_t new_count)
991d9fa02   Joe Thornber   dm: add thin prov...
1849
1850
1851
  {
  	int r;
  	dm_block_t old_count;
b17446df2   Joe Thornber   dm thin: refactor...
1852
  	r = dm_sm_get_nr_blocks(sm, &old_count);
991d9fa02   Joe Thornber   dm: add thin prov...
1853
1854
1855
1856
1857
1858
1859
  	if (r)
  		return r;
  
  	if (new_count == old_count)
  		return 0;
  
  	if (new_count < old_count) {
b17446df2   Joe Thornber   dm thin: refactor...
1860
  		DMERR("cannot reduce size of space map");
991d9fa02   Joe Thornber   dm: add thin prov...
1861
1862
  		return -EINVAL;
  	}
b17446df2   Joe Thornber   dm thin: refactor...
1863
  	return dm_sm_extend(sm, new_count - old_count);
991d9fa02   Joe Thornber   dm: add thin prov...
1864
1865
1866
1867
  }
  
  int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1868
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1869
1870
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1871
  	if (!pmd->fail_io)
b17446df2   Joe Thornber   dm thin: refactor...
1872
  		r = __resize_space_map(pmd->data_sm, new_count);
991d9fa02   Joe Thornber   dm: add thin prov...
1873
1874
1875
1876
  	up_write(&pmd->root_lock);
  
  	return r;
  }
12ba58af4   Joe Thornber   dm thin metadata:...
1877

24347e959   Joe Thornber   dm thin: detect m...
1878
1879
1880
1881
1882
  int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_count)
  {
  	int r = -EINVAL;
  
  	down_write(&pmd->root_lock);
1484d4ff2   Joe Thornber   dm thin metadata:...
1883
  	if (!pmd->fail_io) {
24347e959   Joe Thornber   dm thin: detect m...
1884
  		r = __resize_space_map(pmd->metadata_sm, new_count);
1484d4ff2   Joe Thornber   dm thin metadata:...
1885
1886
1887
  		if (!r)
  			__set_metadata_reserve(pmd);
  	}
24347e959   Joe Thornber   dm thin: detect m...
1888
1889
1890
1891
  	up_write(&pmd->root_lock);
  
  	return r;
  }
12ba58af4   Joe Thornber   dm thin metadata:...
1892
1893
1894
  void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd)
  {
  	down_write(&pmd->root_lock);
12ba58af4   Joe Thornber   dm thin metadata:...
1895
1896
1897
  	dm_bm_set_read_only(pmd->bm);
  	up_write(&pmd->root_lock);
  }
ac8c3f3df   Joe Thornber   dm thin: generate...
1898

9b7aaa64f   Joe Thornber   dm thin: allow po...
1899
1900
1901
  void dm_pool_metadata_read_write(struct dm_pool_metadata *pmd)
  {
  	down_write(&pmd->root_lock);
9b7aaa64f   Joe Thornber   dm thin: allow po...
1902
1903
1904
  	dm_bm_set_read_write(pmd->bm);
  	up_write(&pmd->root_lock);
  }
ac8c3f3df   Joe Thornber   dm thin: generate...
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
  int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
  					dm_block_t threshold,
  					dm_sm_threshold_fn fn,
  					void *context)
  {
  	int r;
  
  	down_write(&pmd->root_lock);
  	r = dm_sm_register_threshold_callback(pmd->metadata_sm, threshold, fn, context);
  	up_write(&pmd->root_lock);
  
  	return r;
  }
07f2b6e03   Mike Snitzer   dm thin: ensure u...
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
  
  int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
  {
  	int r;
  	struct dm_block *sblock;
  	struct thin_disk_superblock *disk_super;
  
  	down_write(&pmd->root_lock);
  	pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG;
  
  	r = superblock_lock(pmd, &sblock);
  	if (r) {
  		DMERR("couldn't read superblock");
  		goto out;
  	}
  
  	disk_super = dm_block_data(sblock);
  	disk_super->flags = cpu_to_le32(pmd->flags);
  
  	dm_bm_unlock(sblock);
  out:
  	up_write(&pmd->root_lock);
  	return r;
  }
  
  bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd)
  {
  	bool needs_check;
  
  	down_read(&pmd->root_lock);
  	needs_check = pmd->flags & THIN_METADATA_NEEDS_CHECK_FLAG;
  	up_read(&pmd->root_lock);
  
  	return needs_check;
  }
8a01a6af7   Joe Thornber   dm thin: prefetch...
1953
1954
1955
  
  void dm_pool_issue_prefetches(struct dm_pool_metadata *pmd)
  {
2eae9e448   Joe Thornber   dm thin metadata:...
1956
1957
1958
1959
  	down_read(&pmd->root_lock);
  	if (!pmd->fail_io)
  		dm_tm_issue_prefetches(pmd->tm);
  	up_read(&pmd->root_lock);
8a01a6af7   Joe Thornber   dm thin: prefetch...
1960
  }