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, &params);
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