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

dm space map disk: cache a small number of index entries

The disk space map stores it's index entries in a btree, these are
accessed very frequently, so having a few cached makes a big difference
to performance.

With this change provisioning a new block takes roughly 20% less cpu.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>

authored by

Joe Thornber and committed by
Mike Snitzer
6b06dd5a be500ed7

+96 -6
+80 -6
drivers/md/persistent-data/dm-space-map-common.c
··· 7 7 #include "dm-space-map-common.h" 8 8 #include "dm-transaction-manager.h" 9 9 #include "dm-btree-internal.h" 10 + #include "dm-persistent-data-internal.h" 10 11 11 12 #include <linux/bitops.h> 12 13 #include <linux/device-mapper.h> ··· 1084 1083 1085 1084 /*----------------------------------------------------------------*/ 1086 1085 1086 + static inline int ie_cache_writeback(struct ll_disk *ll, struct ie_cache *iec) 1087 + { 1088 + iec->dirty = false; 1089 + __dm_bless_for_disk(iec->ie); 1090 + return dm_btree_insert(&ll->bitmap_info, ll->bitmap_root, 1091 + &iec->index, &iec->ie, &ll->bitmap_root); 1092 + } 1093 + 1094 + static inline unsigned hash_index(dm_block_t index) 1095 + { 1096 + return dm_hash_block(index, IE_CACHE_MASK); 1097 + } 1098 + 1087 1099 static int disk_ll_load_ie(struct ll_disk *ll, dm_block_t index, 1088 1100 struct disk_index_entry *ie) 1089 1101 { 1090 - return dm_btree_lookup(&ll->bitmap_info, ll->bitmap_root, &index, ie); 1102 + int r; 1103 + unsigned h = hash_index(index); 1104 + struct ie_cache *iec = ll->ie_cache + h; 1105 + 1106 + if (iec->valid) { 1107 + if (iec->index == index) { 1108 + memcpy(ie, &iec->ie, sizeof(*ie)); 1109 + return 0; 1110 + } 1111 + 1112 + if (iec->dirty) { 1113 + r = ie_cache_writeback(ll, iec); 1114 + if (r) 1115 + return r; 1116 + } 1117 + } 1118 + 1119 + r = dm_btree_lookup(&ll->bitmap_info, ll->bitmap_root, &index, ie); 1120 + if (!r) { 1121 + iec->valid = true; 1122 + iec->dirty = false; 1123 + iec->index = index; 1124 + memcpy(&iec->ie, ie, sizeof(*ie)); 1125 + } 1126 + 1127 + return r; 1091 1128 } 1092 1129 1093 1130 static int disk_ll_save_ie(struct ll_disk *ll, dm_block_t index, 1094 1131 struct disk_index_entry *ie) 1095 1132 { 1096 - __dm_bless_for_disk(ie); 1097 - return dm_btree_insert(&ll->bitmap_info, ll->bitmap_root, 1098 - &index, ie, &ll->bitmap_root); 1133 + int r; 1134 + unsigned h = hash_index(index); 1135 + struct ie_cache *iec = ll->ie_cache + h; 1136 + 1137 + ll->bitmap_index_changed = true; 1138 + if (iec->valid) { 1139 + if (iec->index == index) { 1140 + memcpy(&iec->ie, ie, sizeof(*ie)); 1141 + iec->dirty = true; 1142 + return 0; 1143 + } 1144 + 1145 + if (iec->dirty) { 1146 + r = ie_cache_writeback(ll, iec); 1147 + if (r) 1148 + return r; 1149 + } 1150 + } 1151 + 1152 + iec->valid = true; 1153 + iec->dirty = true; 1154 + iec->index = index; 1155 + memcpy(&iec->ie, ie, sizeof(*ie)); 1156 + return 0; 1099 1157 } 1100 1158 1101 1159 static int disk_ll_init_index(struct ll_disk *ll) 1102 1160 { 1161 + unsigned i; 1162 + for (i = 0; i < IE_CACHE_SIZE; i++) { 1163 + struct ie_cache *iec = ll->ie_cache + i; 1164 + iec->valid = false; 1165 + iec->dirty = false; 1166 + } 1103 1167 return dm_btree_empty(&ll->bitmap_info, &ll->bitmap_root); 1104 1168 } 1105 1169 1106 1170 static int disk_ll_open(struct ll_disk *ll) 1107 1171 { 1108 - /* nothing to do */ 1109 1172 return 0; 1110 1173 } 1111 1174 ··· 1180 1115 1181 1116 static int disk_ll_commit(struct ll_disk *ll) 1182 1117 { 1183 - return 0; 1118 + int r = 0; 1119 + unsigned i; 1120 + 1121 + for (i = 0; i < IE_CACHE_SIZE; i++) { 1122 + struct ie_cache *iec = ll->ie_cache + i; 1123 + if (iec->valid && iec->dirty) 1124 + r = ie_cache_writeback(ll, iec); 1125 + } 1126 + 1127 + return r; 1184 1128 } 1185 1129 1186 1130 int sm_ll_new_disk(struct ll_disk *ll, struct dm_transaction_manager *tm)
+16
drivers/md/persistent-data/dm-space-map-common.h
··· 54 54 typedef dm_block_t (*max_index_entries_fn)(struct ll_disk *ll); 55 55 typedef int (*commit_fn)(struct ll_disk *ll); 56 56 57 + /* 58 + * A lot of time can be wasted reading and writing the same 59 + * index entry. So we cache a few entries. 60 + */ 61 + #define IE_CACHE_SIZE 64 62 + #define IE_CACHE_MASK (IE_CACHE_SIZE - 1) 63 + 64 + struct ie_cache { 65 + bool valid; 66 + bool dirty; 67 + dm_block_t index; 68 + struct disk_index_entry ie; 69 + }; 70 + 57 71 struct ll_disk { 58 72 struct dm_transaction_manager *tm; 59 73 struct dm_btree_info bitmap_info; ··· 93 79 max_index_entries_fn max_entries; 94 80 commit_fn commit; 95 81 bool bitmap_index_changed:1; 82 + 83 + struct ie_cache ie_cache[IE_CACHE_SIZE]; 96 84 }; 97 85 98 86 struct disk_sm_root {