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