diff options
Diffstat (limited to 'tests/fs-tests')
-rw-r--r-- | tests/fs-tests/integrity/integck.c | 167 |
1 files changed, 165 insertions, 2 deletions
diff --git a/tests/fs-tests/integrity/integck.c b/tests/fs-tests/integrity/integck.c index 7a4bcdc..9bf42af 100644 --- a/tests/fs-tests/integrity/integck.c +++ b/tests/fs-tests/integrity/integck.c @@ -67,6 +67,11 @@ static struct { * can_mmap: file-system supports share writable 'mmap()' operation * is_rootfs: the tested file-system the root file-system * fstype: file-system type (e.g., "ubifs") + * fsdev: the underlying device mounted by the tested file-system + * mount_opts: non-standard mount options of the tested file-system (non-standard + * options are stored in string form as a comma-separated list) + * mount_flags: standard mount options of the tested file-system (standard + * options as stored as a set of flags) * mount_point: tested file-system mount point path * test_dir: the directory on the tested file-system where we test */ @@ -78,6 +83,9 @@ static struct { unsigned int can_mmap:1; unsigned int is_rootfs:1; const char *fstype; + const char *fsdev; + const char *mount_opts; + unsigned long mount_flags; const char *mount_point; const char *test_dir; } fsinfo = { @@ -2011,6 +2019,98 @@ static void update_test_data(void) do_an_operation(); } +/** + * Re-mount the test file-system. This function randomly select how to + * re-mount. + */ +void remount_tested_fs(void) +{ + char *wd_save; + int ret; + unsigned long flags; + unsigned int rorw1, um, um_ro, um_rorw, rorw2; + + /* Save current working directory */ + wd_save = malloc(PATH_MAX + 1); + CHECK(wd_save != NULL); + CHECK(getcwd(wd_save, PATH_MAX + 1) != NULL); + + /* Temporarily change working directory to '/' */ + CHECK(chdir("/") == 0); + + /* Choose what to do */ + rorw1 = rand() & 1; + um = rand() & 1; + um_ro = rand() & 1; + um_rorw = rand() & 1; + rorw2 = rand() & 1; + + if (rorw1 + um + rorw2 == 0) + um = 1; + + if (rorw1) { + flags = fsinfo.mount_flags | MS_RDONLY | MS_REMOUNT; + ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype, + flags, fsinfo.mount_opts); + CHECK(ret == 0); + + flags = fsinfo.mount_flags | MS_REMOUNT; + flags &= ~((unsigned long)MS_RDONLY); + ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype, + flags, fsinfo.mount_opts); + CHECK(ret == 0); + } + + if (um) { + if (um_ro) { + flags = fsinfo.mount_flags | MS_RDONLY | MS_REMOUNT; + ret = mount(fsinfo.fsdev, fsinfo.mount_point, + fsinfo.fstype, flags, fsinfo.mount_opts); + CHECK(ret == 0); + } + + CHECK(umount(fsinfo.mount_point) != -1); + + if (!um_rorw) { + ret = mount(fsinfo.fsdev, fsinfo.mount_point, + fsinfo.fstype, fsinfo.mount_flags, + fsinfo.mount_opts); + CHECK(ret == 0); + } else { + ret = mount(fsinfo.fsdev, fsinfo.mount_point, + fsinfo.fstype, fsinfo.mount_flags | MS_RDONLY, + fsinfo.mount_opts); + CHECK(ret == 0); + + flags = fsinfo.mount_flags | MS_REMOUNT; + flags &= ~((unsigned long)MS_RDONLY); + ret = mount(fsinfo.fsdev, fsinfo.mount_point, + fsinfo.fstype, flags, fsinfo.mount_opts); + CHECK(ret == 0); + } + } + + if (rorw2) { + flags = fsinfo.mount_flags | MS_RDONLY | MS_REMOUNT; + ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype, + flags, fsinfo.mount_opts); + CHECK(ret == 0); + + flags = fsinfo.mount_flags | MS_REMOUNT; + flags &= ~((unsigned long)MS_RDONLY); + ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype, + flags, fsinfo.mount_opts); + CHECK(ret == 0); + } + + /* Restore the previous working directory */ + CHECK(chdir(wd_save) == 0); + free(wd_save); +} + +/* + * Perform the test. Returns zero on success and -1 on failure. + */ static int integck(void) { int64_t rpt; @@ -2030,7 +2130,7 @@ static int integck(void) if (fsinfo.is_rootfs) { close_open_files(); - tests_remount(); /* Requires root access */ + remount_tested_fs(); } /* Check everything */ @@ -2043,7 +2143,7 @@ static int integck(void) if (!fsinfo.is_rootfs) { close_open_files(); - tests_remount(); /* Requires root access */ + remount_tested_fs(); } /* Check everything */ @@ -2060,6 +2160,67 @@ static int integck(void) } /* + * This is a helper function for 'get_tested_fs_info()'. It parses file-system + * mount options string, extracts standard mount options from there, and saves + * them in the 'fsinfo.mount_flags' variable, and non-standard mount options + * are saved in the 'fsinfo.mount_opts' variable. The reason for this is that + * we want to preserve mount options when unmounting the file-system and + * mounting it again. This is because we cannot pass standard mount optins + * (like sync, ro, etc) as a string to the 'mount()' function, because it + * fails. It accepts standard mount options only as flags. And only the + * FS-specific mount options are accepted in form of a string. + */ +static void parse_mount_options(const char *mount_opts) +{ + char *tmp, *opts, *p; + const char *opt; + + /* + * We are going to use 'strtok()' which modifies the original string, + * so duplicate it. + */ + tmp = dup_string(mount_opts); + p = opts = calloc(1, strlen(mount_opts) + 1); + CHECK(opts != NULL); + + opt = strtok(tmp, ","); + while (opt) { + if (!strcmp(opt, "rw")) + ; + else if (!strcmp(opt, "ro")) + fsinfo.mount_flags |= MS_RDONLY; + else if (!strcmp(opt, "dirsync")) + fsinfo.mount_flags |= MS_DIRSYNC; + else if (!strcmp(opt, "noatime")) + fsinfo.mount_flags |= MS_NOATIME; + else if (!strcmp(opt, "nodiratime")) + fsinfo.mount_flags |= MS_NODIRATIME; + else if (!strcmp(opt, "noexec")) + fsinfo.mount_flags |= MS_NOEXEC; + else if (!strcmp(opt, "nosuid")) + fsinfo.mount_flags |= MS_NOSUID; + else if (!strcmp(opt, "relatime")) + fsinfo.mount_flags |= MS_RELATIME; + else if (!strcmp(opt, "sync")) + fsinfo.mount_flags |= MS_SYNCHRONOUS; + else { + int len = strlen(opt); + + if (p != opts) + *p++ = ','; + memcpy(p, opt, len); + p += len; + *p = '\0'; + } + + opt = strtok(NULL, ","); + } + + free(tmp); + fsinfo.mount_opts = opts; +} + +/* * Fill 'fsinfo' with information about the tested file-system. */ static void get_tested_fs_info(void) @@ -2104,6 +2265,8 @@ static void get_tested_fs_info(void) fclose(f); fsinfo.fstype = dup_string(mntent->mnt_type); + fsinfo.fsdev = strdup(mntent->mnt_fsname); + parse_mount_options(mntent->mnt_opts); /* Get memory page size for 'mmap()' */ fsinfo.page_size = sysconf(_SC_PAGE_SIZE); |