Home | History | Annotate | Download | only in fs_fill
      1 /*
      2  * Copyright (c) 2017 Cyril Hrubis <chrubis (at) suse.cz>
      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 the
     12  * 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, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 /*
     19  * Runs several threads that fills up the filesystem repeatedly.
     20  */
     21 
     22 #define _GNU_SOURCE
     23 
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <errno.h>
     27 #include <fcntl.h>
     28 #include <pthread.h>
     29 #include "tst_safe_pthread.h"
     30 #include "tst_test.h"
     31 
     32 #define MNTPOINT "mntpoint"
     33 
     34 static volatile int run;
     35 static unsigned int nthreads;
     36 static int enospc_cnt;
     37 static struct worker *workers;
     38 
     39 struct worker {
     40 	char dir[PATH_MAX];
     41 };
     42 
     43 static void *worker(void *p)
     44 {
     45 	struct worker *w = p;
     46 	DIR *d;
     47 	struct dirent *ent;
     48 	char file[PATH_MAX];
     49 
     50 	while (run) {
     51 		tst_fill_fs(w->dir, 0);
     52 
     53 		tst_atomic_inc(&enospc_cnt);
     54 
     55 		d = SAFE_OPENDIR(w->dir);
     56 		while ((ent = SAFE_READDIR(d))) {
     57 
     58 			if (!strcmp(ent->d_name, ".") ||
     59 			    !strcmp(ent->d_name, ".."))
     60 				continue;
     61 
     62 			snprintf(file, sizeof(file), "%s/%s",
     63 				 w->dir, ent->d_name);
     64 
     65 			tst_res(TINFO, "Unlinking %s", file);
     66 
     67 			SAFE_UNLINK(file);
     68 			break;
     69 		}
     70 		SAFE_CLOSEDIR(d);
     71 	}
     72 
     73 	return NULL;
     74 }
     75 
     76 static void testrun(void)
     77 {
     78 	pthread_t threads[nthreads];
     79 	unsigned int i, ms;
     80 
     81 	run = 1;
     82 	for (i = 0; i < nthreads; i++)
     83 		SAFE_PTHREAD_CREATE(&threads[i], NULL, worker, &workers[i]);
     84 
     85 	for (ms = 0; ; ms++) {
     86 		usleep(1000);
     87 
     88 		if (ms >= 1000 && enospc_cnt)
     89 			break;
     90 
     91 		if (enospc_cnt > 100)
     92 			break;
     93 	}
     94 
     95 	run = 0;
     96 	for (i = 0; i < nthreads; i++)
     97 		SAFE_PTHREAD_JOIN(threads[i], NULL);
     98 
     99 	tst_res(TPASS, "Got %i ENOSPC runtime %ims", enospc_cnt, ms);
    100 }
    101 
    102 static void setup(void)
    103 {
    104 	unsigned int i;
    105 
    106 	nthreads = tst_ncpus_conf() + 2;
    107 	workers = SAFE_MALLOC(sizeof(struct worker) * nthreads);
    108 
    109 	for (i = 0; i < nthreads; i++) {
    110 		snprintf(workers[i].dir, sizeof(workers[i].dir),
    111 			 MNTPOINT "/thread%i", i + 1);
    112 		SAFE_MKDIR(workers[i].dir, 0700);
    113 	}
    114 
    115 	tst_res(TINFO, "Running %i writer threads", nthreads);
    116 }
    117 
    118 static void cleanup(void)
    119 {
    120 	free(workers);
    121 }
    122 
    123 static struct tst_test test = {
    124 	.needs_root = 1,
    125 	.needs_tmpdir = 1,
    126 	.mount_device = 1,
    127 	.mntpoint = MNTPOINT,
    128 	.all_filesystems = 1,
    129 	.setup = setup,
    130 	.cleanup = cleanup,
    131 	.test_all = testrun,
    132 };
    133