HAMMER - Implement experimental volume removal
[dragonfly.git] / sys / vfs / hammer / hammer_blockmap.c
CommitLineData
40043e7f
MD
1/*
2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
e469566b 34 * $DragonFly: src/sys/vfs/hammer/hammer_blockmap.c,v 1.27 2008/07/31 22:30:33 dillon Exp $
40043e7f
MD
35 */
36
37/*
38 * HAMMER blockmap
39 */
40#include "hammer.h"
41
0832c9bb 42static int hammer_res_rb_compare(hammer_reserve_t res1, hammer_reserve_t res2);
362ec2dc 43static void hammer_reserve_setdelay_offset(hammer_mount_t hmp,
1ce12d35 44 hammer_off_t base_offset, int zone,
5e435c92 45 struct hammer_blockmap_layer2 *layer2);
362ec2dc 46static void hammer_reserve_setdelay(hammer_mount_t hmp, hammer_reserve_t resv);
0832c9bb
MD
47
48/*
49 * Reserved big-blocks red-black tree support
50 */
51RB_GENERATE2(hammer_res_rb_tree, hammer_reserve, rb_node,
52 hammer_res_rb_compare, hammer_off_t, zone_offset);
53
54static int
55hammer_res_rb_compare(hammer_reserve_t res1, hammer_reserve_t res2)
56{
57 if (res1->zone_offset < res2->zone_offset)
58 return(-1);
59 if (res1->zone_offset > res2->zone_offset)
60 return(1);
61 return(0);
62}
bf686dbe 63
40043e7f
MD
64/*
65 * Allocate bytes from a zone
66 */
67hammer_off_t
df2ccbac
MD
68hammer_blockmap_alloc(hammer_transaction_t trans, int zone, int bytes,
69 hammer_off_t hint, int *errorp)
40043e7f 70{
0832c9bb 71 hammer_mount_t hmp;
40043e7f 72 hammer_volume_t root_volume;
cb51be26
MD
73 hammer_blockmap_t blockmap;
74 hammer_blockmap_t freemap;
0832c9bb 75 hammer_reserve_t resv;
c3be93f2
MD
76 struct hammer_blockmap_layer1 *layer1;
77 struct hammer_blockmap_layer2 *layer2;
f03c9cf4
MD
78 hammer_buffer_t buffer1 = NULL;
79 hammer_buffer_t buffer2 = NULL;
80 hammer_buffer_t buffer3 = NULL;
c3be93f2 81 hammer_off_t tmp_offset;
f03c9cf4 82 hammer_off_t next_offset;
0832c9bb 83 hammer_off_t result_offset;
c3be93f2
MD
84 hammer_off_t layer1_offset;
85 hammer_off_t layer2_offset;
cb51be26 86 hammer_off_t base_off;
f03c9cf4 87 int loops = 0;
df301614 88 int offset; /* offset within big-block */
df2ccbac 89 int use_hint;
40043e7f 90
0832c9bb 91 hmp = trans->hmp;
40043e7f
MD
92
93 /*
94 * Deal with alignment and buffer-boundary issues.
95 *
96 * Be careful, certain primary alignments are used below to allocate
97 * new blockmap blocks.
98 */
0832c9bb 99 bytes = (bytes + 15) & ~15;
4a2796f3 100 KKASSERT(bytes > 0 && bytes <= HAMMER_XBUFSIZE);
0832c9bb 101 KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
bf686dbe
MD
102
103 /*
cb51be26 104 * Setup
bf686dbe 105 */
cb51be26
MD
106 root_volume = trans->rootvol;
107 *errorp = 0;
108 blockmap = &hmp->blockmap[zone];
109 freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
110 KKASSERT(HAMMER_ZONE_DECODE(blockmap->next_offset) == zone);
111
df2ccbac
MD
112 /*
113 * Use the hint if we have one.
114 */
115 if (hint && HAMMER_ZONE_DECODE(hint) == zone) {
116 next_offset = (hint + 15) & ~(hammer_off_t)15;
117 use_hint = 1;
118 } else {
119 next_offset = blockmap->next_offset;
120 use_hint = 0;
121 }
cb51be26 122again:
df2ccbac
MD
123
124 /*
125 * use_hint is turned off if we leave the hinted big-block.
126 */
127 if (use_hint && ((next_offset ^ hint) & ~HAMMER_HINTBLOCK_MASK64)) {
128 next_offset = blockmap->next_offset;
129 use_hint = 0;
130 }
131
0832c9bb 132 /*
cb51be26 133 * Check for wrap
0832c9bb 134 */
4a2796f3 135 if (next_offset == HAMMER_ZONE_ENCODE(zone + 1, 0)) {
cb51be26
MD
136 if (++loops == 2) {
137 result_offset = 0;
138 *errorp = ENOSPC;
df301614 139 goto failed;
cb51be26
MD
140 }
141 next_offset = HAMMER_ZONE_ENCODE(zone, 0);
142 }
0832c9bb 143
f03c9cf4 144 /*
4a2796f3
MD
145 * The allocation request may not cross a buffer boundary. Special
146 * large allocations must not cross a large-block boundary.
f03c9cf4 147 */
bf686dbe 148 tmp_offset = next_offset + bytes - 1;
4a2796f3
MD
149 if (bytes <= HAMMER_BUFSIZE) {
150 if ((next_offset ^ tmp_offset) & ~HAMMER_BUFMASK64) {
151 next_offset = tmp_offset & ~HAMMER_BUFMASK64;
152 goto again;
153 }
154 } else {
155 if ((next_offset ^ tmp_offset) & ~HAMMER_LARGEBLOCK_MASK64) {
156 next_offset = tmp_offset & ~HAMMER_LARGEBLOCK_MASK64;
157 goto again;
158 }
bf686dbe 159 }
df301614 160 offset = (int)next_offset & HAMMER_LARGEBLOCK_MASK;
40043e7f
MD
161
162 /*
cb51be26 163 * Dive layer 1.
40043e7f 164 */
cb51be26 165 layer1_offset = freemap->phys_offset +
f03c9cf4 166 HAMMER_BLOCKMAP_LAYER1_OFFSET(next_offset);
865c9609
MN
167
168 /*
169 * Skip this block if it is belonging to a volume that we are
170 * currently trying to remove from the file-system.
171 */
172 if ((int)HAMMER_VOL_DECODE(layer1_offset) == hmp->volume_to_remove) {
173 next_offset = (next_offset + HAMMER_BLOCKMAP_LAYER2) &
174 ~HAMMER_BLOCKMAP_LAYER2_MASK;
175 goto again;
176 }
177
0832c9bb 178 layer1 = hammer_bread(hmp, layer1_offset, errorp, &buffer1);
cdb6e4e6
MD
179 if (*errorp) {
180 result_offset = 0;
181 goto failed;
182 }
19619882
MD
183
184 /*
cb51be26 185 * Check CRC.
c3be93f2 186 */
cb51be26 187 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
db9f9d7f
MD
188 hammer_lock_ex(&hmp->blkmap_lock);
189 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
190 panic("CRC FAILED: LAYER1");
191 hammer_unlock(&hmp->blkmap_lock);
40043e7f 192 }
40043e7f
MD
193
194 /*
cb51be26
MD
195 * If we are at a big-block boundary and layer1 indicates no
196 * free big-blocks, then we cannot allocate a new bigblock in
197 * layer2, skip to the next layer1 entry.
40043e7f 198 */
df301614 199 if (offset == 0 && layer1->blocks_free == 0) {
cb51be26 200 next_offset = (next_offset + HAMMER_BLOCKMAP_LAYER2) &
f03c9cf4 201 ~HAMMER_BLOCKMAP_LAYER2_MASK;
f03c9cf4
MD
202 goto again;
203 }
cb51be26 204 KKASSERT(layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
40043e7f 205
c3be93f2 206 /*
f03c9cf4 207 * Dive layer 2, each entry represents a large-block.
c3be93f2 208 */
f03c9cf4
MD
209 layer2_offset = layer1->phys_offset +
210 HAMMER_BLOCKMAP_LAYER2_OFFSET(next_offset);
0832c9bb 211 layer2 = hammer_bread(hmp, layer2_offset, errorp, &buffer2);
cdb6e4e6
MD
212 if (*errorp) {
213 result_offset = 0;
214 goto failed;
215 }
f03c9cf4 216
19619882 217 /*
db9f9d7f
MD
218 * Check CRC. This can race another thread holding the lock
219 * and in the middle of modifying layer2.
19619882 220 */
cb51be26 221 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
db9f9d7f
MD
222 hammer_lock_ex(&hmp->blkmap_lock);
223 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
224 panic("CRC FAILED: LAYER2");
225 hammer_unlock(&hmp->blkmap_lock);
19619882
MD
226 }
227
cb51be26 228 /*
df301614 229 * Skip the layer if the zone is owned by someone other then us.
cb51be26 230 */
df301614
MD
231 if (layer2->zone && layer2->zone != zone) {
232 next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
233 goto again;
234 }
235 if (offset < layer2->append_off) {
236 next_offset += layer2->append_off - offset;
4a2796f3
MD
237 goto again;
238 }
239
240 /*
df2ccbac
MD
241 * If operating in the current non-hint blockmap block, do not
242 * allow it to get over-full. Also drop any active hinting so
243 * blockmap->next_offset is updated at the end.
244 *
245 * We do this for B-Tree and meta-data allocations to provide
246 * localization for updates.
247 */
248 if ((zone == HAMMER_ZONE_BTREE_INDEX ||
249 zone == HAMMER_ZONE_META_INDEX) &&
250 offset >= HAMMER_LARGEBLOCK_OVERFILL &&
251 !((next_offset ^ blockmap->next_offset) & ~HAMMER_LARGEBLOCK_MASK64)
252 ) {
253 if (offset >= HAMMER_LARGEBLOCK_OVERFILL) {
254 next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
255 use_hint = 0;
256 goto again;
257 }
258 }
259
260 /*
df301614
MD
261 * We need the lock from this point on. We have to re-check zone
262 * ownership after acquiring the lock and also check for reservations.
263 */
264 hammer_lock_ex(&hmp->blkmap_lock);
265
266 if (layer2->zone && layer2->zone != zone) {
267 hammer_unlock(&hmp->blkmap_lock);
268 next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
269 goto again;
270 }
271 if (offset < layer2->append_off) {
272 hammer_unlock(&hmp->blkmap_lock);
273 next_offset += layer2->append_off - offset;
274 goto again;
275 }
276
277 /*
278 * The bigblock might be reserved by another zone. If it is reserved
279 * by our zone we may have to move next_offset past the append_off.
4a2796f3
MD
280 */
281 base_off = (next_offset &
282 (~HAMMER_LARGEBLOCK_MASK64 & ~HAMMER_OFF_ZONE_MASK)) |
283 HAMMER_ZONE_RAW_BUFFER;
284 resv = RB_LOOKUP(hammer_res_rb_tree, &hmp->rb_resv_root, base_off);
285 if (resv) {
4a2796f3 286 if (resv->zone != zone) {
df301614 287 hammer_unlock(&hmp->blkmap_lock);
cb51be26
MD
288 next_offset = (next_offset + HAMMER_LARGEBLOCK_SIZE) &
289 ~HAMMER_LARGEBLOCK_MASK64;
f03c9cf4
MD
290 goto again;
291 }
df301614
MD
292 if (offset < resv->append_off) {
293 hammer_unlock(&hmp->blkmap_lock);
294 next_offset += resv->append_off - offset;
295 goto again;
296 }
1ce12d35 297 ++resv->refs;
cb51be26
MD
298 }
299
4a2796f3
MD
300 /*
301 * Ok, we can allocate out of this layer2 big-block. Assume ownership
302 * of the layer for real. At this point we've validated any
303 * reservation that might exist and can just ignore resv.
304 */
cb51be26 305 if (layer2->zone == 0) {
f03c9cf4 306 /*
cb51be26 307 * Assign the bigblock to our zone
f03c9cf4 308 */
cb51be26
MD
309 hammer_modify_buffer(trans, buffer1,
310 layer1, sizeof(*layer1));
311 --layer1->blocks_free;
312 layer1->layer1_crc = crc32(layer1,
313 HAMMER_LAYER1_CRCSIZE);
314 hammer_modify_buffer_done(buffer1);
315 hammer_modify_buffer(trans, buffer2,
316 layer2, sizeof(*layer2));
317 layer2->zone = zone;
318 KKASSERT(layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE);
319 KKASSERT(layer2->append_off == 0);
320 hammer_modify_volume_field(trans, trans->rootvol,
321 vol0_stat_freebigblocks);
322 --root_volume->ondisk->vol0_stat_freebigblocks;
323 hmp->copy_stat_freebigblocks =
324 root_volume->ondisk->vol0_stat_freebigblocks;
325 hammer_modify_volume_done(trans->rootvol);
cb51be26
MD
326 } else {
327 hammer_modify_buffer(trans, buffer2,
328 layer2, sizeof(*layer2));
40043e7f 329 }
cb51be26 330 KKASSERT(layer2->zone == zone);
40043e7f 331
c3be93f2 332 layer2->bytes_free -= bytes;
df301614
MD
333 KKASSERT(layer2->append_off <= offset);
334 layer2->append_off = offset + bytes;
19619882 335 layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE);
10a5d1ba 336 hammer_modify_buffer_done(buffer2);
eb3f8f1f 337 KKASSERT(layer2->bytes_free >= 0);
40043e7f 338
1ce12d35
MD
339 /*
340 * We hold the blockmap lock and should be the only ones
341 * capable of modifying resv->append_off. Track the allocation
342 * as appropriate.
343 */
344 KKASSERT(bytes != 0);
df301614
MD
345 if (resv) {
346 KKASSERT(resv->append_off <= offset);
347 resv->append_off = offset + bytes;
5e435c92 348 resv->flags &= ~HAMMER_RESF_LAYER2FREE;
1ce12d35 349 hammer_blockmap_reserve_complete(hmp, resv);
df301614
MD
350 }
351
40043e7f 352 /*
0832c9bb
MD
353 * If we are allocating from the base of a new buffer we can avoid
354 * a disk read by calling hammer_bnew().
40043e7f 355 */
f03c9cf4 356 if ((next_offset & HAMMER_BUFMASK) == 0) {
4a2796f3
MD
357 hammer_bnew_ext(trans->hmp, next_offset, bytes,
358 errorp, &buffer3);
40043e7f 359 }
0832c9bb 360 result_offset = next_offset;
40043e7f 361
c3be93f2 362 /*
df2ccbac
MD
363 * If we weren't supplied with a hint or could not use the hint
364 * then we wound up using blockmap->next_offset as the hint and
365 * need to save it.
c3be93f2 366 */
df2ccbac
MD
367 if (use_hint == 0) {
368 hammer_modify_volume(NULL, root_volume, NULL, 0);
369 blockmap->next_offset = next_offset + bytes;
370 hammer_modify_volume_done(root_volume);
371 }
d99d6bf5 372 hammer_unlock(&hmp->blkmap_lock);
df301614 373failed:
0832c9bb
MD
374
375 /*
376 * Cleanup
377 */
f03c9cf4
MD
378 if (buffer1)
379 hammer_rel_buffer(buffer1, 0);
380 if (buffer2)
381 hammer_rel_buffer(buffer2, 0);
382 if (buffer3)
383 hammer_rel_buffer(buffer3, 0);
0832c9bb
MD
384
385 return(result_offset);
40043e7f
MD
386}
387
388/*
4a2796f3 389 * Frontend function - Reserve bytes in a zone.
47637bff
MD
390 *
391 * This code reserves bytes out of a blockmap without committing to any
cb51be26
MD
392 * meta-data modifications, allowing the front-end to directly issue disk
393 * write I/O for large blocks of data
4a2796f3
MD
394 *
395 * The backend later finalizes the reservation with hammer_blockmap_finalize()
396 * upon committing the related record.
47637bff 397 */
0832c9bb
MD
398hammer_reserve_t
399hammer_blockmap_reserve(hammer_mount_t hmp, int zone, int bytes,
400 hammer_off_t *zone_offp, int *errorp)
47637bff
MD
401{
402 hammer_volume_t root_volume;
cb51be26
MD
403 hammer_blockmap_t blockmap;
404 hammer_blockmap_t freemap;
47637bff
MD
405 struct hammer_blockmap_layer1 *layer1;
406 struct hammer_blockmap_layer2 *layer2;
407 hammer_buffer_t buffer1 = NULL;
408 hammer_buffer_t buffer2 = NULL;
409 hammer_buffer_t buffer3 = NULL;
410 hammer_off_t tmp_offset;
411 hammer_off_t next_offset;
412 hammer_off_t layer1_offset;
413 hammer_off_t layer2_offset;
cb51be26 414 hammer_off_t base_off;
0832c9bb 415 hammer_reserve_t resv;
cb51be26 416 hammer_reserve_t resx;
47637bff 417 int loops = 0;
df301614 418 int offset;
47637bff 419
0832c9bb
MD
420 /*
421 * Setup
422 */
47637bff
MD
423 KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
424 root_volume = hammer_get_root_volume(hmp, errorp);
425 if (*errorp)
0832c9bb 426 return(NULL);
cb51be26
MD
427 blockmap = &hmp->blockmap[zone];
428 freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
429 KKASSERT(HAMMER_ZONE_DECODE(blockmap->next_offset) == zone);
47637bff
MD
430
431 /*
432 * Deal with alignment and buffer-boundary issues.
433 *
434 * Be careful, certain primary alignments are used below to allocate
435 * new blockmap blocks.
436 */
0832c9bb 437 bytes = (bytes + 15) & ~15;
4a2796f3 438 KKASSERT(bytes > 0 && bytes <= HAMMER_XBUFSIZE);
47637bff 439
cb51be26 440 next_offset = blockmap->next_offset;
df301614 441again:
fce862c7 442 resv = NULL;
47637bff 443 /*
cb51be26 444 * Check for wrap
47637bff 445 */
4a2796f3 446 if (next_offset == HAMMER_ZONE_ENCODE(zone + 1, 0)) {
cb51be26 447 if (++loops == 2) {
47637bff 448 *errorp = ENOSPC;
df301614 449 goto failed;
47637bff
MD
450 }
451 next_offset = HAMMER_ZONE_ENCODE(zone, 0);
452 }
453
454 /*
4a2796f3
MD
455 * The allocation request may not cross a buffer boundary. Special
456 * large allocations must not cross a large-block boundary.
47637bff
MD
457 */
458 tmp_offset = next_offset + bytes - 1;
4a2796f3
MD
459 if (bytes <= HAMMER_BUFSIZE) {
460 if ((next_offset ^ tmp_offset) & ~HAMMER_BUFMASK64) {
461 next_offset = tmp_offset & ~HAMMER_BUFMASK64;
462 goto again;
463 }
464 } else {
465 if ((next_offset ^ tmp_offset) & ~HAMMER_LARGEBLOCK_MASK64) {
466 next_offset = tmp_offset & ~HAMMER_LARGEBLOCK_MASK64;
467 goto again;
468 }
47637bff 469 }
df301614 470 offset = (int)next_offset & HAMMER_LARGEBLOCK_MASK;
47637bff
MD
471
472 /*
473 * Dive layer 1.
474 */
cb51be26 475 layer1_offset = freemap->phys_offset +
47637bff
MD
476 HAMMER_BLOCKMAP_LAYER1_OFFSET(next_offset);
477 layer1 = hammer_bread(hmp, layer1_offset, errorp, &buffer1);
cdb6e4e6
MD
478 if (*errorp)
479 goto failed;
47637bff
MD
480
481 /*
cb51be26 482 * Check CRC.
47637bff
MD
483 */
484 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
db9f9d7f
MD
485 hammer_lock_ex(&hmp->blkmap_lock);
486 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
487 panic("CRC FAILED: LAYER1");
488 hammer_unlock(&hmp->blkmap_lock);
47637bff 489 }
47637bff
MD
490
491 /*
cb51be26
MD
492 * If we are at a big-block boundary and layer1 indicates no
493 * free big-blocks, then we cannot allocate a new bigblock in
494 * layer2, skip to the next layer1 entry.
47637bff 495 */
cb51be26
MD
496 if ((next_offset & HAMMER_LARGEBLOCK_MASK) == 0 &&
497 layer1->blocks_free == 0) {
498 next_offset = (next_offset + HAMMER_BLOCKMAP_LAYER2) &
47637bff
MD
499 ~HAMMER_BLOCKMAP_LAYER2_MASK;
500 goto again;
501 }
cb51be26 502 KKASSERT(layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
47637bff
MD
503
504 /*
505 * Dive layer 2, each entry represents a large-block.
506 */
507 layer2_offset = layer1->phys_offset +
508 HAMMER_BLOCKMAP_LAYER2_OFFSET(next_offset);
509 layer2 = hammer_bread(hmp, layer2_offset, errorp, &buffer2);
cdb6e4e6
MD
510 if (*errorp)
511 goto failed;
47637bff
MD
512
513 /*
0832c9bb
MD
514 * Check CRC if not allocating into uninitialized space (which we
515 * aren't when reserving space).
47637bff
MD
516 */
517 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
db9f9d7f
MD
518 hammer_lock_ex(&hmp->blkmap_lock);
519 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
520 panic("CRC FAILED: LAYER2");
521 hammer_unlock(&hmp->blkmap_lock);
47637bff
MD
522 }
523
0832c9bb 524 /*
df301614 525 * Skip the layer if the zone is owned by someone other then us.
0832c9bb 526 */
df301614
MD
527 if (layer2->zone && layer2->zone != zone) {
528 next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
529 goto again;
530 }
531 if (offset < layer2->append_off) {
532 next_offset += layer2->append_off - offset;
4a2796f3
MD
533 goto again;
534 }
535
536 /*
df301614
MD
537 * We need the lock from this point on. We have to re-check zone
538 * ownership after acquiring the lock and also check for reservations.
539 */
540 hammer_lock_ex(&hmp->blkmap_lock);
541
542 if (layer2->zone && layer2->zone != zone) {
543 hammer_unlock(&hmp->blkmap_lock);
544 next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
545 goto again;
546 }
547 if (offset < layer2->append_off) {
548 hammer_unlock(&hmp->blkmap_lock);
549 next_offset += layer2->append_off - offset;
550 goto again;
551 }
552
553 /*
554 * The bigblock might be reserved by another zone. If it is reserved
555 * by our zone we may have to move next_offset past the append_off.
4a2796f3
MD
556 */
557 base_off = (next_offset &
df301614 558 (~HAMMER_LARGEBLOCK_MASK64 & ~HAMMER_OFF_ZONE_MASK)) |
4a2796f3
MD
559 HAMMER_ZONE_RAW_BUFFER;
560 resv = RB_LOOKUP(hammer_res_rb_tree, &hmp->rb_resv_root, base_off);
561 if (resv) {
4a2796f3 562 if (resv->zone != zone) {
df301614 563 hammer_unlock(&hmp->blkmap_lock);
4a2796f3
MD
564 next_offset = (next_offset + HAMMER_LARGEBLOCK_SIZE) &
565 ~HAMMER_LARGEBLOCK_MASK64;
566 goto again;
567 }
df301614
MD
568 if (offset < resv->append_off) {
569 hammer_unlock(&hmp->blkmap_lock);
570 next_offset += resv->append_off - offset;
571 goto again;
572 }
cb51be26 573 ++resv->refs;
df301614 574 resx = NULL;
cb51be26 575 } else {
bac808fe 576 resx = kmalloc(sizeof(*resv), hmp->m_misc,
df301614
MD
577 M_WAITOK | M_ZERO | M_USE_RESERVE);
578 resx->refs = 1;
579 resx->zone = zone;
580 resx->zone_offset = base_off;
5e435c92
MD
581 if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE)
582 resx->flags |= HAMMER_RESF_LAYER2FREE;
df301614
MD
583 resv = RB_INSERT(hammer_res_rb_tree, &hmp->rb_resv_root, resx);
584 KKASSERT(resv == NULL);
585 resv = resx;
a7e9bef1 586 ++hammer_count_reservations;
cb51be26 587 }
df301614 588 resv->append_off = offset + bytes;
cb51be26
MD
589
590 /*
0832c9bb
MD
591 * If we are not reserving a whole buffer but are at the start of
592 * a new block, call hammer_bnew() to avoid a disk read.
593 *
4a2796f3
MD
594 * If we are reserving a whole buffer (or more), the caller will
595 * probably use a direct read, so do nothing.
47637bff 596 */
0832c9bb
MD
597 if (bytes < HAMMER_BUFSIZE && (next_offset & HAMMER_BUFMASK) == 0) {
598 hammer_bnew(hmp, next_offset, errorp, &buffer3);
599 }
600
47637bff
MD
601 /*
602 * Adjust our iterator and alloc_offset. The layer1 and layer2
603 * space beyond alloc_offset is uninitialized. alloc_offset must
604 * be big-block aligned.
605 */
df301614
MD
606 blockmap->next_offset = next_offset + bytes;
607 hammer_unlock(&hmp->blkmap_lock);
0832c9bb 608
df301614 609failed:
47637bff
MD
610 if (buffer1)
611 hammer_rel_buffer(buffer1, 0);
612 if (buffer2)
613 hammer_rel_buffer(buffer2, 0);
614 if (buffer3)
615 hammer_rel_buffer(buffer3, 0);
616 hammer_rel_volume(root_volume, 0);
0832c9bb
MD
617 *zone_offp = next_offset;
618
619 return(resv);
620}
621
1b0ab2c3 622/*
5e435c92
MD
623 * Dereference a reservation structure. Upon the final release the
624 * underlying big-block is checked and if it is entirely free we delete
625 * any related HAMMER buffers to avoid potential conflicts with future
626 * reuse of the big-block.
0832c9bb
MD
627 */
628void
629hammer_blockmap_reserve_complete(hammer_mount_t hmp, hammer_reserve_t resv)
630{
5e435c92 631 hammer_off_t base_offset;
362ec2dc 632 int error;
1b0ab2c3 633
0832c9bb 634 KKASSERT(resv->refs > 0);
5e435c92
MD
635 KKASSERT((resv->zone_offset & HAMMER_OFF_ZONE_MASK) ==
636 HAMMER_ZONE_RAW_BUFFER);
637
638 /*
639 * Setting append_off to the max prevents any new allocations
640 * from occuring while we are trying to dispose of the reservation,
641 * allowing us to safely delete any related HAMMER buffers.
362ec2dc
MD
642 *
643 * If we are unable to clean out all related HAMMER buffers we
644 * requeue the delay.
5e435c92
MD
645 */
646 if (resv->refs == 1 && (resv->flags & HAMMER_RESF_LAYER2FREE)) {
647 resv->append_off = HAMMER_LARGEBLOCK_SIZE;
1ce12d35
MD
648 base_offset = resv->zone_offset & ~HAMMER_OFF_ZONE_MASK;
649 base_offset = HAMMER_ZONE_ENCODE(resv->zone, base_offset);
362ec2dc
MD
650 error = hammer_del_buffers(hmp, base_offset,
651 resv->zone_offset,
652 HAMMER_LARGEBLOCK_SIZE,
653 0);
654 if (error)
655 hammer_reserve_setdelay(hmp, resv);
5e435c92 656 }
0832c9bb 657 if (--resv->refs == 0) {
cb51be26 658 KKASSERT((resv->flags & HAMMER_RESF_ONDELAY) == 0);
0832c9bb 659 RB_REMOVE(hammer_res_rb_tree, &hmp->rb_resv_root, resv);
bac808fe 660 kfree(resv, hmp->m_misc);
0832c9bb
MD
661 --hammer_count_reservations;
662 }
47637bff
MD
663}
664
665/*
5e435c92
MD
666 * Prevent a potentially free big-block from being reused until after
667 * the related flushes have completely cycled, otherwise crash recovery
668 * could resurrect a data block that was already reused and overwritten.
669 *
1ce12d35
MD
670 * The caller might reset the underlying layer2 entry's append_off to 0, so
671 * our covering append_off must be set to max to prevent any reallocation
672 * until after the flush delays complete, not to mention proper invalidation
673 * of any underlying cached blocks.
cb51be26 674 */
5e435c92 675static void
362ec2dc 676hammer_reserve_setdelay_offset(hammer_mount_t hmp, hammer_off_t base_offset,
1ce12d35 677 int zone, struct hammer_blockmap_layer2 *layer2)
cb51be26 678{
5e435c92 679 hammer_reserve_t resv;
df301614 680
5e435c92
MD
681 /*
682 * Allocate the reservation if necessary.
1ce12d35
MD
683 *
684 * NOTE: need lock in future around resv lookup/allocation and
685 * the setdelay call, currently refs is not bumped until the call.
5e435c92
MD
686 */
687again:
688 resv = RB_LOOKUP(hammer_res_rb_tree, &hmp->rb_resv_root, base_offset);
cb51be26 689 if (resv == NULL) {
bac808fe 690 resv = kmalloc(sizeof(*resv), hmp->m_misc,
df301614 691 M_WAITOK | M_ZERO | M_USE_RESERVE);
1ce12d35 692 resv->zone = zone;
5e435c92
MD
693 resv->zone_offset = base_offset;
694 resv->refs = 0;
1ce12d35
MD
695 resv->append_off = HAMMER_LARGEBLOCK_SIZE;
696
5e435c92
MD
697 if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE)
698 resv->flags |= HAMMER_RESF_LAYER2FREE;
df301614 699 if (RB_INSERT(hammer_res_rb_tree, &hmp->rb_resv_root, resv)) {
bac808fe 700 kfree(resv, hmp->m_misc);
5e435c92 701 goto again;
df301614 702 }
5e435c92 703 ++hammer_count_reservations;
1ce12d35
MD
704 } else {
705 if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE)
706 resv->flags |= HAMMER_RESF_LAYER2FREE;
5e435c92 707 }
1ce12d35 708 hammer_reserve_setdelay(hmp, resv);
362ec2dc 709}
5e435c92 710
362ec2dc
MD
711/*
712 * Enter the reservation on the on-delay list, or move it if it
713 * is already on the list.
714 */
715static void
716hammer_reserve_setdelay(hammer_mount_t hmp, hammer_reserve_t resv)
717{
5e435c92 718 if (resv->flags & HAMMER_RESF_ONDELAY) {
cb51be26
MD
719 TAILQ_REMOVE(&hmp->delay_list, resv, delay_entry);
720 resv->flush_group = hmp->flusher.next + 1;
5e435c92 721 TAILQ_INSERT_TAIL(&hmp->delay_list, resv, delay_entry);
cb51be26 722 } else {
5e435c92 723 ++resv->refs;
a7e9bef1 724 ++hmp->rsv_fromdelay;
df301614
MD
725 resv->flags |= HAMMER_RESF_ONDELAY;
726 resv->flush_group = hmp->flusher.next + 1;
727 TAILQ_INSERT_TAIL(&hmp->delay_list, resv, delay_entry);
728 }
cb51be26
MD
729}
730
731void
732hammer_reserve_clrdelay(hammer_mount_t hmp, hammer_reserve_t resv)
733{
734 KKASSERT(resv->flags & HAMMER_RESF_ONDELAY);
735 resv->flags &= ~HAMMER_RESF_ONDELAY;
736 TAILQ_REMOVE(&hmp->delay_list, resv, delay_entry);
a7e9bef1 737 --hmp->rsv_fromdelay;
cb51be26
MD
738 hammer_blockmap_reserve_complete(hmp, resv);
739}
740
cb51be26 741/*
4a2796f3 742 * Backend function - free (offset, bytes) in a zone.
cdb6e4e6
MD
743 *
744 * XXX error return
40043e7f 745 */
c3be93f2 746void
36f82b23 747hammer_blockmap_free(hammer_transaction_t trans,
cb51be26 748 hammer_off_t zone_offset, int bytes)
40043e7f 749{
0832c9bb 750 hammer_mount_t hmp;
c3be93f2 751 hammer_volume_t root_volume;
cb51be26
MD
752 hammer_blockmap_t blockmap;
753 hammer_blockmap_t freemap;
c3be93f2
MD
754 struct hammer_blockmap_layer1 *layer1;
755 struct hammer_blockmap_layer2 *layer2;
f03c9cf4
MD
756 hammer_buffer_t buffer1 = NULL;
757 hammer_buffer_t buffer2 = NULL;
c3be93f2
MD
758 hammer_off_t layer1_offset;
759 hammer_off_t layer2_offset;
cb51be26 760 hammer_off_t base_off;
c3be93f2
MD
761 int error;
762 int zone;
763
cb51be26
MD
764 if (bytes == 0)
765 return;
0832c9bb
MD
766 hmp = trans->hmp;
767
cb51be26
MD
768 /*
769 * Alignment
770 */
4a2796f3
MD
771 bytes = (bytes + 15) & ~15;
772 KKASSERT(bytes <= HAMMER_XBUFSIZE);
773 KKASSERT(((zone_offset ^ (zone_offset + (bytes - 1))) &
774 ~HAMMER_LARGEBLOCK_MASK64) == 0);
f03c9cf4 775
cb51be26
MD
776 /*
777 * Basic zone validation & locking
778 */
779 zone = HAMMER_ZONE_DECODE(zone_offset);
780 KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
781 root_volume = trans->rootvol;
782 error = 0;
f03c9cf4 783
cb51be26
MD
784 blockmap = &hmp->blockmap[zone];
785 freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
c3be93f2
MD
786
787 /*
788 * Dive layer 1.
789 */
cb51be26
MD
790 layer1_offset = freemap->phys_offset +
791 HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset);
0832c9bb 792 layer1 = hammer_bread(hmp, layer1_offset, &error, &buffer1);
cdb6e4e6
MD
793 if (error)
794 goto failed;
cb51be26
MD
795 KKASSERT(layer1->phys_offset &&
796 layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
19619882 797 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
db9f9d7f
MD
798 hammer_lock_ex(&hmp->blkmap_lock);
799 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
800 panic("CRC FAILED: LAYER1");
801 hammer_unlock(&hmp->blkmap_lock);
19619882 802 }
c3be93f2
MD
803
804 /*
805 * Dive layer 2, each entry represents a large-block.
806 */
807 layer2_offset = layer1->phys_offset +
cb51be26 808 HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset);
0832c9bb 809 layer2 = hammer_bread(hmp, layer2_offset, &error, &buffer2);
cdb6e4e6
MD
810 if (error)
811 goto failed;
19619882 812 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
db9f9d7f
MD
813 hammer_lock_ex(&hmp->blkmap_lock);
814 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
815 panic("CRC FAILED: LAYER2");
816 hammer_unlock(&hmp->blkmap_lock);
19619882
MD
817 }
818
df301614
MD
819 hammer_lock_ex(&hmp->blkmap_lock);
820
36f82b23 821 hammer_modify_buffer(trans, buffer2, layer2, sizeof(*layer2));
4a2796f3
MD
822
823 /*
5e435c92 824 * Free space previously allocated via blockmap_alloc().
4a2796f3
MD
825 */
826 KKASSERT(layer2->zone == zone);
827 layer2->bytes_free += bytes;
828 KKASSERT(layer2->bytes_free <= HAMMER_LARGEBLOCK_SIZE);
5e435c92
MD
829
830 /*
831 * If a big-block becomes entirely free we must create a covering
832 * reservation to prevent premature reuse. Note, however, that
833 * the big-block and/or reservation may still have an append_off
834 * that allows further (non-reused) allocations.
835 *
836 * Once the reservation has been made we re-check layer2 and if
837 * the big-block is still entirely free we reset the layer2 entry.
838 * The reservation will prevent premature reuse.
839 *
840 * NOTE: hammer_buffer's are only invalidated when the reservation
841 * is completed, if the layer2 entry is still completely free at
842 * that time. Any allocations from the reservation that may have
843 * occured in the mean time, or active references on the reservation
844 * from new pending allocations, will prevent the invalidation from
845 * occuring.
846 */
4a2796f3
MD
847 if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE) {
848 base_off = (zone_offset & (~HAMMER_LARGEBLOCK_MASK64 & ~HAMMER_OFF_ZONE_MASK)) | HAMMER_ZONE_RAW_BUFFER;
5e435c92 849
1ce12d35 850 hammer_reserve_setdelay_offset(hmp, base_off, zone, layer2);
5e435c92 851 if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE) {
4a2796f3
MD
852 layer2->zone = 0;
853 layer2->append_off = 0;
36f82b23
MD
854 hammer_modify_buffer(trans, buffer1,
855 layer1, sizeof(*layer1));
4a2796f3 856 ++layer1->blocks_free;
19619882
MD
857 layer1->layer1_crc = crc32(layer1,
858 HAMMER_LAYER1_CRCSIZE);
10a5d1ba 859 hammer_modify_buffer_done(buffer1);
cb51be26
MD
860 hammer_modify_volume_field(trans,
861 trans->rootvol,
862 vol0_stat_freebigblocks);
4a2796f3 863 ++root_volume->ondisk->vol0_stat_freebigblocks;
cb51be26
MD
864 hmp->copy_stat_freebigblocks =
865 root_volume->ondisk->vol0_stat_freebigblocks;
866 hammer_modify_volume_done(trans->rootvol);
c3be93f2
MD
867 }
868 }
4a2796f3
MD
869 layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE);
870 hammer_modify_buffer_done(buffer2);
871 hammer_unlock(&hmp->blkmap_lock);
872
cdb6e4e6 873failed:
4a2796f3
MD
874 if (buffer1)
875 hammer_rel_buffer(buffer1, 0);
876 if (buffer2)
877 hammer_rel_buffer(buffer2, 0);
878}
879
880/*
881 * Backend function - finalize (offset, bytes) in a zone.
882 *
883 * Allocate space that was previously reserved by the frontend.
884 */
cdb6e4e6 885int
4a2796f3 886hammer_blockmap_finalize(hammer_transaction_t trans,
5e435c92 887 hammer_reserve_t resv,
4a2796f3
MD
888 hammer_off_t zone_offset, int bytes)
889{
890 hammer_mount_t hmp;
891 hammer_volume_t root_volume;
892 hammer_blockmap_t blockmap;
893 hammer_blockmap_t freemap;
894 struct hammer_blockmap_layer1 *layer1;
895 struct hammer_blockmap_layer2 *layer2;
896 hammer_buffer_t buffer1 = NULL;
897 hammer_buffer_t buffer2 = NULL;
898 hammer_off_t layer1_offset;
899 hammer_off_t layer2_offset;
900 int error;
901 int zone;
df301614 902 int offset;
4a2796f3
MD
903
904 if (bytes == 0)
cdb6e4e6 905 return(0);
4a2796f3
MD
906 hmp = trans->hmp;
907
908 /*
909 * Alignment
910 */
911 bytes = (bytes + 15) & ~15;
912 KKASSERT(bytes <= HAMMER_XBUFSIZE);
913
914 /*
915 * Basic zone validation & locking
916 */
917 zone = HAMMER_ZONE_DECODE(zone_offset);
918 KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
919 root_volume = trans->rootvol;
920 error = 0;
4a2796f3
MD
921
922 blockmap = &hmp->blockmap[zone];
923 freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
924
925 /*
926 * Dive layer 1.
927 */
928 layer1_offset = freemap->phys_offset +
929 HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset);
930 layer1 = hammer_bread(hmp, layer1_offset, &error, &buffer1);
cdb6e4e6
MD
931 if (error)
932 goto failed;
4a2796f3
MD
933 KKASSERT(layer1->phys_offset &&
934 layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
935 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
db9f9d7f
MD
936 hammer_lock_ex(&hmp->blkmap_lock);
937 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
938 panic("CRC FAILED: LAYER1");
939 hammer_unlock(&hmp->blkmap_lock);
4a2796f3
MD
940 }
941
942 /*
943 * Dive layer 2, each entry represents a large-block.
944 */
945 layer2_offset = layer1->phys_offset +
946 HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset);
947 layer2 = hammer_bread(hmp, layer2_offset, &error, &buffer2);
cdb6e4e6
MD
948 if (error)
949 goto failed;
4a2796f3 950 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
db9f9d7f
MD
951 hammer_lock_ex(&hmp->blkmap_lock);
952 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
953 panic("CRC FAILED: LAYER2");
954 hammer_unlock(&hmp->blkmap_lock);
4a2796f3
MD
955 }
956
df301614
MD
957 hammer_lock_ex(&hmp->blkmap_lock);
958
4a2796f3
MD
959 hammer_modify_buffer(trans, buffer2, layer2, sizeof(*layer2));
960
961 /*
962 * Finalize some or all of the space covered by a current
963 * reservation. An allocation in the same layer may have
964 * already assigned ownership.
965 */
966 if (layer2->zone == 0) {
967 hammer_modify_buffer(trans, buffer1,
968 layer1, sizeof(*layer1));
969 --layer1->blocks_free;
970 layer1->layer1_crc = crc32(layer1,
971 HAMMER_LAYER1_CRCSIZE);
972 hammer_modify_buffer_done(buffer1);
973 layer2->zone = zone;
974 KKASSERT(layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE);
975 KKASSERT(layer2->append_off == 0);
976 hammer_modify_volume_field(trans,
977 trans->rootvol,
978 vol0_stat_freebigblocks);
979 --root_volume->ondisk->vol0_stat_freebigblocks;
980 hmp->copy_stat_freebigblocks =
981 root_volume->ondisk->vol0_stat_freebigblocks;
982 hammer_modify_volume_done(trans->rootvol);
983 }
984 if (layer2->zone != zone)
985 kprintf("layer2 zone mismatch %d %d\n", layer2->zone, zone);
986 KKASSERT(layer2->zone == zone);
1ce12d35 987 KKASSERT(bytes != 0);
4a2796f3 988 layer2->bytes_free -= bytes;
5e435c92
MD
989 if (resv)
990 resv->flags &= ~HAMMER_RESF_LAYER2FREE;
4a2796f3
MD
991
992 /*
993 * Finalizations can occur out of order, or combined with allocations.
994 * append_off must be set to the highest allocated offset.
995 */
df301614
MD
996 offset = ((int)zone_offset & HAMMER_LARGEBLOCK_MASK) + bytes;
997 if (layer2->append_off < offset)
998 layer2->append_off = offset;
4a2796f3 999
19619882 1000 layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE);
10a5d1ba 1001 hammer_modify_buffer_done(buffer2);
d99d6bf5 1002 hammer_unlock(&hmp->blkmap_lock);
f03c9cf4 1003
cdb6e4e6 1004failed:
f03c9cf4
MD
1005 if (buffer1)
1006 hammer_rel_buffer(buffer1, 0);
1007 if (buffer2)
1008 hammer_rel_buffer(buffer2, 0);
cdb6e4e6 1009 return(error);
40043e7f
MD
1010}
1011
1012/*
bf686dbe
MD
1013 * Return the number of free bytes in the big-block containing the
1014 * specified blockmap offset.
1015 */
1016int
cb51be26 1017hammer_blockmap_getfree(hammer_mount_t hmp, hammer_off_t zone_offset,
bf686dbe
MD
1018 int *curp, int *errorp)
1019{
1020 hammer_volume_t root_volume;
cb51be26
MD
1021 hammer_blockmap_t blockmap;
1022 hammer_blockmap_t freemap;
bf686dbe
MD
1023 struct hammer_blockmap_layer1 *layer1;
1024 struct hammer_blockmap_layer2 *layer2;
1025 hammer_buffer_t buffer = NULL;
1026 hammer_off_t layer1_offset;
1027 hammer_off_t layer2_offset;
1028 int bytes;
1029 int zone;
1030
cb51be26 1031 zone = HAMMER_ZONE_DECODE(zone_offset);
bf686dbe
MD
1032 KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
1033 root_volume = hammer_get_root_volume(hmp, errorp);
1034 if (*errorp) {
1035 *curp = 0;
1036 return(0);
1037 }
cb51be26
MD
1038 blockmap = &hmp->blockmap[zone];
1039 freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
bf686dbe
MD
1040
1041 /*
1042 * Dive layer 1.
1043 */
cb51be26
MD
1044 layer1_offset = freemap->phys_offset +
1045 HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset);
bf686dbe 1046 layer1 = hammer_bread(hmp, layer1_offset, errorp, &buffer);
cdb6e4e6
MD
1047 if (*errorp) {
1048 bytes = 0;
1049 goto failed;
1050 }
bf686dbe 1051 KKASSERT(layer1->phys_offset);
19619882 1052 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
db9f9d7f
MD
1053 hammer_lock_ex(&hmp->blkmap_lock);
1054 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
1055 panic("CRC FAILED: LAYER1");
1056 hammer_unlock(&hmp->blkmap_lock);
19619882 1057 }
bf686dbe
MD
1058
1059 /*
1060 * Dive layer 2, each entry represents a large-block.
cdb6e4e6
MD
1061 *
1062 * (reuse buffer, layer1 pointer becomes invalid)
bf686dbe
MD
1063 */
1064 layer2_offset = layer1->phys_offset +
cb51be26 1065 HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset);
bf686dbe 1066 layer2 = hammer_bread(hmp, layer2_offset, errorp, &buffer);
cdb6e4e6
MD
1067 if (*errorp) {
1068 bytes = 0;
1069 goto failed;
1070 }
19619882 1071 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
db9f9d7f
MD
1072 hammer_lock_ex(&hmp->blkmap_lock);
1073 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
1074 panic("CRC FAILED: LAYER2");
1075 hammer_unlock(&hmp->blkmap_lock);
19619882 1076 }
cb51be26 1077 KKASSERT(layer2->zone == zone);
bf686dbe
MD
1078
1079 bytes = layer2->bytes_free;
1080
cb51be26 1081 if ((blockmap->next_offset ^ zone_offset) & ~HAMMER_LARGEBLOCK_MASK64)
bf686dbe
MD
1082 *curp = 0;
1083 else
1084 *curp = 1;
cdb6e4e6 1085failed:
bf686dbe
MD
1086 if (buffer)
1087 hammer_rel_buffer(buffer, 0);
1088 hammer_rel_volume(root_volume, 0);
1089 if (hammer_debug_general & 0x0800) {
1090 kprintf("hammer_blockmap_getfree: %016llx -> %d\n",
973c11b9 1091 (long long)zone_offset, bytes);
bf686dbe
MD
1092 }
1093 return(bytes);
1094}
1095
1096
1097/*
40043e7f
MD
1098 * Lookup a blockmap offset.
1099 */
1100hammer_off_t
cb51be26
MD
1101hammer_blockmap_lookup(hammer_mount_t hmp, hammer_off_t zone_offset,
1102 int *errorp)
40043e7f
MD
1103{
1104 hammer_volume_t root_volume;
cb51be26 1105 hammer_blockmap_t freemap;
c3be93f2
MD
1106 struct hammer_blockmap_layer1 *layer1;
1107 struct hammer_blockmap_layer2 *layer2;
40043e7f 1108 hammer_buffer_t buffer = NULL;
c3be93f2
MD
1109 hammer_off_t layer1_offset;
1110 hammer_off_t layer2_offset;
40043e7f 1111 hammer_off_t result_offset;
cb51be26
MD
1112 hammer_off_t base_off;
1113 hammer_reserve_t resv;
40043e7f 1114 int zone;
40043e7f 1115
cb51be26
MD
1116 /*
1117 * Calculate the zone-2 offset.
1118 */
1119 zone = HAMMER_ZONE_DECODE(zone_offset);
40043e7f 1120 KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
cb51be26
MD
1121
1122 result_offset = (zone_offset & ~HAMMER_OFF_ZONE_MASK) |
1123 HAMMER_ZONE_RAW_BUFFER;
1124
1125 /*
1126 * We can actually stop here, normal blockmaps are now direct-mapped
1127 * onto the freemap and so represent zone-2 addresses.
1128 */
1129 if (hammer_verify_zone == 0) {
1130 *errorp = 0;
1131 return(result_offset);
1132 }
1133
1134 /*
1135 * Validate the allocation zone
1136 */
40043e7f
MD
1137 root_volume = hammer_get_root_volume(hmp, errorp);
1138 if (*errorp)
1139 return(0);
cb51be26
MD
1140 freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
1141 KKASSERT(freemap->phys_offset != 0);
40043e7f
MD
1142
1143 /*
c3be93f2 1144 * Dive layer 1.
40043e7f 1145 */
cb51be26
MD
1146 layer1_offset = freemap->phys_offset +
1147 HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset);
c3be93f2 1148 layer1 = hammer_bread(hmp, layer1_offset, errorp, &buffer);
cdb6e4e6
MD
1149 if (*errorp)
1150 goto failed;
cb51be26 1151 KKASSERT(layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
19619882 1152 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
db9f9d7f
MD
1153 hammer_lock_ex(&hmp->blkmap_lock);
1154 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
1155 panic("CRC FAILED: LAYER1");
1156 hammer_unlock(&hmp->blkmap_lock);
19619882 1157 }
40043e7f
MD
1158
1159 /*
c3be93f2 1160 * Dive layer 2, each entry represents a large-block.
40043e7f 1161 */
c3be93f2 1162 layer2_offset = layer1->phys_offset +
cb51be26 1163 HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset);
c3be93f2 1164 layer2 = hammer_bread(hmp, layer2_offset, errorp, &buffer);
40043e7f 1165
cdb6e4e6
MD
1166 if (*errorp)
1167 goto failed;
cb51be26
MD
1168 if (layer2->zone == 0) {
1169 base_off = (zone_offset & (~HAMMER_LARGEBLOCK_MASK64 & ~HAMMER_OFF_ZONE_MASK)) | HAMMER_ZONE_RAW_BUFFER;
1170 resv = RB_LOOKUP(hammer_res_rb_tree, &hmp->rb_resv_root,
1171 base_off);
1172 KKASSERT(resv && resv->zone == zone);
1173
1174 } else if (layer2->zone != zone) {
1175 panic("hammer_blockmap_lookup: bad zone %d/%d\n",
1176 layer2->zone, zone);
1177 }
19619882 1178 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
db9f9d7f
MD
1179 hammer_lock_ex(&hmp->blkmap_lock);
1180 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
1181 panic("CRC FAILED: LAYER2");
1182 hammer_unlock(&hmp->blkmap_lock);
19619882 1183 }
c3be93f2 1184
cdb6e4e6 1185failed:
40043e7f
MD
1186 if (buffer)
1187 hammer_rel_buffer(buffer, 0);
1188 hammer_rel_volume(root_volume, 0);
1189 if (hammer_debug_general & 0x0800) {
1190 kprintf("hammer_blockmap_lookup: %016llx -> %016llx\n",
973c11b9 1191 (long long)zone_offset, (long long)result_offset);
40043e7f
MD
1192 }
1193 return(result_offset);
1194}
1195
bf686dbe
MD
1196
1197/*
cb51be26 1198 * Check space availability
bf686dbe 1199 */
cb51be26 1200int
0f65be10 1201_hammer_checkspace(hammer_mount_t hmp, int slop, int64_t *resp)
bf686dbe 1202{
cb51be26
MD
1203 const int in_size = sizeof(struct hammer_inode_data) +
1204 sizeof(union hammer_btree_elm);
1205 const int rec_size = (sizeof(union hammer_btree_elm) * 2);
a7e9bef1 1206 int64_t usedbytes;
cb51be26 1207
a7e9bef1
MD
1208 usedbytes = hmp->rsv_inodes * in_size +
1209 hmp->rsv_recs * rec_size +
1210 hmp->rsv_databytes +
7b6ccb11
MD
1211 ((int64_t)hmp->rsv_fromdelay << HAMMER_LARGEBLOCK_BITS) +
1212 ((int64_t)hidirtybufspace << 2) +
1213 (slop << HAMMER_LARGEBLOCK_BITS);
a7e9bef1 1214
7b6ccb11 1215 hammer_count_extra_space_used = usedbytes; /* debugging */
0f65be10
MD
1216 if (resp)
1217 *resp = usedbytes;
a7e9bef1 1218
7b6ccb11
MD
1219 if (hmp->copy_stat_freebigblocks >=
1220 (usedbytes >> HAMMER_LARGEBLOCK_BITS)) {
cb51be26 1221 return(0);
7b6ccb11 1222 }
cb51be26 1223 return (ENOSPC);
6f97fce3
MD
1224}
1225