diff options
| -rw-r--r-- | libglusterfs/src/libglusterfs.sym | 1 | ||||
| -rw-r--r-- | libglusterfs/src/syncop-utils.c | 42 | ||||
| -rw-r--r-- | libglusterfs/src/syncop-utils.h | 5 | ||||
| -rw-r--r-- | xlators/features/bit-rot/src/bitd/bit-rot-scrub.c | 20 | ||||
| -rw-r--r-- | xlators/features/bit-rot/src/stub/bit-rot-stub-helpers.c | 218 | ||||
| -rw-r--r-- | xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h | 4 | ||||
| -rw-r--r-- | xlators/features/bit-rot/src/stub/bit-rot-stub.h | 14 | 
7 files changed, 292 insertions, 12 deletions
diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym index d2d25838647..8b2567a4c62 100644 --- a/libglusterfs/src/libglusterfs.sym +++ b/libglusterfs/src/libglusterfs.sym @@ -944,6 +944,7 @@ syncop_fxattrop  syncop_getactivelk  syncop_getxattr  syncop_gfid_to_path +syncop_gfid_to_path_hard  syncop_inode_find  syncop_inodelk  syncop_entrylk diff --git a/libglusterfs/src/syncop-utils.c b/libglusterfs/src/syncop-utils.c index b743bdfae88..40ced03cb45 100644 --- a/libglusterfs/src/syncop-utils.c +++ b/libglusterfs/src/syncop-utils.c @@ -554,9 +554,20 @@ out:          return ret;  } +/** + * For hard resove, it it telling posix to make use of the + * gfid2path extended attribute stored on disk. Otherwise + * posix xlator (with GFID_TO_PATH_KEY as the key) will just + * do a in memory inode_path to get the path. Depending upon + * the consumer of this function, they can choose how they want + * to proceed. If doing a xattr operation sounds costly, then + * use GFID_TO_PATH_KEY as the key for getxattr. + **/ +  int -syncop_gfid_to_path (inode_table_t *itable, xlator_t *subvol, uuid_t gfid, -                     char **path_p) +syncop_gfid_to_path_hard (inode_table_t *itable, xlator_t *subvol, uuid_t gfid, +                          inode_t *inode, char **path_p, +                          gf_boolean_t hard_resolve)  {          int      ret   = 0;          char    *path  = NULL; @@ -564,14 +575,25 @@ syncop_gfid_to_path (inode_table_t *itable, xlator_t *subvol, uuid_t gfid,          dict_t  *xattr = NULL;          gf_uuid_copy (loc.gfid, gfid); -        loc.inode = inode_new (itable); -        ret = syncop_getxattr (subvol, &loc, &xattr, GFID_TO_PATH_KEY, NULL, -                               NULL); +        if (!inode) +                loc.inode = inode_new (itable); +        else +                loc.inode = inode_ref (inode); + +        if (!hard_resolve) +                ret = syncop_getxattr (subvol, &loc, &xattr, GFID_TO_PATH_KEY, +                                       NULL, NULL); +        else +                ret = syncop_getxattr (subvol, &loc, &xattr, +                                       GFID2PATH_VIRT_XATTR_KEY, NULL, NULL); +          if (ret < 0)                  goto out; -        ret = dict_get_str (xattr, GFID_TO_PATH_KEY, &path); +        ret = dict_get_str (xattr, hard_resolve ? +                            GFID2PATH_VIRT_XATTR_KEY : GFID_TO_PATH_KEY, +                            &path);          if (ret || !path) {                  ret = -EINVAL;                  goto out; @@ -596,6 +618,14 @@ out:  }  int +syncop_gfid_to_path (inode_table_t *itable, xlator_t *subvol, uuid_t gfid, +                     char **path_p) +{ +        return syncop_gfid_to_path_hard (itable, subvol, gfid, NULL, path_p, +                                         _gf_false); +} + +int  syncop_inode_find (xlator_t *this, xlator_t *subvol,                     uuid_t gfid, inode_t **inode,                     dict_t *xdata, dict_t **rsp_dict) diff --git a/libglusterfs/src/syncop-utils.h b/libglusterfs/src/syncop-utils.h index 4761371c120..97b35046780 100644 --- a/libglusterfs/src/syncop-utils.h +++ b/libglusterfs/src/syncop-utils.h @@ -47,4 +47,9 @@ int  syncop_inode_find (xlator_t *this, xlator_t *subvol,                     uuid_t gfid, inode_t **inode,                     dict_t *xdata, dict_t **rsp_dict); + +int +syncop_gfid_to_path_hard (inode_table_t *itable, xlator_t *subvol, uuid_t gfid, +                          inode_t *inode, char **path_p, +                          gf_boolean_t hard_resolve);  #endif /* _SYNCOP_H */ diff --git a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c index 7012f2f0a4a..ee996525f76 100644 --- a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c +++ b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c @@ -1625,11 +1625,12 @@ br_read_bad_object_dir (xlator_t *this, br_child_t *child, fd_t *fd,          off_t        offset  = 0;          int32_t      count   = 0;          char         key[PATH_MAX] = {0, }; +        dict_t      *out_dict = NULL;          INIT_LIST_HEAD (&entries.list);          while ((ret = syncop_readdir (child->xl, fd, 131072, offset, &entries, -                                      NULL, NULL))) { +                                      NULL, &out_dict))) {                  if (ret < 0)                          goto out; @@ -1647,6 +1648,12 @@ br_read_bad_object_dir (xlator_t *this, br_child_t *child, fd_t *fd,                                                             entry->d_name);                          if (!ret)                                  count++; + +                        if (out_dict) { +                                dict_copy (out_dict, dict); +                                dict_unref (out_dict); +                                out_dict = NULL; +                        }                  }                  gf_dirent_free (&entries); @@ -1742,6 +1749,7 @@ br_collect_bad_objects_of_child (xlator_t *this, br_child_t *child,          int32_t    tmp_count = 0;          char       *entry = NULL;          char       tmp[PATH_MAX]  = {0, }; +        char       *path = NULL;          ret = dict_get_int32 (child_dict, "count", &count);          if (ret) @@ -1755,14 +1763,16 @@ br_collect_bad_objects_of_child (xlator_t *this, br_child_t *child,                  if (ret)                          continue; -                snprintf (tmp, PATH_MAX, "%s ==> BRICK: %s", -                          entry, child->brick_path); +                ret = dict_get_str (child_dict, entry, &path); +                snprintf (tmp, PATH_MAX, "%s ==> BRICK: %s\n path: %s", +                          entry, child->brick_path, path);                  snprintf (main_key, PATH_MAX, "quarantine-%d",                            tmp_count);                  ret = dict_set_dynstr_with_alloc (dict, main_key, tmp); -                          if (!ret) -                                  tmp_count++; +                if (!ret) +                        tmp_count++; +                path = NULL;          }          ret = tmp_count; diff --git a/xlators/features/bit-rot/src/stub/bit-rot-stub-helpers.c b/xlators/features/bit-rot/src/stub/bit-rot-stub-helpers.c index 8a88617a487..24aa9aa5ff4 100644 --- a/xlators/features/bit-rot/src/stub/bit-rot-stub-helpers.c +++ b/xlators/features/bit-rot/src/stub/bit-rot-stub-helpers.c @@ -560,6 +560,8 @@ br_stub_readdir_wrapper (call_frame_t *frame, xlator_t *this,          int32_t               op_errno       = 0;          int                   count          = 0;          gf_dirent_t           entries; +        gf_boolean_t          xdata_unref    = _gf_false; +        dict_t               *dict           = NULL;          INIT_LIST_HEAD (&entries.list); @@ -587,9 +589,225 @@ br_stub_readdir_wrapper (call_frame_t *frame, xlator_t *this,          /* pick ENOENT to indicate EOF */          op_errno = errno;          op_ret = count; + +        dict = xdata; +        (void) br_stub_bad_objects_path (this, fd, &entries, &dict); +        if (!xdata && dict) { +                xdata = dict; +                xdata_unref = _gf_true; +        } +  done:          STACK_UNWIND_STRICT (readdir, frame, op_ret, op_errno, &entries, xdata);          gf_dirent_free (&entries); +        if (xdata_unref) +                dict_unref (xdata);          return 0;  } +/** + * This function is called to mainly obtain the paths of the corrupt + * objects (files as of now). Currently scrub status prints only the + * gfid of the corrupted files. Reason is, bitrot-stub maintains the + * list of the corrupted objects as entries inside the quarantine + * directory (<brick export>/.glusterfs/quarantine) + * + * And the name of each entry in the qurantine directory is the gfid + * of the corrupted object. So scrub status will just show that info. + * But it helps the users a lot if the actual path to the object is + * also reported. Hence the below function to get that information. + * The function allocates a new dict to be returned (if it does not + * get one from the caller of readdir i.e. scrubber as of now), and + * stores the paths of each corrupted gfid there. The gfid is used as + * the key and path is used as the value. + * + * NOTE: The path will be there in following situations + * 1) gfid2path option has been enabled (posix xlator option) + *    and the corrupted file contains the path as an extended + *    attribute. + * 2) If the gfid2path option is not enabled, OR if the xattr + *    is absent, then the inode table should have it. + *    The path will be there if a name based lookup has happened + *    on the file which has been corrupted. With lookup a inode and + *    dentry would be created in the inode table. And the path is + *    constructed using the in memory inode and dentry. If a lookup + *    has not happened OR the inode corresponding to the corrupted + *    file does not exist in the inode table (because it got purged + *    as lru limit of the inodes exceeded) OR a nameless lookup had + *    happened to populate the inode in the inode table, then the + *    path will not be printed in scrub and only the gfid will be there. + **/ +int +br_stub_bad_objects_path (xlator_t *this, fd_t *fd, gf_dirent_t *entries, +                          dict_t **dict) +{ +        gf_dirent_t     *entry    = NULL; +        inode_t         *inode    = NULL; +        char            *hpath    = NULL; +        uuid_t           gfid     = {0}; +        int              ret      = -1; +        dict_t          *tmp_dict = NULL; +        char             str_gfid[64] = {0}; + +        if (list_empty(&entries->list)) +                return 0; + +        tmp_dict = *dict; + +        if (!tmp_dict) { +                tmp_dict = dict_new (); +                /* +                 * If the allocation of dict fails then no need treat it +                 * it as a error. This path (or function) is executed when +                 * "gluster volume bitrot <volume name> scrub status" is +                 * executed, to get the list of the corrupted objects. +                 * And the motive of this function is to get the paths of +                 * the corrupted objects. If the dict allocation fails, then +                 * the scrub status will only show the gfids of those corrupted +                 * objects (which is the behavior as of the time of this patch +                 * being worked upon). So just return and only the gfids will +                 * be shown. +                 */ +                if (!tmp_dict) { +                        gf_msg (this->name, GF_LOG_ERROR, 0, BRS_MSG_NO_MEMORY, +                                "failed to allocate new dict for saving the paths " +                                "of the corrupted objects. Scrub status will only " +                                "display the gfid"); +                        goto out; +                } +        } + +        list_for_each_entry (entry, &entries->list, list) { +                gf_uuid_clear (gfid); +                gf_uuid_parse (entry->d_name, gfid); + +                inode = inode_find (fd->inode->table, gfid); + +                /* No need to check the return value here. +                 * Because @hpath is examined. +                 */ +                (void) br_stub_get_path_of_gfid (this, fd->inode, inode, +                                                 gfid, &hpath); + +                if (hpath) { +                        gf_msg_debug (this->name, 0, "path of the corrupted " +                                      "object (gfid: %s) is %s", +                                      uuid_utoa (gfid), hpath); +                        br_stub_entry_xattr_fill (this, hpath, entry, tmp_dict); +                } else +                        gf_msg (this->name, GF_LOG_WARNING, 0, +                                BRS_MSG_PATH_GET_FAILED, +                                "failed to get the path for the inode %s", +                                uuid_utoa_r (gfid, str_gfid)); + +                inode = NULL; +                hpath = NULL; +        } + +         ret = 0; +         *dict = tmp_dict; + +out: +         return ret; + } + +int +br_stub_get_path_of_gfid (xlator_t *this, inode_t *parent, inode_t *inode, +                          uuid_t gfid, char **path) +{ +        int32_t    ret = -1; +        char       gfid_str[64] = {0}; + +        GF_VALIDATE_OR_GOTO ("bitrot-stub", this, out); +        GF_VALIDATE_OR_GOTO (this->name, parent, out); +        GF_VALIDATE_OR_GOTO (this->name, path, out); + +        /* No need to validate the @inode for hard resolution. Because inode +         * can be NULL and if it is NULL, then syncop_gfid_to_path_hard will +         * allocate a new inode and proceed. So no need to bother about +         * @inode. Because we need it only to send a syncop_getxattr call +         * from inside syncop_gfid_to_path_hard. And getxattr fetches the +         * path from the backend. +         */ +        ret = syncop_gfid_to_path_hard (parent->table, FIRST_CHILD (this), gfid, +                                        inode, path, _gf_true); + +        /* +         * This is to handle those corrupted files which does not contain +         * the gfid2path xattr in the backend (because they were created +         * when the option was OFF OR it was upgraded from a version before +         * gfid2path was brought in. +         * Ideally posix should be returning ret < 0 i.e. error if the +         * gfid2path xattr is not present. But for some reason it is +         * returning success and path as "". THis is causing problems. +         * For now handling it by adding extra checks. But the better way +         * is to make posix return error if gfid2path xattr is absent. +         * When that is done remove below if block and also this entire +         * comment. +         */ +        if (ret >= 0 && !strlen (*path)) { +                gf_msg (this->name, GF_LOG_WARNING, 0, BRS_MSG_PATH_GET_FAILED, +                        "path for the object %s is %s. Going for in memory path", +                        uuid_utoa_r (gfid, gfid_str), *path); +                ret = -1; +        } + +        /* +         * Try with soft resolution of path if hard resolve fails. Because +         * checking the xattr on disk to get the path of a inode (or gfid) +         * is dependent on whether that option is enabled in the posix +         * xlator or not. If it is not enabled, then hard resolution by +         * checking the on disk xattr fails. +         * +         * Thus in such situations fall back to the soft resolution which +         * mainly depends on the inode_path() function. And for using +         * inode_path, @inode has to be linked i.e. a successful lookup should +         * have happened on the gfid (or the path) to link the inode to the +         * inode table. And if @inode is NULL, means, the inode has not been +         * found in the inode table and better not to do inode_path() on the +         * inode which has not been linked. +         */ +        if (ret < 0 && inode) +                ret = syncop_gfid_to_path_hard (parent->table, +                                                FIRST_CHILD (this), gfid, inode, +                                                path, _gf_false); + +out: +        return ret; +} + + +/** +* NOTE: If the file has multiple hardlinks (in gluster volume +* namespace), the path would be one of the hardlinks. Its upto +* the user to find the remaining hardlinks (using find -samefile) +* and remove them. +**/ +void +br_stub_entry_xattr_fill (xlator_t *this, char *hpath, gf_dirent_t *entry, +                          dict_t *dict) +{ +                int32_t    ret = -1; + +        GF_VALIDATE_OR_GOTO ("bit-rot-stub", this, out); +        GF_VALIDATE_OR_GOTO (this->name, hpath, out); + +        /* +         * Use the entry->d_name (which is nothing but the gfid of the +         * corrupted object) as the key. And the value will be the actual +         * path of that object (or file). +         * +         * ALso ignore the dict_set errors. scrubber will get the gfid of +         * the corrupted object for sure. So, for now lets just log the +         * dict_set_dynstr failure and move on. +         */ + +        ret = dict_set_dynstr (dict, entry->d_name, hpath); +        if (ret) +                gf_msg (this->name, GF_LOG_WARNING, 0, BRS_MSG_DICT_SET_FAILED, +                        "failed to set the actual path %s as the value in the " +                        "dict for the corrupted object %s", hpath, +                        entry->d_name); +out: +        return; +} diff --git a/xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h b/xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h index 42022adb116..2ade4f03997 100644 --- a/xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h +++ b/xlators/features/bit-rot/src/stub/bit-rot-stub-messages.h @@ -54,7 +54,9 @@ GLFS_MSGID(BITROT_STUB,          BRS_MSG_BAD_OBJ_THREAD_FAIL,          BRS_MSG_BAD_OBJ_DIR_CLOSE_FAIL,          BRS_MSG_LINK_FAIL, -        BRS_MSG_BAD_OBJ_UNLINK_FAIL +        BRS_MSG_BAD_OBJ_UNLINK_FAIL, +        BRS_MSG_DICT_SET_FAILED, +        BRS_MSG_PATH_GET_FAILED  );  #endif /* !_BITROT_STUB_MESSAGES_H_ */ diff --git a/xlators/features/bit-rot/src/stub/bit-rot-stub.h b/xlators/features/bit-rot/src/stub/bit-rot-stub.h index 41b6cb9d2ba..ae4db0fd4f1 100644 --- a/xlators/features/bit-rot/src/stub/bit-rot-stub.h +++ b/xlators/features/bit-rot/src/stub/bit-rot-stub.h @@ -22,6 +22,8 @@  #include "bit-rot-common.h"  #include "bit-rot-stub-messages.h"  #include "glusterfs3-xdr.h" +#include "syncop.h" +#include "syncop-utils.h"  #define BAD_OBJECT_THREAD_STACK_SIZE   ((size_t)(1024*1024))  #define BR_STUB_DUMP_STR_SIZE 65536 @@ -499,4 +501,16 @@ br_stub_readdir_wrapper (call_frame_t *frame, xlator_t *this,  int  br_stub_del (xlator_t *this, uuid_t gfid); +int +br_stub_bad_objects_path (xlator_t *this, fd_t *fd, gf_dirent_t *entries, +                          dict_t **dict); + +void +br_stub_entry_xattr_fill (xlator_t *this, char *hpath, gf_dirent_t *entry, +                          dict_t *dict); + +int +br_stub_get_path_of_gfid (xlator_t *this, inode_t *parent, inode_t *inode, +                          uuid_t gfid, char **path); +  #endif /* __BIT_ROT_STUB_H__ */  | 
