1 /* Test 72 - libminixfs unit test.
2 *
3 * Exercise the caching functionality of libminixfs in isolation.
4 */
5
6 #define _MINIX_SYSTEM
7
8 #include <minix/sysutil.h>
9 #include <minix/syslib.h>
10 #include <minix/vm.h>
11 #include <minix/bdev.h>
12 #include <sys/types.h>
13 #include <sys/mman.h>
14 #include <sys/ioc_memory.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <assert.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <math.h>
23 #include <minix/libminixfs.h>
24
25 int max_error = 0;
26
27 #include "common.h"
28 #include "testcache.h"
29
30 #define MYMAJOR 40 /* doesn't really matter, shouldn't be NO_DEV though */
31
32 #define MYDEV makedev(MYMAJOR, 1)
33
34 static int curblocksize = -1;
35
36 static char *writtenblocks[MAXBLOCKS];
37
38 /* Some functions used by testcache.c */
39
40 int
dowriteblock(int b,int blocksize,u32_t seed,char * data)41 dowriteblock(int b, int blocksize, u32_t seed, char *data)
42 {
43 struct buf *bp;
44 int r;
45
46 assert(blocksize == curblocksize);
47
48 if ((r = lmfs_get_block(&bp, MYDEV, b, NORMAL)) != 0) {
49 e(30);
50 return 0;
51 }
52
53 memcpy(bp->data, data, blocksize);
54
55 lmfs_markdirty(bp);
56
57 lmfs_put_block(bp);
58
59 return blocksize;
60 }
61
62 int
readblock(int b,int blocksize,u32_t seed,char * data)63 readblock(int b, int blocksize, u32_t seed, char *data)
64 {
65 struct buf *bp;
66 int r;
67
68 assert(blocksize == curblocksize);
69
70 if ((r = lmfs_get_block(&bp, MYDEV, b, NORMAL)) != 0) {
71 e(30);
72 return 0;
73 }
74
75 memcpy(data, bp->data, blocksize);
76
77 lmfs_put_block(bp);
78
79 return blocksize;
80 }
81
testend(void)82 void testend(void)
83 {
84 int i;
85 for(i = 0; i < MAXBLOCKS; i++) {
86 if(writtenblocks[i]) {
87 free(writtenblocks[i]);
88 writtenblocks[i] = NULL;
89 }
90 }
91 }
92
93 /* Fake some libminixfs client functions */
94
allocate(int b)95 static void allocate(int b)
96 {
97 assert(curblocksize > 0);
98 assert(!writtenblocks[b]);
99 if(!(writtenblocks[b] = calloc(1, curblocksize))) {
100 fprintf(stderr, "out of memory allocating block %d\n", b);
101 exit(1);
102 }
103 }
104
105 /* Fake some libblockdriver functions */
106 ssize_t
bdev_gather(dev_t dev,u64_t pos,iovec_t * vec,int count,int flags)107 bdev_gather(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags)
108 {
109 int i, block;
110 size_t size, block_off;
111 ssize_t tot = 0;
112 assert(dev == MYDEV);
113 assert(curblocksize > 0);
114 assert(!(pos % curblocksize));
115 for(i = 0; i < count; i++) {
116 char *data = (char *) vec[i].iov_addr;
117 block = pos / curblocksize;
118 block_off = (size_t)(pos % curblocksize);
119 size = vec[i].iov_size;
120 assert(size == PAGE_SIZE);
121 assert(block >= 0);
122 assert(block < MAXBLOCKS);
123 assert(block_off + size <= curblocksize);
124 if(!writtenblocks[block]) {
125 allocate(block);
126 }
127 memcpy(data, writtenblocks[block] + block_off, size);
128 pos += size;
129 tot += size;
130 }
131
132 return tot;
133 }
134
135 ssize_t
bdev_scatter(dev_t dev,u64_t pos,iovec_t * vec,int count,int flags)136 bdev_scatter(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags)
137 {
138 int i, block;
139 size_t size, block_off;
140 ssize_t tot = 0;
141 assert(dev == MYDEV);
142 assert(curblocksize > 0);
143 assert(!(pos % curblocksize));
144 for(i = 0; i < count; i++) {
145 char *data = (char *) vec[i].iov_addr;
146 block = pos / curblocksize;
147 block_off = (size_t)(pos % curblocksize);
148 size = vec[i].iov_size;
149 assert(size == PAGE_SIZE);
150 assert(block >= 0);
151 assert(block < MAXBLOCKS);
152 assert(block_off + size <= curblocksize);
153 if(!writtenblocks[block]) {
154 allocate(block);
155 }
156 memcpy(writtenblocks[block] + block_off, data, size);
157 pos += size;
158 tot += size;
159 }
160
161 return tot;
162 }
163
164 ssize_t
bdev_read(dev_t dev,u64_t pos,char * data,size_t count,int flags)165 bdev_read(dev_t dev, u64_t pos, char *data, size_t count, int flags)
166 {
167 int block;
168
169 assert(dev == MYDEV);
170 assert(curblocksize > 0);
171 assert(!(pos % curblocksize));
172 assert(count > 0);
173 assert(!(count % curblocksize));
174 assert(count == PAGE_SIZE);
175 assert(curblocksize == PAGE_SIZE);
176
177 block = pos / curblocksize;
178 assert(block >= 0);
179 assert(block < MAXBLOCKS);
180 if(!writtenblocks[block]) {
181 allocate(block);
182 }
183 memcpy(data, writtenblocks[block], curblocksize);
184 return count;
185 }
186
187 /* Fake some libsys functions */
188
189 __dead void
panic(const char * fmt,...)190 panic(const char *fmt, ...)
191 {
192 va_list va;
193 va_start(va, fmt);
194 vfprintf(stderr, fmt, va);
195 va_end(va);
196
197 exit(1);
198 }
199
200 int
vm_info_stats(struct vm_stats_info * vsi)201 vm_info_stats(struct vm_stats_info *vsi)
202 {
203 return ENOSYS;
204 }
205
206 void
util_stacktrace(void)207 util_stacktrace(void)
208 {
209 fprintf(stderr, "fake stacktrace\n");
210 }
211
alloc_contig(size_t len,int flags,phys_bytes * phys)212 void *alloc_contig(size_t len, int flags, phys_bytes *phys)
213 {
214 return malloc(len);
215 }
216
free_contig(void * addr,size_t len)217 int free_contig(void *addr, size_t len)
218 {
219 free(addr);
220 return 0;
221 }
222
sqrt_approx(u32_t v)223 u32_t sqrt_approx(u32_t v)
224 {
225 return (u32_t) sqrt(v);
226 }
227
vm_set_cacheblock(void * block,dev_t dev,off_t dev_offset,ino_t ino,off_t ino_offset,u32_t * flags,int blocksize,int setflags)228 int vm_set_cacheblock(void *block, dev_t dev, off_t dev_offset,
229 ino_t ino, off_t ino_offset, u32_t *flags, int blocksize, int setflags)
230 {
231 return ENOSYS;
232 }
233
vm_map_cacheblock(dev_t dev,off_t dev_offset,ino_t ino,off_t ino_offset,u32_t * flags,int blocksize)234 void *vm_map_cacheblock(dev_t dev, off_t dev_offset,
235 ino_t ino, off_t ino_offset, u32_t *flags, int blocksize)
236 {
237 return MAP_FAILED;
238 }
239
vm_forget_cacheblock(dev_t dev,off_t dev_offset,int blocksize)240 int vm_forget_cacheblock(dev_t dev, off_t dev_offset, int blocksize)
241 {
242 return 0;
243 }
244
vm_clear_cache(dev_t dev)245 int vm_clear_cache(dev_t dev)
246 {
247 return 0;
248 }
249
250 int
main(int argc,char * argv[])251 main(int argc, char *argv[])
252 {
253 size_t newblocksize;
254 int wss, cs, n = 0, p;
255
256 #define ITER 3
257 #define BLOCKS 200
258
259 start(72);
260
261 lmfs_setquiet(1);
262
263 /* Can the cache handle differently sized blocks? */
264
265 for(p = 1; p <= 3; p++) {
266 /* Do not update curblocksize until the cache is flushed. */
267 newblocksize = PAGE_SIZE*p;
268 lmfs_set_blocksize(newblocksize);
269 curblocksize = newblocksize; /* now it's safe to update */
270 lmfs_buf_pool(BLOCKS);
271 if(dotest(curblocksize, BLOCKS, ITER)) e(n);
272 n++;
273 }
274
275 /* Can the cache handle various combinations of the working set
276 * being larger and smaller than the cache?
277 */
278 for(wss = 2; wss <= 3; wss++) {
279 int wsblocks = 10*wss*wss*wss*wss*wss;
280 for(cs = wsblocks/4; cs <= wsblocks*3; cs *= 1.5) {
281 lmfs_set_blocksize(PAGE_SIZE);
282 curblocksize = PAGE_SIZE; /* same as above */
283 lmfs_buf_pool(cs);
284 if(dotest(curblocksize, wsblocks, ITER)) e(n);
285 n++;
286 }
287 }
288
289 quit();
290
291 return 0;
292 }
293
294