Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'dm-4.4-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper fixes from Mike Snitzer:
"Five stable fixes:

- Two DM btree bufio buffer leak fixes that resolve reported BUG_ONs
during DM thinp metadata close's dm_bufio_client_destroy().

- A DM thinp range discard fix to handle discarding a partially
mapped range.

- A DM thinp metadata snapshot fix to make sure the btree roots saved
in the metadata snapshot are the most current.

- A DM space map metadata refcounting fix that improves both DM thinp
and DM cache metadata"

* tag 'dm-4.4-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm btree: fix bufio buffer leaks in dm_btree_del() error path
dm space map metadata: fix ref counting bug when bootstrapping a new space map
dm thin metadata: fix bug when taking a metadata snapshot
dm thin metadata: fix bug in dm_thin_remove_range()
dm btree: fix leak of bufio-backed block in btree_split_sibling error path

+161 -20
+29 -5
drivers/md/dm-thin-metadata.c
··· 1207 1207 dm_block_t held_root; 1208 1208 1209 1209 /* 1210 + * We commit to ensure the btree roots which we increment in a 1211 + * moment are up to date. 1212 + */ 1213 + __commit_transaction(pmd); 1214 + 1215 + /* 1210 1216 * Copy the superblock. 1211 1217 */ 1212 1218 dm_sm_inc_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION); ··· 1544 1538 static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_t end) 1545 1539 { 1546 1540 int r; 1547 - unsigned count; 1541 + unsigned count, total_count = 0; 1548 1542 struct dm_pool_metadata *pmd = td->pmd; 1549 1543 dm_block_t keys[1] = { td->id }; 1550 1544 __le64 value; ··· 1567 1561 if (r) 1568 1562 return r; 1569 1563 1570 - r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count); 1571 - if (r) 1572 - return r; 1564 + /* 1565 + * Remove leaves stops at the first unmapped entry, so we have to 1566 + * loop round finding mapped ranges. 1567 + */ 1568 + while (begin < end) { 1569 + r = dm_btree_lookup_next(&pmd->bl_info, mapping_root, &begin, &begin, &value); 1570 + if (r == -ENODATA) 1571 + break; 1573 1572 1574 - td->mapped_blocks -= count; 1573 + if (r) 1574 + return r; 1575 + 1576 + if (begin >= end) 1577 + break; 1578 + 1579 + r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count); 1580 + if (r) 1581 + return r; 1582 + 1583 + total_count += count; 1584 + } 1585 + 1586 + td->mapped_blocks -= total_count; 1575 1587 td->changed = 1; 1576 1588 1577 1589 /*
+99 -2
drivers/md/persistent-data/dm-btree.c
··· 63 63 return bsearch(n, key, 0); 64 64 } 65 65 66 + static int upper_bound(struct btree_node *n, uint64_t key) 67 + { 68 + return bsearch(n, key, 1); 69 + } 70 + 66 71 void inc_children(struct dm_transaction_manager *tm, struct btree_node *n, 67 72 struct dm_btree_value_type *vt) 68 73 { ··· 257 252 dm_tm_unlock(s->tm, f->b); 258 253 } 259 254 255 + static void unlock_all_frames(struct del_stack *s) 256 + { 257 + struct frame *f; 258 + 259 + while (unprocessed_frames(s)) { 260 + f = s->spine + s->top--; 261 + dm_tm_unlock(s->tm, f->b); 262 + } 263 + } 264 + 260 265 int dm_btree_del(struct dm_btree_info *info, dm_block_t root) 261 266 { 262 267 int r; ··· 323 308 pop_frame(s); 324 309 } 325 310 } 326 - 327 311 out: 312 + if (r) { 313 + /* cleanup all frames of del_stack */ 314 + unlock_all_frames(s); 315 + } 328 316 kfree(s); 317 + 329 318 return r; 330 319 } 331 320 EXPORT_SYMBOL_GPL(dm_btree_del); ··· 410 391 return r; 411 392 } 412 393 EXPORT_SYMBOL_GPL(dm_btree_lookup); 394 + 395 + static int dm_btree_lookup_next_single(struct dm_btree_info *info, dm_block_t root, 396 + uint64_t key, uint64_t *rkey, void *value_le) 397 + { 398 + int r, i; 399 + uint32_t flags, nr_entries; 400 + struct dm_block *node; 401 + struct btree_node *n; 402 + 403 + r = bn_read_lock(info, root, &node); 404 + if (r) 405 + return r; 406 + 407 + n = dm_block_data(node); 408 + flags = le32_to_cpu(n->header.flags); 409 + nr_entries = le32_to_cpu(n->header.nr_entries); 410 + 411 + if (flags & INTERNAL_NODE) { 412 + i = lower_bound(n, key); 413 + if (i < 0 || i >= nr_entries) { 414 + r = -ENODATA; 415 + goto out; 416 + } 417 + 418 + r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le); 419 + if (r == -ENODATA && i < (nr_entries - 1)) { 420 + i++; 421 + r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le); 422 + } 423 + 424 + } else { 425 + i = upper_bound(n, key); 426 + if (i < 0 || i >= nr_entries) { 427 + r = -ENODATA; 428 + goto out; 429 + } 430 + 431 + *rkey = le64_to_cpu(n->keys[i]); 432 + memcpy(value_le, value_ptr(n, i), info->value_type.size); 433 + } 434 + out: 435 + dm_tm_unlock(info->tm, node); 436 + return r; 437 + } 438 + 439 + int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root, 440 + uint64_t *keys, uint64_t *rkey, void *value_le) 441 + { 442 + unsigned level; 443 + int r = -ENODATA; 444 + __le64 internal_value_le; 445 + struct ro_spine spine; 446 + 447 + init_ro_spine(&spine, info); 448 + for (level = 0; level < info->levels - 1u; level++) { 449 + r = btree_lookup_raw(&spine, root, keys[level], 450 + lower_bound, rkey, 451 + &internal_value_le, sizeof(uint64_t)); 452 + if (r) 453 + goto out; 454 + 455 + if (*rkey != keys[level]) { 456 + r = -ENODATA; 457 + goto out; 458 + } 459 + 460 + root = le64_to_cpu(internal_value_le); 461 + } 462 + 463 + r = dm_btree_lookup_next_single(info, root, keys[level], rkey, value_le); 464 + out: 465 + exit_ro_spine(&spine); 466 + return r; 467 + } 468 + 469 + EXPORT_SYMBOL_GPL(dm_btree_lookup_next); 413 470 414 471 /* 415 472 * Splits a node by creating a sibling node and shifting half the nodes ··· 568 473 569 474 r = insert_at(sizeof(__le64), pn, parent_index + 1, 570 475 le64_to_cpu(rn->keys[0]), &location); 571 - if (r) 476 + if (r) { 477 + unlock_block(s->info, right); 572 478 return r; 479 + } 573 480 574 481 if (key < le64_to_cpu(rn->keys[0])) { 575 482 unlock_block(s->info, right);
+11 -3
drivers/md/persistent-data/dm-btree.h
··· 110 110 uint64_t *keys, void *value_le); 111 111 112 112 /* 113 + * Tries to find the first key where the bottom level key is >= to that 114 + * given. Useful for skipping empty sections of the btree. 115 + */ 116 + int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root, 117 + uint64_t *keys, uint64_t *rkey, void *value_le); 118 + 119 + /* 113 120 * Insertion (or overwrite an existing value). O(ln(n)) 114 121 */ 115 122 int dm_btree_insert(struct dm_btree_info *info, dm_block_t root, ··· 142 135 uint64_t *keys, dm_block_t *new_root); 143 136 144 137 /* 145 - * Removes values between 'keys' and keys2, where keys2 is keys with the 146 - * final key replaced with 'end_key'. 'end_key' is the one-past-the-end 147 - * value. 'keys' may be altered. 138 + * Removes a _contiguous_ run of values starting from 'keys' and not 139 + * reaching keys2 (where keys2 is keys with the final key replaced with 140 + * 'end_key'). 'end_key' is the one-past-the-end value. 'keys' may be 141 + * altered. 148 142 */ 149 143 int dm_btree_remove_leaves(struct dm_btree_info *info, dm_block_t root, 150 144 uint64_t *keys, uint64_t end_key,
+22 -10
drivers/md/persistent-data/dm-space-map-metadata.c
··· 136 136 return 0; 137 137 } 138 138 139 - static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result) 139 + static int brb_peek(struct bop_ring_buffer *brb, struct block_op *result) 140 140 { 141 141 struct block_op *bop; 142 142 ··· 147 147 result->type = bop->type; 148 148 result->block = bop->block; 149 149 150 + return 0; 151 + } 152 + 153 + static int brb_pop(struct bop_ring_buffer *brb) 154 + { 155 + struct block_op *bop; 156 + 157 + if (brb_empty(brb)) 158 + return -ENODATA; 159 + 160 + bop = brb->bops + brb->begin; 150 161 brb->begin = brb_next(brb, brb->begin); 151 162 152 163 return 0; ··· 222 211 while (!brb_empty(&smm->uncommitted)) { 223 212 struct block_op bop; 224 213 225 - r = brb_pop(&smm->uncommitted, &bop); 214 + r = brb_peek(&smm->uncommitted, &bop); 226 215 if (r) { 227 216 DMERR("bug in bop ring buffer"); 228 217 break; ··· 231 220 r = commit_bop(smm, &bop); 232 221 if (r) 233 222 break; 223 + 224 + brb_pop(&smm->uncommitted); 234 225 } 235 226 236 227 return r; ··· 696 683 static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks) 697 684 { 698 685 int r, i; 699 - enum allocation_event ev; 700 686 struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); 701 687 dm_block_t old_len = smm->ll.nr_blocks; 702 688 ··· 717 705 * allocate any new blocks. 718 706 */ 719 707 do { 720 - for (i = old_len; !r && i < smm->begin; i++) { 721 - r = sm_ll_inc(&smm->ll, i, &ev); 722 - if (r) 723 - goto out; 724 - } 708 + for (i = old_len; !r && i < smm->begin; i++) 709 + r = add_bop(smm, BOP_INC, i); 710 + 711 + if (r) 712 + goto out; 713 + 725 714 old_len = smm->begin; 726 715 727 716 r = apply_bops(smm); ··· 767 754 { 768 755 int r; 769 756 dm_block_t i; 770 - enum allocation_event ev; 771 757 struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); 772 758 773 759 smm->begin = superblock + 1; ··· 794 782 * allocated blocks that they were built from. 795 783 */ 796 784 for (i = superblock; !r && i < smm->begin; i++) 797 - r = sm_ll_inc(&smm->ll, i, &ev); 785 + r = add_bop(smm, BOP_INC, i); 798 786 799 787 if (r) 800 788 return r;