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