1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <limits.h>
8 #include <new>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
14
15 #include <fbl/algorithm.h>
16 #include <fbl/unique_ptr.h>
17 #include <fvm/fvm.h>
18 #include <minfs/format.h>
19 #include <unittest/unittest.h>
20 #include <zircon/compiler.h>
21 #include <zircon/syscalls.h>
22
23 #include "filesystems.h"
24 #include "misc.h"
25
26 namespace {
27
TestUseAllInodes(void)28 bool TestUseAllInodes(void) {
29 BEGIN_TEST;
30 ASSERT_TRUE(test_info->supports_resize);
31
32 // Create 100,000 inodes.
33 // We expect that this will force enough inodes to cause the
34 // filesystem structures to resize partway through.
35 constexpr size_t kFilesPerDirectory = 100;
36 constexpr size_t kDirectoryCount = 1000;
37 for (size_t d = 0; d < kDirectoryCount; d++) {
38 if (d % 100 == 0) {
39 printf("Creating directory (containing 100 files): %lu\n", d);
40 }
41 char dname[128];
42 snprintf(dname, sizeof(dname), "::%lu", d);
43 ASSERT_EQ(mkdir(dname, 0666), 0);
44 for (size_t f = 0; f < kFilesPerDirectory; f++) {
45 char fname[128];
46 snprintf(fname, sizeof(fname), "::%lu/%lu", d, f);
47 int fd = open(fname, O_CREAT | O_RDWR | O_EXCL);
48 ASSERT_GT(fd, 0);
49 ASSERT_EQ(close(fd), 0);
50 }
51 }
52
53 printf("Unmounting, Re-mounting, verifying...\n");
54 ASSERT_TRUE(check_remount(), "Could not remount filesystem");
55
56 for (size_t d = 0; d < kDirectoryCount; d++) {
57 if (d % 100 == 0) {
58 printf("Deleting directory (containing 100 files): %lu\n", d);
59 }
60 for (size_t f = 0; f < kFilesPerDirectory; f++) {
61 char fname[128];
62 snprintf(fname, sizeof(fname), "::%lu/%lu", d, f);
63 ASSERT_EQ(unlink(fname), 0);
64 }
65 char dname[128];
66 snprintf(dname, sizeof(dname), "::%lu", d);
67 ASSERT_EQ(rmdir(dname), 0);
68 }
69
70 END_TEST;
71 }
72
73 const test_disk_t disk = {
74 .block_count = 1LLU << 17,
75 .block_size = 1LLU << 9,
76 .slice_size = 1LLU << 20,
77 };
78
TestUseAllData(void)79 bool TestUseAllData(void) {
80 BEGIN_TEST;
81 constexpr size_t kBufSize = (1 << 20);
82 constexpr size_t kFileBufCount = 19;
83 ASSERT_TRUE(test_info->supports_resize);
84
85 uint64_t disk_size = test_disk_info.block_count * test_disk_info.block_size;
86 size_t metadata_size = fvm::MetadataSize(disk_size, disk.slice_size);
87
88 ASSERT_GT(disk_size, metadata_size * 2);
89 disk_size -= 2 * metadata_size;
90
91 ASSERT_GT(disk_size, minfs::kMinfsMinimumSlices * disk.slice_size);
92 disk_size -= minfs::kMinfsMinimumSlices * disk.slice_size;
93
94 size_t file_count = disk_size / kBufSize / kFileBufCount;
95 ASSERT_GT(file_count, 0);
96
97 fbl::AllocChecker ac;
98 fbl::unique_ptr<uint8_t[]> buf(new (&ac) uint8_t[kBufSize]);
99 ASSERT_TRUE(ac.check());
100 memset(buf.get(), 0, kBufSize);
101
102 for (size_t f = 0; f < file_count; f++) {
103 printf("Creating 19 MB file #%lu\n", f);
104 char fname[128];
105 snprintf(fname, sizeof(fname), "::%lu", f);
106 int fd = open(fname, O_CREAT | O_RDWR | O_EXCL);
107 ASSERT_GT(fd, 0);
108 for (size_t i = 0; i < kFileBufCount; i++) {
109 ASSERT_EQ(write(fd, buf.get(), kBufSize), kBufSize);
110 }
111 ASSERT_EQ(close(fd), 0);
112 }
113
114 ASSERT_TRUE(check_remount(), "Could not remount filesystem");
115
116 for (size_t f = 0; f < file_count; f++) {
117 char fname[128];
118 snprintf(fname, sizeof(fname), "::%lu", f);
119 ASSERT_EQ(unlink(fname), 0);
120 }
121
122 END_TEST;
123 }
124
125 } // namespace
126
127 // Reformat the disk between tests to restore original size.
128 RUN_FOR_ALL_FILESYSTEMS_TYPE(fs_resize_tests_inodes, disk, FS_TEST_FVM,
129 RUN_TEST_LARGE(TestUseAllInodes)
130 )
131
132 RUN_FOR_ALL_FILESYSTEMS_TYPE(fs_resize_tests_data, disk, FS_TEST_FVM,
133 RUN_TEST_LARGE(TestUseAllData)
134 )
135