From 2044df660f193d6eb26e2e5121fb33d2f1dcc145 Mon Sep 17 00:00:00 2001 From: Nikolaus Rath Date: Mon, 10 Oct 2016 11:18:00 -0700 Subject: Fix race condition in notify_* examples The fix in commit cf4159156b was incomplete. While some false positives are caused by sleep() in the file system taking longer than expected, there was also a race condition where the file system would run before the contents are initialized properly. --- example/notify_inval_entry.c | 33 ++++++++++++++++++++------------- example/notify_inval_inode.c | 27 +++++++++++++++++---------- example/notify_store_retrieve.c | 27 +++++++++++++++++---------- test/test_examples.py | 21 ++++++++------------- 4 files changed, 62 insertions(+), 46 deletions(-) diff --git a/example/notify_inval_entry.c b/example/notify_inval_entry.c index d5da1c5..898eff1 100644 --- a/example/notify_inval_entry.c +++ b/example/notify_inval_entry.c @@ -232,23 +232,27 @@ static struct fuse_lowlevel_ops tfs_oper = { .forget = tfs_forget, }; -static void* update_fs(void *data) { - struct fuse_session *se = (struct fuse_session*) data; - struct tm *now; - char *old_name; +static void update_fs(void) { time_t t; + struct tm *now; ssize_t ret; - while(1) { - t = time(NULL); - now = localtime(&t); - assert(now != NULL); + t = time(NULL); + now = localtime(&t); + assert(now != NULL); - old_name = strdup(file_name); - ret = strftime(file_name, MAX_STR_LEN, - "Time_is_%Hh_%Mm_%Ss", now); - assert(ret != 0); + ret = strftime(file_name, MAX_STR_LEN, + "Time_is_%Hh_%Mm_%Ss", now); + assert(ret != 0); +} +static void* update_fs_loop(void *data) { + struct fuse_session *se = (struct fuse_session*) data; + char *old_name; + + while(1) { + old_name = strdup(file_name); + update_fs(); if (!options.no_notify && lookup_cnt) assert(fuse_lowlevel_notify_inval_entry (se, FUSE_ROOT_ID, old_name, strlen(old_name)) == 0); @@ -295,6 +299,9 @@ int main(int argc, char *argv[]) { goto err_out1; } + /* Initial contents */ + update_fs(); + se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL); if (se == NULL) @@ -309,7 +316,7 @@ int main(int argc, char *argv[]) { fuse_daemonize(opts.foreground); /* Start thread to update file contents */ - ret = pthread_create(&updater, NULL, update_fs, (void *)se); + ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se); if (ret != 0) { fprintf(stderr, "pthread_create failed with %s\n", strerror(ret)); diff --git a/example/notify_inval_inode.c b/example/notify_inval_inode.c index 9cd7e95..1b813a0 100644 --- a/example/notify_inval_inode.c +++ b/example/notify_inval_inode.c @@ -255,19 +255,23 @@ static struct fuse_lowlevel_ops tfs_oper = { .forget = tfs_forget, }; -static void* update_fs(void *data) { - struct fuse_session *se = (struct fuse_session*) data; +static void update_fs(void) { struct tm *now; time_t t; + t = time(NULL); + now = localtime(&t); + assert(now != NULL); - while(1) { - t = time(NULL); - now = localtime(&t); - assert(now != NULL); + file_size = strftime(file_contents, MAX_STR_LEN, + "The current time is %H:%M:%S\n", now); + assert(file_size != 0); +} - file_size = strftime(file_contents, MAX_STR_LEN, - "The current time is %H:%M:%S\n", now); - assert(file_size != 0); +static void* update_fs_loop(void *data) { + struct fuse_session *se = (struct fuse_session*) data; + + while(1) { + update_fs(); if (!options.no_notify && lookup_cnt) { /* Only send notification if the kernel is aware of the inode */ @@ -318,6 +322,9 @@ int main(int argc, char *argv[]) { goto err_out1; } + /* Initial contents */ + update_fs(); + se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL); if (se == NULL) @@ -332,7 +339,7 @@ int main(int argc, char *argv[]) { fuse_daemonize(opts.foreground); /* Start thread to update file contents */ - ret = pthread_create(&updater, NULL, update_fs, (void *)se); + ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se); if (ret != 0) { fprintf(stderr, "pthread_create failed with %s\n", strerror(ret)); diff --git a/example/notify_store_retrieve.c b/example/notify_store_retrieve.c index cc7e865..76f3291 100644 --- a/example/notify_store_retrieve.c +++ b/example/notify_store_retrieve.c @@ -286,20 +286,24 @@ static struct fuse_lowlevel_ops tfs_oper = { .retrieve_reply = tfs_retrieve_reply, }; -static void* update_fs(void *data) { - struct fuse_session *se = (struct fuse_session*) data; +static void update_fs(void) { struct tm *now; time_t t; + t = time(NULL); + now = localtime(&t); + assert(now != NULL); + + file_size = strftime(file_contents, MAX_STR_LEN, + "The current time is %H:%M:%S\n", now); + assert(file_size != 0); +} + +static void* update_fs_loop(void *data) { + struct fuse_session *se = (struct fuse_session*) data; struct fuse_bufvec bufv; while(1) { - t = time(NULL); - now = localtime(&t); - assert(now != NULL); - - file_size = strftime(file_contents, MAX_STR_LEN, - "The current time is %H:%M:%S\n", now); - assert(file_size != 0); + update_fs(); if (!options.no_notify && lookup_cnt) { /* Only send notification if the kernel is aware of the inode */ @@ -361,6 +365,9 @@ int main(int argc, char *argv[]) { goto err_out1; } + /* Initial contents */ + update_fs(); + se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL); if (se == NULL) @@ -375,7 +382,7 @@ int main(int argc, char *argv[]) { fuse_daemonize(opts.foreground); /* Start thread to update file contents */ - ret = pthread_create(&updater, NULL, update_fs, (void *)se); + ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se); if (ret != 0) { fprintf(stderr, "pthread_create failed with %s\n", strerror(ret)); diff --git a/test/test_examples.py b/test/test_examples.py index 2990d25..e0f9be4 100755 --- a/test/test_examples.py +++ b/test/test_examples.py @@ -151,21 +151,16 @@ def test_notify1(tmpdir, name, options, notify): mnt_dir = str(tmpdir) cmdline = base_cmdline + \ [ pjoin(basename, 'example', name), - '-f', '--update-interval=2', mnt_dir ] + options + '-f', '--update-interval=1', mnt_dir ] + options if not notify: cmdline.append('--no-notify') mount_process = subprocess.Popen(cmdline) try: wait_for_mount(mount_process, mnt_dir) filename = pjoin(mnt_dir, 'current_time') - # Wait until first update - while True: - with open(filename, 'r') as fh: - read1 = fh.read() - if read1: - break - safe_sleep(2) - safe_sleep(6) + with open(filename, 'r') as fh: + read1 = fh.read() + safe_sleep(2) with open(filename, 'r') as fh: read2 = fh.read() if notify: @@ -183,8 +178,8 @@ def test_notify_inval_entry(tmpdir, notify): mnt_dir = str(tmpdir) cmdline = base_cmdline + \ [ pjoin(basename, 'example', 'notify_inval_entry'), - '-f', '--update-interval=2', - '--timeout=10', mnt_dir ] + '-f', '--update-interval=1', + '--timeout=5', mnt_dir ] if not notify: cmdline.append('--no-notify') mount_process = subprocess.Popen(cmdline) @@ -199,10 +194,10 @@ def test_notify_inval_entry(tmpdir, notify): fname = pjoin(mnt_dir, os.listdir(mnt_dir)[0]) os.stat(fname) - safe_sleep(4) + safe_sleep(2) if not notify: os.stat(fname) - safe_sleep(10) + safe_sleep(5) with pytest.raises(FileNotFoundError): os.stat(fname) except: -- cgit v1.2.3