]> git.saurik.com Git - apple/hfs.git/blob - tests/hfs_alloc_test.c
hfs-522.0.9.tar.gz
[apple/hfs.git] / tests / hfs_alloc_test.c
1 /*
2 * Copyright (c) 2014-2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 // Radar Component: HFS | X
30
31 #include <sys/param.h>
32
33 #include <sys/disk.h>
34 #include <stdint.h>
35 #include <stdbool.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <libkern/OSByteOrder.h>
39 #include <hfs/hfs_format.h>
40
41 #include "test-utils.h"
42
43 // For panic
44 #include <mach/mach.h>
45
46 #include <stdio.h>
47
48 #define HFS_ALLOC_TEST 1
49 #define RANGELIST_TEST 1
50 #define KERNEL 1
51 #define HFS 1
52 #define DEBUG 1
53
54 #include "../core/rangelist.h"
55
56 #define SYSCTL_DECL(a)
57 #define SYSCTL_NODE(a, b, c, d, e, f)
58 #define SYSCTL_INT(a, b, c, d, e, f, g)
59
60 typedef int16_t OSErr;
61
62 typedef struct cnode {
63 uint32_t c_blocks;
64 } cnode_t;
65
66 typedef struct journal {
67
68
69 } journal;
70
71 #define HFS_READ_ONLY 0x00001
72 #define HFS_METADATA_ZONE 0x00080
73 #define HFS_HAS_SPARSE_DEVICE 0x00400
74 #define HFS_UNMAP 0x200000
75 #define HFS_SUMMARY_TABLE 0x800000
76 #define HFS_CS 0x1000000
77
78 #define SFL_BITMAP 0x0004
79
80 enum hfs_locktype {
81 HFS_SHARED_LOCK = 1,
82 HFS_EXCLUSIVE_LOCK = 2
83 };
84
85 typedef struct vnode {
86 } *vnode_t;
87
88 #define kMaxFreeExtents 10
89
90 typedef struct hfsmount {
91 cnode_t *hfs_allocation_cp;
92 uint32_t blockSize;
93 struct journal *jnl;
94 uint64_t hfs_logical_bytes;
95 uint32_t hfsPlusIOPosOffset;
96 uint8_t vcbVN[256];
97 uint32_t hfs_flags;
98 int32_t hfs_raw_dev; /* device mounted */
99 uint32_t totalBlocks, allocLimit, freeBlocks, tentativeBlocks, lockedBlocks;
100 uint32_t sparseAllocation, nextAllocation;
101 uint32_t hfs_metazone_start, hfs_metazone_end;
102 uint32_t vcbFreeExtCnt;
103 u_int32_t hfs_freed_block_count;
104 int16_t vcbFlags;
105 uint32_t vcbVBMIOSize;
106 vnode_t hfs_allocation_vp;
107 uint16_t vcbSigWord;
108 HFSPlusExtentDescriptor vcbFreeExt[kMaxFreeExtents];
109 uint8_t *hfs_summary_table;
110 uint32_t hfs_summary_size;
111 uint32_t hfs_summary_bytes; /* number of BYTES in summary table */
112 struct rl_head hfs_reserved_ranges[2];
113 } hfsmount_t;
114
115 typedef hfsmount_t ExtendedVCB;
116
117 typedef struct _dk_cs_map {
118 dk_extent_t cm_extent;
119 uint64_t cm_bytes_mapped;
120 } _dk_cs_map_t;
121
122 struct jnl_trim_list {
123 uint32_t allocated_count;
124 uint32_t extent_count;
125 dk_extent_t *extents;
126 };
127
128 typedef enum hfs_flush_mode {
129 HFS_FLUSH_JOURNAL, // Flush journal
130 HFS_FLUSH_JOURNAL_META, // Flush journal and metadata blocks
131 HFS_FLUSH_FULL, // Flush journal and does a cache flush
132 HFS_FLUSH_CACHE, // Flush track cache to media
133 HFS_FLUSH_BARRIER, // Barrier-only flush to ensure write order
134 } hfs_flush_mode_t;
135
136 typedef bool Boolean;
137
138 int hfs_isallocated(struct hfsmount *hfsmp, uint32_t startingBlock,
139 uint32_t numBlocks);
140
141 static int journal_trim_add_extent(__unused journal *jnl,
142 __unused uint64_t offset,
143 __unused uint64_t length)
144 {
145 return 0;
146 }
147
148 static int journal_trim_remove_extent(__unused journal *jnl,
149 __unused uint64_t offset,
150 __unused uint64_t length)
151 {
152 return 0;
153 }
154
155 static int journal_trim_extent_overlap(__unused journal *jnl,
156 __unused uint64_t offset,
157 __unused uint64_t length,
158 __unused uint64_t *end)
159 {
160 return 0;
161 }
162
163 int
164 hfs_systemfile_lock(__unused struct hfsmount *hfsmp, __unused int flags, __unused enum hfs_locktype locktype)
165 {
166 return 0;
167 }
168
169 void
170 hfs_systemfile_unlock(__unused struct hfsmount *hfsmp, __unused int flags)
171 {
172
173 }
174
175 typedef struct vfs_context * vfs_context_t;
176
177 #define VNOP_IOCTL(a, b, c, d, e) ((void)c, 0)
178
179 #define VCBTOHFS(x) (x)
180
181 u_int32_t hfs_freeblks(struct hfsmount * hfsmp, __unused int wantreserve)
182 {
183 return hfsmp->freeBlocks - hfsmp->lockedBlocks;
184 }
185
186 enum {
187 noErr = 0,
188 dskFulErr = -34, /*disk full*/
189 bdNamErr = -37, /*there may be no bad names in the final system!*/
190 paramErr = -50, /*error in user parameter list*/
191 memFullErr = -108, /*Not enough room in heap zone*/
192 fileBoundsErr = -1309, /*file's EOF, offset, mark or size is too big*/
193 kTECUsedFallbacksStatus = -8783,
194 };
195
196 static void hfs_lock_mount(__unused struct hfsmount *hfsmp)
197 {
198 }
199 static void hfs_unlock_mount(__unused struct hfsmount *hfsmp)
200 {
201 }
202
203 OSErr BlockDeallocate (ExtendedVCB *vcb, // Which volume to deallocate space on
204 u_int32_t firstBlock, // First block in range to deallocate
205 u_int32_t numBlocks, // Number of contiguous blocks to deallocate
206 u_int32_t flags);
207
208 #define lck_spin_lock(x) ((void)0)
209 #define lck_spin_unlock(x) ((void)0)
210
211 static void HFS_UPDATE_NEXT_ALLOCATION(hfsmount_t *hfsmp,
212 uint32_t new_nextAllocation)
213 {
214 hfsmp->nextAllocation = new_nextAllocation;
215 }
216
217 static void MarkVCBDirty(ExtendedVCB *vcb)
218 {
219 vcb->vcbFlags |= 0xFF00;
220 }
221
222 #define hfs_generate_volume_notifications(x) ((void)0)
223 #define REQUIRE_FILE_LOCK(a, b) ((void)0)
224 #define journal_modify_block_start(a, b) (0)
225 #define journal_modify_block_end(a, b, c, d) (0)
226
227 #define SWAP_BE32(x) OSSwapBigToHostInt32(x)
228
229 typedef enum {
230 HFS_INCONSISTENCY_DETECTED,
231
232 // Used when unable to rollback an operation that failed
233 HFS_ROLLBACK_FAILED,
234
235 // Used when the latter part of an operation failed, but we chose not to roll back
236 HFS_OP_INCOMPLETE,
237
238 // Used when someone told us to force an fsck on next mount
239 HFS_FSCK_FORCED,
240 } hfs_inconsistency_reason_t;
241
242 static void hfs_mark_inconsistent(__unused struct hfsmount *hfsmp,
243 __unused hfs_inconsistency_reason_t reason)
244 {
245 assert(false);
246 }
247
248 static int journal_request_immediate_flush(__unused journal *jnl)
249 {
250 return 0;
251 }
252
253 enum {
254 // These are indices into the array below
255
256 // Tentative ranges can be claimed back at any time
257 HFS_TENTATIVE_BLOCKS = 0,
258
259 // Locked ranges cannot be claimed back, but the allocation
260 // won't have been written to disk yet
261 HFS_LOCKED_BLOCKS = 1,
262 };
263
264 static inline __attribute__((const))
265 off_t hfs_blk_to_bytes(uint32_t blk, uint32_t blk_size)
266 {
267 return (off_t)blk * blk_size; // Avoid the overflow
268 }
269
270 typedef unsigned char Str31[32];
271 #define EXTERN_API_C(x) extern x
272 typedef const unsigned char * ConstUTF8Param;
273 #define CALLBACK_API_C(_type, _name) _type ( * _name)
274 typedef struct vnode* FileReference;
275 typedef struct filefork FCB;
276 typedef int64_t daddr64_t;
277
278 #include "../core/FileMgrInternal.h"
279
280 /*
281 * Map HFS Common errors (negative) to BSD error codes (positive).
282 * Positive errors (ie BSD errors) are passed through unchanged.
283 */
284 short MacToVFSError(OSErr err)
285 {
286 if (err >= 0)
287 return err;
288
289 /* BSD/VFS internal errnos */
290 #if 0
291 switch (err) {
292 case ERESERVEDNAME: /* -8 */
293 return err;
294 }
295 #endif
296
297 switch (err) {
298 case dskFulErr: /* -34 */
299 case btNoSpaceAvail: /* -32733 */
300 return ENOSPC;
301 case fxOvFlErr: /* -32750 */
302 return EOVERFLOW;
303
304 case btBadNode: /* -32731 */
305 return EIO;
306
307 case memFullErr: /* -108 */
308 return ENOMEM; /* +12 */
309
310 case cmExists: /* -32718 */
311 case btExists: /* -32734 */
312 return EEXIST; /* +17 */
313
314 case cmNotFound: /* -32719 */
315 case btNotFound: /* -32735 */
316 return ENOENT; /* 28 */
317
318 case cmNotEmpty: /* -32717 */
319 return ENOTEMPTY; /* 66 */
320
321 case cmFThdDirErr: /* -32714 */
322 return EISDIR; /* 21 */
323
324 case fxRangeErr: /* -32751 */
325 return ERANGE;
326
327 case bdNamErr: /* -37 */
328 return ENAMETOOLONG; /* 63 */
329
330 case paramErr: /* -50 */
331 case fileBoundsErr: /* -1309 */
332 return EINVAL; /* +22 */
333
334 #if 0
335 case fsBTBadNodeSize:
336 return ENXIO;
337 #endif
338
339 default:
340 return EIO; /* +5 */
341 }
342 }
343
344 #define min(a, b) \
345 ({ typeof(a) a_ = (a); typeof(b) b_ = (b); a_ < b_ ? a_ : b_; })
346
347 errno_t hfs_find_free_extents(struct hfsmount *hfsmp,
348 void (*callback)(void *data, off_t), void *callback_arg);
349
350 static void hfs_journal_lock(__unused hfsmount_t *hfsmp)
351 {
352 }
353
354 static errno_t hfs_flush(__unused hfsmount_t *hfsmp, __unused hfs_flush_mode_t x)
355 {
356 return 0;
357 }
358
359 static void hfs_journal_unlock(__unused hfsmount_t *hfsmp)
360 {
361 }
362
363 typedef struct BTreeIterator { } BTreeIterator;
364
365 #define HFS_SYSCTL(...)
366
367 static void *hfs_malloc(size_t size)
368 {
369 return malloc(size);
370 }
371
372 static void hfs_free(void *ptr, __unused size_t size)
373 {
374 return free(ptr);
375 }
376
377 static void *hfs_mallocz(size_t size)
378 {
379 return calloc(1, size);
380 }
381
382 bool panic_on_assert = true;
383
384 void hfs_assert_fail(const char *file, unsigned line, const char *expr)
385 {
386 assert_fail_(file, line, "%s", expr);
387 }
388
389 #include "../core/VolumeAllocation.c"
390 #include "../core/rangelist.c"
391
392 static void *bitmap;
393
394 typedef struct buf {
395 void *ptr;
396 int size;
397 void *fsprivate;
398 bool is_shadow;
399 } *buf_t;
400
401 errno_t buf_bdwrite(__unused buf_t bp)
402 {
403 return 0;
404 }
405
406 void buf_brelse(buf_t bp)
407 {
408 if (bp->is_shadow)
409 free(bp->ptr);
410 free(bp);
411 }
412
413 uint32_t buf_count(__unused buf_t bp)
414 {
415 return bp->size;
416 }
417
418 uintptr_t buf_dataptr(__unused buf_t bp)
419 {
420 return (uintptr_t)bp->ptr;
421 }
422
423 int32_t buf_flags(__unused buf_t bp)
424 {
425 return 0;
426 }
427
428 void buf_markinvalid(__unused buf_t bp)
429 {
430 }
431
432 errno_t buf_meta_bread(__unused vnode_t vp, daddr64_t blkno, int size,
433 __unused kauth_cred_t cred, buf_t *bpp)
434 {
435 buf_t bp = calloc(1, sizeof(struct buf));
436
437 bp->ptr = bitmap + blkno * 4096;
438 bp->size = size;
439
440 *bpp = bp;
441
442 return 0;
443 }
444
445 buf_t
446 buf_create_shadow(buf_t bp, boolean_t force_copy,
447 uintptr_t external_storage,
448 __unused void (*iodone)(buf_t, void *), __unused void *arg)
449 {
450 assert(force_copy && !external_storage);
451
452 buf_t new_bp = calloc(1, sizeof(struct buf));
453
454 new_bp->ptr = malloc(bp->size);
455
456 memcpy(new_bp->ptr, bp->ptr, bp->size);
457 new_bp->size = bp->size;
458 new_bp->is_shadow = true;
459
460 return new_bp;
461 }
462
463 void *buf_fsprivate(buf_t bp)
464 {
465 return bp->fsprivate;
466 }
467
468 void buf_setflags(__unused buf_t bp, __unused int32_t flags)
469 {
470 }
471
472 void buf_setfsprivate(buf_t bp, void *fsprivate)
473 {
474 bp->fsprivate = fsprivate;
475 }
476
477 unsigned int kdebug_enable;
478
479 void kernel_debug(__unused uint32_t debugid,
480 __unused uintptr_t arg1,
481 __unused uintptr_t arg2,
482 __unused uintptr_t arg3,
483 __unused uintptr_t arg4,
484 __unused uintptr_t arg5)
485 {
486 }
487
488 int
489 buf_invalidateblks(__unused vnode_t vp,
490 __unused int flags,
491 __unused int slpflag,
492 __unused int slptimeo)
493 {
494 return 0;
495 }
496
497 #define BITMAP_CHUNK_SIZE 80
498
499 errno_t get_more_bits(bitmap_context_t *bitmap_ctx)
500 {
501 uint32_t start_bit;
502 uint32_t iosize = 0;
503 uint32_t last_bitmap_block;
504
505 start_bit = bitmap_ctx->run_offset;
506
507 if (start_bit >= bitmap_ctx->hfsmp->totalBlocks) {
508 bitmap_ctx->chunk_end = 0;
509 bitmap_ctx->bitmap = NULL;
510 return 0;
511 }
512
513 iosize = BITMAP_CHUNK_SIZE;
514 last_bitmap_block = start_bit + iosize;
515
516 if (last_bitmap_block > bitmap_ctx->hfsmp->totalBlocks)
517 last_bitmap_block = bitmap_ctx->hfsmp->totalBlocks;
518
519 bitmap_ctx->chunk_current = 0;
520 bitmap_ctx->chunk_end = last_bitmap_block - start_bit;
521 if (bitmap_ctx->run_offset != 0)
522 bitmap_ctx->bitmap += iosize / 8;
523
524 return 0;
525 }
526
527 static errno_t update_summary_table(__unused bitmap_context_t *bitmap_ctx,
528 __unused uint32_t start,
529 __unused uint32_t count,
530 __unused bool set)
531 {
532 return 0;
533 }
534
535 int
536 hfs_find_free_extents_test(hfsmount_t *hfsmp)
537 {
538 uint8_t bitmap[] = {
539 /* 0: */ 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
540 /* 64: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
541 /* 128: */ 0xff, 0xfe, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x00,
542 /* 192: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
543 /* 256: */ 0xff, 0xfe, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x00,
544 };
545
546 assert(bit_count_set(bitmap, 0, 32) == 15);
547 assert(bit_count_clr(bitmap, 15, 64) == 3);
548 assert(bit_count_set(bitmap, 48, 160) == 16 + 64 + 15);
549 assert(bit_count_set(bitmap, 48, 320) == 16 + 64 + 15);
550 assert(bit_count_clr(bitmap, 190, 260) == 2 + 64);
551 assert(bit_count_clr(bitmap, 190, 320) == 2 + 64);
552 assert(bit_count_clr(bitmap, 316, 320) == 4);
553
554 hfsmp->totalBlocks = sizeof(bitmap) * 8;
555
556 struct bitmap_context ctx = {
557 .hfsmp = hfsmp,
558 .bitmap = bitmap,
559 };
560
561 uint32_t count;
562
563 assert(!hfs_bit_count_set(&ctx, &count) && count == 15);
564 assert(!hfs_bit_count_clr(&ctx, &count) && count == 3);
565 assert(!hfs_bit_count_set(&ctx, &count) && count == 125);
566 assert(!hfs_bit_count_clr(&ctx, &count) && count == 1);
567 assert(!hfs_bit_count_set(&ctx, &count) && count == 2);
568 assert(!hfs_bit_count_clr(&ctx, &count) && count == 2);
569 assert(!hfs_bit_count_set(&ctx, &count) && count == 36);
570 assert(!hfs_bit_count_clr(&ctx, &count) && count == 72);
571 assert(!hfs_bit_count_set(&ctx, &count) && count == 15);
572 assert(!hfs_bit_count_clr(&ctx, &count) && count == 1);
573 assert(!hfs_bit_count_set(&ctx, &count) && count == 2);
574 assert(!hfs_bit_count_clr(&ctx, &count) && count == 2);
575 assert(!hfs_bit_count_set(&ctx, &count) && count == 36);
576 assert(!hfs_bit_count_clr(&ctx, &count) && count == 8);
577
578 assert(hfs_bit_offset(&ctx) == 320);
579
580 return 0;
581 }
582
583 int main(void)
584 {
585 const int blocks = 100000;
586
587 size_t bitmap_size = howmany(blocks, 8);
588 bitmap = calloc(1, bitmap_size);
589
590 cnode_t alloc_cp = {
591 .c_blocks = howmany(bitmap_size, 4096),
592 };
593
594 struct journal jnl;
595
596 struct hfsmount mnt = {
597 .allocLimit = blocks,
598 .totalBlocks = blocks,
599 .freeBlocks = blocks,
600 .blockSize = 4096,
601 .vcbVBMIOSize = 4096,
602 .hfs_allocation_cp = &alloc_cp,
603 .vcbSigWord = kHFSPlusSigWord,
604 .jnl = &jnl,
605 .hfs_logical_bytes = blocks * 4096,
606 };
607
608 assert(!hfs_init_summary (&mnt));
609
610 uint32_t start, count;
611 assert(!BlockAllocate(&mnt, 0, 10, 10, 0, &start, &count)
612 && start == 0 && count == 10);
613 assert(!BlockAllocate(&mnt, 0, 10, 10, 0, &start, &count)
614 && start == 10 && count == 10);
615 assert(!BlockAllocate(&mnt, 0, 32768 - 20, 32768 - 20, 0, &start, &count)
616 && start == 20 && count == 32768 - 20);
617
618 assert(!ScanUnmapBlocks(&mnt));
619
620 assert(!hfs_find_summary_free(&mnt, 0, &start) && start == 32768);
621
622 assert(!BlockAllocate(&mnt, 0, blocks - 32768, blocks - 32768, 0,
623 &start, &count)
624 && start == 32768 && count == blocks - 32768);
625
626 assert(BlockAllocate(&mnt, 0, 1, 1, 0, &start, &count) == dskFulErr);
627
628 assert(!BlockDeallocate(&mnt, 1, 1, 0));
629 assert(!BlockDeallocate(&mnt, 3, 1, 0));
630
631 assert(!hfs_find_summary_free(&mnt, 0, &start) && start == 0);
632 assert(!hfs_find_summary_free(&mnt, 1, &start) && start == 1);
633 assert(!hfs_find_summary_free(&mnt, 32767, &start) && start == 32767);
634
635 assert(BlockAllocate(&mnt, 0, 2, 2, HFS_ALLOC_FORCECONTIG,
636 &start, &count) == dskFulErr);
637
638 // The last block never gets marked
639 assert(!hfs_find_summary_free(&mnt, 32768, &start) && start == 98304);
640
641 assert(!BlockDeallocate(&mnt, 33000, 1, 0));
642
643 assert(!hfs_find_summary_free(&mnt, 32768, &start) && start == 32768);
644 assert(!hfs_find_summary_free(&mnt, 65535, &start) && start == 65535);
645 assert(!hfs_find_summary_free(&mnt, 65536, &start) && start == 98304);
646
647 assert(!BlockDeallocate(&mnt, 33001, 1, 0));
648 assert(!BlockAllocate(&mnt, 0, 2, 2, HFS_ALLOC_FORCECONTIG,
649 &start, &count) && start == 33000 && count == 2);
650
651 // Test tentative allocations
652
653 HFSPlusExtentDescriptor ext = {
654 .blockCount = 1,
655 };
656
657 struct rl_entry *reservation = NULL;
658
659 hfs_alloc_extra_args_t args = {
660 .max_blocks = 2,
661 .reservation_out = &reservation,
662 };
663
664 assert(!hfs_block_alloc(&mnt, &ext, HFS_ALLOC_TENTATIVE, &args)
665 && ext.startBlock == 1 && ext.blockCount == 1);
666
667 assert(rl_len(reservation) == 1);
668
669 // This shouldn't use the tentative block
670 assert(!BlockAllocate(&mnt, 0, 1, 1, 0, &start, &count)
671 && start == 3 && count == 1);
672
673 // This should steal the tentative block
674 assert(!BlockAllocate(&mnt, 0, 1, 1, 0, &start, &count)
675 && start == 1 && count == 1);
676 assert(reservation->rl_start == -1 && reservation->rl_end == -2);
677
678 // Free 200
679 assert(!BlockDeallocate(&mnt, 32700, 200, 0));
680
681 // Make 100 tentative
682 ext.blockCount = 100;
683
684 args.max_blocks = 100;
685 assert(!hfs_block_alloc(&mnt, &ext, HFS_ALLOC_TENTATIVE, &args)
686 && ext.startBlock == 32700 && ext.blockCount == 100);
687
688 // This should allocate the other 100
689 assert(!BlockAllocate(&mnt, 0, 100, 100, 0, &start, &count)
690 && start == 32800 && count == 100);
691
692 assert(mnt.tentativeBlocks == 100);
693
694 // Allocate 25 in the middle of the tentative block
695 assert(!BlockAllocate(&mnt, 32750, 25, 25, 0, &start, &count)
696 && start == 32750 && count == 25);
697
698 // That should have split the reservation
699 assert(reservation->rl_start == 32700 && reservation->rl_end == 32749);
700
701 assert(mnt.tentativeBlocks == 50);
702
703 // The tail should have been freed
704 assert(mnt.vcbFreeExtCnt == 1
705 && mnt.vcbFreeExt[0].startBlock == 32775
706 && mnt.vcbFreeExt[0].blockCount == 25);
707
708 // Allocate the bit we just freed
709 assert(!BlockAllocate(&mnt, 32705, 1, 25, HFS_ALLOC_FORCECONTIG,
710 &start, &count)
711 && start == 32775 && count == 25);
712
713 // Split the tentative reservation again
714 assert(!BlockAllocate(&mnt, 32705, 1, 3, 0,
715 &start, &count)
716 && start == 32705 && count == 3);
717
718 // This time head should have been free
719 assert(mnt.vcbFreeExtCnt == 1
720 && mnt.vcbFreeExt[0].startBlock == 32700
721 && mnt.vcbFreeExt[0].blockCount == 5);
722
723 // Reservation will be tail
724 assert(reservation->rl_start == 32708 && reservation->rl_end == 32749);
725
726 assert(mnt.tentativeBlocks == 42);
727
728 // Free up what we just allocated
729 assert(!BlockDeallocate(&mnt, 32705, 3, 0));
730
731 // This should allocate something overlapping the start of the reservation
732 assert(!BlockAllocate(&mnt, 0, 15, 15, HFS_ALLOC_FORCECONTIG,
733 &start, &count)
734 && start == 32700 && count == 15);
735
736 // Should have eaten into start of reservation
737 assert(reservation->rl_start == 32715 && reservation->rl_end == 32749);
738
739 // Free up a bit at the end
740 assert(!BlockDeallocate(&mnt, 32750, 5, 0));
741
742 // Allocate a bit overlapping end of reservation
743 assert(!BlockAllocate(&mnt, 32740, 15, 15, HFS_ALLOC_FORCECONTIG,
744 &start, &count)
745 && start == 32740 && count == 15);
746
747 // Should have eaten into end of reservation
748 assert(reservation->rl_start == 32715 && reservation->rl_end == 32739);
749
750 assert(!BlockDeallocate(&mnt, 32700, 15, 0));
751
752 ext.startBlock = 0;
753 ext.blockCount = 40;
754
755 struct rl_entry *locked_reservation;
756
757 args.max_blocks = 40;
758 args.reservation_in = &reservation;
759 args.reservation_out = &locked_reservation;
760
761 assert(!hfs_block_alloc(&mnt, &ext,
762 HFS_ALLOC_TRY_HARD | HFS_ALLOC_USE_TENTATIVE | HFS_ALLOC_LOCKED,
763 &args));
764
765 assert(ext.startBlock == 32700 && ext.blockCount == 40);
766 assert(reservation == NULL);
767
768 hfs_free_locked(&mnt, &locked_reservation);
769
770 assert(mnt.freeBlocks == 40 && mnt.lockedBlocks == 0);
771
772 args.reservation_out = &reservation;
773
774 assert(!hfs_block_alloc(&mnt, &ext, HFS_ALLOC_TRY_HARD | HFS_ALLOC_TENTATIVE,
775 &args));
776
777 assert(mnt.freeBlocks == 40 && mnt.tentativeBlocks == 40
778 && rl_len(reservation) == 40);
779
780 // Hack lockedBlocks so that hfs_free_blocks returns 20
781 mnt.lockedBlocks = 20;
782
783 ext.blockCount = 20; // Minimum
784
785 args.reservation_in = &reservation;
786
787 assert(!hfs_block_alloc(&mnt, &ext,
788 HFS_ALLOC_TRY_HARD | HFS_ALLOC_USE_TENTATIVE,
789 &args));
790
791 // Should have only returned 20 blocks
792 assert(rl_len(reservation) == 20 && ext.blockCount == 20
793 && ext.startBlock == 32700);
794
795 mnt.lockedBlocks = 10;
796
797 // ENOSPC because minimum == 20
798 assert(hfs_block_alloc(&mnt, &ext,
799 HFS_ALLOC_TRY_HARD | HFS_ALLOC_USE_TENTATIVE,
800 &args) == ENOSPC);
801
802 mnt.lockedBlocks = 0;
803 assert(!hfs_block_alloc(&mnt, &ext,
804 HFS_ALLOC_TRY_HARD | HFS_ALLOC_USE_TENTATIVE,
805 &args));
806
807 // Should use up the remaining reservation
808 assert(!reservation && ext.startBlock == 32720 && ext.blockCount == 20);
809
810 assert(!BlockDeallocate(&mnt, 32700, 40, 0));
811
812 // Check alignment
813 args.alignment = 16;
814 args.max_blocks = 1000;
815 ext.blockCount = 1;
816 assert(!hfs_block_alloc(&mnt, &ext, HFS_ALLOC_TRY_HARD, &args));
817
818 assert(ext.startBlock == 32700 && ext.blockCount == 32);
819
820 assert(!BlockDeallocate(&mnt, 32700, 32, 0));
821
822 args.alignment_offset = 3;
823 ext.blockCount = 1;
824 assert(!hfs_block_alloc(&mnt, &ext, HFS_ALLOC_TRY_HARD, &args));
825
826 assert(ext.startBlock == 32700 && ext.blockCount == 29);
827
828 hfs_find_free_extents_test(&mnt);
829
830 printf("[PASSED] hfs_alloc_test\n");
831
832 return 0;
833 }