From 2cd72ac0e054bb070cad880d0cc9366ebf08b3eb Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 28 Mar 2007 18:43:03 +0200 Subject: [PATCH] tests: add lock_mtab() performance and reliability test The test starts concurrently many processes that use lock_mtab() as lock for access to same file. Signed-off-by: Karel Zak --- mount/Makefile.am | 3 + mount/fstab.c | 117 +++++++++++++++++++++++++++++++ tests/Makefile.am | 3 +- tests/commands.sh.in | 2 + tests/expected/ts-mount-mtablock | 1 + tests/ts-mount-mtablock | 35 +++++++++ 6 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 tests/expected/ts-mount-mtablock create mode 100755 tests/ts-mount-mtablock diff --git a/mount/Makefile.am b/mount/Makefile.am index 605c4520..f34fc83b 100644 --- a/mount/Makefile.am +++ b/mount/Makefile.am @@ -48,6 +48,9 @@ sbin_PROGRAMS += pivot_root man_MANS += pivot_root.8 endif +noinst_PROGRAMS = mtab_lock_test +mtab_lock_test_SOURCES = fstab.c sundries.c xmalloc.c $(MNTHDRS) +mtab_lock_test_CFLAGS = -DMAIN_TEST_MTABLOCK swapon.c: swapargs.h diff --git a/mount/fstab.c b/mount/fstab.c index 2de44e68..2c00dea5 100644 --- a/mount/fstab.c +++ b/mount/fstab.c @@ -662,3 +662,120 @@ update_mtab (const char *dir, struct my_mntent *instead) { leave: unlock_mtab(); } + + +#ifdef MAIN_TEST_MTABLOCK + +/* + * This is mtab locking code test for: + * + * - performance (how many concurrent processes) + * + * - lock reliability (is possible to see corrupted data if more + * concurrent processes modify a same file) + * + * The test is very simple -- it reads a number from locked file, increments the + * number and writes the number back to the file. + */ + +/* dummy */ +int verbose; +int mount_quiet; +char *progname; + +const char *mount_get_volume_label_by_spec(const char *spec) { return NULL; } +const char *mount_get_devname_by_uuid(const char *uuid) { return NULL; } +struct my_mntent *my_getmntent (mntFILE *mfp) { return NULL; } +mntFILE *my_setmntent (const char *file, char *mode) { return NULL; } +void my_endmntent (mntFILE *mfp) { } +int my_addmntent (mntFILE *mfp, struct my_mntent *mnt) { return 0; } +char *myrealpath(const char *path, char *resolved_path, int m) { return NULL; } + +int +main(int argc, char **argv) +{ + time_t synctime; + char *filename; + int nloops, id, i; + pid_t pid = getpid(); + unsigned int usecs; + struct timeval tv; + struct stat st; + long last = 0; + + progname = argv[0]; + + if (argc < 3) + die(EXIT_FAILURE, + "usage: %s \n", + progname); + + id = atoi(argv[1]); + synctime = (time_t) atol(argv[2]); + filename = argv[3]; + nloops = atoi(argv[4]); + + if (stat(filename, &st) < -1) + die(EXIT_FAILURE, "%s: %s\n", filename, strerror(errno)); + + fprintf(stderr, "%05d (pid=%05d): START\n", id, pid); + + gettimeofday(&tv, NULL); + if (synctime && synctime - tv.tv_sec > 1) { + usecs = ((synctime - tv.tv_sec) * 1000000UL) - + (1000000UL - tv.tv_usec); + usleep(usecs); + } + + for (i = 0; i < nloops; i++) { + FILE *f; + long num; + char buf[256]; + + lock_mtab(); + + if (!(f = fopen(filename, "r"))) { + unlock_mtab(); + die(EXIT_FAILURE, "ERROR: %d (pid=%d, loop=%d): " + "open for read failed\n", id, pid, i); + } + if (!fgets(buf, sizeof(buf), f)) { + unlock_mtab(); + die(EXIT_FAILURE, "ERROR: %d (pid=%d, loop=%d): " + "read failed\n", id, pid, i); + } + fclose(f); + + num = atol(buf) + 1; + + if (!(f = fopen(filename, "w"))) { + unlock_mtab(); + die(EXIT_FAILURE, "ERROR: %d (pid=%d, loop=%d): " + "open for write failed\n", id, pid, i); + } + fprintf(f, "%ld", num); + fclose(f); + + unlock_mtab(); + + gettimeofday(&tv, NULL); + + fprintf(stderr, "%010ld.%06ld %04d (pid=%05d, loop=%05d): " + "num=%09ld last=%09ld\n", + tv.tv_sec, tv.tv_usec, id, + pid, i, num, last); + last = num; + + /* The mount command usually finish after mtab update. We + * simulate this via short sleep -- it's also enough to make + * concurrent processes happy. + */ + usleep(50000); + } + + fprintf(stderr, "%05d (pid=%05d): DONE\n", id, pid); + + exit(EXIT_SUCCESS); +} +#endif + diff --git a/tests/Makefile.am b/tests/Makefile.am index 1cf3101c..79b43d36 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -19,7 +19,8 @@ EXTRA_DIST = expected/* \ ts-look-separator \ ts-login-checktty \ ts-hwclock-systohc \ - ts-mount-special + ts-mount-special \ + ts-mount-mtablock distclean-local: rm -rf output diff diff --git a/tests/commands.sh.in b/tests/commands.sh.in index 44eca14a..9ed88a9c 100644 --- a/tests/commands.sh.in +++ b/tests/commands.sh.in @@ -11,6 +11,8 @@ TS_CMD_SWAPON=${TS_CMD_SWAPON:-"$TOPDIR/mount/swapon"} TS_CMD_SWAPOFF=${TS_CMD_SWAPOFF:-"$TOPDIR/mount/swapoff"} TS_CMD_LOSETUP=${TS_CMD_LOSETUP:-"$TOPDIR/mount/losetup"} +TS_CMD_MTABLOCK=${TS_CMD_MTABLOCK:-"$TOPDIR/mount/mtab_lock_test"} + TS_CMD_MKSWAP=${TS_CMD_MKSWAP:-"$TOPDIR/disk-utils/mkswap"} TS_CMD_MKCRAMFS=${TS_CMD_MKCRAMFS:-"$TOPDIR/disk-utils/mkfs.cramfs"} diff --git a/tests/expected/ts-mount-mtablock b/tests/expected/ts-mount-mtablock new file mode 100644 index 00000000..c5b431b6 --- /dev/null +++ b/tests/expected/ts-mount-mtablock @@ -0,0 +1 @@ +50 \ No newline at end of file diff --git a/tests/ts-mount-mtablock b/tests/ts-mount-mtablock new file mode 100755 index 00000000..44834dc3 --- /dev/null +++ b/tests/ts-mount-mtablock @@ -0,0 +1,35 @@ +#!/bin/bash + +. commands.sh +. functions.sh + +TS_COMPONENT="mount" +TS_DESC="mtablock" + +# +# Be careful with number of processes. Don't forget that there is time limit +# when the mount waits on the mtab lock. If you define too much processes some +# of them will fail with timeout. +# +# Note: the original version (< 2.13) of util-linux is completely useless for +# this test (maximum for this old version is NLOOPS=10 and NPROCESSES=5 (2-way +# 2GHz machine)). It has terrible performance due a bad timeouts implemntation +# in lock_mtab(). +# +NLOOPS=10 +NPROCESSES=5 + +ts_init + +> $TS_OUTPUT.debug +echo 0 > $TS_OUTPUT +SYNCTIME=$(( $(date +%s) + 10 )) + +for id in $(seq 0 $(( $NPROCESSES - 1 ))); do + $TS_CMD_MTABLOCK $id $SYNCTIME $TS_OUTPUT $NLOOPS >> $TS_OUTPUT.debug 2>&1 & +done + +wait + +ts_finalize + -- 2.39.5