diff options
| author | Anuradha <atalur@redhat.com> | 2015-01-05 16:37:07 +0530 | 
|---|---|---|
| committer | Raghavendra Bhat <raghavendra@redhat.com> | 2015-01-06 02:04:49 -0800 | 
| commit | 59ba78ae1461651e290ce72013786d828545d4c1 (patch) | |
| tree | 19bc7b37b3d2fff0cd2870acc8d1cd7e93d3f470 | |
| parent | 50952cda111c84c966dc0427bbdb618e31bf8d78 (diff) | |
afr : glfs-heal implementation
    Backport of http://review.gluster.org/6529
and http://review.gluster.org/9119
Change-Id: Ie420efcb399b5119c61f448b421979c228b27b15
BUG: 1173528
Signed-off-by: Anuradha <atalur@redhat.com>
Reviewed-on: http://review.gluster.org/9335
Reviewed-by: Ravishankar N <ravishankar@redhat.com>
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Raghavendra Bhat <raghavendra@redhat.com>
| -rw-r--r-- | Makefile.am | 3 | ||||
| -rw-r--r-- | cli/src/cli-cmd-volume.c | 33 | ||||
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | glusterfs.spec.in | 1 | ||||
| -rw-r--r-- | heal/Makefile.am | 3 | ||||
| -rw-r--r-- | heal/src/Makefile.am | 30 | ||||
| -rw-r--r-- | heal/src/glfs-heal.c | 522 | ||||
| -rw-r--r-- | libglusterfs/src/common-utils.h | 1 | ||||
| -rw-r--r-- | libglusterfs/src/glusterfs.h | 2 | ||||
| -rw-r--r-- | tests/basic/afr/self-heald.t | 184 | ||||
| -rw-r--r-- | tests/basic/self-heald.t | 44 | ||||
| -rw-r--r-- | tests/bugs/bug-880898.t | 4 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-common.c | 313 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-inode-read.c | 5 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-common.c | 21 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-data.c | 24 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-entry.c | 25 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-metadata.c | 9 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heal.h | 29 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heald.c | 2 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heald.h | 6 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr.h | 4 | 
22 files changed, 1177 insertions, 90 deletions
diff --git a/Makefile.am b/Makefile.am index 7bb4b96da2f..187bfd5ed16 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,9 +10,8 @@ EXTRA_DIST = autogen.sh \  	$(shell find $(top_srcdir)/tests -type f -print)  SUBDIRS = $(ARGP_STANDALONE_DIR) libglusterfs rpc api xlators glusterfsd \ -	$(FUSERMOUNT_SUBDIR) doc extras cli @SYNCDAEMON_SUBDIR@ \ +	$(FUSERMOUNT_SUBDIR) doc extras cli heal @SYNCDAEMON_SUBDIR@ \  	@UMOUNTD_SUBDIR@ -	  pkgconfigdir = @pkgconfigdir@  pkgconfig_DATA = glusterfs-api.pc libgfchangelog.pc diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index df9d0c2ad62..84209adf936 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -16,6 +16,7 @@  #include <sys/socket.h>  #include <netdb.h>  #include <sys/types.h> +#include <sys/wait.h>  #include <netinet/in.h>  #ifndef _CONFIG_H @@ -2093,6 +2094,10 @@ cli_cmd_volume_heal_cbk (struct cli_state *state, struct cli_cmd_word *word,          dict_t                  *options = NULL;          xlator_t                *this = NULL;          cli_local_t             *local = NULL; +        int                     heal_op = 0; +        runner_t                runner = {0}; +        char                    buff[PATH_MAX] = {0}; +        char                    *out = NULL;          this = THIS;          frame = create_frame (this, this->ctx->pool); @@ -2111,13 +2116,33 @@ cli_cmd_volume_heal_cbk (struct cli_state *state, struct cli_cmd_word *word,                  parse_error = 1;                  goto out;          } +        ret = dict_get_int32 (options, "heal-op", &heal_op); +        if (ret < 0) +                goto out; -        proc = &cli_rpc_prog->proctable[GLUSTER_CLI_HEAL_VOLUME]; +        if (heal_op == GF_AFR_OP_INDEX_SUMMARY) { +                runinit (&runner); +                runner_add_args (&runner, SBIN_DIR"/glfsheal", words[2], NULL); +                runner_redir (&runner, STDOUT_FILENO, RUN_PIPE); +                ret = runner_start (&runner); +                if (ret == -1) +                        goto out; +                while ((out = fgets(buff, sizeof(buff), +                                   runner_chio (&runner, STDOUT_FILENO)))) { +                        printf ("%s", out); +                } -        CLI_LOCAL_INIT (local, words, frame, options); +                ret = runner_end (&runner); +                ret = WEXITSTATUS (ret); +        } +        else { +                proc = &cli_rpc_prog->proctable[GLUSTER_CLI_HEAL_VOLUME]; -        if (proc->fn) { -                ret = proc->fn (frame, THIS, options); +                CLI_LOCAL_INIT (local, words, frame, options); + +                if (proc->fn) { +                        ret = proc->fn (frame, THIS, options); +                }          }  out: diff --git a/configure.ac b/configure.ac index f18238355bd..b809bc10c11 100644 --- a/configure.ac +++ b/configure.ac @@ -211,6 +211,8 @@ AC_CONFIG_FILES([Makefile                  geo-replication/Makefile                  geo-replication/src/Makefile                  geo-replication/syncdaemon/Makefile +                heal/Makefile +                heal/src/Makefile                  glusterfs.spec])  AC_CANONICAL_HOST diff --git a/glusterfs.spec.in b/glusterfs.spec.in index f373b457dd8..09ffdc85fd1 100644 --- a/glusterfs.spec.in +++ b/glusterfs.spec.in @@ -991,6 +991,7 @@ fi  %endif  # binaries  %{_sbindir}/glusterd +%{_sbindir}/glfsheal  %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/storage*  %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/posix*  %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/protocol/server* diff --git a/heal/Makefile.am b/heal/Makefile.am new file mode 100644 index 00000000000..a985f42a877 --- /dev/null +++ b/heal/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/heal/src/Makefile.am b/heal/src/Makefile.am new file mode 100644 index 00000000000..a91c5d2877e --- /dev/null +++ b/heal/src/Makefile.am @@ -0,0 +1,30 @@ +sbin_PROGRAMS = glfsheal + +glfsheal_SOURCES = glfs-heal.c + +glfsheal_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la $(GF_LDADD)\ +		$(RLLIBS) $(top_builddir)/rpc/xdr/src/libgfxdr.la \ +		$(top_builddir)/rpc/rpc-lib/src/libgfrpc.la \ +		$(top_builddir)/api/src/libgfapi.la \ +		$(GF_GLUSTERFS_LIBS) $(XML_LIBS) + +glfsheal_LDFLAGS = $(GF_LDFLAGS) + +AM_CPPFLAGS = $(GF_CPPFLAGS) \ +	-I$(top_srcdir)/xlators/lib/src\ +	-I$(top_srcdir)/libglusterfs/src -I$(top_srcdir)/rpc/rpc-lib/src\ +	-I$(top_srcdir)/rpc/xdr/src\ +	-I$(top_srcdir)/api/src\ +	-I$(top_srcdir)/contrib/argp-standalone\ +	-DDATADIR=\"$(localstatedir)\" \ +	-DCONFDIR=\"$(sysconfdir)/glusterfs\" \ +	-DGSYNCD_PREFIX=\"$(libexecdir)/glusterfs\"\ +	-DSYNCDAEMON_COMPILE=$(SYNCDAEMON_COMPILE) -DSBIN_DIR=\"$(sbindir)\"\ +	$(XML_CPPFLAGS) + +AM_CFLAGS = -Wall $(GF_GLUSTERFS_CFLAGS) + +CLEANFILES = + +$(top_builddir)/libglusterfs/src/libglusterfs.la: +	$(MAKE) -C $(top_builddir)/libglusterfs/src/ all diff --git a/heal/src/glfs-heal.c b/heal/src/glfs-heal.c new file mode 100644 index 00000000000..4aa8d58ed57 --- /dev/null +++ b/heal/src/glfs-heal.c @@ -0,0 +1,522 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include "glfs.h" +#include "glfs-handles.h" +#include "glfs-internal.h" +#include "syncop.h" +#include <string.h> +#include <time.h> + +#define DEFAULT_HEAL_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs" + +int +glfsh_link_inode_update_loc (loc_t *loc, struct iatt *iattr) +{ +        inode_t       *link_inode = NULL; +        int           ret = -1; + +        link_inode = inode_link (loc->inode, NULL, NULL, iattr); +        if (link_inode == NULL) +                goto out; + +        inode_unref (loc->inode); +        loc->inode = link_inode; +        ret = 0; +out: +        return ret; +} + +extern int glfs_loc_touchup (loc_t *); +xlator_t *glfs_active_subvol (struct glfs *); +void glfs_subvol_done (struct glfs *, xlator_t *); + +int +glfsh_get_index_dir_loc (loc_t *rootloc, xlator_t *xl, loc_t *dirloc, +                         int32_t *op_errno) +{ +        void      *index_gfid = NULL; +        int       ret = 0; +        dict_t    *xattr = NULL; +        struct iatt   iattr = {0}; +        struct iatt   parent = {0}; + +        ret = syncop_getxattr (xl, rootloc, &xattr, GF_XATTROP_INDEX_GFID); +        if (ret < 0) { +                *op_errno = -ret; +                goto out; +        } + +        ret = dict_get_ptr (xattr, GF_XATTROP_INDEX_GFID, &index_gfid); +        if (ret < 0) { +                *op_errno = EINVAL; +                goto out; +        } + +        uuid_copy (dirloc->gfid, index_gfid); +        dirloc->path = ""; +        dirloc->inode = inode_new (rootloc->inode->table); +        ret = syncop_lookup (xl, dirloc, NULL, +                             &iattr, NULL, &parent); +        dirloc->path = NULL; +        if (ret < 0) { +                *op_errno = -ret; +                goto out; +        } +        ret = glfsh_link_inode_update_loc (dirloc, &iattr); +        if (ret) +                goto out; +        glfs_loc_touchup (dirloc); + +        ret = 0; +out: +        if (xattr) +                dict_unref (xattr); +        return ret; +} + +static xlator_t* +_get_afr_ancestor (xlator_t *xl) +{ +        if (!xl || !xl->parents) +                return NULL; + +        while (xl->parents) { +                xl = xl->parents->xlator; +                if (!xl) +                        break; +                if (strcmp (xl->type, "cluster/replicate") == 0) +                        return xl; +        } + +        return NULL; +} + +int +glfsh_index_purge (xlator_t *subvol, inode_t *inode, char *name) +{ +        loc_t loc = {0, }; +        int ret = 0; + +        loc.parent = inode_ref (inode); +        loc.name = name; + +        ret = syncop_unlink (subvol, &loc); + +        loc_wipe (&loc); +        return ret; +} + +int +glfsh_gfid_to_path (xlator_t *this, xlator_t *subvol, uuid_t gfid, char **path_p) +{ +        int      ret   = 0; +        char    *path  = NULL; +        loc_t    loc   = {0,}; +        dict_t  *xattr = NULL; + +        uuid_copy (loc.gfid, gfid); +        loc.inode = inode_new (this->itable); + +        ret = syncop_getxattr (subvol, &loc, &xattr, GFID_TO_PATH_KEY); +        if (ret) +                goto out; + +        ret = dict_get_str (xattr, GFID_TO_PATH_KEY, &path); +        if (ret || !path) { +                ret = -EINVAL; +                goto out; +        } + +        *path_p = gf_strdup (path); +        if (!*path_p) { +                ret = -ENOMEM; +                goto out; +        } + +        ret = 0; + +out: +        if (xattr) +                dict_unref (xattr); +        loc_wipe (&loc); + +        return ret; +} + +void +glfsh_print_heal_status (dict_t *dict, char *path, uuid_t gfid, +                         uint64_t *num_entries) +{ +       char *value  = NULL; +       int   ret    = 0; +       char *status = NULL; + +       ret = dict_get_str (dict, "heal-info", &value); +       if (ret || (!strcmp (value, "no-heal"))) +               return; + +       (*num_entries)++; +       if (!strcmp (value, "heal")) { +               ret = gf_asprintf (&status, " "); +       } else if (!strcmp (value, "possibly-healing")) { +               ret = gf_asprintf (&status, " - Possibly undergoing heal\n"); +       } else if (!strcmp (value, "split-brain")) { +               ret = gf_asprintf (&status, " - Is in split-brain\n"); +       } +       if (ret == -1) +               status = NULL; + +       printf ("%s%s\n", +               path ? path : uuid_utoa (gfid), +               status); + +       if (status) +               GF_FREE (status); +       return; +} + +static int +glfsh_process_entries (xlator_t *xl, fd_t *fd, gf_dirent_t *entries, +                       uint64_t *offset, uint64_t *num_entries) +{ +        gf_dirent_t      *entry = NULL; +        gf_dirent_t      *tmp = NULL; +        int              ret = 0; +        char            *path = NULL; +        uuid_t          gfid = {0}; +        xlator_t        *this = NULL; +        dict_t          *dict = NULL; +        loc_t           loc   = {0,}; +        this = THIS; + +        list_for_each_entry_safe (entry, tmp, &entries->list, list) { +                *offset = entry->d_off; +                if ((strcmp (entry->d_name, ".") == 0) || +                    (strcmp (entry->d_name, "..") == 0)) +                        continue; + +                if (dict) { +                        dict_unref (dict); +                        dict = NULL; +                } +                uuid_clear (gfid); +                GF_FREE (path); +                path = NULL; + +                uuid_parse (entry->d_name, gfid); +                uuid_copy (loc.gfid, gfid); +                ret = syncop_getxattr (this, &loc, &dict, GF_AFR_HEAL_INFO); +                if (ret) +                        continue; + +                ret = glfsh_gfid_to_path (this, xl, gfid, &path); + +                if (ret == -ENOENT || ret == -ESTALE) { +                        glfsh_index_purge (xl, fd->inode, entry->d_name); +                        ret = 0; +                        continue; +                } +                if (dict) +                        glfsh_print_heal_status (dict, path, gfid, +                                                 num_entries); +        } +        ret = 0; +        GF_FREE (path); +        if (dict) { +                dict_unref (dict); +                dict = NULL; +        } +        return ret; +} + +static int +glfsh_crawl_directory (xlator_t   *readdir_xl, fd_t *fd, loc_t *loc) +{ +        uint64_t        offset = 0; +        gf_dirent_t     entries; +        int             ret = 0; +        gf_boolean_t    free_entries = _gf_false; +        uint64_t        num_entries = 0; + +        INIT_LIST_HEAD (&entries.list); + +        while (1) { +                ret = syncop_readdir (readdir_xl, fd, 131072, offset, &entries); +                if (ret <= 0) +                        break; +                ret = 0; +                free_entries = _gf_true; + +                if (list_empty (&entries.list)) +                        goto out; + +                ret = glfsh_process_entries (readdir_xl, fd, &entries, &offset, +                                             &num_entries); +                if (ret < 0) +                        goto out; + +                gf_dirent_free (&entries); +                free_entries = _gf_false; +        } +        ret = 0; +out: +        if (free_entries) +                gf_dirent_free (&entries); +        if (ret < 0) { +                printf ("Failed to complete gathering info. " +                         "Number of entries so far: %"PRIu64"\n", num_entries); +        } +        else { +                printf ("Number of entries: %"PRIu64"\n", num_entries); +        } +        return ret; +} + +static int +glfsh_print_brick (xlator_t *xl, loc_t *rootloc) +{ +        int     ret = 0; +        dict_t  *xattr = NULL; +        char    *pathinfo = NULL; +        char    *brick_start = NULL; +        char    *brick_end = NULL; + +        ret = syncop_getxattr (xl, rootloc, &xattr, GF_XATTR_PATHINFO_KEY); +        if (ret < 0) +                goto out; + +        ret = dict_get_str (xattr, GF_XATTR_PATHINFO_KEY, &pathinfo); +        if (ret < 0) +                goto out; + +        brick_start = strchr (pathinfo, ':') + 1; +        brick_end = pathinfo + strlen (pathinfo) - 1; +        *brick_end = 0; +        printf ("Brick %s\n", brick_start); + +out: +        if (xattr) +                dict_unref (xattr); +        return ret; +} + +void +glfsh_print_brick_from_xl (xlator_t *xl) +{ +        char    *remote_host = NULL; +        char    *remote_subvol = NULL; +        int     ret = 0; + +        ret = dict_get_str (xl->options, "remote-host", &remote_host); +        if (ret < 0) +                goto out; + +        ret = dict_get_str (xl->options, "remote-subvolume", &remote_subvol); +        if (ret < 0) +                goto out; +out: +        if (ret < 0) +                printf ("Brick - Not able to get brick information\n"); +        else +                printf ("Brick %s:%s\n", remote_host, remote_subvol); +} + +void +glfsh_print_pending_heals (xlator_t *xl, loc_t *rootloc) +{ +        int ret = 0; +        loc_t   dirloc = {0}; +        fd_t    *fd = NULL; +        int32_t op_errno = 0; + +        ret = glfsh_print_brick (xl, rootloc); +        if (ret < 0) { +                glfsh_print_brick_from_xl (xl); +                printf ("Status: %s\n", strerror (-ret)); +                goto out; +        } + +        ret = glfsh_get_index_dir_loc (rootloc, xl, &dirloc, &op_errno); +        if (ret < 0) { +                if (op_errno == ESTALE || op_errno == ENOENT) +                        printf ("Number of entries: 0\n"); +                else +                        printf ("Status: %s\n", strerror (op_errno)); +                goto out; +        } + +        fd = fd_create (dirloc.inode, GF_CLIENT_PID_GLFS_HEAL); +        if (!fd) { +                printf ("fd_create failed: %s", strerror(errno)); +                goto out; +        } +        ret = syncop_opendir (xl, &dirloc, fd); +        if (ret) { +                fd_unref(fd); +#ifdef GF_LINUX_HOST_OS /* See comment in afr_shd_index_opendir() */ +                fd = fd_anonymous (dirloc.inode); +                if (!fd) { +                        printf ("fd_anonymous failed: %s", +                                strerror(errno)); +                        goto out; +                } +#else +                printf ("opendir failed: %s", strerror(errno)); +                goto out; +#endif +        } + +        ret = glfsh_crawl_directory (xl, fd, &dirloc); +        if (fd) +                fd_unref (fd); +        if (ret < 0) +                printf ("Failed to find entries with pending self-heal\n"); +out: +        loc_wipe (&dirloc); +        return; +} + +static int +glfsh_validate_replicate_volume (xlator_t *xl) +{ +        xlator_t        *afr_xl = NULL; +        int             ret = -1; + +        while (xl->next) +                xl = xl->next; + +        while (xl) { +                if (strcmp (xl->type, "protocol/client") == 0) { +                        afr_xl = _get_afr_ancestor (xl); +                        if (afr_xl) { +                                ret = 0; +                                break; +                        } +                } + +                xl = xl->prev; +        } + +        return ret; +} + +int +main (int argc, char **argv) +{ +        glfs_t    *fs = NULL; +        int        ret = 0; +        char      *volname = NULL; +        xlator_t  *top_subvol = NULL; +        xlator_t  *xl = NULL; +        loc_t     rootloc = {0}; +        char      logfilepath[PATH_MAX] = {0}; +        xlator_t  *old_THIS = NULL; +        xlator_t  *afr_xl = NULL; + +        if (argc != 2) { +                printf ("Usage: %s <volname>\n", argv[0]); +                ret = -1; +                goto out; +        } +        volname = argv[1]; + +        fs = glfs_new (volname); +        if (!fs) { +                ret = -1; +                printf ("Not able to initialize volume '%s'\n", volname); +                goto out; +        } + +        ret = glfs_set_volfile_server (fs, "tcp", "localhost", 24007); +        snprintf (logfilepath, sizeof (logfilepath), +                  DEFAULT_HEAL_LOG_FILE_DIRECTORY"/glfsheal-%s.log", volname); +        ret = glfs_set_logging(fs, logfilepath, GF_LOG_INFO); +        if (ret < 0) { +                ret = -1; +                printf ("Not able to initialize volume '%s'\n", volname); +                goto out; +        } + +        ret = glfs_init (fs); +        if (ret < 0) { +                ret = -1; +                if (errno == ENOENT) { +                        printf ("Volume %s does not exist\n", volname); +                } +                else { +                        printf ("%s: Not able to fetch volfile from " +                                 "glusterd\n", volname); +                } +                goto out; +        } + +        sleep (2); +        __glfs_entry_fs (fs); +        top_subvol = glfs_active_subvol (fs); +        if (!top_subvol) { +                ret = -1; +                if (errno == ENOTCONN) { +                        printf ("Volume %s is not started (Or) All the bricks " +                                 "are not running.\n", volname); +                } +                else { +                        printf ("%s: Not able to mount the volume, %s\n", +                                 volname, strerror (errno)); +                } +                goto out; +        } + +        ret = glfsh_validate_replicate_volume (top_subvol); +        if (ret < 0) { +                printf ("Volume %s is not of type replicate\n", volname); +                goto out; +        } +        rootloc.inode = inode_ref (top_subvol->itable->root); +        glfs_loc_touchup (&rootloc); + +        xl = top_subvol; +        while (xl->next) +                xl = xl->next; + +        while (xl) { +                if (strcmp (xl->type, "protocol/client") == 0) { +                        afr_xl = _get_afr_ancestor (xl); +                        if (afr_xl) { +                                old_THIS = THIS; +                                THIS = afr_xl; +                                glfsh_print_pending_heals (xl, &rootloc); +                                THIS = old_THIS; +                                printf("\n"); +                        } +                } + +                xl = xl->prev; +        } + +        loc_wipe (&rootloc); +        glfs_subvol_done (fs, top_subvol); +/* +        glfs_fini (fs); +*/ +        return 0; +out: +        if (fs && top_subvol) +                glfs_subvol_done (fs, top_subvol); +        loc_wipe (&rootloc); +/* +        if (fs) +                glfs_fini (fs); +*/ +        return ret; +} diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index 0d5abb42ec2..528d6d27241 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -115,6 +115,7 @@ enum _gf_client_pid          GF_CLIENT_PID_NO_ROOT_SQUASH    = -4,          GF_CLIENT_PID_QUOTA_MOUNT       = -5,          GF_CLIENT_PID_AFR_SELF_HEALD    = -6, +        GF_CLIENT_PID_GLFS_HEAL         = -7,  };  typedef enum _gf_boolean gf_boolean_t; diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index 5c22166d1b8..286a6325341 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -136,6 +136,8 @@  #define GF_XATTROP_INDEX_GFID "glusterfs.xattrop_index_gfid"  #define GF_XATTROP_INDEX_COUNT "glusterfs.xattrop_index_count" +#define GF_AFR_HEAL_INFO "glusterfs.heal-info" +  #define GF_GFIDLESS_LOOKUP "gfidless-lookup"  /* replace-brick and pump related internal xattrs */  #define RB_PUMP_CMD_START       "glusterfs.pump.start" diff --git a/tests/basic/afr/self-heald.t b/tests/basic/afr/self-heald.t new file mode 100644 index 00000000000..1c8bd0ff52e --- /dev/null +++ b/tests/basic/afr/self-heald.t @@ -0,0 +1,184 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +function kill_multiple_bricks { +        local vol=$1 +        local host=$2 +        local brickpath=$3 + +        if [ $decide_kill == 0 ] +        then +                for ((i=0; i<=4; i=i+2)) do +                        TEST kill_brick $vol $host $brickpath/${vol}$i +                done +        else +                for ((i=1; i<=5; i=i+2)) do +                        TEST kill_brick $vol $host $brickpath/${vol}$i +                done +        fi +} +function check_bricks_up { +        local vol=$1 +        if [ $decide_kill == 0 ] +        then +                for ((i=0; i<=4; i=i+2)) do +                        EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_in_shd $vol $i +                done +        else +                for ((i=1; i<=5; i=i+2)) do +                        EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_in_shd $vol $i +                done +        fi +} + +function disconnected_brick_count { +        local vol=$1 +        $CLI volume heal $vol info | grep -i transport | wc -l +} + +TESTS_EXPECTED_IN_LOOP=20 +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1,2,3,4,5} +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $CLI volume set $V0 cluster.eager-lock off +TEST $CLI volume start $V0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 + +decide_kill=$((`date +"%j"`))%2 + +kill_multiple_bricks $V0 $H0 $B0 +cd $M0 +HEAL_FILES=0 +for i in {1..10} +do +        dd if=/dev/urandom of=f bs=1M count=10 2>/dev/null +        HEAL_FILES=$(($HEAL_FILES+1)) #+1 for data/metadata self-heal of 'f' +        mkdir a; cd a; +        #+3 for metadata self-heal of 'a' one per subvolume of DHT +        HEAL_FILES=$(($HEAL_FILES+3)) +done +#+3 represents entry sh on "/", one per subvolume of DHT? +HEAL_FILES=$(($HEAL_FILES + 3)) + +cd ~ +EXPECT "$HEAL_FILES" afr_get_pending_heal_count $V0 + +#When bricks are down, it says Transport End point Not connected for them +EXPECT "3" disconnected_brick_count $V0 + +#Create some stale indices and verify that they are not counted in heal info +#TO create stale index create and delete files when one brick is down in +#replica pair. +for i in {11..20}; do echo abc > $M0/$i; done +HEAL_FILES=$(($HEAL_FILES + 10)) #count extra 10 files +EXPECT "$HEAL_FILES" afr_get_pending_heal_count $V0 +#delete the files now, so that stale indices will remain. +for i in {11..20}; do rm -f $M0/$i; done +#After deleting files they should not appear in heal info +HEAL_FILES=$(($HEAL_FILES - 10)) +EXPECT "$HEAL_FILES" afr_get_pending_heal_count $V0 + + +TEST ! $CLI volume heal $V0 +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST ! $CLI volume heal $V0 +TEST ! $CLI volume heal $V0 full +TEST $CLI volume start $V0 force +TEST $CLI volume set $V0 cluster.self-heal-daemon on +EXPECT_WITHIN 20 "Y" glustershd_up_status + +check_bricks_up $V0 + +TEST $CLI volume heal $V0 +sleep 5 #Until the heal-statistics command implementation +#check that this heals the contents partially +TEST [ $HEAL_FILES -gt $(afr_get_pending_heal_count $V0) ] + +TEST $CLI volume heal $V0 full +EXPECT_WITHIN 30 "0" afr_get_pending_heal_count $V0 + +#Test that ongoing IO is not considered as Pending heal +(dd if=/dev/zero of=$M0/file1 bs=1K 2>/dev/null 1>/dev/null)& +back_pid1=$!; +(dd if=/dev/zero of=$M0/file2 bs=1K 2>/dev/null 1>/dev/null)& +back_pid2=$!; +(dd if=/dev/zero of=$M0/file3 bs=1K 2>/dev/null 1>/dev/null)& +back_pid3=$!; +(dd if=/dev/zero of=$M0/file4 bs=1K 2>/dev/null 1>/dev/null)& +back_pid4=$!; +(dd if=/dev/zero of=$M0/file5 bs=1K 2>/dev/null 1>/dev/null)& +back_pid5=$!; +EXPECT 0 afr_get_pending_heal_count $V0 +kill -SIGTERM $back_pid1; +kill -SIGTERM $back_pid2; +kill -SIGTERM $back_pid3; +kill -SIGTERM $back_pid4; +kill -SIGTERM $back_pid5; +wait >/dev/null 2>&1; + +#Test that volume heal info reports files even when self-heal +#options are disabled +TEST touch $M0/f +TEST mkdir $M0/d +#DATA +TEST $CLI volume set $V0 cluster.data-self-heal off +EXPECT "off" volume_option $V0 cluster.data-self-heal +kill_multiple_bricks $V0 $H0 $B0 +echo abc > $M0/f +EXPECT 1 afr_get_pending_heal_count $V0 +TEST $CLI volume start $V0 force +EXPECT_WITHIN 20 "Y" glustershd_up_status +check_bricks_up $V0 + +TEST $CLI volume heal $V0 +EXPECT_WITHIN 30 "0" afr_get_pending_heal_count $V0 +TEST $CLI volume set $V0 cluster.data-self-heal on + +#METADATA +TEST $CLI volume set $V0 cluster.metadata-self-heal off +EXPECT "off" volume_option $V0 cluster.metadata-self-heal +kill_multiple_bricks $V0 $H0 $B0 + +TEST chmod 777 $M0/f +EXPECT 1 afr_get_pending_heal_count $V0 +TEST $CLI volume start $V0 force +EXPECT_WITHIN 20 "Y" glustershd_up_status +check_bricks_up $V0 + +TEST $CLI volume heal $V0 +EXPECT_WITHIN 30 "0" afr_get_pending_heal_count $V0 +TEST $CLI volume set $V0 cluster.metadata-self-heal on + +#ENTRY +TEST $CLI volume set $V0 cluster.entry-self-heal off +EXPECT "off" volume_option $V0 cluster.entry-self-heal +kill_multiple_bricks $V0 $H0 $B0 +TEST touch $M0/d/a +EXPECT 2 afr_get_pending_heal_count $V0 +TEST $CLI volume start $V0 force +EXPECT_WITHIN 20 "Y" glustershd_up_status +check_bricks_up $V0 +TEST $CLI volume heal $V0 +EXPECT_WITHIN 30 "0" afr_get_pending_heal_count $V0 +TEST $CLI volume set $V0 cluster.entry-self-heal on + +#Negative test cases +#Fail volume does not exist case +TEST ! $CLI volume heal fail info + +#Fail volume stopped case +TEST $CLI volume stop $V0 +TEST ! $CLI volume heal $V0 info + +#Fail non-replicate volume info +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 $H0:$B0/${V0}{6} +TEST $CLI volume start $V0 +TEST ! $CLI volume heal $V0 info + +cleanup diff --git a/tests/basic/self-heald.t b/tests/basic/self-heald.t deleted file mode 100644 index b5815a6773f..00000000000 --- a/tests/basic/self-heald.t +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -. $(dirname $0)/../include.rc -. $(dirname $0)/../volume.rc - -cleanup; - -TEST glusterd -TEST pidof glusterd -TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1,2,3,4,5} -TEST $CLI volume set $V0 cluster.background-self-heal-count 0 -TEST $CLI volume set $V0 cluster.eager-lock off -TEST $CLI volume start $V0 -TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 -TEST kill_brick $V0 $H0 $B0/${V0}0 -TEST kill_brick $V0 $H0 $B0/${V0}2 -TEST kill_brick $V0 $H0 $B0/${V0}4 -cd $M0 -HEAL_FILES=0 -for i in {1..10} -do -        dd if=/dev/urandom of=f bs=1024k count=10 2>/dev/null -        HEAL_FILES=$(($HEAL_FILES+1)) -        mkdir a; cd a; -        HEAL_FILES=$(($HEAL_FILES+3)) #As many times as distribute subvols -done -HEAL_FILES=$(($HEAL_FILES + 3)) #Count the brick root dir - -cd ~ -EXPECT "$HEAL_FILES" afr_get_pending_heal_count $V0 -TEST ! $CLI volume heal $V0 -TEST $CLI volume set $V0 cluster.self-heal-daemon off -TEST ! $CLI volume heal $V0 info -TEST ! $CLI volume heal $V0 -TEST $CLI volume start $V0 force -TEST $CLI volume set $V0 cluster.self-heal-daemon on -EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status -EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 -EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 -EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 4 - -TEST $CLI volume heal $V0 full -EXPECT_WITHIN $HEAL_TIMEOUT "0" afr_get_pending_heal_count $V0 -cleanup diff --git a/tests/bugs/bug-880898.t b/tests/bugs/bug-880898.t index 8ba35ec1a59..4b9fb50a522 100644 --- a/tests/bugs/bug-880898.t +++ b/tests/bugs/bug-880898.t @@ -17,7 +17,7 @@ do  	fi  done -gluster volume heal $V0 info | grep "Status: self-heal-daemon is not running on $uuid"; -EXPECT "0" echo $? +#Command execution should fail reporting that the bricks are not running. +TEST ! $CLI volume heal $V0 info  cleanup; diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c index 1527a47f716..aefad8be959 100644 --- a/xlators/cluster/afr/src/afr-common.c +++ b/xlators/cluster/afr/src/afr-common.c @@ -494,7 +494,6 @@ afr_selfheal_enabled (xlator_t *this)  } -  int  afr_inode_refresh_done (call_frame_t *frame, xlator_t *this)  { @@ -4032,3 +4031,315 @@ afr_mark_pending_changelog (afr_private_t *priv, unsigned char *pending,  out:         return changelog;  } + +gf_boolean_t +afr_decide_heal_info (afr_private_t *priv, unsigned char *sources, int ret) +{ +        int sources_count = 0; + +        if (ret) +                goto out; + +        sources_count = AFR_COUNT (sources, priv->child_count); +        if (sources_count == priv->child_count) +                return _gf_false; +out: +        return _gf_true; +} + +int +afr_selfheal_locked_metadata_inspect (call_frame_t *frame, xlator_t *this, +                                      inode_t *inode, gf_boolean_t *msh) +{ +        int ret = -1; +        unsigned char *locked_on = NULL; +        unsigned char *sources = NULL; +        unsigned char *sinks = NULL; +        unsigned char *healed_sinks = NULL; +        struct afr_reply *locked_replies = NULL; + +        afr_private_t *priv = this->private; + +        locked_on = alloca0 (priv->child_count); +        sources = alloca0 (priv->child_count); +        sinks = alloca0 (priv->child_count); +        healed_sinks = alloca0 (priv->child_count); + +        locked_replies = alloca0 (sizeof (*locked_replies) * priv->child_count); + +        ret = afr_selfheal_inodelk (frame, this, inode, this->name, +                                    LLONG_MAX - 1, 0, locked_on); +        { +                if (ret == 0) { +                        /* Not a single lock */ +                        ret = -afr_final_errno (frame->local, priv); +                        if (ret == 0) +                                ret = -ENOTCONN;/* all invalid responses */ +                        goto out; +                } +                ret = __afr_selfheal_metadata_prepare (frame, this, inode, +                                                       locked_on, sources, +                                                       sinks, healed_sinks, +                                                       locked_replies); +                *msh = afr_decide_heal_info (priv, sources, ret); +        } +        afr_selfheal_uninodelk (frame, this, inode, this->name, +                                LLONG_MAX - 1, 0, locked_on); +out: +        if (locked_replies) +                afr_replies_wipe (locked_replies, priv->child_count); +        return ret; +} + +int +afr_selfheal_locked_data_inspect (call_frame_t *frame, xlator_t *this, +                                  inode_t *inode, gf_boolean_t *dsh) +{ +        int ret = -1; +        afr_private_t   *priv = NULL; +        unsigned char *locked_on = NULL; +        unsigned char *data_lock = NULL; +        unsigned char *sources = NULL; +        unsigned char *sinks = NULL; +        unsigned char *healed_sinks = NULL; +        struct afr_reply *locked_replies = NULL; + +        priv = this->private; +        locked_on = alloca0 (priv->child_count); +        data_lock = alloca0 (priv->child_count); +        sources = alloca0 (priv->child_count); +        sinks = alloca0 (priv->child_count); +        healed_sinks = alloca0 (priv->child_count); + +        locked_replies = alloca0 (sizeof (*locked_replies) * priv->child_count); + +        ret = afr_selfheal_tryinodelk (frame, this, inode, priv->sh_domain, +                                       0, 0, locked_on); +        { +                if (ret == 0) { +                        ret = -afr_final_errno (frame->local, priv); +                        if (ret == 0) +                                ret = -ENOTCONN;/* all invalid responses */ +                        goto out; +                } +                ret = afr_selfheal_inodelk (frame, this, inode, this->name, +                                            0, 0, data_lock); +                { +                        if (ret == 0) { +                                ret = -afr_final_errno (frame->local, priv); +                                if (ret == 0) +                                        ret = -ENOTCONN; +                                /* all invalid responses */ +                                goto unlock; +                        } +                        ret = __afr_selfheal_data_prepare (frame, this, inode, +                                                           data_lock, sources, +                                                           sinks, healed_sinks, +                                                           locked_replies); +                        *dsh = afr_decide_heal_info (priv, sources, ret); +                } +                afr_selfheal_uninodelk (frame, this, inode, this->name, 0, 0, +                                        data_lock); +        } +unlock: +        afr_selfheal_uninodelk (frame, this, inode, priv->sh_domain, 0, 0, +                                locked_on); +out: +        if (locked_replies) +                afr_replies_wipe (locked_replies, priv->child_count); +        return ret; +} + +int +afr_selfheal_locked_entry_inspect (call_frame_t *frame, xlator_t *this, +                                   inode_t *inode, +                                   gf_boolean_t *esh) +{ +        int ret = -1; +        int source = -1; +        afr_private_t   *priv = NULL; +        unsigned char *locked_on = NULL; +        unsigned char *data_lock = NULL; +        unsigned char *sources = NULL; +        unsigned char *sinks = NULL; +        unsigned char *healed_sinks = NULL; +        struct afr_reply *locked_replies = NULL; + +        priv = this->private; +        locked_on = alloca0 (priv->child_count); +        data_lock = alloca0 (priv->child_count); +        sources = alloca0 (priv->child_count); +        sinks = alloca0 (priv->child_count); +        healed_sinks = alloca0 (priv->child_count); + +        locked_replies = alloca0 (sizeof (*locked_replies) * priv->child_count); + +        ret = afr_selfheal_tryentrylk (frame, this, inode, priv->sh_domain, +                                       NULL, locked_on); +        { +                if (ret == 0) { +                        ret = -afr_final_errno (frame->local, priv); +                        if (ret == 0) +                                ret = -ENOTCONN;/* all invalid responses */ +                        goto out; +                } + +                ret = afr_selfheal_entrylk (frame, this, inode, this->name, +                                            NULL, data_lock); +                { +                        if (ret == 0) { +                                ret = -afr_final_errno (frame->local, priv); +                                if (ret == 0) +                                        ret = -ENOTCONN; +                                /* all invalid responses */ +                                goto unlock; +                        } +                        ret = __afr_selfheal_entry_prepare (frame, this, inode, +                                                            data_lock, sources, +                                                            sinks, healed_sinks, +                                                            locked_replies, +                                                            &source); +                        if ((ret == 0) && source < 0) +                                ret = -EIO; +                        *esh = afr_decide_heal_info (priv, sources, ret); +                } +                afr_selfheal_unentrylk (frame, this, inode, this->name, NULL, +                                        data_lock); +        } +unlock: +        afr_selfheal_unentrylk (frame, this, inode, priv->sh_domain, NULL, +                                locked_on); +out: +        if (locked_replies) +                afr_replies_wipe (locked_replies, priv->child_count); +        return ret; +} + +int +afr_selfheal_locked_inspect (call_frame_t *frame, xlator_t *this, uuid_t gfid, +                             inode_t **inode, +                             gf_boolean_t *entry_selfheal, +                             gf_boolean_t *data_selfheal, +                             gf_boolean_t *metadata_selfheal) + +{ +        int ret             = -1; +        gf_boolean_t    dsh = _gf_false; +        gf_boolean_t    msh = _gf_false; +        gf_boolean_t    esh = _gf_false; + +        ret = afr_selfheal_unlocked_inspect (frame, this, gfid, inode, +                                             &dsh, &msh, &esh); +        if (ret) +                goto out; + +        /* For every heal type hold locks and check if it indeed needs heal */ + +        if (msh) { +                ret = afr_selfheal_locked_metadata_inspect (frame, this, +                                                            *inode, &msh); +                if (ret == -EIO) +                        goto out; +        } + +        if (dsh) { +                ret = afr_selfheal_locked_data_inspect (frame, this, *inode, +                                                        &dsh); +                if (ret == -EIO || (ret == -EAGAIN)) +                        goto out; +        } + +        if (esh) { +                ret = afr_selfheal_locked_entry_inspect (frame, this, *inode, +                                                         &esh); +        } + +out: +        *data_selfheal = dsh; +        *entry_selfheal = esh; +        *metadata_selfheal = msh; +        return ret; +} + +dict_t* +afr_set_heal_info (char *status) +{ +        dict_t *dict = NULL; +        int    ret   = -1; + +        dict = dict_new (); +        if (!dict) { +                ret = -ENOMEM; +                goto out; +        } + +        if (!strcmp (status, "heal")) { +                ret = dict_set_str (dict, "heal-info", "heal"); +                if (ret) +                        gf_log ("", GF_LOG_WARNING, +                                "Failed to set heal-info key to" +                                "heal"); +        } else if (!strcmp (status, "split-brain")) { +                ret = dict_set_str (dict, "heal-info", "split-brain"); +                if (ret) +                        gf_log ("", GF_LOG_WARNING, +                                "Failed to set heal-info key to" +                                "split-brain"); +        } else if (!strcmp (status, "possibly-healing")) { +                ret = dict_set_str (dict, "heal-info", "possibly-healing"); +                if (ret) +                       gf_log ("", GF_LOG_WARNING, +                                "Failed to set heal-info key to" +                                "possibly-healing"); +        } +out: +        return dict; +} + +int +afr_get_heal_info (call_frame_t *frame, xlator_t *this, loc_t *loc, +                   dict_t *xdata) +{ +        gf_boolean_t    data_selfheal     = _gf_false; +        gf_boolean_t    metadata_selfheal = _gf_false; +        gf_boolean_t    entry_selfheal    = _gf_false; +        dict_t         *dict              = NULL; +        int             ret               = -1; +        int             op_errno          = 0; +        inode_t        *inode             = NULL; + +        ret = afr_selfheal_locked_inspect (frame, this, loc->gfid, &inode, +                                           &entry_selfheal, +                                           &data_selfheal, &metadata_selfheal); + +        if (ret == -ENOMEM) { +                op_errno = -ret; +                ret = -1; +                goto out; +        } + +        if (ret == -EIO) { +                dict = afr_set_heal_info ("split-brain"); +        } else if (ret == -EAGAIN) { +                dict = afr_set_heal_info ("possibly-healing"); +        } else if (ret == 0) { +                if (!data_selfheal && !entry_selfheal && +                    !metadata_selfheal) { +                        dict = afr_set_heal_info ("no-heal"); +                } else { +                        dict = afr_set_heal_info ("heal"); +                } +        } else if (ret < 0) { +                if (data_selfheal || entry_selfheal || +                    metadata_selfheal) { +                        dict = afr_set_heal_info ("heal"); +                } +        } +        ret = 0; + +out: +        AFR_STACK_UNWIND (getxattr, frame, ret, op_errno, dict, NULL); +        if (dict) +               dict_unref (dict); +        return ret; +} diff --git a/xlators/cluster/afr/src/afr-inode-read.c b/xlators/cluster/afr/src/afr-inode-read.c index 4cb219246f7..210d710a2b3 100644 --- a/xlators/cluster/afr/src/afr-inode-read.c +++ b/xlators/cluster/afr/src/afr-inode-read.c @@ -1373,6 +1373,11 @@ afr_getxattr (call_frame_t *frame, xlator_t *this,                  return 0;          } +        if (!strcmp (name, GF_AFR_HEAL_INFO)) { +                afr_get_heal_info (frame, this, loc, xdata); +                return 0; +        } +          /*           * if we are doing getxattr with pathinfo as the key then we           * collect information from all childs diff --git a/xlators/cluster/afr/src/afr-self-heal-common.c b/xlators/cluster/afr/src/afr-self-heal-common.c index 14a514beffa..6198d4cf72c 100644 --- a/xlators/cluster/afr/src/afr-self-heal-common.c +++ b/xlators/cluster/afr/src/afr-self-heal-common.c @@ -932,13 +932,14 @@ afr_selfheal_unlocked_inspect (call_frame_t *frame, xlator_t *this,  		if (replies[i].op_ret == -1)  			continue; -		if (afr_is_data_set (this, replies[i].xdata)) +		if (data_selfheal && afr_is_data_set (this, replies[i].xdata))  			*data_selfheal = _gf_true; -		if (afr_is_metadata_set (this, replies[i].xdata)) +		if (metadata_selfheal && +                    afr_is_metadata_set (this, replies[i].xdata))  			*metadata_selfheal = _gf_true; -		if (afr_is_entry_set (this, replies[i].xdata)) +		if (entry_selfheal && afr_is_entry_set (this, replies[i].xdata))  			*entry_selfheal = _gf_true;  		valid_cnt ++; @@ -967,7 +968,8 @@ afr_selfheal_unlocked_inspect (call_frame_t *frame, xlator_t *this,  				priv->children[i]->name,  				uuid_utoa (replies[i].poststat.ia_gfid)); -			*metadata_selfheal = _gf_true; +                        if (metadata_selfheal) +                                *metadata_selfheal = _gf_true;  		}  		if (!IA_EQUAL (first, replies[i].poststat, gid)) { @@ -978,7 +980,8 @@ afr_selfheal_unlocked_inspect (call_frame_t *frame, xlator_t *this,  				priv->children[i]->name,  				uuid_utoa (replies[i].poststat.ia_gfid)); -			*metadata_selfheal = _gf_true; +                        if (metadata_selfheal) +                                *metadata_selfheal = _gf_true;  		}  		if (!IA_EQUAL (first, replies[i].poststat, prot)) { @@ -989,7 +992,8 @@ afr_selfheal_unlocked_inspect (call_frame_t *frame, xlator_t *this,  				priv->children[i]->name,  				uuid_utoa (replies[i].poststat.ia_gfid)); -			*metadata_selfheal = _gf_true; +                        if (metadata_selfheal) +                                *metadata_selfheal = _gf_true;  		}  		if (IA_ISREG(first.ia_type) && @@ -1001,11 +1005,12 @@ afr_selfheal_unlocked_inspect (call_frame_t *frame, xlator_t *this,  				priv->children[i]->name,  				uuid_utoa (replies[i].poststat.ia_gfid)); -			*data_selfheal = _gf_true; +                        if (data_selfheal) +                                *data_selfheal = _gf_true;  		}  	} -	if (valid_cnt > 0) { +	if (valid_cnt > 0 && link_inode) {  		*link_inode = afr_inode_link (inode, &first);                  if (!*link_inode) {                          ret = -EINVAL; diff --git a/xlators/cluster/afr/src/afr-self-heal-data.c b/xlators/cluster/afr/src/afr-self-heal-data.c index f7503faa719..a434b9e6ba1 100644 --- a/xlators/cluster/afr/src/afr-self-heal-data.c +++ b/xlators/cluster/afr/src/afr-self-heal-data.c @@ -569,10 +569,11 @@ out:   * The return value is the index of the subvolume to be used as the source   * for self-healing, or -1 if no healing is necessary/split brain.   */ -static int -__afr_selfheal_data_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd, -			     unsigned char *locked_on, unsigned char *sources, -			     unsigned char *sinks, unsigned char *healed_sinks, +int +__afr_selfheal_data_prepare (call_frame_t *frame, xlator_t *this, +                             inode_t *inode, unsigned char *locked_on, +                             unsigned char *sources, unsigned char *sinks, +                             unsigned char *healed_sinks,  			     struct afr_reply *replies)  {  	int ret = -1; @@ -582,10 +583,11 @@ __afr_selfheal_data_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd,  	priv = this->private; -	ret = afr_selfheal_unlocked_discover (frame, fd->inode, fd->inode->gfid, +	ret = afr_selfheal_unlocked_discover (frame, inode, inode->gfid,  					      replies); -	if (ret) -		return ret; + +        if (ret) +                return ret;          witness = alloca0(priv->child_count * sizeof (*witness));  	ret = afr_selfheal_find_direction (frame, this, replies, @@ -650,8 +652,9 @@ __afr_selfheal_data (call_frame_t *frame, xlator_t *this, fd_t *fd,  			goto unlock;  		} -		ret = __afr_selfheal_data_prepare (frame, this, fd, data_lock, -						   sources, sinks, healed_sinks, +		ret = __afr_selfheal_data_prepare (frame, this, fd->inode, +                                                   data_lock, sources, sinks, +                                                   healed_sinks,  						   locked_replies);  		if (ret < 0)  			goto unlock; @@ -678,7 +681,7 @@ __afr_selfheal_data (call_frame_t *frame, xlator_t *this, fd_t *fd,  unlock:  	afr_selfheal_uninodelk (frame, this, fd->inode, this->name, 0, 0,  				data_lock); -	if (ret < 0) +        if (ret < 0)  		goto out;  	ret = afr_selfheal_data_do (frame, this, fd, source, healed_sinks, @@ -731,7 +734,6 @@ afr_selfheal_data_open (xlator_t *this, inode_t *inode)  	return fd;  } -  int  afr_selfheal_data (call_frame_t *frame, xlator_t *this, inode_t *inode)  { diff --git a/xlators/cluster/afr/src/afr-self-heal-entry.c b/xlators/cluster/afr/src/afr-self-heal-entry.c index 4b513ffc73d..6af9488f9a4 100644 --- a/xlators/cluster/afr/src/afr-self-heal-entry.c +++ b/xlators/cluster/afr/src/afr-self-heal-entry.c @@ -366,11 +366,11 @@ __afr_selfheal_entry_finalize_source (xlator_t *this, unsigned char *sources,  	return source;  } - -static int -__afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd, -			      unsigned char *locked_on, unsigned char *sources, -			      unsigned char *sinks, unsigned char *healed_sinks, +int +__afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, +                              inode_t *inode, unsigned char *locked_on, +                              unsigned char *sources, unsigned char *sinks, +                              unsigned char *healed_sinks,  			      struct afr_reply *replies, int *source_p)  {  	int ret = -1; @@ -380,10 +380,10 @@ __afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd,  	priv = this->private; -	ret = afr_selfheal_unlocked_discover (frame, fd->inode, fd->inode->gfid, +	ret = afr_selfheal_unlocked_discover (frame, inode, inode->gfid,  					      replies); -	if (ret) -		return ret; +        if (ret) +                return ret;          witness = alloca0 (sizeof (*witness) * priv->child_count);  	ret = afr_selfheal_find_direction (frame, this, replies, @@ -416,7 +416,6 @@ __afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd,  	return ret;  } -  static int  afr_selfheal_entry_dirent (call_frame_t *frame, xlator_t *this,                             fd_t *fd, char *name) @@ -454,7 +453,8 @@ afr_selfheal_entry_dirent (call_frame_t *frame, xlator_t *this,  			goto unlock;  		} -                ret = __afr_selfheal_entry_prepare (frame, this, fd, locked_on, +                ret = __afr_selfheal_entry_prepare (frame, this, fd->inode, +                                                    locked_on,                                                      sources, sinks,                                                      healed_sinks, par_replies,                                                      &source); @@ -602,8 +602,9 @@ __afr_selfheal_entry (call_frame_t *frame, xlator_t *this, fd_t *fd,  			goto unlock;  		} -		ret = __afr_selfheal_entry_prepare (frame, this, fd, data_lock, -						    sources, sinks, healed_sinks, +		ret = __afr_selfheal_entry_prepare (frame, this, fd->inode, +                                                    data_lock, sources, sinks, +                                                    healed_sinks,  						    locked_replies, &source);  	}  unlock: diff --git a/xlators/cluster/afr/src/afr-self-heal-metadata.c b/xlators/cluster/afr/src/afr-self-heal-metadata.c index 87600df3bad..7c0d5cb08c6 100644 --- a/xlators/cluster/afr/src/afr-self-heal-metadata.c +++ b/xlators/cluster/afr/src/afr-self-heal-metadata.c @@ -294,7 +294,8 @@ __afr_selfheal_metadata_finalize_source (call_frame_t *frame, xlator_t *this,  	return source;  } -static int + +int  __afr_selfheal_metadata_prepare (call_frame_t *frame, xlator_t *this, inode_t *inode,  				 unsigned char *locked_on, unsigned char *sources,  				 unsigned char *sinks, unsigned char *healed_sinks, @@ -310,11 +311,11 @@ __afr_selfheal_metadata_prepare (call_frame_t *frame, xlator_t *this, inode_t *i  	ret = afr_selfheal_unlocked_discover (frame, inode, inode->gfid,  					      replies); -	if (ret) -		return ret; +        if (ret) +                return ret;          witness = alloca0 (sizeof (*witness) * priv->child_count); -	ret = afr_selfheal_find_direction (frame, this, replies, +        ret = afr_selfheal_find_direction (frame, this, replies,  					   AFR_METADATA_TRANSACTION,  					   locked_on, sources, sinks, witness);  	if (ret) diff --git a/xlators/cluster/afr/src/afr-self-heal.h b/xlators/cluster/afr/src/afr-self-heal.h index f208e6bc813..50cff91ccb3 100644 --- a/xlators/cluster/afr/src/afr-self-heal.h +++ b/xlators/cluster/afr/src/afr-self-heal.h @@ -198,4 +198,33 @@ afr_mark_active_sinks (xlator_t *this, unsigned char *sources,  gf_boolean_t  afr_does_witness_exist (xlator_t *this, uint64_t *witness); + +int +__afr_selfheal_data_prepare (call_frame_t *frame, xlator_t *this, +                             inode_t *inode, unsigned char *locked_on, +                             unsigned char *sources, +                             unsigned char *sinks, unsigned char *healed_sinks, +                             struct afr_reply *replies); + +int +__afr_selfheal_metadata_prepare (call_frame_t *frame, xlator_t *this, +                                 inode_t *inode, unsigned char *locked_on, +                                 unsigned char *sources, +                                 unsigned char *sinks, +                                 unsigned char *healed_sinks, +                                 struct afr_reply *replies); +int +__afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, +                              inode_t *inode, unsigned char *locked_on, +                              unsigned char *sources, +                              unsigned char *sinks, +                              unsigned char *healed_sinks, +                              struct afr_reply *replies, int *source_p); + +int +afr_selfheal_unlocked_inspect (call_frame_t *frame, xlator_t *this, +                               uuid_t gfid, inode_t **link_inode, +                               gf_boolean_t *data_selfheal, +                               gf_boolean_t *metadata_selfheal, +                               gf_boolean_t *entry_selfheal);  #endif /* !_AFR_SELFHEAL_H */ diff --git a/xlators/cluster/afr/src/afr-self-heald.c b/xlators/cluster/afr/src/afr-self-heald.c index 6ce52aad1c4..29f34107481 100644 --- a/xlators/cluster/afr/src/afr-self-heald.c +++ b/xlators/cluster/afr/src/afr-self-heald.c @@ -40,8 +40,6 @@  #define NTH_INDEX_HEALER(this, n) &((((afr_private_t *)this->private))->shd.index_healers[n])  #define NTH_FULL_HEALER(this, n) &((((afr_private_t *)this->private))->shd.full_healers[n]) -int afr_shd_gfid_to_path (xlator_t *this, xlator_t *subvol, uuid_t gfid, char **path_p); -  char *  afr_subvol_name (xlator_t *this, int subvol)  { diff --git a/xlators/cluster/afr/src/afr-self-heald.h b/xlators/cluster/afr/src/afr-self-heald.h index 59f06b79cff..02b26b8061f 100644 --- a/xlators/cluster/afr/src/afr-self-heald.h +++ b/xlators/cluster/afr/src/afr-self-heald.h @@ -67,4 +67,10 @@ afr_selfheal_daemon_init (xlator_t *this);  int  afr_xl_op (xlator_t *this, dict_t *input, dict_t *output); +int +afr_shd_gfid_to_path (xlator_t *this, xlator_t *subvol, uuid_t gfid, +                      char **path_p); + +int +afr_shd_index_purge (xlator_t *subvol, inode_t *inode, char *name);  #endif /* !_AFR_SELF_HEALD_H */ diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h index 51e57e8207f..7e138c54ec0 100644 --- a/xlators/cluster/afr/src/afr.h +++ b/xlators/cluster/afr/src/afr.h @@ -1011,4 +1011,8 @@ afr_xattrs_are_equal (dict_t *dict1, dict_t *dict2);  gf_boolean_t  afr_is_xattr_ignorable (char *key); + +int +afr_get_heal_info (call_frame_t *frame, xlator_t *this, loc_t *loc, +                   dict_t *xdata);  #endif /* __AFR_H__ */  | 
