This patch adds a "-D" switch to fsstress so that every time we call readdir, we stat the dentry & compare it's st_mode to the d_type. If -D is specified only once, it ignores DT_UNKNOWN. If specified twice, it considers DT_UNKNOWN to be an error. It skips paths of "./." and "./.." so that we only look at files newly created within the filesystem. This could be used in an xfstest; it's noisy on a failures so would break expected output. Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx> --- fsstress doesn't usually do validation, but it's such a handy framework for creating a ton of random files, this seems like an ok place to put it. What do folks think? diff --git a/ltp/fsstress.c b/ltp/fsstress.c index 5d5611f..711ea9a 100644 --- a/ltp/fsstress.c +++ b/ltp/fsstress.c @@ -246,6 +246,7 @@ int rtpct; unsigned long seed = 0; ino_t top_ino; int verbose = 0; +int verify_d_type = 0; sig_atomic_t should_stop = 0; char *execute_cmd = NULL; int execute_freq = 1; @@ -315,7 +316,7 @@ int main(int argc, char **argv) int nousage = 0; xfs_error_injection_t err_inj; struct sigaction action; - const char *allopts = "d:e:f:i:m:M:n:o:p:rs:S:vwx:X:zH"; + const char *allopts = "d:De:f:i:m:M:n:o:p:rs:S:vwx:X:zH"; errrange = errtag = 0; umask(0); @@ -327,6 +328,9 @@ int main(int argc, char **argv) case 'd': dirname = optarg; break; + case 'D': + verify_d_type++; + break; case 'e': sscanf(optarg, "%d", &errtag); if (errtag < 0) { @@ -1491,6 +1495,7 @@ usage(void) printf(" [-p nproc][-r len][-s seed][-v][-w][-x cmd][-z][-S][-X ncmd]\n"); printf("where\n"); printf(" -d dir specifies the base directory for operations\n"); + printf(" -D verify d_type in any readdir operations, 2x to disallow DT_UNKNOWN\n"); printf(" -e errtg specifies error injection stuff\n"); printf(" -f op_name=freq changes the frequency of option name to freq\n"); printf(" the valid operation names are:\n"); @@ -2338,12 +2343,71 @@ getattr_f(int opno, long r) close(fd); } +void test_d_type(int opno, pathname_t *f, struct dirent64 *de) +{ + struct stat64 sb; + char path[PATH_MAX]; + + snprintf(path, PATH_MAX, "%s/%s", f->path, de->d_name); + + /* Don't check ./. or ./.. */ + if (!strncmp(path, "./.", 3)) + return; + + if (lstat64(path, &sb)) { + printf("%d/%d: getdents - can't stat %s\n", + procid, opno, path); + } else { + int bad_d_type = 0; + + switch (de->d_type) { + case DT_BLK: + if (!S_ISBLK(sb.st_mode)) + bad_d_type++; + break; + case DT_CHR: + if (!S_ISCHR(sb.st_mode)) + bad_d_type++; + break; + case DT_DIR: + if (!S_ISDIR(sb.st_mode)) + bad_d_type++; + break; + case DT_FIFO: + if (!S_ISFIFO(sb.st_mode)) + bad_d_type++; + break; + case DT_LNK: + if (!S_ISLNK(sb.st_mode)) + bad_d_type++; + break; + case DT_REG: + if (!S_ISREG(sb.st_mode)) + bad_d_type++; + break; + case DT_SOCK: + if (!S_ISSOCK(sb.st_mode)) + bad_d_type++; + break; + case DT_UNKNOWN: + if (verify_d_type > 1) + bad_d_type++; + break; + } + if (bad_d_type) + printf("%d/%d: getdents - bad d_type %d for %s\n", + procid, opno, de->d_type, path); + + } +} + void getdents_f(int opno, long r) { DIR *dir; pathname_t f; int v; + struct dirent64 *de; init_pathname(&f); if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v)) @@ -2357,8 +2421,11 @@ getdents_f(int opno, long r) free_pathname(&f); return; } - while (readdir64(dir) != NULL) + while ((de = readdir64(dir)) != NULL) { + if (verify_d_type) + test_d_type(opno, &f, de); continue; + } if (v) printf("%d/%d: getdents %s 0\n", procid, opno, f.path); free_pathname(&f); _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs