13241b1d3SJoe Thornber /* 23241b1d3SJoe Thornber * Copyright (C) 2011 Red Hat, Inc. 33241b1d3SJoe Thornber * 43241b1d3SJoe Thornber * This file is released under the GPL. 53241b1d3SJoe Thornber */ 63241b1d3SJoe Thornber 73241b1d3SJoe Thornber #include "dm-btree-internal.h" 83241b1d3SJoe Thornber #include "dm-transaction-manager.h" 93241b1d3SJoe Thornber 103241b1d3SJoe Thornber #include <linux/device-mapper.h> 113241b1d3SJoe Thornber 123241b1d3SJoe Thornber #define DM_MSG_PREFIX "btree spine" 133241b1d3SJoe Thornber 143241b1d3SJoe Thornber /*----------------------------------------------------------------*/ 153241b1d3SJoe Thornber 163241b1d3SJoe Thornber #define BTREE_CSUM_XOR 121107 173241b1d3SJoe Thornber 183241b1d3SJoe Thornber static int node_check(struct dm_block_validator *v, 193241b1d3SJoe Thornber struct dm_block *b, 203241b1d3SJoe Thornber size_t block_size); 213241b1d3SJoe Thornber 223241b1d3SJoe Thornber static void node_prepare_for_write(struct dm_block_validator *v, 233241b1d3SJoe Thornber struct dm_block *b, 243241b1d3SJoe Thornber size_t block_size) 253241b1d3SJoe Thornber { 26550929faSMikulas Patocka struct btree_node *n = dm_block_data(b); 273241b1d3SJoe Thornber struct node_header *h = &n->header; 283241b1d3SJoe Thornber 293241b1d3SJoe Thornber h->blocknr = cpu_to_le64(dm_block_location(b)); 303241b1d3SJoe Thornber h->csum = cpu_to_le32(dm_bm_checksum(&h->flags, 313241b1d3SJoe Thornber block_size - sizeof(__le32), 323241b1d3SJoe Thornber BTREE_CSUM_XOR)); 333241b1d3SJoe Thornber } 343241b1d3SJoe Thornber 353241b1d3SJoe Thornber static int node_check(struct dm_block_validator *v, 363241b1d3SJoe Thornber struct dm_block *b, 373241b1d3SJoe Thornber size_t block_size) 383241b1d3SJoe Thornber { 39550929faSMikulas Patocka struct btree_node *n = dm_block_data(b); 403241b1d3SJoe Thornber struct node_header *h = &n->header; 413241b1d3SJoe Thornber size_t value_size; 423241b1d3SJoe Thornber __le32 csum_disk; 433241b1d3SJoe Thornber uint32_t flags; 443241b1d3SJoe Thornber 453241b1d3SJoe Thornber if (dm_block_location(b) != le64_to_cpu(h->blocknr)) { 4689ddeb8cSMike Snitzer DMERR_LIMIT("node_check failed: blocknr %llu != wanted %llu", 473241b1d3SJoe Thornber le64_to_cpu(h->blocknr), dm_block_location(b)); 483241b1d3SJoe Thornber return -ENOTBLK; 493241b1d3SJoe Thornber } 503241b1d3SJoe Thornber 513241b1d3SJoe Thornber csum_disk = cpu_to_le32(dm_bm_checksum(&h->flags, 523241b1d3SJoe Thornber block_size - sizeof(__le32), 533241b1d3SJoe Thornber BTREE_CSUM_XOR)); 543241b1d3SJoe Thornber if (csum_disk != h->csum) { 5589ddeb8cSMike Snitzer DMERR_LIMIT("node_check failed: csum %u != wanted %u", 563241b1d3SJoe Thornber le32_to_cpu(csum_disk), le32_to_cpu(h->csum)); 573241b1d3SJoe Thornber return -EILSEQ; 583241b1d3SJoe Thornber } 593241b1d3SJoe Thornber 603241b1d3SJoe Thornber value_size = le32_to_cpu(h->value_size); 613241b1d3SJoe Thornber 623241b1d3SJoe Thornber if (sizeof(struct node_header) + 633241b1d3SJoe Thornber (sizeof(__le64) + value_size) * le32_to_cpu(h->max_entries) > block_size) { 6489ddeb8cSMike Snitzer DMERR_LIMIT("node_check failed: max_entries too large"); 653241b1d3SJoe Thornber return -EILSEQ; 663241b1d3SJoe Thornber } 673241b1d3SJoe Thornber 683241b1d3SJoe Thornber if (le32_to_cpu(h->nr_entries) > le32_to_cpu(h->max_entries)) { 6989ddeb8cSMike Snitzer DMERR_LIMIT("node_check failed: too many entries"); 703241b1d3SJoe Thornber return -EILSEQ; 713241b1d3SJoe Thornber } 723241b1d3SJoe Thornber 733241b1d3SJoe Thornber /* 743241b1d3SJoe Thornber * The node must be either INTERNAL or LEAF. 753241b1d3SJoe Thornber */ 763241b1d3SJoe Thornber flags = le32_to_cpu(h->flags); 773241b1d3SJoe Thornber if (!(flags & INTERNAL_NODE) && !(flags & LEAF_NODE)) { 7889ddeb8cSMike Snitzer DMERR_LIMIT("node_check failed: node is neither INTERNAL or LEAF"); 793241b1d3SJoe Thornber return -EILSEQ; 803241b1d3SJoe Thornber } 813241b1d3SJoe Thornber 823241b1d3SJoe Thornber return 0; 833241b1d3SJoe Thornber } 843241b1d3SJoe Thornber 853241b1d3SJoe Thornber struct dm_block_validator btree_node_validator = { 863241b1d3SJoe Thornber .name = "btree_node", 873241b1d3SJoe Thornber .prepare_for_write = node_prepare_for_write, 883241b1d3SJoe Thornber .check = node_check 893241b1d3SJoe Thornber }; 903241b1d3SJoe Thornber 913241b1d3SJoe Thornber /*----------------------------------------------------------------*/ 923241b1d3SJoe Thornber 939b460d36SJoe Thornber int bn_read_lock(struct dm_btree_info *info, dm_block_t b, 943241b1d3SJoe Thornber struct dm_block **result) 953241b1d3SJoe Thornber { 963241b1d3SJoe Thornber return dm_tm_read_lock(info->tm, b, &btree_node_validator, result); 973241b1d3SJoe Thornber } 983241b1d3SJoe Thornber 993241b1d3SJoe Thornber static int bn_shadow(struct dm_btree_info *info, dm_block_t orig, 1003241b1d3SJoe Thornber struct dm_btree_value_type *vt, 1013241b1d3SJoe Thornber struct dm_block **result) 1023241b1d3SJoe Thornber { 1033241b1d3SJoe Thornber int r, inc; 1043241b1d3SJoe Thornber 1053241b1d3SJoe Thornber r = dm_tm_shadow_block(info->tm, orig, &btree_node_validator, 1063241b1d3SJoe Thornber result, &inc); 1073241b1d3SJoe Thornber if (!r && inc) 1083241b1d3SJoe Thornber inc_children(info->tm, dm_block_data(*result), vt); 1093241b1d3SJoe Thornber 1103241b1d3SJoe Thornber return r; 1113241b1d3SJoe Thornber } 1123241b1d3SJoe Thornber 1133241b1d3SJoe Thornber int new_block(struct dm_btree_info *info, struct dm_block **result) 1143241b1d3SJoe Thornber { 1153241b1d3SJoe Thornber return dm_tm_new_block(info->tm, &btree_node_validator, result); 1163241b1d3SJoe Thornber } 1173241b1d3SJoe Thornber 1184c7da06fSMikulas Patocka void unlock_block(struct dm_btree_info *info, struct dm_block *b) 1193241b1d3SJoe Thornber { 1204c7da06fSMikulas Patocka dm_tm_unlock(info->tm, b); 1213241b1d3SJoe Thornber } 1223241b1d3SJoe Thornber 1233241b1d3SJoe Thornber /*----------------------------------------------------------------*/ 1243241b1d3SJoe Thornber 1253241b1d3SJoe Thornber void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info) 1263241b1d3SJoe Thornber { 1273241b1d3SJoe Thornber s->info = info; 1283241b1d3SJoe Thornber s->count = 0; 1293241b1d3SJoe Thornber s->nodes[0] = NULL; 1303241b1d3SJoe Thornber s->nodes[1] = NULL; 1313241b1d3SJoe Thornber } 1323241b1d3SJoe Thornber 1339431cf6eSZhiqiang Liu void exit_ro_spine(struct ro_spine *s) 1343241b1d3SJoe Thornber { 1359431cf6eSZhiqiang Liu int i; 1363241b1d3SJoe Thornber 1373241b1d3SJoe Thornber for (i = 0; i < s->count; i++) { 1384c7da06fSMikulas Patocka unlock_block(s->info, s->nodes[i]); 1393241b1d3SJoe Thornber } 1403241b1d3SJoe Thornber } 1413241b1d3SJoe Thornber 1423241b1d3SJoe Thornber int ro_step(struct ro_spine *s, dm_block_t new_child) 1433241b1d3SJoe Thornber { 1443241b1d3SJoe Thornber int r; 1453241b1d3SJoe Thornber 1463241b1d3SJoe Thornber if (s->count == 2) { 1474c7da06fSMikulas Patocka unlock_block(s->info, s->nodes[0]); 1483241b1d3SJoe Thornber s->nodes[0] = s->nodes[1]; 1493241b1d3SJoe Thornber s->count--; 1503241b1d3SJoe Thornber } 1513241b1d3SJoe Thornber 1523241b1d3SJoe Thornber r = bn_read_lock(s->info, new_child, s->nodes + s->count); 1533241b1d3SJoe Thornber if (!r) 1543241b1d3SJoe Thornber s->count++; 1553241b1d3SJoe Thornber 1563241b1d3SJoe Thornber return r; 1573241b1d3SJoe Thornber } 1583241b1d3SJoe Thornber 1594e7f1f90SJoe Thornber void ro_pop(struct ro_spine *s) 1604e7f1f90SJoe Thornber { 1614e7f1f90SJoe Thornber BUG_ON(!s->count); 1624e7f1f90SJoe Thornber --s->count; 1634e7f1f90SJoe Thornber unlock_block(s->info, s->nodes[s->count]); 1644e7f1f90SJoe Thornber } 1654e7f1f90SJoe Thornber 166550929faSMikulas Patocka struct btree_node *ro_node(struct ro_spine *s) 1673241b1d3SJoe Thornber { 1683241b1d3SJoe Thornber struct dm_block *block; 1693241b1d3SJoe Thornber 1703241b1d3SJoe Thornber BUG_ON(!s->count); 1713241b1d3SJoe Thornber block = s->nodes[s->count - 1]; 1723241b1d3SJoe Thornber 1733241b1d3SJoe Thornber return dm_block_data(block); 1743241b1d3SJoe Thornber } 1753241b1d3SJoe Thornber 1763241b1d3SJoe Thornber /*----------------------------------------------------------------*/ 1773241b1d3SJoe Thornber 1783241b1d3SJoe Thornber void init_shadow_spine(struct shadow_spine *s, struct dm_btree_info *info) 1793241b1d3SJoe Thornber { 1803241b1d3SJoe Thornber s->info = info; 1813241b1d3SJoe Thornber s->count = 0; 1823241b1d3SJoe Thornber } 1833241b1d3SJoe Thornber 184ece25773SJiapeng Chong void exit_shadow_spine(struct shadow_spine *s) 1853241b1d3SJoe Thornber { 186ece25773SJiapeng Chong int i; 1873241b1d3SJoe Thornber 1883241b1d3SJoe Thornber for (i = 0; i < s->count; i++) { 1894c7da06fSMikulas Patocka unlock_block(s->info, s->nodes[i]); 1903241b1d3SJoe Thornber } 1913241b1d3SJoe Thornber } 1923241b1d3SJoe Thornber 1933241b1d3SJoe Thornber int shadow_step(struct shadow_spine *s, dm_block_t b, 1943241b1d3SJoe Thornber struct dm_btree_value_type *vt) 1953241b1d3SJoe Thornber { 1963241b1d3SJoe Thornber int r; 1973241b1d3SJoe Thornber 1983241b1d3SJoe Thornber if (s->count == 2) { 1994c7da06fSMikulas Patocka unlock_block(s->info, s->nodes[0]); 2003241b1d3SJoe Thornber s->nodes[0] = s->nodes[1]; 2013241b1d3SJoe Thornber s->count--; 2023241b1d3SJoe Thornber } 2033241b1d3SJoe Thornber 2043241b1d3SJoe Thornber r = bn_shadow(s->info, b, vt, s->nodes + s->count); 2053241b1d3SJoe Thornber if (!r) { 2063241b1d3SJoe Thornber if (!s->count) 2073241b1d3SJoe Thornber s->root = dm_block_location(s->nodes[0]); 2083241b1d3SJoe Thornber 2093241b1d3SJoe Thornber s->count++; 2103241b1d3SJoe Thornber } 2113241b1d3SJoe Thornber 2123241b1d3SJoe Thornber return r; 2133241b1d3SJoe Thornber } 2143241b1d3SJoe Thornber 2153241b1d3SJoe Thornber struct dm_block *shadow_current(struct shadow_spine *s) 2163241b1d3SJoe Thornber { 2173241b1d3SJoe Thornber BUG_ON(!s->count); 2183241b1d3SJoe Thornber 2193241b1d3SJoe Thornber return s->nodes[s->count - 1]; 2203241b1d3SJoe Thornber } 2213241b1d3SJoe Thornber 2223241b1d3SJoe Thornber struct dm_block *shadow_parent(struct shadow_spine *s) 2233241b1d3SJoe Thornber { 2243241b1d3SJoe Thornber BUG_ON(s->count != 2); 2253241b1d3SJoe Thornber 2263241b1d3SJoe Thornber return s->count == 2 ? s->nodes[0] : NULL; 2273241b1d3SJoe Thornber } 2283241b1d3SJoe Thornber 2293241b1d3SJoe Thornber int shadow_has_parent(struct shadow_spine *s) 2303241b1d3SJoe Thornber { 2313241b1d3SJoe Thornber return s->count >= 2; 2323241b1d3SJoe Thornber } 2333241b1d3SJoe Thornber 2344c9e9883SJinoh Kang dm_block_t shadow_root(struct shadow_spine *s) 2353241b1d3SJoe Thornber { 2363241b1d3SJoe Thornber return s->root; 2373241b1d3SJoe Thornber } 238b0dc3c8bSJoe Thornber 239*be500ed7SJoe Thornber static void le64_inc(void *context, const void *value_le, unsigned count) 240b0dc3c8bSJoe Thornber { 241*be500ed7SJoe Thornber dm_tm_with_runs(context, value_le, count, dm_tm_inc_range); 242b0dc3c8bSJoe Thornber } 243b0dc3c8bSJoe Thornber 244*be500ed7SJoe Thornber static void le64_dec(void *context, const void *value_le, unsigned count) 245b0dc3c8bSJoe Thornber { 246*be500ed7SJoe Thornber dm_tm_with_runs(context, value_le, count, dm_tm_dec_range); 247b0dc3c8bSJoe Thornber } 248b0dc3c8bSJoe Thornber 249b0dc3c8bSJoe Thornber static int le64_equal(void *context, const void *value1_le, const void *value2_le) 250b0dc3c8bSJoe Thornber { 251b0dc3c8bSJoe Thornber __le64 v1_le, v2_le; 252b0dc3c8bSJoe Thornber 253b0dc3c8bSJoe Thornber memcpy(&v1_le, value1_le, sizeof(v1_le)); 254b0dc3c8bSJoe Thornber memcpy(&v2_le, value2_le, sizeof(v2_le)); 255b0dc3c8bSJoe Thornber return v1_le == v2_le; 256b0dc3c8bSJoe Thornber } 257b0dc3c8bSJoe Thornber 258b0dc3c8bSJoe Thornber void init_le64_type(struct dm_transaction_manager *tm, 259b0dc3c8bSJoe Thornber struct dm_btree_value_type *vt) 260b0dc3c8bSJoe Thornber { 261b0dc3c8bSJoe Thornber vt->context = tm; 262b0dc3c8bSJoe Thornber vt->size = sizeof(__le64); 263b0dc3c8bSJoe Thornber vt->inc = le64_inc; 264b0dc3c8bSJoe Thornber vt->dec = le64_dec; 265b0dc3c8bSJoe Thornber vt->equal = le64_equal; 266b0dc3c8bSJoe Thornber } 267