]> git.saurik.com Git - apple/hfs.git/blame - tests/hfs_alloc_test.c
hfs-366.30.3.tar.gz
[apple/hfs.git] / tests / hfs_alloc_test.c
CommitLineData
558d2836
A
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
60typedef int16_t OSErr;
61
62typedef struct cnode {
63 uint32_t c_blocks;
64} cnode_t;
65
66typedef 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
80enum hfs_locktype {
81 HFS_SHARED_LOCK = 1,
82 HFS_EXCLUSIVE_LOCK = 2
83};
84
85typedef struct vnode {
86} *vnode_t;
87
88#define kMaxFreeExtents 10
89
90typedef 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
115typedef hfsmount_t ExtendedVCB;
116
117typedef struct _dk_cs_map {
118 dk_extent_t cm_extent;
119 uint64_t cm_bytes_mapped;
120} _dk_cs_map_t;
121
122struct jnl_trim_list {
123 uint32_t allocated_count;
124 uint32_t extent_count;
125 dk_extent_t *extents;
126};
127
128typedef 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
136typedef bool Boolean;
137
138int hfs_isallocated(struct hfsmount *hfsmp, uint32_t startingBlock,
139 uint32_t numBlocks);
140
141static int journal_trim_add_extent(__unused journal *jnl,
142 __unused uint64_t offset,
143 __unused uint64_t length)
144{
145 return 0;
146}
147
148static int journal_trim_remove_extent(__unused journal *jnl,
149 __unused uint64_t offset,
150 __unused uint64_t length)
151{
152 return 0;
153}
154
155static 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
163int
164hfs_systemfile_lock(__unused struct hfsmount *hfsmp, __unused int flags, __unused enum hfs_locktype locktype)
165{
166 return 0;
167}
168
169void
170hfs_systemfile_unlock(__unused struct hfsmount *hfsmp, __unused int flags)
171{
172
173}
174
175typedef 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
181u_int32_t hfs_freeblks(struct hfsmount * hfsmp, __unused int wantreserve)
182{
183 return hfsmp->freeBlocks - hfsmp->lockedBlocks;
184}
185
186enum {
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
196static void hfs_lock_mount(__unused struct hfsmount *hfsmp)
197{
198}
199static void hfs_unlock_mount(__unused struct hfsmount *hfsmp)
200{
201}
202
203OSErr 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
211static void HFS_UPDATE_NEXT_ALLOCATION(hfsmount_t *hfsmp,
212 uint32_t new_nextAllocation)
213{
214 hfsmp->nextAllocation = new_nextAllocation;
215}
216
217static 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
229typedef 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
242static void hfs_mark_inconsistent(__unused struct hfsmount *hfsmp,
243 __unused hfs_inconsistency_reason_t reason)
244{
245 assert(false);
246}
247
248static int journal_request_immediate_flush(__unused journal *jnl)
249{
250 return 0;
251}
252
253enum {
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
264static inline __attribute__((const))
265off_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
270typedef unsigned char Str31[32];
271#define EXTERN_API_C(x) extern x
272typedef const unsigned char * ConstUTF8Param;
273#define CALLBACK_API_C(_type, _name) _type ( * _name)
274typedef struct vnode* FileReference;
275typedef struct filefork FCB;
276typedef 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 */
284short 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
347errno_t hfs_find_free_extents(struct hfsmount *hfsmp,
348 void (*callback)(void *data, off_t), void *callback_arg);
349
350static void hfs_journal_lock(__unused hfsmount_t *hfsmp)
351{
352}
353
354static errno_t hfs_flush(__unused hfsmount_t *hfsmp, __unused hfs_flush_mode_t x)
355{
356 return 0;
357}
358
359static void hfs_journal_unlock(__unused hfsmount_t *hfsmp)
360{
361}
362
363typedef struct BTreeIterator { } BTreeIterator;
364
365#define HFS_SYSCTL(...)
366
367static void *hfs_malloc(size_t size)
368{
369 return malloc(size);
370}
371
372static void hfs_free(void *ptr, __unused size_t size)
373{
374 return free(ptr);
375}
376
377static void *hfs_mallocz(size_t size)
378{
379 return calloc(1, size);
380}
381
382bool panic_on_assert = true;
383
384void 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
392static void *bitmap;
393
394typedef struct buf {
395 void *ptr;
396 int size;
397 void *fsprivate;
398 bool is_shadow;
399} *buf_t;
400
401errno_t buf_bdwrite(__unused buf_t bp)
402{
403 return 0;
404}
405
406void buf_brelse(buf_t bp)
407{
408 if (bp->is_shadow)
409 free(bp->ptr);
410 free(bp);
411}
412
413uint32_t buf_count(__unused buf_t bp)
414{
415 return bp->size;
416}
417
418uintptr_t buf_dataptr(__unused buf_t bp)
419{
420 return (uintptr_t)bp->ptr;
421}
422
423int32_t buf_flags(__unused buf_t bp)
424{
425 return 0;
426}
427
428void buf_markinvalid(__unused buf_t bp)
429{
430}
431
432errno_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
445buf_t
446buf_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
463void *buf_fsprivate(buf_t bp)
464{
465 return bp->fsprivate;
466}
467
468void buf_setflags(__unused buf_t bp, __unused int32_t flags)
469{
470}
471
472void buf_setfsprivate(buf_t bp, void *fsprivate)
473{
474 bp->fsprivate = fsprivate;
475}
476
477unsigned int kdebug_enable;
478
479void 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
488int
489buf_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
499errno_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
527static 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
535int
536hfs_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
583int 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}