diff options
author | Joel Becker <joel.becker@oracle.com> | 2008-02-01 15:06:54 -0500 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2008-04-18 11:56:03 -0400 |
commit | 386a2ef8576e966076c293f6496b9e3d7e3d9035 (patch) | |
tree | 08b6cae47060497359a6ab78134a1bf8e38012cc /fs/ocfs2 | |
parent | fb86b1f07120b66769a39c445da5c4300069dd44 (diff) |
ocfs2: New slot map format
The old slot map had a few limitations:
- It was limited to one block, so the maximum slot count was 255.
- Each slot was signed 16bits, limiting node numbers to INT16_MAX.
- An empty slot was marked by the magic 0xFFFF (-1).
The new slot map format provides 32bit node numbers (UINT32_MAX), a
separate space to mark a slot in use, and extra room to grow. The slot
map is now bounded by i_size, not a block.
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/ocfs2.h | 7 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_fs.h | 31 | ||||
-rw-r--r-- | fs/ocfs2/slot_map.c | 110 |
3 files changed, 133 insertions, 15 deletions
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 95f783dbe8b2..f78e9ed53249 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -374,6 +374,13 @@ static inline int ocfs2_mount_local(struct ocfs2_super *osb) | |||
374 | return (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT); | 374 | return (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT); |
375 | } | 375 | } |
376 | 376 | ||
377 | static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb) | ||
378 | { | ||
379 | return (osb->s_feature_incompat & | ||
380 | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP); | ||
381 | } | ||
382 | |||
383 | |||
377 | #define OCFS2_IS_VALID_DINODE(ptr) \ | 384 | #define OCFS2_IS_VALID_DINODE(ptr) \ |
378 | (!strcmp((ptr)->i_signature, OCFS2_INODE_SIGNATURE)) | 385 | (!strcmp((ptr)->i_signature, OCFS2_INODE_SIGNATURE)) |
379 | 386 | ||
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index 3299116b8021..c49502329ab0 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h | |||
@@ -88,7 +88,8 @@ | |||
88 | #define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB | 88 | #define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB |
89 | #define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \ | 89 | #define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \ |
90 | | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \ | 90 | | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \ |
91 | | OCFS2_FEATURE_INCOMPAT_INLINE_DATA) | 91 | | OCFS2_FEATURE_INCOMPAT_INLINE_DATA \ |
92 | | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP) | ||
92 | #define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN | 93 | #define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN |
93 | 94 | ||
94 | /* | 95 | /* |
@@ -125,6 +126,10 @@ | |||
125 | /* Support for data packed into inode blocks */ | 126 | /* Support for data packed into inode blocks */ |
126 | #define OCFS2_FEATURE_INCOMPAT_INLINE_DATA 0x0040 | 127 | #define OCFS2_FEATURE_INCOMPAT_INLINE_DATA 0x0040 |
127 | 128 | ||
129 | /* Support for the extended slot map */ | ||
130 | #define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100 | ||
131 | |||
132 | |||
128 | /* | 133 | /* |
129 | * backup superblock flag is used to indicate that this volume | 134 | * backup superblock flag is used to indicate that this volume |
130 | * has backup superblocks. | 135 | * has backup superblocks. |
@@ -476,7 +481,8 @@ struct ocfs2_extent_block | |||
476 | 481 | ||
477 | /* | 482 | /* |
478 | * On disk slot map for OCFS2. This defines the contents of the "slot_map" | 483 | * On disk slot map for OCFS2. This defines the contents of the "slot_map" |
479 | * system file. | 484 | * system file. A slot is valid if it contains a node number >= 0. The |
485 | * value -1 (0xFFFF) is OCFS2_INVALID_SLOT. This marks a slot empty. | ||
480 | */ | 486 | */ |
481 | struct ocfs2_slot_map { | 487 | struct ocfs2_slot_map { |
482 | /*00*/ __le16 sm_slots[0]; | 488 | /*00*/ __le16 sm_slots[0]; |
@@ -486,6 +492,27 @@ struct ocfs2_slot_map { | |||
486 | */ | 492 | */ |
487 | }; | 493 | }; |
488 | 494 | ||
495 | struct ocfs2_extended_slot { | ||
496 | /*00*/ __u8 es_valid; | ||
497 | __u8 es_reserved1[3]; | ||
498 | __le32 es_node_num; | ||
499 | /*10*/ | ||
500 | }; | ||
501 | |||
502 | /* | ||
503 | * The extended slot map, used when OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP | ||
504 | * is set. It separates out the valid marker from the node number, and | ||
505 | * has room to grow. Unlike the old slot map, this format is defined by | ||
506 | * i_size. | ||
507 | */ | ||
508 | struct ocfs2_slot_map_extended { | ||
509 | /*00*/ struct ocfs2_extended_slot se_slots[0]; | ||
510 | /* | ||
511 | * Actual size is i_size of the slot_map system file. It should | ||
512 | * match s_max_slots * sizeof(struct ocfs2_extended_slot) | ||
513 | */ | ||
514 | }; | ||
515 | |||
489 | /* | 516 | /* |
490 | * On disk superblock for OCFS2 | 517 | * On disk superblock for OCFS2 |
491 | * Note that it is contained inside an ocfs2_dinode, so all offsets | 518 | * Note that it is contained inside an ocfs2_dinode, so all offsets |
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c index e7e7a74156b1..63fb1b26d964 100644 --- a/fs/ocfs2/slot_map.c +++ b/fs/ocfs2/slot_map.c | |||
@@ -49,6 +49,8 @@ struct ocfs2_slot { | |||
49 | }; | 49 | }; |
50 | 50 | ||
51 | struct ocfs2_slot_info { | 51 | struct ocfs2_slot_info { |
52 | int si_extended; | ||
53 | int si_slots_per_block; | ||
52 | struct inode *si_inode; | 54 | struct inode *si_inode; |
53 | unsigned int si_blocks; | 55 | unsigned int si_blocks; |
54 | struct buffer_head **si_bh; | 56 | struct buffer_head **si_bh; |
@@ -78,17 +80,37 @@ static void ocfs2_set_slot(struct ocfs2_slot_info *si, | |||
78 | si->si_slots[slot_num].sl_node_num = node_num; | 80 | si->si_slots[slot_num].sl_node_num = node_num; |
79 | } | 81 | } |
80 | 82 | ||
83 | /* This version is for the extended slot map */ | ||
84 | static void ocfs2_update_slot_info_extended(struct ocfs2_slot_info *si) | ||
85 | { | ||
86 | int b, i, slotno; | ||
87 | struct ocfs2_slot_map_extended *se; | ||
88 | |||
89 | slotno = 0; | ||
90 | for (b = 0; b < si->si_blocks; b++) { | ||
91 | se = (struct ocfs2_slot_map_extended *)si->si_bh[b]->b_data; | ||
92 | for (i = 0; | ||
93 | (i < si->si_slots_per_block) && | ||
94 | (slotno < si->si_num_slots); | ||
95 | i++, slotno++) { | ||
96 | if (se->se_slots[i].es_valid) | ||
97 | ocfs2_set_slot(si, slotno, | ||
98 | le32_to_cpu(se->se_slots[i].es_node_num)); | ||
99 | else | ||
100 | ocfs2_invalidate_slot(si, slotno); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
81 | /* | 105 | /* |
82 | * Post the slot information on disk into our slot_info struct. | 106 | * Post the slot information on disk into our slot_info struct. |
83 | * Must be protected by osb_lock. | 107 | * Must be protected by osb_lock. |
84 | */ | 108 | */ |
85 | static void ocfs2_update_slot_info(struct ocfs2_slot_info *si) | 109 | static void ocfs2_update_slot_info_old(struct ocfs2_slot_info *si) |
86 | { | 110 | { |
87 | int i; | 111 | int i; |
88 | struct ocfs2_slot_map *sm; | 112 | struct ocfs2_slot_map *sm; |
89 | 113 | ||
90 | /* we don't read the slot block here as ocfs2_super_lock | ||
91 | * should've made sure we have the most recent copy. */ | ||
92 | sm = (struct ocfs2_slot_map *)si->si_bh[0]->b_data; | 114 | sm = (struct ocfs2_slot_map *)si->si_bh[0]->b_data; |
93 | 115 | ||
94 | for (i = 0; i < si->si_num_slots; i++) { | 116 | for (i = 0; i < si->si_num_slots; i++) { |
@@ -99,6 +121,18 @@ static void ocfs2_update_slot_info(struct ocfs2_slot_info *si) | |||
99 | } | 121 | } |
100 | } | 122 | } |
101 | 123 | ||
124 | static void ocfs2_update_slot_info(struct ocfs2_slot_info *si) | ||
125 | { | ||
126 | /* | ||
127 | * The slot data will have been refreshed when ocfs2_super_lock | ||
128 | * was taken. | ||
129 | */ | ||
130 | if (si->si_extended) | ||
131 | ocfs2_update_slot_info_extended(si); | ||
132 | else | ||
133 | ocfs2_update_slot_info_old(si); | ||
134 | } | ||
135 | |||
102 | int ocfs2_refresh_slot_info(struct ocfs2_super *osb) | 136 | int ocfs2_refresh_slot_info(struct ocfs2_super *osb) |
103 | { | 137 | { |
104 | int ret; | 138 | int ret; |
@@ -131,13 +165,31 @@ int ocfs2_refresh_slot_info(struct ocfs2_super *osb) | |||
131 | 165 | ||
132 | /* post the our slot info stuff into it's destination bh and write it | 166 | /* post the our slot info stuff into it's destination bh and write it |
133 | * out. */ | 167 | * out. */ |
134 | static int ocfs2_update_disk_slots(struct ocfs2_super *osb, | 168 | static void ocfs2_update_disk_slot_extended(struct ocfs2_slot_info *si, |
135 | struct ocfs2_slot_info *si) | 169 | int slot_num, |
170 | struct buffer_head **bh) | ||
171 | { | ||
172 | int blkind = slot_num / si->si_slots_per_block; | ||
173 | int slotno = slot_num % si->si_slots_per_block; | ||
174 | struct ocfs2_slot_map_extended *se; | ||
175 | |||
176 | BUG_ON(blkind >= si->si_blocks); | ||
177 | |||
178 | se = (struct ocfs2_slot_map_extended *)si->si_bh[blkind]->b_data; | ||
179 | se->se_slots[slotno].es_valid = si->si_slots[slot_num].sl_valid; | ||
180 | if (si->si_slots[slot_num].sl_valid) | ||
181 | se->se_slots[slotno].es_node_num = | ||
182 | cpu_to_le32(si->si_slots[slot_num].sl_node_num); | ||
183 | *bh = si->si_bh[blkind]; | ||
184 | } | ||
185 | |||
186 | static void ocfs2_update_disk_slot_old(struct ocfs2_slot_info *si, | ||
187 | int slot_num, | ||
188 | struct buffer_head **bh) | ||
136 | { | 189 | { |
137 | int status, i; | 190 | int i; |
138 | struct ocfs2_slot_map *sm; | 191 | struct ocfs2_slot_map *sm; |
139 | 192 | ||
140 | spin_lock(&osb->osb_lock); | ||
141 | sm = (struct ocfs2_slot_map *)si->si_bh[0]->b_data; | 193 | sm = (struct ocfs2_slot_map *)si->si_bh[0]->b_data; |
142 | for (i = 0; i < si->si_num_slots; i++) { | 194 | for (i = 0; i < si->si_num_slots; i++) { |
143 | if (si->si_slots[i].sl_valid) | 195 | if (si->si_slots[i].sl_valid) |
@@ -146,9 +198,24 @@ static int ocfs2_update_disk_slots(struct ocfs2_super *osb, | |||
146 | else | 198 | else |
147 | sm->sm_slots[i] = cpu_to_le16(OCFS2_INVALID_SLOT); | 199 | sm->sm_slots[i] = cpu_to_le16(OCFS2_INVALID_SLOT); |
148 | } | 200 | } |
201 | *bh = si->si_bh[0]; | ||
202 | } | ||
203 | |||
204 | static int ocfs2_update_disk_slot(struct ocfs2_super *osb, | ||
205 | struct ocfs2_slot_info *si, | ||
206 | int slot_num) | ||
207 | { | ||
208 | int status; | ||
209 | struct buffer_head *bh; | ||
210 | |||
211 | spin_lock(&osb->osb_lock); | ||
212 | if (si->si_extended) | ||
213 | ocfs2_update_disk_slot_extended(si, slot_num, &bh); | ||
214 | else | ||
215 | ocfs2_update_disk_slot_old(si, slot_num, &bh); | ||
149 | spin_unlock(&osb->osb_lock); | 216 | spin_unlock(&osb->osb_lock); |
150 | 217 | ||
151 | status = ocfs2_write_block(osb, si->si_bh[0], si->si_inode); | 218 | status = ocfs2_write_block(osb, bh, si->si_inode); |
152 | if (status < 0) | 219 | if (status < 0) |
153 | mlog_errno(status); | 220 | mlog_errno(status); |
154 | 221 | ||
@@ -165,7 +232,12 @@ static int ocfs2_slot_map_physical_size(struct ocfs2_super *osb, | |||
165 | { | 232 | { |
166 | unsigned long long bytes_needed; | 233 | unsigned long long bytes_needed; |
167 | 234 | ||
168 | bytes_needed = osb->max_slots * sizeof(__le16); | 235 | if (ocfs2_uses_extended_slot_map(osb)) { |
236 | bytes_needed = osb->max_slots * | ||
237 | sizeof(struct ocfs2_extended_slot); | ||
238 | } else { | ||
239 | bytes_needed = osb->max_slots * sizeof(__le16); | ||
240 | } | ||
169 | if (bytes_needed > i_size_read(inode)) { | 241 | if (bytes_needed > i_size_read(inode)) { |
170 | mlog(ML_ERROR, | 242 | mlog(ML_ERROR, |
171 | "Slot map file is too small! (size %llu, needed %llu)\n", | 243 | "Slot map file is too small! (size %llu, needed %llu)\n", |
@@ -279,7 +351,7 @@ int ocfs2_clear_slot(struct ocfs2_super *osb, int slot_num) | |||
279 | ocfs2_invalidate_slot(si, slot_num); | 351 | ocfs2_invalidate_slot(si, slot_num); |
280 | spin_unlock(&osb->osb_lock); | 352 | spin_unlock(&osb->osb_lock); |
281 | 353 | ||
282 | return ocfs2_update_disk_slots(osb, osb->slot_info); | 354 | return ocfs2_update_disk_slot(osb, osb->slot_info, slot_num); |
283 | } | 355 | } |
284 | 356 | ||
285 | static int ocfs2_map_slot_buffers(struct ocfs2_super *osb, | 357 | static int ocfs2_map_slot_buffers(struct ocfs2_super *osb, |
@@ -301,6 +373,16 @@ static int ocfs2_map_slot_buffers(struct ocfs2_super *osb, | |||
301 | if (!si->si_blocks) | 373 | if (!si->si_blocks) |
302 | goto bail; | 374 | goto bail; |
303 | 375 | ||
376 | if (si->si_extended) | ||
377 | si->si_slots_per_block = | ||
378 | (osb->sb->s_blocksize / | ||
379 | sizeof(struct ocfs2_extended_slot)); | ||
380 | else | ||
381 | si->si_slots_per_block = osb->sb->s_blocksize / sizeof(__le16); | ||
382 | |||
383 | /* The size checks above should ensure this */ | ||
384 | BUG_ON((osb->max_slots / si->si_slots_per_block) > blocks); | ||
385 | |||
304 | mlog(0, "Slot map needs %u buffers for %llu bytes\n", | 386 | mlog(0, "Slot map needs %u buffers for %llu bytes\n", |
305 | si->si_blocks, bytes); | 387 | si->si_blocks, bytes); |
306 | 388 | ||
@@ -352,6 +434,7 @@ int ocfs2_init_slot_info(struct ocfs2_super *osb) | |||
352 | goto bail; | 434 | goto bail; |
353 | } | 435 | } |
354 | 436 | ||
437 | si->si_extended = ocfs2_uses_extended_slot_map(osb); | ||
355 | si->si_num_slots = osb->max_slots; | 438 | si->si_num_slots = osb->max_slots; |
356 | si->si_slots = (struct ocfs2_slot *)((char *)si + | 439 | si->si_slots = (struct ocfs2_slot *)((char *)si + |
357 | sizeof(struct ocfs2_slot_info)); | 440 | sizeof(struct ocfs2_slot_info)); |
@@ -425,7 +508,7 @@ int ocfs2_find_slot(struct ocfs2_super *osb) | |||
425 | 508 | ||
426 | mlog(0, "taking node slot %d\n", osb->slot_num); | 509 | mlog(0, "taking node slot %d\n", osb->slot_num); |
427 | 510 | ||
428 | status = ocfs2_update_disk_slots(osb, si); | 511 | status = ocfs2_update_disk_slot(osb, si, osb->slot_num); |
429 | if (status < 0) | 512 | if (status < 0) |
430 | mlog_errno(status); | 513 | mlog_errno(status); |
431 | 514 | ||
@@ -436,7 +519,7 @@ bail: | |||
436 | 519 | ||
437 | void ocfs2_put_slot(struct ocfs2_super *osb) | 520 | void ocfs2_put_slot(struct ocfs2_super *osb) |
438 | { | 521 | { |
439 | int status; | 522 | int status, slot_num; |
440 | struct ocfs2_slot_info *si = osb->slot_info; | 523 | struct ocfs2_slot_info *si = osb->slot_info; |
441 | 524 | ||
442 | if (!si) | 525 | if (!si) |
@@ -445,11 +528,12 @@ void ocfs2_put_slot(struct ocfs2_super *osb) | |||
445 | spin_lock(&osb->osb_lock); | 528 | spin_lock(&osb->osb_lock); |
446 | ocfs2_update_slot_info(si); | 529 | ocfs2_update_slot_info(si); |
447 | 530 | ||
531 | slot_num = osb->slot_num; | ||
448 | ocfs2_invalidate_slot(si, osb->slot_num); | 532 | ocfs2_invalidate_slot(si, osb->slot_num); |
449 | osb->slot_num = OCFS2_INVALID_SLOT; | 533 | osb->slot_num = OCFS2_INVALID_SLOT; |
450 | spin_unlock(&osb->osb_lock); | 534 | spin_unlock(&osb->osb_lock); |
451 | 535 | ||
452 | status = ocfs2_update_disk_slots(osb, si); | 536 | status = ocfs2_update_disk_slot(osb, si, slot_num); |
453 | if (status < 0) { | 537 | if (status < 0) { |
454 | mlog_errno(status); | 538 | mlog_errno(status); |
455 | goto bail; | 539 | goto bail; |