diff options
author | Poornima G <pgurusid@redhat.com> | 2016-06-06 06:29:40 -0400 |
---|---|---|
committer | Jeff Darcy <jdarcy@redhat.com> | 2016-06-17 04:35:25 -0700 |
commit | cf1e98ff5bf8233803b4f74debee1b1f474765af (patch) | |
tree | f175b10113ddeefa6541ffc79afeda068381f2f9 /tests/bugs/libgfapi/bug-1093594.c | |
parent | 1d42e5e2312a8de45d9c83350f3e3260afba03ae (diff) |
gfapi: Fix IO error caused when there is consecutive graph switches
Backport of http://review.gluster.org/#/c/14656/
Issue:
Consider a simple situation, where glfs_init() is done, i.e. initial
graph is up. Now perform 2 volume sets that results in 2 client side
graph changes. After this perform some IO, the IO fails with ENOTCON.
The only way to recover this client is i guess another graph switch
or restart.
What actually is happening from code perspective:
Initial graph lets say A, followed by 2 consecutive graph switches
to B and C without any IO those two switches.
- graph_setup (A) as a result of GF_EVENT_CHILD_UP, and
fs->next_subvol = A
- glfs_init() results in fs->active_subvol = A, fs->next_subvol = NULL
- graph_setup (B) as a result of GF_EVENT_CHILD_UP, and
fs->next_subvol = B
- graph_setup (C) as a result of GF_EVENT_CHILD_UP, and
fs->next_subvol = C. It also sees that the previous graph B was never
set as fs->active_subvol, i.e. no IO or anything happened on B, so
can safely send GF_EVENT_PARENT_DOWN (by calling glfs_subvol_done(B)).
This parent down on B, results in child_down(B), which is fine.
But child_down also triggers graph_setup(B).
- graph_setup(B) as a result of GF_EVENT_CHILD_DOWN, and
fs->next_subvol = B, and GF_EVENT_PARENT_DOWN on C as explained
above. This again leads to GF_EVENT_CHILD_DOWN on C.
- graph_setup(C) as a result of GF_EVENT_CHILD_DOWN, and
fs->next_subvol = C, and GF_EVENT_PARENT_DOWN on B as explained
above.
Thus both the graphs B and C are disconnected, and hence the ENOTCON
Solution:
Remove the call to graph_setup() when the event is GF_EVENT_CHILD_DOWN.
It don't see any reason why graph_setup should be called when there is
child_down. Not sure what the original reason was, to have graph_setup
in child_down. git hostory shows the first patch itself had this call.
Change-Id: I9de86555f66cc94a05649ac863b40ed3426ffd4b
BUG: 1347489
Signed-off-by: Poornima G <pgurusid@redhat.com>
Reviewed-on: http://review.gluster.org/14656
Smoke: Gluster Build System <jenkins@build.gluster.org>
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
Reviewed-by: Jeff Darcy <jdarcy@redhat.com>
(cherry picked from commit b8ac20e888fbacad9d90cd8f1c6ff8579a5cefe9)
Reviewed-on: http://review.gluster.org/14747
Diffstat (limited to 'tests/bugs/libgfapi/bug-1093594.c')
-rw-r--r-- | tests/bugs/libgfapi/bug-1093594.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/tests/bugs/libgfapi/bug-1093594.c b/tests/bugs/libgfapi/bug-1093594.c new file mode 100644 index 00000000000..8f5aa9be66c --- /dev/null +++ b/tests/bugs/libgfapi/bug-1093594.c @@ -0,0 +1,315 @@ +#include "../../api/src/glfs.h" +#include "../../api/src/glfs-handles.h" +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define WRITE_SIZE (128*1024) +#define READ_WRITE_LOOP 100 +#define FOP_LOOP_COUNT 20 +#define TEST_CASE_LOOP 20 + +int gfapi = 1; +static int extension = 1; + +static int +large_number_of_fops (glfs_t *fs) { + int ret = 0; + int i = 0; + glfs_fd_t *fd = NULL; + glfs_fd_t *fd1 = NULL; + char *dir1 = NULL, *dir2 = NULL, *filename1 = NULL, *filename2 = NULL; + char *buf = NULL; + struct stat sb = {0, }; + + for (i = 0 ; i < FOP_LOOP_COUNT ; i++) { + ret = asprintf (&dir1, "dir%d", extension); + if (ret < 0) { + fprintf (stderr, "cannot construct filename (%s)", + strerror (errno)); + return ret; + } + + extension++; + + ret = glfs_mkdir (fs, dir1, 0755); + if (ret < 0) { + fprintf (stderr, "mkdir(%s): %s\n", dir1, strerror (errno)); + return -1; + } + + fd = glfs_opendir (fs, dir1); + if (!fd) { + fprintf (stderr, "/: %s\n", strerror (errno)); + return -1; + } + + ret = glfs_fsetxattr (fd, "user.dirfattr", "fsetxattr", 8, 0); + if (ret < 0) { + fprintf (stderr, "fsetxattr(%s): %d (%s)\n", dir1, ret, + strerror (errno)); + return -1; + } + + ret = glfs_closedir (fd); + if (ret < 0) { + fprintf (stderr, "glfs_closedir failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + + ret = glfs_rmdir (fs, dir1); + if (ret < 0) { + fprintf (stderr, "glfs_unlink failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + + ret = asprintf (&filename1, "file%d", extension); + if (ret < 0) { + fprintf (stderr, "cannot construct filename (%s)", + strerror (errno)); + return ret; + } + + ret = asprintf (&filename2, "file-%d", extension); + if (ret < 0) { + fprintf (stderr, "cannot construct filename (%s)", + strerror (errno)); + return ret; + } + + extension++; + + fd = glfs_creat (fs, filename1, O_RDWR, 0644); + if (!fd) { + fprintf (stderr, "%s: (%p) %s\n", filename1, fd, + strerror (errno)); + return -1; + } + + ret = glfs_rename (fs, filename1, filename2); + if (ret < 0) { + fprintf (stderr, "glfs_rename failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + + ret = glfs_lstat (fs, filename2, &sb); + if (ret < 0) { + fprintf (stderr, "glfs_lstat failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + + ret = glfs_close (fd); + if (ret < 0) { + fprintf (stderr, "glfs_close failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + + ret = glfs_unlink (fs, filename2); + if (ret < 0) { + fprintf (stderr, "glfs_unlink failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + } +} + +static int +large_read_write (glfs_t *fs) { + + int ret = 0; + int j = 0; + glfs_fd_t *fd = NULL; + glfs_fd_t *fd1 = NULL; + char *filename = NULL; + char *buf = NULL; + + ret = asprintf (&filename, "filerw%d", extension); + if (ret < 0) { + fprintf (stderr, "cannot construct filename (%s)", + strerror (errno)); + return ret; + } + + extension++; + + fd = glfs_creat (fs, filename, O_RDWR, 0644); + if (!fd) { + fprintf (stderr, "%s: (%p) %s\n", filename, fd, + strerror (errno)); + return -1; + } + + buf = (char *) malloc (WRITE_SIZE); + memset (buf, '-', WRITE_SIZE); + + for (j = 0; j < READ_WRITE_LOOP; j++) { + ret = glfs_write (fd, buf, WRITE_SIZE, 0); + if (ret < 0) { + fprintf (stderr, "Write(%s): %d (%s)\n", filename, ret, + strerror (errno)); + return ret; + } + } + + fd1 = glfs_open (fs, filename, O_RDWR); + if (fd1 < 0) { + fprintf (stderr, "Open(%s): %d (%s)\n", filename, ret, + strerror (errno)); + return -1; + } + + glfs_lseek (fd1, 0, SEEK_SET); + for (j = 0; j < READ_WRITE_LOOP; j++) { + ret = glfs_read (fd1, buf, WRITE_SIZE, 0); + if (ret < 0) { + fprintf (stderr, "Read(%s): %d (%s)\n", filename, ret, + strerror (errno)); + return ret; + } + } + + for (j = 0; j < READ_WRITE_LOOP; j++) { + ret = glfs_write (fd1, buf, WRITE_SIZE, 0); + if (ret < 0) { + fprintf (stderr, "Write(%s): %d (%s)\n", filename, ret, + strerror (errno)); + return ret; + } + } + + glfs_close (fd); + glfs_close (fd1); + ret = glfs_unlink (fs, filename); + if (ret < 0) { + fprintf (stderr, "glfs_unlink failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + + free (buf); + free (filename); +} + +static int +volfile_change (const char *volname) { + int ret = 0; + char *cmd = NULL, *cmd1 = NULL; + + ret = asprintf (&cmd, "gluster volume set %s stat-prefetch off", + volname); + if (ret < 0) { + fprintf (stderr, "cannot construct cli command string (%s)", + strerror (errno)); + return ret; + } + + ret = asprintf (&cmd1, "gluster volume set %s stat-prefetch on", + volname); + if (ret < 0) { + fprintf (stderr, "cannot construct cli command string (%s)", + strerror (errno)); + return ret; + } + + ret = system (cmd); + if (ret < 0) { + fprintf (stderr, "stat-prefetch off on (%s) failed", volname); + return ret; + } + + ret = system (cmd1); + if (ret < 0) { + fprintf (stderr, "stat-prefetch on on (%s) failed", volname); + return ret; + } + + free (cmd); + free (cmd1); + return ret; +} + +int +main (int argc, char *argv[]) +{ + glfs_t *fs = NULL; + int ret = 0; + int i = 0; + glfs_fd_t *fd = NULL; + glfs_fd_t *fd1 = NULL; + char *topdir = "topdir", *filename = "file1"; + char *buf = NULL; + char *logfile = NULL; + + if (argc != 3) { + fprintf (stderr, + "Expect following args %s <Vol> <log file>\n" + , argv[0]); + return -1; + } + + logfile = argv[2]; + + for (i = 0; i < TEST_CASE_LOOP; i++) { + fs = glfs_new (argv[1]); + if (!fs) { + fprintf (stderr, "glfs_new: returned NULL (%s)\n", + strerror (errno)); + return -1; + } + + ret = glfs_set_volfile_server (fs, "tcp", "localhost", 24007); + if (ret < 0) { + fprintf (stderr, "glfs_set_volfile_server failed ret:%d (%s)\n", + ret, strerror (errno)); + return -1; + } + + ret = glfs_set_logging (fs, logfile, 7); + if (ret < 0) { + fprintf (stderr, "glfs_set_logging failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + + ret = glfs_init (fs); + if (ret < 0) { + fprintf (stderr, "glfs_init failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + + ret = large_number_of_fops (fs); + if (ret < 0) + return -1; + + ret = large_read_write (fs); + if (ret < 0) + return -1; + + ret = volfile_change (argv[1]); + if (ret < 0) + return -1; + + ret = large_number_of_fops (fs); + if (ret < 0) + return -1; + + ret = large_read_write (fs); + if (ret < 0) + return -1; + + ret = glfs_fini (fs); + if (ret < 0) { + fprintf (stderr, "glfs_fini failed with ret: %d (%s)\n", + ret, strerror (errno)); + return -1; + } + } + return 0; +} |