Blame view

drivers/md/dm-thin-metadata.c 40.7 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
81
  #define THIN_METADATA_CACHE_SIZE 64
  #define SECTOR_TO_BLOCK_SHIFT 3
8c971178a   Joe Thornber   dm thin metadata:...
82
83
84
85
86
  /*
   *  3 for btree insert +
   *  2 for btree lookup used within space map
   */
  #define THIN_MAX_CONCURRENT_LOCKS 5
991d9fa02   Joe Thornber   dm: add thin prov...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
  /* 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...
179
180
181
182
183
184
  	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;
12ba58af4   Joe Thornber   dm thin metadata:...
185
  	bool read_only:1;
da105ed5f   Joe Thornber   dm thin metadata:...
186
187
188
189
190
191
192
  
  	/*
  	 * 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 ...
193
194
195
196
197
198
199
  
  	/*
  	 * 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...
200
201
202
203
204
205
206
207
  };
  
  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:...
208
209
  	bool changed:1;
  	bool aborted_with_changes:1;
991d9fa02   Joe Thornber   dm: add thin prov...
210
211
212
213
214
215
216
217
218
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
  	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...
287
  static void data_block_inc(void *context, const void *value_le)
991d9fa02   Joe Thornber   dm: add thin prov...
288
289
290
291
292
293
294
295
296
297
  {
  	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...
298
  static void data_block_dec(void *context, const void *value_le)
991d9fa02   Joe Thornber   dm: add thin prov...
299
300
301
302
303
304
305
306
307
308
  {
  	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...
309
  static int data_block_equal(void *context, const void *value1_le, const void *value2_le)
991d9fa02   Joe Thornber   dm: add thin prov...
310
311
312
313
314
315
316
317
318
319
320
321
  {
  	__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...
322
  static void subtree_inc(void *context, const void *value)
991d9fa02   Joe Thornber   dm: add thin prov...
323
324
325
326
327
328
329
330
331
  {
  	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...
332
  static void subtree_dec(void *context, const void *value)
991d9fa02   Joe Thornber   dm: add thin prov...
333
334
335
336
337
338
339
340
341
342
343
  {
  	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))
  		DMERR("btree delete failed
  ");
  }
018cede93   Mike Snitzer   dm persistent dat...
344
  static int subtree_equal(void *context, const void *value1_le, const void *value2_le)
991d9fa02   Joe Thornber   dm: add thin prov...
345
346
347
348
349
350
351
352
353
  {
  	__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:...
354
355
356
357
358
359
360
361
362
363
364
365
366
  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:...
367
  static int __superblock_all_zeroes(struct dm_block_manager *bm, int *result)
991d9fa02   Joe Thornber   dm: add thin prov...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  {
  	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;
  		}
  	}
  
  	return dm_bm_unlock(b);
  }
41675aea3   Joe Thornber   dm thin metadata:...
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  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...
408
  	pmd->tl_info.value_type.context = &pmd->bl_info;
41675aea3   Joe Thornber   dm thin metadata:...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  	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 ...
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
  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:...
461
462
463
464
465
466
467
468
469
  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 ...
470
  	r = dm_sm_commit(pmd->data_sm);
10d2a9ff7   Joe Thornber   dm thin metadata:...
471
472
  	if (r < 0)
  		return r;
5a32083d0   Joe Thornber   dm: take care to ...
473
  	r = save_sm_roots(pmd);
10d2a9ff7   Joe Thornber   dm thin metadata:...
474
475
476
477
478
479
  	if (r < 0)
  		return r;
  
  	r = dm_tm_pre_commit(pmd->tm);
  	if (r < 0)
  		return r;
9cb6653f9   Joe Thornber   dm thin metadata:...
480
481
482
483
484
  	r = superblock_lock_zero(pmd, &sblock);
  	if (r)
  		return r;
  
  	disk_super = dm_block_data(sblock);
10d2a9ff7   Joe Thornber   dm thin metadata:...
485
  	disk_super->flags = 0;
583ceee2e   Joe Thornber   dm thin metadata:...
486
  	memset(disk_super->uuid, 0, sizeof(disk_super->uuid));
9cb6653f9   Joe Thornber   dm thin metadata:...
487
488
489
  	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:...
490
491
  	disk_super->trans_id = 0;
  	disk_super->held_root = 0;
5a32083d0   Joe Thornber   dm: take care to ...
492
  	copy_sm_roots(pmd, disk_super);
10d2a9ff7   Joe Thornber   dm thin metadata:...
493
494
495
  
  	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...
496
  	disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE);
9cb6653f9   Joe Thornber   dm thin metadata:...
497
498
  	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:...
499
  	return dm_tm_commit(pmd->tm, sblock);
9cb6653f9   Joe Thornber   dm thin metadata:...
500
  }
a97e5e6fd   Joe Thornber   dm thin metadata:...
501
  static int __format_metadata(struct dm_pool_metadata *pmd)
991d9fa02   Joe Thornber   dm: add thin prov...
502
503
  {
  	int r;
384ef0e62   Joe Thornber   dm persistent dat...
504

e4d2205cd   Joe Thornber   dm thin metadata:...
505
506
507
508
509
510
  	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...
511

a97e5e6fd   Joe Thornber   dm thin metadata:...
512
  	pmd->data_sm = dm_sm_disk_create(pmd->tm, 0);
e4d2205cd   Joe Thornber   dm thin metadata:...
513
514
515
  	if (IS_ERR(pmd->data_sm)) {
  		DMERR("sm_disk_create failed");
  		r = PTR_ERR(pmd->data_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
516
  		goto bad_cleanup_tm;
991d9fa02   Joe Thornber   dm: add thin prov...
517
  	}
d6332814e   Joe Thornber   dm thin metadata:...
518
  	pmd->nb_tm = dm_tm_create_non_blocking_clone(pmd->tm);
991d9fa02   Joe Thornber   dm: add thin prov...
519
  	if (!pmd->nb_tm) {
0fa5b17b0   Joe Thornber   dm thin metadata:...
520
  		DMERR("could not create non-blocking clone tm");
991d9fa02   Joe Thornber   dm: add thin prov...
521
  		r = -ENOMEM;
0fa5b17b0   Joe Thornber   dm thin metadata:...
522
  		goto bad_cleanup_data_sm;
991d9fa02   Joe Thornber   dm: add thin prov...
523
  	}
41675aea3   Joe Thornber   dm thin metadata:...
524
  	__setup_btree_details(pmd);
991d9fa02   Joe Thornber   dm: add thin prov...
525

9cb6653f9   Joe Thornber   dm thin metadata:...
526
527
  	r = dm_btree_empty(&pmd->info, &pmd->root);
  	if (r < 0)
0fa5b17b0   Joe Thornber   dm thin metadata:...
528
  		goto bad_cleanup_nb_tm;
9cb6653f9   Joe Thornber   dm thin metadata:...
529
530
531
532
  
  	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:...
533
  		goto bad_cleanup_nb_tm;
9cb6653f9   Joe Thornber   dm thin metadata:...
534
535
536
537
  	}
  
  	r = __write_initial_superblock(pmd);
  	if (r)
0fa5b17b0   Joe Thornber   dm thin metadata:...
538
  		goto bad_cleanup_nb_tm;
9cb6653f9   Joe Thornber   dm thin metadata:...
539

991d9fa02   Joe Thornber   dm: add thin prov...
540
  	return 0;
0fa5b17b0   Joe Thornber   dm thin metadata:...
541
542
543
  bad_cleanup_nb_tm:
  	dm_tm_destroy(pmd->nb_tm);
  bad_cleanup_data_sm:
d6332814e   Joe Thornber   dm thin metadata:...
544
  	dm_sm_destroy(pmd->data_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
545
  bad_cleanup_tm:
d6332814e   Joe Thornber   dm thin metadata:...
546
547
  	dm_tm_destroy(pmd->tm);
  	dm_sm_destroy(pmd->metadata_sm);
991d9fa02   Joe Thornber   dm: add thin prov...
548
549
550
  
  	return r;
  }
d73ec5253   Mike Snitzer   dm thin metadata:...
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
  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:...
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  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:...
592

9aec8629e   Mike Snitzer   dm thin metadata:...
593
594
595
596
597
598
599
600
  	/* 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:...
601
  	r = __check_incompat_features(disk_super, pmd);
0fa5b17b0   Joe Thornber   dm thin metadata:...
602
603
  	if (r < 0)
  		goto bad_unlock_sblock;
d73ec5253   Mike Snitzer   dm thin metadata:...
604

e4d2205cd   Joe Thornber   dm thin metadata:...
605
606
607
608
609
610
  	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:...
611
  		goto bad_unlock_sblock;
e4d2205cd   Joe Thornber   dm thin metadata:...
612
613
614
615
616
617
  	}
  
  	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:...
618
  		r = PTR_ERR(pmd->data_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
619
  		goto bad_cleanup_tm;
e4d2205cd   Joe Thornber   dm thin metadata:...
620
  	}
e4d2205cd   Joe Thornber   dm thin metadata:...
621
622
  	pmd->nb_tm = dm_tm_create_non_blocking_clone(pmd->tm);
  	if (!pmd->nb_tm) {
0fa5b17b0   Joe Thornber   dm thin metadata:...
623
  		DMERR("could not create non-blocking clone tm");
e4d2205cd   Joe Thornber   dm thin metadata:...
624
  		r = -ENOMEM;
0fa5b17b0   Joe Thornber   dm thin metadata:...
625
  		goto bad_cleanup_data_sm;
e4d2205cd   Joe Thornber   dm thin metadata:...
626
627
628
  	}
  
  	__setup_btree_details(pmd);
0fa5b17b0   Joe Thornber   dm thin metadata:...
629
  	return dm_bm_unlock(sblock);
e4d2205cd   Joe Thornber   dm thin metadata:...
630

0fa5b17b0   Joe Thornber   dm thin metadata:...
631
  bad_cleanup_data_sm:
e4d2205cd   Joe Thornber   dm thin metadata:...
632
  	dm_sm_destroy(pmd->data_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
633
  bad_cleanup_tm:
e4d2205cd   Joe Thornber   dm thin metadata:...
634
635
  	dm_tm_destroy(pmd->tm);
  	dm_sm_destroy(pmd->metadata_sm);
0fa5b17b0   Joe Thornber   dm thin metadata:...
636
637
  bad_unlock_sblock:
  	dm_bm_unlock(sblock);
e4d2205cd   Joe Thornber   dm thin metadata:...
638
639
640
  
  	return r;
  }
66b1edc05   Joe Thornber   dm thin metadata:...
641
  static int __open_or_format_metadata(struct dm_pool_metadata *pmd, bool format_device)
e4d2205cd   Joe Thornber   dm thin metadata:...
642
  {
8801e0694   Joe Thornber   dm thin metadata:...
643
  	int r, unformatted;
237074c0a   Joe Thornber   dm thin metadata:...
644

8801e0694   Joe Thornber   dm thin metadata:...
645
  	r = __superblock_all_zeroes(pmd->bm, &unformatted);
237074c0a   Joe Thornber   dm thin metadata:...
646
647
  	if (r)
  		return r;
8801e0694   Joe Thornber   dm thin metadata:...
648
  	if (unformatted)
66b1edc05   Joe Thornber   dm thin metadata:...
649
650
651
  		return format_device ? __format_metadata(pmd) : -EPERM;
  
  	return __open_metadata(pmd);
e4d2205cd   Joe Thornber   dm thin metadata:...
652
  }
66b1edc05   Joe Thornber   dm thin metadata:...
653
  static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool format_device)
332627db0   Joe Thornber   dm thin metadata:...
654
655
  {
  	int r;
7d48935ef   Mike Snitzer   dm thin: allow me...
656
  	pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
332627db0   Joe Thornber   dm thin metadata:...
657
658
659
660
661
662
  					  THIN_METADATA_CACHE_SIZE,
  					  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:...
663
  	r = __open_or_format_metadata(pmd, format_device);
332627db0   Joe Thornber   dm thin metadata:...
664
665
666
667
668
  	if (r)
  		dm_block_manager_destroy(pmd->bm);
  
  	return r;
  }
f9dd9352b   Joe Thornber   dm thin metadata:...
669
670
671
672
673
674
675
676
  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...
677
678
679
  static int __begin_transaction(struct dm_pool_metadata *pmd)
  {
  	int r;
991d9fa02   Joe Thornber   dm: add thin prov...
680
681
682
683
  	struct thin_disk_superblock *disk_super;
  	struct dm_block *sblock;
  
  	/*
991d9fa02   Joe Thornber   dm: add thin prov...
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  	 * 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...
699
  	dm_bm_unlock(sblock);
d73ec5253   Mike Snitzer   dm thin metadata:...
700
  	return 0;
991d9fa02   Joe Thornber   dm: add thin prov...
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  }
  
  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...
733
734
735
736
737
738
739
  	}
  
  	return 0;
  }
  
  static int __commit_transaction(struct dm_pool_metadata *pmd)
  {
991d9fa02   Joe Thornber   dm: add thin prov...
740
741
742
743
744
745
746
747
748
749
750
751
  	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:...
752
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
753

991d9fa02   Joe Thornber   dm: add thin prov...
754
755
  	r = dm_sm_commit(pmd->data_sm);
  	if (r < 0)
d973ac196   Joe Thornber   dm thin metadata:...
756
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
757
758
759
  
  	r = dm_tm_pre_commit(pmd->tm);
  	if (r < 0)
d973ac196   Joe Thornber   dm thin metadata:...
760
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
761
762
763
  
  	r = dm_sm_root_size(pmd->metadata_sm, &metadata_len);
  	if (r < 0)
d973ac196   Joe Thornber   dm thin metadata:...
764
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
765

fef838cc1   Joe Thornber   dm thin metadata:...
766
  	r = dm_sm_root_size(pmd->data_sm, &data_len);
991d9fa02   Joe Thornber   dm: add thin prov...
767
  	if (r < 0)
d973ac196   Joe Thornber   dm thin metadata:...
768
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
769

5a32083d0   Joe Thornber   dm: take care to ...
770
771
772
  	r = save_sm_roots(pmd);
  	if (r < 0)
  		return r;
259711920   Joe Thornber   dm thin metadata:...
773
  	r = superblock_lock(pmd, &sblock);
991d9fa02   Joe Thornber   dm: add thin prov...
774
  	if (r)
d973ac196   Joe Thornber   dm thin metadata:...
775
  		return r;
991d9fa02   Joe Thornber   dm: add thin prov...
776
777
778
779
780
781
782
  
  	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 ...
783
  	copy_sm_roots(pmd, disk_super);
991d9fa02   Joe Thornber   dm: add thin prov...
784

eb04cf634   Joe Thornber   dm thin metadata:...
785
  	return dm_tm_commit(pmd->tm, sblock);
991d9fa02   Joe Thornber   dm: add thin prov...
786
787
788
  }
  
  struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
66b1edc05   Joe Thornber   dm thin metadata:...
789
790
  					       sector_t data_block_size,
  					       bool format_device)
991d9fa02   Joe Thornber   dm: add thin prov...
791
792
  {
  	int r;
991d9fa02   Joe Thornber   dm: add thin prov...
793
  	struct dm_pool_metadata *pmd;
991d9fa02   Joe Thornber   dm: add thin prov...
794
795
796
797
798
799
  
  	pmd = kmalloc(sizeof(*pmd), GFP_KERNEL);
  	if (!pmd) {
  		DMERR("could not allocate metadata struct");
  		return ERR_PTR(-ENOMEM);
  	}
6a0ebd31b   Joe Thornber   dm thin metadata:...
800
801
802
  	init_rwsem(&pmd->root_lock);
  	pmd->time = 0;
  	INIT_LIST_HEAD(&pmd->thin_devices);
12ba58af4   Joe Thornber   dm thin metadata:...
803
  	pmd->read_only = false;
da105ed5f   Joe Thornber   dm thin metadata:...
804
  	pmd->fail_io = false;
332627db0   Joe Thornber   dm thin metadata:...
805
  	pmd->bdev = bdev;
9cb6653f9   Joe Thornber   dm thin metadata:...
806
  	pmd->data_block_size = data_block_size;
991d9fa02   Joe Thornber   dm: add thin prov...
807

66b1edc05   Joe Thornber   dm thin metadata:...
808
  	r = __create_persistent_data_objects(pmd, format_device);
991d9fa02   Joe Thornber   dm: add thin prov...
809
  	if (r) {
991d9fa02   Joe Thornber   dm: add thin prov...
810
811
812
  		kfree(pmd);
  		return ERR_PTR(r);
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
813

270938bac   Joe Thornber   dm thin metadata:...
814
815
816
817
818
  	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...
819
820
821
  	}
  
  	return pmd;
991d9fa02   Joe Thornber   dm: add thin prov...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
  }
  
  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;
  	}
da105ed5f   Joe Thornber   dm thin metadata:...
846
  	if (!pmd->read_only && !pmd->fail_io) {
12ba58af4   Joe Thornber   dm thin metadata:...
847
848
849
850
851
  		r = __commit_transaction(pmd);
  		if (r < 0)
  			DMWARN("%s: __commit_transaction() failed, error = %d",
  			       __func__, r);
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
852

da105ed5f   Joe Thornber   dm thin metadata:...
853
854
  	if (!pmd->fail_io)
  		__destroy_persistent_data_objects(pmd);
991d9fa02   Joe Thornber   dm: add thin prov...
855

da105ed5f   Joe Thornber   dm thin metadata:...
856
  	kfree(pmd);
991d9fa02   Joe Thornber   dm: add thin prov...
857
858
  	return 0;
  }
1f3db25d8   Mike Snitzer   dm thin metadata:...
859
860
861
862
863
  /*
   * __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...
864
865
866
867
868
869
870
871
872
873
  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:...
874
  	 * If the device is already open, return it.
991d9fa02   Joe Thornber   dm: add thin prov...
875
876
877
  	 */
  	list_for_each_entry(td2, &pmd->thin_devices, list)
  		if (td2->id == dev) {
1f3db25d8   Mike Snitzer   dm thin metadata:...
878
879
880
881
882
  			/*
  			 * May not create an already-open device.
  			 */
  			if (create)
  				return -EEXIST;
991d9fa02   Joe Thornber   dm: add thin prov...
883
884
885
886
887
888
889
890
891
892
893
894
895
  			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:...
896
897
898
  		/*
  		 * Create new device.
  		 */
991d9fa02   Joe Thornber   dm: add thin prov...
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
  		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:...
914
  	(*td)->aborted_with_changes = false;
991d9fa02   Joe Thornber   dm: add thin prov...
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
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
  	(*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...
965
966
967
968
  		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...
969
970
971
972
973
974
975
  	__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:...
976
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
977
978
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
979
980
  	if (!pmd->fail_io)
  		r = __create_thin(pmd, dev);
991d9fa02   Joe Thornber   dm: add thin prov...
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
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
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
  	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:...
1049
  	__close_device(td);
991d9fa02   Joe Thornber   dm: add thin prov...
1050
1051
  	if (r)
  		goto bad;
991d9fa02   Joe Thornber   dm: add thin prov...
1052
1053
1054
  	return 0;
  
  bad:
991d9fa02   Joe Thornber   dm: add thin prov...
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
  	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:...
1065
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1066
1067
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1068
1069
  	if (!pmd->fail_io)
  		r = __create_snap(pmd, dev, origin);
991d9fa02   Joe Thornber   dm: add thin prov...
1070
1071
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
  	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...
1101
1102
1103
1104
1105
1106
  	return 0;
  }
  
  int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd,
  			       dm_thin_id dev)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1107
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1108
1109
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1110
1111
  	if (!pmd->fail_io)
  		r = __delete_device(pmd, dev);
991d9fa02   Joe Thornber   dm: add thin prov...
1112
1113
1114
1115
1116
1117
1118
1119
1120
  	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:...
1121
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1122
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1123
1124
1125
  
  	if (pmd->fail_io)
  		goto out;
991d9fa02   Joe Thornber   dm: add thin prov...
1126
  	if (pmd->trans_id != current_id) {
991d9fa02   Joe Thornber   dm: add thin prov...
1127
  		DMERR("mismatched transaction id");
da105ed5f   Joe Thornber   dm thin metadata:...
1128
  		goto out;
991d9fa02   Joe Thornber   dm: add thin prov...
1129
1130
1131
  	}
  
  	pmd->trans_id = new_id;
da105ed5f   Joe Thornber   dm thin metadata:...
1132
1133
1134
  	r = 0;
  
  out:
991d9fa02   Joe Thornber   dm: add thin prov...
1135
  	up_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1136
  	return r;
991d9fa02   Joe Thornber   dm: add thin prov...
1137
1138
1139
1140
1141
  }
  
  int dm_pool_get_metadata_transaction_id(struct dm_pool_metadata *pmd,
  					uint64_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1142
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1143
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1144
1145
1146
1147
  	if (!pmd->fail_io) {
  		*result = pmd->trans_id;
  		r = 0;
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
1148
  	up_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1149
  	return r;
991d9fa02   Joe Thornber   dm: add thin prov...
1150
  }
cc8394d86   Joe Thornber   dm thin: provide ...
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
  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;
  
  	/*
  	 * 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 ...
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
  		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:...
1198
  	r = superblock_lock(pmd, &sblock);
cc8394d86   Joe Thornber   dm thin: provide ...
1199
1200
  	if (r) {
  		dm_tm_dec(pmd->tm, held_root);
cc8394d86   Joe Thornber   dm thin: provide ...
1201
1202
1203
1204
1205
1206
  		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 ...
1207
1208
1209
1210
1211
  	return 0;
  }
  
  int dm_pool_reserve_metadata_snap(struct dm_pool_metadata *pmd)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1212
  	int r = -EINVAL;
cc8394d86   Joe Thornber   dm thin: provide ...
1213
1214
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1215
1216
  	if (!pmd->fail_io)
  		r = __reserve_metadata_snap(pmd);
cc8394d86   Joe Thornber   dm thin: provide ...
1217
1218
1219
1220
1221
1222
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  static int __release_metadata_snap(struct dm_pool_metadata *pmd)
991d9fa02   Joe Thornber   dm: add thin prov...
1223
1224
1225
  {
  	int r;
  	struct thin_disk_superblock *disk_super;
cc8394d86   Joe Thornber   dm thin: provide ...
1226
1227
  	struct dm_block *sblock, *copy;
  	dm_block_t held_root;
991d9fa02   Joe Thornber   dm: add thin prov...
1228

259711920   Joe Thornber   dm thin metadata:...
1229
  	r = superblock_lock(pmd, &sblock);
991d9fa02   Joe Thornber   dm: add thin prov...
1230
1231
1232
1233
  	if (r)
  		return r;
  
  	disk_super = dm_block_data(sblock);
cc8394d86   Joe Thornber   dm thin: provide ...
1234
1235
  	held_root = le64_to_cpu(disk_super->held_root);
  	disk_super->held_root = cpu_to_le64(0);
cc8394d86   Joe Thornber   dm thin: provide ...
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
  
  	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);
  	dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->data_mapping_root));
  	dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->device_details_root));
  	dm_sm_dec_block(pmd->metadata_sm, held_root);
  
  	return dm_tm_unlock(pmd->tm, copy);
  }
  
  int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1258
  	int r = -EINVAL;
cc8394d86   Joe Thornber   dm thin: provide ...
1259
1260
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1261
1262
  	if (!pmd->fail_io)
  		r = __release_metadata_snap(pmd);
cc8394d86   Joe Thornber   dm thin: provide ...
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
  	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...
1281
1282
1283
1284
  	*result = le64_to_cpu(disk_super->held_root);
  
  	return dm_bm_unlock(sblock);
  }
cc8394d86   Joe Thornber   dm thin: provide ...
1285
1286
  int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd,
  			      dm_block_t *result)
991d9fa02   Joe Thornber   dm: add thin prov...
1287
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1288
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1289
1290
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1291
1292
  	if (!pmd->fail_io)
  		r = __get_metadata_snap(pmd, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1293
1294
1295
1296
1297
1298
1299
1300
  	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:...
1301
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1302
1303
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1304
1305
  	if (!pmd->fail_io)
  		r = __open_device(pmd, dev, 0, td);
991d9fa02   Joe Thornber   dm: add thin prov...
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
  	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...
1324
1325
1326
1327
1328
1329
  /*
   * 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...
1330
  static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time)
991d9fa02   Joe Thornber   dm: add thin prov...
1331
1332
1333
1334
1335
  {
  	return td->snapshotted_time > time;
  }
  
  int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
e5cfc69a5   Joe Thornber   dm thin metadata:...
1336
  		       int can_issue_io, struct dm_thin_lookup_result *result)
991d9fa02   Joe Thornber   dm: add thin prov...
1337
  {
e5cfc69a5   Joe Thornber   dm thin metadata:...
1338
  	int r;
991d9fa02   Joe Thornber   dm: add thin prov...
1339
1340
1341
  	__le64 value;
  	struct dm_pool_metadata *pmd = td->pmd;
  	dm_block_t keys[2] = { td->id, block };
da105ed5f   Joe Thornber   dm thin metadata:...
1342
  	struct dm_btree_info *info;
991d9fa02   Joe Thornber   dm: add thin prov...
1343

da105ed5f   Joe Thornber   dm thin metadata:...
1344
  	if (pmd->fail_io)
e5cfc69a5   Joe Thornber   dm thin metadata:...
1345
  		return -EINVAL;
da105ed5f   Joe Thornber   dm thin metadata:...
1346

e5cfc69a5   Joe Thornber   dm thin metadata:...
1347
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1348

e5cfc69a5   Joe Thornber   dm thin metadata:...
1349
1350
1351
1352
  	if (can_issue_io) {
  		info = &pmd->info;
  	} else
  		info = &pmd->nb_info;
da105ed5f   Joe Thornber   dm thin metadata:...
1353

e5cfc69a5   Joe Thornber   dm thin metadata:...
1354
  	r = dm_btree_lookup(info, pmd->root, keys, &value);
991d9fa02   Joe Thornber   dm: add thin prov...
1355
  	if (!r) {
e5cfc69a5   Joe Thornber   dm thin metadata:...
1356
  		uint64_t block_time = 0;
991d9fa02   Joe Thornber   dm: add thin prov...
1357
1358
  		dm_block_t exception_block;
  		uint32_t exception_time;
e5cfc69a5   Joe Thornber   dm thin metadata:...
1359
1360
  
  		block_time = le64_to_cpu(value);
991d9fa02   Joe Thornber   dm: add thin prov...
1361
1362
1363
1364
1365
  		unpack_block_time(block_time, &exception_block,
  				  &exception_time);
  		result->block = exception_block;
  		result->shared = __snapshotted_since(td, exception_time);
  	}
e5cfc69a5   Joe Thornber   dm thin metadata:...
1366
  	up_read(&pmd->root_lock);
991d9fa02   Joe Thornber   dm: add thin prov...
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
  	return r;
  }
  
  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...
1377
1378
1379
1380
1381
1382
1383
  	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:...
1384
1385
  	td->changed = 1;
  	if (inserted)
991d9fa02   Joe Thornber   dm: add thin prov...
1386
  		td->mapped_blocks++;
991d9fa02   Joe Thornber   dm: add thin prov...
1387
1388
1389
1390
1391
1392
1393
  
  	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:...
1394
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1395
1396
  
  	down_write(&td->pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1397
1398
  	if (!td->pmd->fail_io)
  		r = __insert(td, block, data_block);
991d9fa02   Joe Thornber   dm: add thin prov...
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
  	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:...
1413
1414
  	td->mapped_blocks--;
  	td->changed = 1;
991d9fa02   Joe Thornber   dm: add thin prov...
1415
1416
1417
1418
1419
1420
  
  	return 0;
  }
  
  int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1421
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1422
1423
  
  	down_write(&td->pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1424
1425
  	if (!td->pmd->fail_io)
  		r = __remove(td, block);
991d9fa02   Joe Thornber   dm: add thin prov...
1426
  	up_write(&td->pmd->root_lock);
19fa1a675   Joe Thornber   dm thin: fix disc...
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
  
  	return r;
  }
  
  int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result)
  {
  	int r;
  	uint32_t ref_count;
  
  	down_read(&pmd->root_lock);
  	r = dm_sm_get_count(pmd->data_sm, b, &ref_count);
  	if (!r)
  		*result = (ref_count != 0);
  	up_read(&pmd->root_lock);
991d9fa02   Joe Thornber   dm: add thin prov...
1441
1442
1443
  
  	return r;
  }
40db5a537   Joe Thornber   dm thin metadata:...
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
  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...
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
  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:...
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
  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...
1480
1481
  int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1482
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1483
1484
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1485
1486
  	if (!pmd->fail_io)
  		r = dm_sm_new_block(pmd->data_sm, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1487
1488
1489
1490
1491
1492
1493
  	up_write(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_pool_commit_metadata(struct dm_pool_metadata *pmd)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1494
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1495
1496
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1497
1498
  	if (pmd->fail_io)
  		goto out;
991d9fa02   Joe Thornber   dm: add thin prov...
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
  
  	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:...
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
  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...
1539
1540
  int dm_pool_get_free_block_count(struct dm_pool_metadata *pmd, dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1541
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1542
1543
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1544
1545
  	if (!pmd->fail_io)
  		r = dm_sm_get_nr_free(pmd->data_sm, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1546
1547
1548
1549
1550
1551
1552
1553
  	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:...
1554
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1555
1556
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1557
1558
  	if (!pmd->fail_io)
  		r = dm_sm_get_nr_free(pmd->metadata_sm, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1559
1560
1561
1562
1563
1564
1565
1566
  	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:...
1567
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1568
1569
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1570
1571
  	if (!pmd->fail_io)
  		r = dm_sm_get_nr_blocks(pmd->metadata_sm, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
  	up_read(&pmd->root_lock);
  
  	return r;
  }
  
  int dm_pool_get_data_block_size(struct dm_pool_metadata *pmd, sector_t *result)
  {
  	down_read(&pmd->root_lock);
  	*result = pmd->data_block_size;
  	up_read(&pmd->root_lock);
  
  	return 0;
  }
  
  int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1588
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1589
1590
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1591
1592
  	if (!pmd->fail_io)
  		r = dm_sm_get_nr_blocks(pmd->data_sm, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1593
1594
1595
1596
1597
1598
1599
  	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:...
1600
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1601
1602
1603
  	struct dm_pool_metadata *pmd = td->pmd;
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1604
1605
1606
1607
  	if (!pmd->fail_io) {
  		*result = td->mapped_blocks;
  		r = 0;
  	}
991d9fa02   Joe Thornber   dm: add thin prov...
1608
  	up_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1609
  	return r;
991d9fa02   Joe Thornber   dm: add thin prov...
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
  }
  
  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:...
1631
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1632
1633
1634
  	struct dm_pool_metadata *pmd = td->pmd;
  
  	down_read(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1635
1636
  	if (!pmd->fail_io)
  		r = __highest_block(td, result);
991d9fa02   Joe Thornber   dm: add thin prov...
1637
1638
1639
1640
  	up_read(&pmd->root_lock);
  
  	return r;
  }
b17446df2   Joe Thornber   dm thin: refactor...
1641
  static int __resize_space_map(struct dm_space_map *sm, dm_block_t new_count)
991d9fa02   Joe Thornber   dm: add thin prov...
1642
1643
1644
  {
  	int r;
  	dm_block_t old_count;
b17446df2   Joe Thornber   dm thin: refactor...
1645
  	r = dm_sm_get_nr_blocks(sm, &old_count);
991d9fa02   Joe Thornber   dm: add thin prov...
1646
1647
1648
1649
1650
1651
1652
  	if (r)
  		return r;
  
  	if (new_count == old_count)
  		return 0;
  
  	if (new_count < old_count) {
b17446df2   Joe Thornber   dm thin: refactor...
1653
  		DMERR("cannot reduce size of space map");
991d9fa02   Joe Thornber   dm: add thin prov...
1654
1655
  		return -EINVAL;
  	}
b17446df2   Joe Thornber   dm thin: refactor...
1656
  	return dm_sm_extend(sm, new_count - old_count);
991d9fa02   Joe Thornber   dm: add thin prov...
1657
1658
1659
1660
  }
  
  int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count)
  {
da105ed5f   Joe Thornber   dm thin metadata:...
1661
  	int r = -EINVAL;
991d9fa02   Joe Thornber   dm: add thin prov...
1662
1663
  
  	down_write(&pmd->root_lock);
da105ed5f   Joe Thornber   dm thin metadata:...
1664
  	if (!pmd->fail_io)
b17446df2   Joe Thornber   dm thin: refactor...
1665
  		r = __resize_space_map(pmd->data_sm, new_count);
991d9fa02   Joe Thornber   dm: add thin prov...
1666
1667
1668
1669
  	up_write(&pmd->root_lock);
  
  	return r;
  }
12ba58af4   Joe Thornber   dm thin metadata:...
1670

24347e959   Joe Thornber   dm thin: detect m...
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
  int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_count)
  {
  	int r = -EINVAL;
  
  	down_write(&pmd->root_lock);
  	if (!pmd->fail_io)
  		r = __resize_space_map(pmd->metadata_sm, new_count);
  	up_write(&pmd->root_lock);
  
  	return r;
  }
12ba58af4   Joe Thornber   dm thin metadata:...
1682
1683
1684
1685
1686
1687
1688
  void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd)
  {
  	down_write(&pmd->root_lock);
  	pmd->read_only = true;
  	dm_bm_set_read_only(pmd->bm);
  	up_write(&pmd->root_lock);
  }
ac8c3f3df   Joe Thornber   dm thin: generate...
1689

9b7aaa64f   Joe Thornber   dm thin: allow po...
1690
1691
1692
1693
1694
1695
1696
  void dm_pool_metadata_read_write(struct dm_pool_metadata *pmd)
  {
  	down_write(&pmd->root_lock);
  	pmd->read_only = false;
  	dm_bm_set_read_write(pmd->bm);
  	up_write(&pmd->root_lock);
  }
ac8c3f3df   Joe Thornber   dm thin: generate...
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
  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...
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
  
  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...
1745
1746
1747
1748
1749
  
  void dm_pool_issue_prefetches(struct dm_pool_metadata *pmd)
  {
  	dm_tm_issue_prefetches(pmd->tm);
  }