1 /*
2 * Copyright (c) International Business Machines Corp., 2001-2004
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <dirent.h>
23 #include <fcntl.h>
24
25 #include "ffsb_fs.h"
26 #include "util.h"
27 #include "fh.h"
28
29 /* First zero out struct, set num_dirs, and strdups basedir */
init_ffsb_fs(ffsb_fs_t * fs,char * basedir,uint32_t num_data_dirs,uint32_t numstartfiles,unsigned flags)30 void init_ffsb_fs(ffsb_fs_t * fs, char *basedir, uint32_t num_data_dirs,
31 uint32_t numstartfiles, unsigned flags)
32 {
33 memset(fs, 0, sizeof(ffsb_fs_t));
34 fs->basedir = ffsb_strdup(basedir);
35 fs->num_dirs = num_data_dirs;
36 fs->num_start_files = numstartfiles;
37 fs->flags = flags;
38 fs->create_blocksize = FFSB_FS_DEFAULT_CREATE_BLOCKSIZE;
39 fs->age_blocksize = FFSB_FS_DEFAULT_AGE_BLOCKSIZE;
40 fs->age_fs = 0;
41 }
42
43 /*
44 * Does not remove files/dirs on disk, only frees up data
45 * structures
46 */
destroy_ffsb_fs(ffsb_fs_t * fs)47 void destroy_ffsb_fs(ffsb_fs_t * fs)
48 {
49 free(fs->basedir);
50 destroy_filelist(&fs->files);
51 destroy_filelist(&fs->fill);
52 destroy_filelist(&fs->meta);
53 }
54
clone_ffsb_fs(ffsb_fs_t * target,ffsb_fs_t * orig)55 void clone_ffsb_fs(ffsb_fs_t * target, ffsb_fs_t * orig)
56 {
57 target->basedir = orig->basedir;
58 target->flags = orig->flags;
59
60 /* !!!! hackish, write a filelist_clone() function later */
61 memcpy(&target->files, &orig->files, sizeof(orig->files));
62 memcpy(&target->fill, &orig->fill, sizeof(orig->fill));
63 memcpy(&target->meta, &orig->meta, sizeof(orig->meta));
64
65 target->num_dirs = orig->num_dirs;
66 target->num_start_files = orig->num_start_files;
67 target->minfilesize = orig->minfilesize;
68 target->maxfilesize = orig->maxfilesize;
69
70 target->start_fsutil = orig->start_fsutil;
71 target->desired_fsutil = orig->desired_fsutil;
72
73 target->age_fs = orig->age_fs;
74 target->num_age_dirs = orig->num_age_dirs;
75 target->aging_tg = orig->aging_tg;
76
77 target->create_blocksize = orig->create_blocksize;
78 target->age_blocksize = orig->age_blocksize;
79
80 memcpy(target->op_data, orig->op_data, sizeof(void *) * FFSB_NUMOPS);
81 }
82
add_files(ffsb_fs_t * fs,struct benchfiles * bf,int num,uint64_t minsize,uint64_t maxsize,unsigned blocksize)83 static void add_files(ffsb_fs_t * fs, struct benchfiles *bf, int num,
84 uint64_t minsize, uint64_t maxsize, unsigned blocksize)
85 {
86 struct ffsb_file *cur;
87 int i, fd, condition = 0, has_directio = 0;
88 randdata_t rd;
89 char *buf = ffsb_malloc(blocksize);
90 uint64_t initial_free = getfsutil_size(fs->basedir);
91
92 if (fs_get_directio(fs)) {
93 has_directio = 1;
94 fs_set_directio(fs, 0);
95 }
96
97 assert(blocksize);
98
99 init_random(&rd, 0);
100
101 if (num)
102 condition = num;
103 else if (fs->init_size) {
104 if (getfsutil(fs->basedir) != initial_free ||
105 fs->init_size > (getfsutil_size(fs->basedir) -
106 initial_free))
107 condition = 1;
108 else
109 condition = 0;
110 } else if (fs->init_fsutil) {
111 if (fs->init_fsutil > getfsutil(fs->basedir))
112 condition = 1;
113 else
114 condition = 0;
115 }
116
117 while (condition) {
118 uint64_t size;
119 if (fs->num_weights) {
120 int num = 1 + getrandom(&rd, fs->sum_weights);
121 int curop = 0;
122
123 while (fs->size_weights[curop].weight < num) {
124 num -= fs->size_weights[curop].weight;
125 curop++;
126 }
127 size = fs->size_weights[curop].size;
128 } else
129 size = minsize + getllrandom(&rd, maxsize - minsize);
130
131 cur = add_file(bf, size, &rd);
132 fd = fhopencreate(cur->name, NULL, fs);
133 writefile_helper(fd, size, blocksize, buf, NULL, fs);
134 fhclose(fd, NULL, fs);
135 unlock_file_writer(cur);
136
137 if (num)
138 condition--;
139 else if (fs->init_size) {
140 if (fs->init_size > getfsutil_size(fs->basedir) -
141 initial_free)
142 condition = 1;
143 else
144 condition = 0;
145 } else if (fs->init_fsutil) {
146 if (fs->init_fsutil > getfsutil(fs->basedir))
147 condition = 1;
148 else
149 condition = 0;
150 }
151
152 }
153 free(buf);
154 if (has_directio)
155 fs_set_directio(fs, 1);
156 }
157
158 static void age_fs(ffsb_fs_t * fs, double utilization);
159 static ffsb_fs_t *construct_new_fileset(ffsb_fs_t * fs);
160 static ffsb_fs_t *check_existing_fileset(ffsb_fs_t * fs);
161
construct_ffsb_fs(void * data)162 void *construct_ffsb_fs(void *data)
163 {
164 ffsb_fs_t *fs = (ffsb_fs_t *) data;
165 ffsb_fs_t *ret = NULL;
166
167 if (fs_get_reuse_fs(fs)) {
168 printf("checking existing fs: %s\n", fs->basedir);
169 ret = check_existing_fileset(fs);
170 if (ret == NULL) {
171 printf("recreating new fileset\n");
172 ret = construct_new_fileset(fs);
173 }
174 } else {
175 printf("creating new fileset %s\n", fs->basedir);
176 ret = construct_new_fileset(fs);
177 }
178 if (ret == NULL) {
179 printf("fs setup on %s failed\n", fs->basedir);
180 exit(1);
181 }
182 return ret;
183 }
184
verify_file(struct benchfiles * bf,char * fname,void * fs_ptr)185 static int verify_file(struct benchfiles *bf, char *fname, void *fs_ptr)
186 {
187 ffsb_fs_t *fs = (ffsb_fs_t *) fs_ptr;
188 uint64_t minsize = fs->minfilesize;
189 uint64_t maxsize = fs->maxfilesize;
190 uint64_t filesize = 0;
191 int fd = 0;
192 DIR *dirptr = NULL;
193
194 /* If it is a directory and it passed the name verification we
195 * don't need to do anything here
196 */
197 dirptr = opendir(fname);
198 if (dirptr) {
199 closedir(dirptr);
200 return 0;
201 }
202
203 fd = open(fname, O_RDONLY);
204 /* If we can't open it for read we're done */
205 if (fd < 0) {
206 printf("verify_file: error opening %s for readonly\n", fname);
207 perror(fname);
208 return 1;
209 }
210 close(fd);
211 filesize = ffsb_get_filesize(fname);
212
213 if (filesize < minsize || filesize > maxsize) {
214 printf("size %llu bytes for file %s is invalid\n",
215 filesize, fname);
216 return 1;
217 }
218
219 return 0;
220 }
221
222 /* Record the number of files and directorys there are supposed to be
223 * grab (check and build the structures) the regular data fileset then
224 * check to make sure the number of directories and files in that
225 * filelist matches up. Then grab the meta filelist and verify that
226 * the meta filelist is empty. Set up the filelist for fill (aging)
227 * and setup the ops for the benchmark.
228 */
check_existing_fileset(ffsb_fs_t * fs)229 static ffsb_fs_t *check_existing_fileset(ffsb_fs_t * fs)
230 {
231 char buf[FILENAME_MAX * 3];
232 int retval = 0;
233 uint32_t num_dirs = fs->num_dirs;
234 uint32_t num_files = fs->num_start_files;
235
236 if (fs->age_fs) {
237 printf("Aging and reusing the fileset are mutually "
238 "exclusive\n");
239 printf("aborting\n");
240 return NULL;
241 }
242
243 /* Set up bench/age dir */
244 if (FILENAME_MAX <=
245 snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, FILES_BASE)) {
246 printf("pathname \"%s\" is too long, aborting\n", buf);
247 return NULL;
248 }
249
250 /* Make a "dummy" filelist that has numsubdirs set to 0 and
251 * numstartfiles set to 0
252 */
253 init_filelist(&fs->files, buf, FILES_BASE, 0, 0);
254
255 retval = grab_old_fileset(&fs->files, buf, verify_file, fs);
256
257 if (retval)
258 return NULL;
259
260 if ((get_listsize(&fs->files) != num_files) ||
261 (get_numsubdirs(&fs->files) != num_dirs)) {
262 printf("check_existing_fileset: number of files (%u)"
263 " or directorys (%u) don't match up\n",
264 get_listsize(&fs->files), get_numsubdirs(&fs->files));
265 destroy_filelist(&fs->files);
266 return NULL;
267 }
268
269 if (FILENAME_MAX <=
270 snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, META_BASE)) {
271 printf("pathname \"%s\" is too long, aborting\n", buf);
272 return NULL;
273 }
274
275 init_filelist(&fs->meta, buf, META_BASE, 0, 1);
276 retval = grab_old_fileset(&fs->meta, buf, verify_file, fs);
277
278 if (retval) {
279 destroy_filelist(&fs->files);
280 return NULL;
281 }
282
283 if ((get_listsize(&fs->meta) != 0) || (get_numsubdirs(&fs->meta) != 0)) {
284 printf("check_existing_fileset: meta directory isn't empty\n"
285 "aborting\n");
286 destroy_filelist(&fs->files);
287 destroy_filelist(&fs->meta);
288 return NULL;
289 }
290
291 /* Even though we won't use it, we still need to be consistent
292 * here.
293 */
294 init_filelist(&fs->fill, buf, AGE_BASE, 0, 0);
295
296 /* Have to do this or everything else could break. */
297 ops_setup_bench(fs);
298
299 return fs;
300 }
301
302 /*
303 * clean up fs, "rm -rf data meta"
304 * record utilization
305 * set up the dirs: files, meta
306 * age filesystem
307 * have ffsb_ops setup their data
308 * create starting files in files
309 */
construct_new_fileset(ffsb_fs_t * fs)310 static ffsb_fs_t *construct_new_fileset(ffsb_fs_t * fs)
311 {
312 char buf[FILENAME_MAX * 3];
313
314 /* TODO: Convert this quick and dirty rm -rf to a "real"
315 * programmatic version, that doesn't rely on the rm command.
316 */
317 if (FILENAME_MAX * 3 <= snprintf(buf, FILENAME_MAX * 3,
318 "rm -rf %s/data %s/meta",
319 fs->basedir, fs->basedir)) {
320 printf("pathname too long for command \"%s\"\n", buf);
321 return NULL;
322 }
323
324 if (ffsb_system(buf) < 0) {
325 perror(buf);
326 return NULL;
327 }
328
329 fs->start_fsutil = getfsutil(fs->basedir);
330
331 /* Set up bench/age dir */
332 if (FILENAME_MAX <=
333 snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, FILES_BASE)) {
334 printf("pathname \"%s\" is too long, aborting\n", buf);
335 return NULL;
336 }
337
338 ffsb_mkdir(buf);
339
340 /* Regular files and aging share this directory */
341 init_filelist(&fs->files, buf, FILES_BASE, fs->num_dirs, 1);
342 init_filelist(&fs->fill, buf, AGE_BASE, fs->num_age_dirs, 1);
343
344 /* Set up meta dir */
345 snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, META_BASE);
346
347 ffsb_mkdir(buf);
348
349 init_filelist(&fs->meta, buf, META_BASE, 0, 1);
350
351 /* Do aging */
352 if (fs->age_fs)
353 age_fs(fs, fs->desired_fsutil);
354
355 /* Call back into ops, set for benchmark */
356 ops_setup_bench(fs);
357
358 /* Create initial fileset */
359 add_files(fs, &fs->files, fs->num_start_files, fs->minfilesize,
360 fs->maxfilesize, fs->create_blocksize);
361 return fs;
362 }
363
364 struct poll_data {
365 ffsb_fs_t *fs;
366 double util;
367 };
368
fs_get_util(void * data)369 static int fs_get_util(void *data)
370 {
371 struct poll_data *pd = (struct poll_data *)data;
372 double fsutil = getfsutil(pd->fs->basedir);
373
374 if (fsutil >= pd->util)
375 return 1;
376
377 return 0;
378 }
379
age_fs(ffsb_fs_t * fs,double utilization)380 static void age_fs(ffsb_fs_t * fs, double utilization)
381 {
382 ffsb_barrier_t barrier;
383 pthread_t thread;
384 struct poll_data pdata;
385 ffsb_tg_t *tg = fs_get_aging_tg(fs);
386 tg_run_params_t params;
387 ffsb_config_t fc;
388
389 printf("aging fs %s from %.2lf to %.2lf\n", fs->basedir,
390 fs->start_fsutil, utilization);
391 ffsb_barrier_init(&barrier, tg_get_numthreads(tg));
392
393 init_ffsb_config_1fs(&fc, fs, tg);
394
395 pdata.fs = fs;
396 pdata.util = utilization;
397
398 params.tg = tg;
399 params.poll_fn = fs_get_util;
400 params.poll_data = &pdata;
401 params.wait_time = 1;
402 params.fc = &fc;
403
404 params.tg_barrier = NULL;
405 params.thread_barrier = &barrier;
406
407 /* Call back into ops, setup for aging */
408 ops_setup_age(fs);
409
410 /* Throw in some files to start off, so there's something */
411 add_files(fs, &fs->fill, 10, 0, 0, fs->age_blocksize);
412
413 pthread_create(&thread, NULL, tg_run, ¶ms);
414 pthread_join(thread, NULL);
415 }
416
fs_set_create_blocksize(ffsb_fs_t * fs,uint32_t blocksize)417 void fs_set_create_blocksize(ffsb_fs_t * fs, uint32_t blocksize)
418 {
419 fs->create_blocksize = blocksize;
420 }
421
fs_set_age_blocksize(ffsb_fs_t * fs,uint32_t blocksize)422 void fs_set_age_blocksize(ffsb_fs_t * fs, uint32_t blocksize)
423 {
424 fs->age_blocksize = blocksize;
425 }
426
fs_get_create_blocksize(ffsb_fs_t * fs)427 uint32_t fs_get_create_blocksize(ffsb_fs_t * fs)
428 {
429 return fs->create_blocksize;
430 }
431
fs_get_age_blocksize(ffsb_fs_t * fs)432 uint32_t fs_get_age_blocksize(ffsb_fs_t * fs)
433 {
434 return fs->age_blocksize;
435 }
436
fs_get_basedir(ffsb_fs_t * fs)437 char *fs_get_basedir(ffsb_fs_t * fs)
438 {
439 return fs->basedir;
440 }
441
fs_get_numstartfiles(ffsb_fs_t * fs)442 uint32_t fs_get_numstartfiles(ffsb_fs_t * fs)
443 {
444 return fs->num_start_files;
445 }
446
fs_get_numdirs(ffsb_fs_t * fs)447 uint32_t fs_get_numdirs(ffsb_fs_t * fs)
448 {
449 return fs->num_dirs;
450 }
451
fs_get_libcio(ffsb_fs_t * fs)452 int fs_get_libcio(ffsb_fs_t * fs)
453 {
454 return fs->flags & FFSB_FS_LIBCIO;
455 }
456
fs_set_libcio(ffsb_fs_t * fs,int lio)457 void fs_set_libcio(ffsb_fs_t * fs, int lio)
458 {
459 if (lio)
460 fs->flags |= FFSB_FS_LIBCIO;
461 else
462 fs->flags &= ~0 & ~FFSB_FS_LIBCIO;
463 }
464
fs_get_directio(ffsb_fs_t * fs)465 int fs_get_directio(ffsb_fs_t * fs)
466 {
467 return fs->flags & FFSB_FS_DIRECTIO;
468 }
469
fs_set_directio(ffsb_fs_t * fs,int dio)470 void fs_set_directio(ffsb_fs_t * fs, int dio)
471 {
472 if (dio)
473 fs->flags |= FFSB_FS_DIRECTIO;
474 else
475 fs->flags &= ~0 & ~FFSB_FS_DIRECTIO;
476 }
477
fs_get_alignio(ffsb_fs_t * fs)478 int fs_get_alignio(ffsb_fs_t * fs)
479 {
480 return fs->flags & FFSB_FS_ALIGNIO4K;
481 }
482
fs_set_alignio(ffsb_fs_t * fs,int aio)483 void fs_set_alignio(ffsb_fs_t * fs, int aio)
484 {
485 if (aio)
486 fs->flags |= FFSB_FS_ALIGNIO4K;
487 else
488 fs->flags &= ~0 & ~FFSB_FS_ALIGNIO4K;
489 }
490
fs_get_reuse_fs(ffsb_fs_t * fs)491 int fs_get_reuse_fs(ffsb_fs_t * fs)
492 {
493 return fs->flags & FFSB_FS_REUSE_FS;
494 }
495
fs_set_reuse_fs(ffsb_fs_t * fs,int rfs)496 void fs_set_reuse_fs(ffsb_fs_t * fs, int rfs)
497 {
498 if (rfs)
499 fs->flags |= FFSB_FS_REUSE_FS;
500 else
501 fs->flags &= ~0 & ~FFSB_FS_REUSE_FS;
502 }
503
fs_get_datafiles(ffsb_fs_t * fs)504 struct benchfiles *fs_get_datafiles(ffsb_fs_t * fs)
505 {
506 return &fs->files;
507 }
508
fs_get_metafiles(ffsb_fs_t * fs)509 struct benchfiles *fs_get_metafiles(ffsb_fs_t * fs)
510 {
511 return &fs->meta;
512 }
513
fs_get_agefiles(ffsb_fs_t * fs)514 struct benchfiles *fs_get_agefiles(ffsb_fs_t * fs)
515 {
516 return &fs->fill;
517 }
518
fs_set_aging_tg(ffsb_fs_t * fs,struct ffsb_tg * tg,double util)519 void fs_set_aging_tg(ffsb_fs_t * fs, struct ffsb_tg *tg, double util)
520 {
521 fs->aging_tg = tg;
522 fs->age_fs = 1;
523 fs->desired_fsutil = util;
524 }
525
fs_get_aging_tg(ffsb_fs_t * fs)526 struct ffsb_tg *fs_get_aging_tg(ffsb_fs_t * fs)
527 {
528 return fs->aging_tg;
529 }
530
fs_get_agefs(ffsb_fs_t * fs)531 int fs_get_agefs(ffsb_fs_t * fs)
532 {
533 return fs->age_fs;
534 }
535
536 /* TODO: Implement this!!!*/
fs_set_num_age_dirs(ffsb_fs_t * fs,uint32_t numdirs)537 void fs_set_num_age_dirs(ffsb_fs_t * fs, uint32_t numdirs)
538 {
539 fs->num_age_dirs = numdirs;
540 }
541
fs_set_opdata(ffsb_fs_t * fs,void * data,unsigned opnum)542 void fs_set_opdata(ffsb_fs_t * fs, void *data, unsigned opnum)
543 {
544 fs->op_data[opnum] = data;
545 }
546
fs_get_opdata(ffsb_fs_t * fs,unsigned opnum)547 void *fs_get_opdata(ffsb_fs_t * fs, unsigned opnum)
548 {
549 return fs->op_data[opnum];
550 }
551
fs_set_min_filesize(ffsb_fs_t * fs,uint64_t size)552 void fs_set_min_filesize(ffsb_fs_t * fs, uint64_t size)
553 {
554 fs->minfilesize = size;
555 }
556
fs_set_max_filesize(ffsb_fs_t * fs,uint64_t size)557 void fs_set_max_filesize(ffsb_fs_t * fs, uint64_t size)
558 {
559 fs->maxfilesize = size;
560 }
561
fs_get_min_filesize(ffsb_fs_t * fs)562 uint64_t fs_get_min_filesize(ffsb_fs_t * fs)
563 {
564 return fs->minfilesize;
565 }
566
fs_get_max_filesize(ffsb_fs_t * fs)567 uint64_t fs_get_max_filesize(ffsb_fs_t * fs)
568 {
569 return fs->maxfilesize;
570 }
571
fs_get_desired_fsutil(ffsb_fs_t * fs)572 double fs_get_desired_fsutil(ffsb_fs_t * fs)
573 {
574 return fs->desired_fsutil;
575 }
576
fs_print_config(ffsb_fs_t * fs)577 void fs_print_config(ffsb_fs_t * fs)
578 {
579 char buf[256];
580
581 printf("FileSystem %s\n", fs->basedir);
582 printf("==========\n");
583 printf("\t num_dirs = %u\n", fs->num_dirs);
584 printf("\t starting files = %u\n", fs->num_start_files);
585 printf("\t\n");
586 if (fs->num_weights) {
587 int i;
588 printf("\t Fileset weight:\n");
589 for (i = 0; i < fs->num_weights; i++)
590 printf("\t\t %12llu (%6s) -> %u (%.2f\%)\n",
591 fs->size_weights[i].size,
592 ffsb_printsize(buf, fs->size_weights[i].size,
593 256), fs->size_weights[i].weight,
594 ((float)fs->size_weights[i].weight /
595 (float)fs->sum_weights) * 100);
596 } else {
597 printf("\t min file size = %llu\t(%s)\n", fs->minfilesize,
598 ffsb_printsize(buf, fs->minfilesize, 256));
599 printf("\t max file size = %llu\t(%s)\n", fs->maxfilesize,
600 ffsb_printsize(buf, fs->maxfilesize, 256));
601 }
602 printf("\t directio = %s\n", (fs->flags & FFSB_FS_DIRECTIO) ?
603 "on" : "off");
604 printf("\t alignedio = %s\n", (fs->flags & FFSB_FS_ALIGNIO4K) ?
605 "on" : "off");
606 printf("\t bufferedio = %s\n", (fs->flags & FFSB_FS_LIBCIO) ?
607 "on" : "off");
608 printf("\t\n");
609 printf("\t aging is %s\n", (fs->age_fs) ? "on" : "off");
610 printf("\t current utilization = %.2f\%\n",
611 getfsutil(fs->basedir) * 100);
612 if (fs->age_fs) {
613 printf("\t desired utilization = %.2lf%\n",
614 fs->desired_fsutil * 100);
615 printf("\t \n");
616 tg_print_config_aging(fs->aging_tg, fs->basedir);
617 }
618 printf("\t\n");
619 }
620
fs_needs_stats(ffsb_fs_t * fs,syscall_t sys)621 int fs_needs_stats(ffsb_fs_t * fs, syscall_t sys)
622 {
623 return (fs != NULL) ? (int)fs->fsd.config : 0;
624 }
625
fs_add_stat(ffsb_fs_t * fs,syscall_t sys,uint32_t val)626 void fs_add_stat(ffsb_fs_t * fs, syscall_t sys, uint32_t val)
627 {
628 if (fs)
629 ffsb_add_data(&fs->fsd, sys, val);
630 }
631