2 * Copyright (c) 2014-2015 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 // Radar Component: HFS | X
31 #include <sys/param.h>
38 #include <libkern/OSByteOrder.h>
39 #include <hfs/hfs_format.h>
41 #include "test-utils.h"
44 #include <mach/mach.h>
48 #define HFS_ALLOC_TEST 1
49 #define RANGELIST_TEST 1
54 #include "../core/rangelist.h"
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)
60 typedef int16_t OSErr
;
62 typedef struct cnode
{
66 typedef struct journal
{
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
78 #define SFL_BITMAP 0x0004
82 HFS_EXCLUSIVE_LOCK
= 2
85 typedef struct vnode
{
88 #define kMaxFreeExtents 10
90 typedef struct hfsmount
{
91 cnode_t
*hfs_allocation_cp
;
94 uint64_t hfs_logical_bytes
;
95 uint32_t hfsPlusIOPosOffset
;
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
;
105 uint32_t vcbVBMIOSize
;
106 vnode_t hfs_allocation_vp
;
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];
115 typedef hfsmount_t ExtendedVCB
;
117 typedef struct _dk_cs_map
{
118 dk_extent_t cm_extent
;
119 uint64_t cm_bytes_mapped
;
122 struct jnl_trim_list
{
123 uint32_t allocated_count
;
124 uint32_t extent_count
;
125 dk_extent_t
*extents
;
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
136 typedef bool Boolean
;
138 int hfs_isallocated(struct hfsmount
*hfsmp
, uint32_t startingBlock
,
141 static int journal_trim_add_extent(__unused journal
*jnl
,
142 __unused
uint64_t offset
,
143 __unused
uint64_t length
)
148 static int journal_trim_remove_extent(__unused journal
*jnl
,
149 __unused
uint64_t offset
,
150 __unused
uint64_t length
)
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
)
164 hfs_systemfile_lock(__unused
struct hfsmount
*hfsmp
, __unused
int flags
, __unused
enum hfs_locktype locktype
)
170 hfs_systemfile_unlock(__unused
struct hfsmount
*hfsmp
, __unused
int flags
)
175 typedef struct vfs_context
* vfs_context_t
;
177 #define VNOP_IOCTL(a, b, c, d, e) ((void)c, 0)
179 #define VCBTOHFS(x) (x)
181 u_int32_t
hfs_freeblks(struct hfsmount
* hfsmp
, __unused
int wantreserve
)
183 return hfsmp
->freeBlocks
- hfsmp
->lockedBlocks
;
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,
196 static void hfs_lock_mount(__unused
struct hfsmount
*hfsmp
)
199 static void hfs_unlock_mount(__unused
struct hfsmount
*hfsmp
)
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
208 #define lck_spin_lock(x) ((void)0)
209 #define lck_spin_unlock(x) ((void)0)
211 static void HFS_UPDATE_NEXT_ALLOCATION(hfsmount_t
*hfsmp
,
212 uint32_t new_nextAllocation
)
214 hfsmp
->nextAllocation
= new_nextAllocation
;
217 static void MarkVCBDirty(ExtendedVCB
*vcb
)
219 vcb
->vcbFlags
|= 0xFF00;
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)
227 #define SWAP_BE32(x) OSSwapBigToHostInt32(x)
230 HFS_INCONSISTENCY_DETECTED
,
232 // Used when unable to rollback an operation that failed
235 // Used when the latter part of an operation failed, but we chose not to roll back
238 // Used when someone told us to force an fsck on next mount
240 } hfs_inconsistency_reason_t
;
242 static void hfs_mark_inconsistent(__unused
struct hfsmount
*hfsmp
,
243 __unused hfs_inconsistency_reason_t reason
)
248 static int journal_request_immediate_flush(__unused journal
*jnl
)
254 // These are indices into the array below
256 // Tentative ranges can be claimed back at any time
257 HFS_TENTATIVE_BLOCKS
= 0,
259 // Locked ranges cannot be claimed back, but the allocation
260 // won't have been written to disk yet
261 HFS_LOCKED_BLOCKS
= 1,
264 static inline __attribute__((const))
265 off_t
hfs_blk_to_bytes(uint32_t blk
, uint32_t blk_size
)
267 return (off_t
)blk
* blk_size
; // Avoid the overflow
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
;
278 #include "../core/FileMgrInternal.h"
281 * Map HFS Common errors (negative) to BSD error codes (positive).
282 * Positive errors (ie BSD errors) are passed through unchanged.
284 short MacToVFSError(OSErr err
)
289 /* BSD/VFS internal errnos */
292 case ERESERVEDNAME
: /* -8 */
298 case dskFulErr
: /* -34 */
299 case btNoSpaceAvail
: /* -32733 */
301 case fxOvFlErr
: /* -32750 */
304 case btBadNode
: /* -32731 */
307 case memFullErr
: /* -108 */
308 return ENOMEM
; /* +12 */
310 case cmExists
: /* -32718 */
311 case btExists
: /* -32734 */
312 return EEXIST
; /* +17 */
314 case cmNotFound
: /* -32719 */
315 case btNotFound
: /* -32735 */
316 return ENOENT
; /* 28 */
318 case cmNotEmpty
: /* -32717 */
319 return ENOTEMPTY
; /* 66 */
321 case cmFThdDirErr
: /* -32714 */
322 return EISDIR
; /* 21 */
324 case fxRangeErr
: /* -32751 */
327 case bdNamErr
: /* -37 */
328 return ENAMETOOLONG
; /* 63 */
330 case paramErr
: /* -50 */
331 case fileBoundsErr
: /* -1309 */
332 return EINVAL
; /* +22 */
335 case fsBTBadNodeSize
:
345 ({ typeof(a) a_ = (a); typeof(b) b_ = (b); a_ < b_ ? a_ : b_; })
347 errno_t
hfs_find_free_extents(struct hfsmount
*hfsmp
,
348 void (*callback
)(void *data
, off_t
), void *callback_arg
);
350 static void hfs_journal_lock(__unused hfsmount_t
*hfsmp
)
354 static errno_t
hfs_flush(__unused hfsmount_t
*hfsmp
, __unused hfs_flush_mode_t x
)
359 static void hfs_journal_unlock(__unused hfsmount_t
*hfsmp
)
363 typedef struct BTreeIterator
{ } BTreeIterator
;
365 #define HFS_SYSCTL(...)
367 static void *hfs_malloc(size_t size
)
372 static void hfs_free(void *ptr
, __unused
size_t size
)
377 static void *hfs_mallocz(size_t size
)
379 return calloc(1, size
);
382 bool panic_on_assert
= true;
384 void hfs_assert_fail(const char *file
, unsigned line
, const char *expr
)
386 assert_fail_(file
, line
, "%s", expr
);
389 #include "../core/VolumeAllocation.c"
390 #include "../core/rangelist.c"
401 errno_t
buf_bdwrite(__unused buf_t bp
)
406 void buf_brelse(buf_t bp
)
413 uint32_t buf_count(__unused buf_t bp
)
418 uintptr_t buf_dataptr(__unused buf_t bp
)
420 return (uintptr_t)bp
->ptr
;
423 int32_t buf_flags(__unused buf_t bp
)
428 void buf_markinvalid(__unused buf_t bp
)
432 errno_t
buf_meta_bread(__unused vnode_t vp
, daddr64_t blkno
, int size
,
433 __unused kauth_cred_t cred
, buf_t
*bpp
)
435 buf_t bp
= calloc(1, sizeof(struct buf
));
437 bp
->ptr
= bitmap
+ blkno
* 4096;
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
)
450 assert(force_copy
&& !external_storage
);
452 buf_t new_bp
= calloc(1, sizeof(struct buf
));
454 new_bp
->ptr
= malloc(bp
->size
);
456 memcpy(new_bp
->ptr
, bp
->ptr
, bp
->size
);
457 new_bp
->size
= bp
->size
;
458 new_bp
->is_shadow
= true;
463 void *buf_fsprivate(buf_t bp
)
465 return bp
->fsprivate
;
468 void buf_setflags(__unused buf_t bp
, __unused
int32_t flags
)
472 void buf_setfsprivate(buf_t bp
, void *fsprivate
)
474 bp
->fsprivate
= fsprivate
;
477 unsigned int kdebug_enable
;
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
)
489 buf_invalidateblks(__unused vnode_t vp
,
491 __unused
int slpflag
,
492 __unused
int slptimeo
)
497 #define BITMAP_CHUNK_SIZE 80
499 errno_t
get_more_bits(bitmap_context_t
*bitmap_ctx
)
503 uint32_t last_bitmap_block
;
505 start_bit
= bitmap_ctx
->run_offset
;
507 if (start_bit
>= bitmap_ctx
->hfsmp
->totalBlocks
) {
508 bitmap_ctx
->chunk_end
= 0;
509 bitmap_ctx
->bitmap
= NULL
;
513 iosize
= BITMAP_CHUNK_SIZE
;
514 last_bitmap_block
= start_bit
+ iosize
;
516 if (last_bitmap_block
> bitmap_ctx
->hfsmp
->totalBlocks
)
517 last_bitmap_block
= bitmap_ctx
->hfsmp
->totalBlocks
;
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;
527 static errno_t
update_summary_table(__unused bitmap_context_t
*bitmap_ctx
,
528 __unused
uint32_t start
,
529 __unused
uint32_t count
,
536 hfs_find_free_extents_test(hfsmount_t
*hfsmp
)
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,
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);
554 hfsmp
->totalBlocks
= sizeof(bitmap
) * 8;
556 struct bitmap_context ctx
= {
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);
578 assert(hfs_bit_offset(&ctx
) == 320);
585 const int blocks
= 100000;
587 size_t bitmap_size
= howmany(blocks
, 8);
588 bitmap
= calloc(1, bitmap_size
);
591 .c_blocks
= howmany(bitmap_size
, 4096),
596 struct hfsmount mnt
= {
597 .allocLimit
= blocks
,
598 .totalBlocks
= blocks
,
599 .freeBlocks
= blocks
,
601 .vcbVBMIOSize
= 4096,
602 .hfs_allocation_cp
= &alloc_cp
,
603 .vcbSigWord
= kHFSPlusSigWord
,
605 .hfs_logical_bytes
= blocks
* 4096,
608 assert(!hfs_init_summary (&mnt
));
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);
618 assert(!ScanUnmapBlocks(&mnt
));
620 assert(!hfs_find_summary_free(&mnt
, 0, &start
) && start
== 32768);
622 assert(!BlockAllocate(&mnt
, 0, blocks
- 32768, blocks
- 32768, 0,
624 && start
== 32768 && count
== blocks
- 32768);
626 assert(BlockAllocate(&mnt
, 0, 1, 1, 0, &start
, &count
) == dskFulErr
);
628 assert(!BlockDeallocate(&mnt
, 1, 1, 0));
629 assert(!BlockDeallocate(&mnt
, 3, 1, 0));
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);
635 assert(BlockAllocate(&mnt
, 0, 2, 2, HFS_ALLOC_FORCECONTIG
,
636 &start
, &count
) == dskFulErr
);
638 // The last block never gets marked
639 assert(!hfs_find_summary_free(&mnt
, 32768, &start
) && start
== 98304);
641 assert(!BlockDeallocate(&mnt
, 33000, 1, 0));
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);
647 assert(!BlockDeallocate(&mnt
, 33001, 1, 0));
648 assert(!BlockAllocate(&mnt
, 0, 2, 2, HFS_ALLOC_FORCECONTIG
,
649 &start
, &count
) && start
== 33000 && count
== 2);
651 // Test tentative allocations
653 HFSPlusExtentDescriptor ext
= {
657 struct rl_entry
*reservation
= NULL
;
659 hfs_alloc_extra_args_t args
= {
661 .reservation_out
= &reservation
,
664 assert(!hfs_block_alloc(&mnt
, &ext
, HFS_ALLOC_TENTATIVE
, &args
)
665 && ext
.startBlock
== 1 && ext
.blockCount
== 1);
667 assert(rl_len(reservation
) == 1);
669 // This shouldn't use the tentative block
670 assert(!BlockAllocate(&mnt
, 0, 1, 1, 0, &start
, &count
)
671 && start
== 3 && count
== 1);
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);
679 assert(!BlockDeallocate(&mnt
, 32700, 200, 0));
681 // Make 100 tentative
682 ext
.blockCount
= 100;
684 args
.max_blocks
= 100;
685 assert(!hfs_block_alloc(&mnt
, &ext
, HFS_ALLOC_TENTATIVE
, &args
)
686 && ext
.startBlock
== 32700 && ext
.blockCount
== 100);
688 // This should allocate the other 100
689 assert(!BlockAllocate(&mnt
, 0, 100, 100, 0, &start
, &count
)
690 && start
== 32800 && count
== 100);
692 assert(mnt
.tentativeBlocks
== 100);
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);
698 // That should have split the reservation
699 assert(reservation
->rl_start
== 32700 && reservation
->rl_end
== 32749);
701 assert(mnt
.tentativeBlocks
== 50);
703 // The tail should have been freed
704 assert(mnt
.vcbFreeExtCnt
== 1
705 && mnt
.vcbFreeExt
[0].startBlock
== 32775
706 && mnt
.vcbFreeExt
[0].blockCount
== 25);
708 // Allocate the bit we just freed
709 assert(!BlockAllocate(&mnt
, 32705, 1, 25, HFS_ALLOC_FORCECONTIG
,
711 && start
== 32775 && count
== 25);
713 // Split the tentative reservation again
714 assert(!BlockAllocate(&mnt
, 32705, 1, 3, 0,
716 && start
== 32705 && count
== 3);
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);
723 // Reservation will be tail
724 assert(reservation
->rl_start
== 32708 && reservation
->rl_end
== 32749);
726 assert(mnt
.tentativeBlocks
== 42);
728 // Free up what we just allocated
729 assert(!BlockDeallocate(&mnt
, 32705, 3, 0));
731 // This should allocate something overlapping the start of the reservation
732 assert(!BlockAllocate(&mnt
, 0, 15, 15, HFS_ALLOC_FORCECONTIG
,
734 && start
== 32700 && count
== 15);
736 // Should have eaten into start of reservation
737 assert(reservation
->rl_start
== 32715 && reservation
->rl_end
== 32749);
739 // Free up a bit at the end
740 assert(!BlockDeallocate(&mnt
, 32750, 5, 0));
742 // Allocate a bit overlapping end of reservation
743 assert(!BlockAllocate(&mnt
, 32740, 15, 15, HFS_ALLOC_FORCECONTIG
,
745 && start
== 32740 && count
== 15);
747 // Should have eaten into end of reservation
748 assert(reservation
->rl_start
== 32715 && reservation
->rl_end
== 32739);
750 assert(!BlockDeallocate(&mnt
, 32700, 15, 0));
755 struct rl_entry
*locked_reservation
;
757 args
.max_blocks
= 40;
758 args
.reservation_in
= &reservation
;
759 args
.reservation_out
= &locked_reservation
;
761 assert(!hfs_block_alloc(&mnt
, &ext
,
762 HFS_ALLOC_TRY_HARD
| HFS_ALLOC_USE_TENTATIVE
| HFS_ALLOC_LOCKED
,
765 assert(ext
.startBlock
== 32700 && ext
.blockCount
== 40);
766 assert(reservation
== NULL
);
768 hfs_free_locked(&mnt
, &locked_reservation
);
770 assert(mnt
.freeBlocks
== 40 && mnt
.lockedBlocks
== 0);
772 args
.reservation_out
= &reservation
;
774 assert(!hfs_block_alloc(&mnt
, &ext
, HFS_ALLOC_TRY_HARD
| HFS_ALLOC_TENTATIVE
,
777 assert(mnt
.freeBlocks
== 40 && mnt
.tentativeBlocks
== 40
778 && rl_len(reservation
) == 40);
780 // Hack lockedBlocks so that hfs_free_blocks returns 20
781 mnt
.lockedBlocks
= 20;
783 ext
.blockCount
= 20; // Minimum
785 args
.reservation_in
= &reservation
;
787 assert(!hfs_block_alloc(&mnt
, &ext
,
788 HFS_ALLOC_TRY_HARD
| HFS_ALLOC_USE_TENTATIVE
,
791 // Should have only returned 20 blocks
792 assert(rl_len(reservation
) == 20 && ext
.blockCount
== 20
793 && ext
.startBlock
== 32700);
795 mnt
.lockedBlocks
= 10;
797 // ENOSPC because minimum == 20
798 assert(hfs_block_alloc(&mnt
, &ext
,
799 HFS_ALLOC_TRY_HARD
| HFS_ALLOC_USE_TENTATIVE
,
802 mnt
.lockedBlocks
= 0;
803 assert(!hfs_block_alloc(&mnt
, &ext
,
804 HFS_ALLOC_TRY_HARD
| HFS_ALLOC_USE_TENTATIVE
,
807 // Should use up the remaining reservation
808 assert(!reservation
&& ext
.startBlock
== 32720 && ext
.blockCount
== 20);
810 assert(!BlockDeallocate(&mnt
, 32700, 40, 0));
814 args
.max_blocks
= 1000;
816 assert(!hfs_block_alloc(&mnt
, &ext
, HFS_ALLOC_TRY_HARD
, &args
));
818 assert(ext
.startBlock
== 32700 && ext
.blockCount
== 32);
820 assert(!BlockDeallocate(&mnt
, 32700, 32, 0));
822 args
.alignment_offset
= 3;
824 assert(!hfs_block_alloc(&mnt
, &ext
, HFS_ALLOC_TRY_HARD
, &args
));
826 assert(ext
.startBlock
== 32700 && ext
.blockCount
== 29);
828 hfs_find_free_extents_test(&mnt
);
830 printf("[PASSED] hfs_alloc_test\n");