Home | History | Annotate | Download | only in ffsb-6.0-rc2
      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 */
     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 */
     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 
     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 
     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 
    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 
    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 */
    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  */
    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 
    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 
    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 
    417 void fs_set_create_blocksize(ffsb_fs_t * fs, uint32_t blocksize)
    418 {
    419 	fs->create_blocksize = blocksize;
    420 }
    421 
    422 void fs_set_age_blocksize(ffsb_fs_t * fs, uint32_t blocksize)
    423 {
    424 	fs->age_blocksize = blocksize;
    425 }
    426 
    427 uint32_t fs_get_create_blocksize(ffsb_fs_t * fs)
    428 {
    429 	return fs->create_blocksize;
    430 }
    431 
    432 uint32_t fs_get_age_blocksize(ffsb_fs_t * fs)
    433 {
    434 	return fs->age_blocksize;
    435 }
    436 
    437 char *fs_get_basedir(ffsb_fs_t * fs)
    438 {
    439 	return fs->basedir;
    440 }
    441 
    442 uint32_t fs_get_numstartfiles(ffsb_fs_t * fs)
    443 {
    444 	return fs->num_start_files;
    445 }
    446 
    447 uint32_t fs_get_numdirs(ffsb_fs_t * fs)
    448 {
    449 	return fs->num_dirs;
    450 }
    451 
    452 int fs_get_libcio(ffsb_fs_t * fs)
    453 {
    454 	return fs->flags & FFSB_FS_LIBCIO;
    455 }
    456 
    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 
    465 int fs_get_directio(ffsb_fs_t * fs)
    466 {
    467 	return fs->flags & FFSB_FS_DIRECTIO;
    468 }
    469 
    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 
    478 int fs_get_alignio(ffsb_fs_t * fs)
    479 {
    480 	return fs->flags & FFSB_FS_ALIGNIO4K;
    481 }
    482 
    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 
    491 int fs_get_reuse_fs(ffsb_fs_t * fs)
    492 {
    493 	return fs->flags & FFSB_FS_REUSE_FS;
    494 }
    495 
    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 
    504 struct benchfiles *fs_get_datafiles(ffsb_fs_t * fs)
    505 {
    506 	return &fs->files;
    507 }
    508 
    509 struct benchfiles *fs_get_metafiles(ffsb_fs_t * fs)
    510 {
    511 	return &fs->meta;
    512 }
    513 
    514 struct benchfiles *fs_get_agefiles(ffsb_fs_t * fs)
    515 {
    516 	return &fs->fill;
    517 }
    518 
    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 
    526 struct ffsb_tg *fs_get_aging_tg(ffsb_fs_t * fs)
    527 {
    528 	return fs->aging_tg;
    529 }
    530 
    531 int fs_get_agefs(ffsb_fs_t * fs)
    532 {
    533 	return fs->age_fs;
    534 }
    535 
    536 /* TODO: Implement this!!!*/
    537 void fs_set_num_age_dirs(ffsb_fs_t * fs, uint32_t numdirs)
    538 {
    539 	fs->num_age_dirs = numdirs;
    540 }
    541 
    542 void fs_set_opdata(ffsb_fs_t * fs, void *data, unsigned opnum)
    543 {
    544 	fs->op_data[opnum] = data;
    545 }
    546 
    547 void *fs_get_opdata(ffsb_fs_t * fs, unsigned opnum)
    548 {
    549 	return fs->op_data[opnum];
    550 }
    551 
    552 void fs_set_min_filesize(ffsb_fs_t * fs, uint64_t size)
    553 {
    554 	fs->minfilesize = size;
    555 }
    556 
    557 void fs_set_max_filesize(ffsb_fs_t * fs, uint64_t size)
    558 {
    559 	fs->maxfilesize = size;
    560 }
    561 
    562 uint64_t fs_get_min_filesize(ffsb_fs_t * fs)
    563 {
    564 	return fs->minfilesize;
    565 }
    566 
    567 uint64_t fs_get_max_filesize(ffsb_fs_t * fs)
    568 {
    569 	return fs->maxfilesize;
    570 }
    571 
    572 double fs_get_desired_fsutil(ffsb_fs_t * fs)
    573 {
    574 	return fs->desired_fsutil;
    575 }
    576 
    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 
    621 int fs_needs_stats(ffsb_fs_t * fs, syscall_t sys)
    622 {
    623 	return (fs != NULL) ? (int)fs->fsd.config : 0;
    624 }
    625 
    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