diff options
| -rw-r--r-- | libglusterfs/src/glusterfs.h | 4 | ||||
| -rwxr-xr-x | tests/bugs/bug-990028.t | 156 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-quota.c | 1 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.c | 51 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix-handle.c | 162 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix-handle.h | 96 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix-helpers.c | 87 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix.c | 759 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix.h | 11 | 
9 files changed, 1156 insertions, 171 deletions
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index d8c7060f7ef..525d6909a59 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -101,10 +101,14 @@  #define GF_XATTR_LINKINFO_KEY   "trusted.distribute.linkinfo"  #define GFID_XATTR_KEY          "trusted.gfid" +#define PGFID_XATTR_KEY_PREFIX  "trusted.pgfid."  #define VIRTUAL_GFID_XATTR_KEY_STR  "glusterfs.gfid.string"  #define VIRTUAL_GFID_XATTR_KEY      "glusterfs.gfid"  #define UUID_CANONICAL_FORM_LEN 36 +#define GET_ANCESTRY_PATH_KEY "glusterfs.ancestry.path" +#define GET_ANCESTRY_DENTRY_KEY "glusterfs.ancestry.dentry" +  #define GLUSTERFS_INTERNAL_FOP_KEY  "glusterfs-internal-fop"  #define ZR_FILE_CONTENT_STR     "glusterfs.file." diff --git a/tests/bugs/bug-990028.t b/tests/bugs/bug-990028.t new file mode 100755 index 00000000000..ece7235cd96 --- /dev/null +++ b/tests/bugs/bug-990028.t @@ -0,0 +1,156 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../fileio.rc + +cleanup; + +TESTS_EXPECTED_IN_LOOP=153 + +function __init() +{ +    TEST glusterd +    TEST pidof glusterd +    TEST $CLI volume info; + +    TEST $CLI volume create $V0 $H0:$B0/brick + +    EXPECT 'Created' volinfo_field $V0 'Status'; + +    TEST $CLI volume start $V0 + +    TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0 + +    TEST $CLI volume quota $V0 enable +    sleep 15 +} + +#CASE-1 +#checking pgfid under same directory +function links_in_same_directory() +{ +    # create a file file1 +    TEST touch $M0/file1 + +    # create 50 hardlinks for file1 +    for i in `seq 2 50`; do +        TEST_IN_LOOP ln $M0/file1 $M0/file$i +    done + +    # store the pgfid of file1 in PGFID_FILE1 [should be 50 now (0x000000032)] +    PGFID_FILE1=`getfattr -m "trusted.pgfid.*" -de hex  $B0/brick/file1 2>&1 | grep "trusted.pgfid" | gawk -F '=' '{print $2}'` + +    # compare the pgfid(link value ) of each  hard links are equal or not +    for i in `seq  2 50`; do +        TEMP=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/file$i 2>&1 | grep "trusted.pgfid" | gawk -F '=' '{print $2}'` +        TEST_IN_LOOP [ $PGFID_FILE1 = $TEMP ] +    done + +    # check if no of links value is 50 or not +    TEST [ $PGFID_FILE1 = "0x00000032" ] + +    # unlink file 2 to 50 +    for i in `seq 2 50`; do +        TEST_IN_LOOP unlink $M0/file$i; +    done + +    # now check if pgfid value is 1 or not +    PGFID_FILE1=`getfattr -m "trusted.pgfid.*" -de hex  $B0/brick/file1 2>&1 | grep "trusted.pgfid" | gawk -F '=' '{print $2}'`; + +    TEST [ $PGFID_FILE1 = "0x00000001" ] + +    TEST rm -f $M0/* +} + +##checking pgfid under diff directories +function links_across_directories() +{ +    TEST mkdir $M0/dir1 $M0/dir2; + +    # create a file in dir1 +    TEST touch $M0/dir1/file1; + +    # create  hard link for file1 in dir2 +    TEST ln $M0/dir1/file1 $M0/dir2/file2; + +    #first check is to find whether there are two pgfids or not +    LINES=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir1/file1 2>&1 | grep "trusted.pgfid" | wc -l` +    TEST [ $LINES = 2 ] + +    for i in $(seq 1  2); do +        HL=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir$i/file$i 2>&1 | grep "trusted.pgfid" | cut -d$'\n' -f$i | cut -d'=' -f2`         +        TEST_IN_LOOP [ $HL = "0x00000001" ] +    done + +    #now unlink file2 and check the pgfid of file1 +    #1. no. of pgfid should be one +    #2. no. of hard link should be one +    TEST unlink $M0/dir2/file2 + +    LINES=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir1/file1 2>&1 | grep "trusted.pgfid" | wc -l` +    TEST [ $LINES == 1 ] + +    #next to check is to whether they contain hard link value of one or not +    HL=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir1/file1 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2` +    TEST [ $HL = "0x00000001" ] + +    #rename file under same directory + +    TEST touch $M0/r_file1 +    PGFID_rfile1=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/r_file1 2>&1 | grep "trusted.pgfid"` + +    #cross check whether hard link count is one +    HL=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/r_file1 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2` + +    TEST [ $HL = "0x00000001" ] + +    #now rename the file to r_file1 +    TEST mv $M0/r_file1 $M0/r_file2 + +    #now check the pgfid hard link count is still one or not +    HL=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/r_file2 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2`  + +    TEST [ $HL = "0x00000001" ] + +    #now move the file to a different directory where it has no hard link and check +    TEST mkdir $M0/dir3; +    TEST mv $M0/r_file2 $M0/dir3; + +    #now check the pgfid has changed or not and hard limit is one or not +    PGFID_newDir=`getfattr -m "trusted.pgfid.*" -de hex $B0/brick/dir3/r_file2 2>&1 | grep "trusted.pgfid"` + +    #now the older pgfid and new pgfid shouldn't match +    TEST [ $PGFID_rfile1 != $PGFID_newDir ] + +    HL=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir3/r_file2 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2` +    TEST [ $HL = "0x00000001" ] + +    TEST touch $M0/dir1/rl_file_1 +    ln $M0/dir1/rl_file_1 $M0/dir2/rl_file_2 +    mv $M0/dir1/rl_file_1 $M0/dir2 + +    #now the there should be just one pgfid for both files +    for i in $(seq 1 2); do +            NL=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir2/rl_file_$i 2>&1 | grep "trusted.pgfid"|wc -l ` +            TEST_IN_LOOP [ $HL = "0x00000001" ] +    done + +    #now pgfid of both files should match +    P_rl_file_1=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir2/rl_file_1 2>&1 | grep "trusted.pgfid"` +    P_rl_file_2=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir2/rl_file_2 2>&1 | grep "trusted.pgfid"` +    TEST [ $P_rl_file_1 = $P_rl_file_2 ] + +    #now the no of hard link should be two for both rl_file_1 and rl_file_2 +    for i in  $(seq 1 2); do +        HL=`getfattr -m "trusted.pgfid" -de hex $B0/brick/dir2/rl_file_$i 2>&1 | grep "trusted.pgfid" | cut -d'=' -f2` +        TEST_IN_LOOP [ $HL = "0x00000002" ] +    done + +    TEST rm -rf $M0/* +} + +__init; +links_in_same_directory; +links_across_directories; + +cleanup diff --git a/xlators/mgmt/glusterd/src/glusterd-quota.c b/xlators/mgmt/glusterd/src/glusterd-quota.c index 31826719947..cef2baf599c 100644 --- a/xlators/mgmt/glusterd/src/glusterd-quota.c +++ b/xlators/mgmt/glusterd/src/glusterd-quota.c @@ -260,6 +260,7 @@ glusterd_quota_initiate_fs_crawl (glusterd_conf_t *priv, char *volname)          runner_add_args (&runner, SBIN_DIR"/glusterfs",                           "-s", "localhost",                           "--volfile-id", volname, +			 "--use-readdirp=no",                           "-l", DEFAULT_LOG_FILE_DIRECTORY"/quota-crawl.log",                           mountdir, NULL); diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index 0de71a49afe..da8ace953cf 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -1404,25 +1404,27 @@ static int  server_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,                        dict_t *set_dict, void *param)  { -        char     *volname                 = NULL; -        char     *path                    = NULL; -        int       pump                    = 0; -        xlator_t *xl                      = NULL; -        xlator_t *txl                     = NULL; -        xlator_t *rbxl                    = NULL; -        char      transt[16]              = {0,}; -        char     *ptranst                 = NULL; -        char      volume_id[64]           = {0,}; -        char      tstamp_file[PATH_MAX]   = {0,}; -        int       ret                     = 0; -        char     *xlator                  = NULL; -        char     *loglevel                = NULL; -        char     *username                = NULL; -        char     *password                = NULL; -        char     index_basepath[PATH_MAX] = {0}; -        char     key[1024]                = {0}; -        glusterd_brickinfo_t *brickinfo   = NULL; -        char changelog_basepath[PATH_MAX] = {0,}; +        char                 *volname       = NULL; +        char                 *path          = NULL; +        int                   pump          = 0; +        xlator_t             *xl            = NULL; +        xlator_t             *txl           = NULL; +        xlator_t             *rbxl          = NULL; +        char      transt[16]                = {0,}; +        char                 *ptranst       = NULL; +        char      volume_id[64]             = {0,}; +        char      tstamp_file[PATH_MAX]     = {0,}; +        int                   ret           = 0; +        char                 *xlator        = NULL; +        char                 *loglevel      = NULL; +        char                 *username      = NULL; +        char                 *password      = NULL; +        char     index_basepath[PATH_MAX]   = {0}; +        char     key[1024]                  = {0}; +        glusterd_brickinfo_t *brickinfo     = NULL; +        char changelog_basepath[PATH_MAX]   = {0,}; +        gf_boolean_t          quota_enabled = _gf_true; +        char                 *value         = NULL;          brickinfo = param;          path      = brickinfo->path; @@ -1441,6 +1443,13 @@ server_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,                  }          } +        ret = glusterd_volinfo_get (volinfo, VKEY_FEATURES_QUOTA, &value); +        if (value) { +                ret = gf_string2boolean (value, "a_enabled); +                if (ret) +                        goto out; +        } +          xl = volgen_graph_add (graph, "storage/posix", volname);          if (!xl)                  return -1; @@ -1454,6 +1463,10 @@ server_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,          if (ret)                  return -1; +        if (quota_enabled) +                xlator_set_option (xl, "update-link-count-parent", +                                   value); +          ret = check_and_add_debug_xl (graph, set_dict, volname,                                        "posix");          if (ret) diff --git a/xlators/storage/posix/src/posix-handle.c b/xlators/storage/posix/src/posix-handle.c index 219a582c9f7..1d8e986314f 100644 --- a/xlators/storage/posix/src/posix-handle.c +++ b/xlators/storage/posix/src/posix-handle.c @@ -26,13 +26,167 @@  #include "xlator.h"  #include "syscall.h" +inode_t * +posix_resolve (xlator_t *this, inode_table_t *itable, inode_t *parent, +               char *bname, struct iatt *iabuf) +{ +        inode_t     *inode = NULL, *linked_inode = NULL; +        int          ret   = -1; + +        ret = posix_istat (this, parent->gfid, bname, iabuf); +        if (ret < 0) +                goto out; + +        inode = inode_find (itable, iabuf->ia_gfid); +        if (inode == NULL) { +                inode = inode_new (itable); +        } + +        linked_inode = inode_link (inode, parent, bname, iabuf); + +        inode_unref (inode); + +out: +        return linked_inode; +} + +int +posix_make_ancestral_node (const char *priv_base_path, char *path, int pathsize, +                           gf_dirent_t *head, +                           char *dir_name, struct iatt *iabuf, inode_t *inode, +                           int type, dict_t *xdata) +{ +        gf_dirent_t *entry           = NULL; +        char real_path[PATH_MAX + 1] = {0, }, len = 0; +        loc_t        loc             = {0, }; +        int          ret             = -1; + +        len = strlen (path) + strlen (dir_name) + 1; +        if (len > pathsize) { +                goto out; +        } + +        strcat (path, dir_name); + +        if (type & POSIX_ANCESTRY_DENTRY) { +                entry = gf_dirent_for_name (dir_name); +                if (!entry) { +                        gf_log (THIS->name, GF_LOG_ERROR, +                                "could not create gf_dirent for entry %s: (%s)", +                                dir_name, strerror (errno)); +                        goto out; +                } + +                entry->d_stat = *iabuf; +                entry->inode = inode_ref (inode); + +                list_add_tail (&entry->list, &head->list); +                strcpy (real_path, priv_base_path); +                strcat (real_path, "/"); +                strcat (real_path, path); +                loc.inode = inode_ref (inode); +                uuid_copy (loc.gfid, inode->gfid); + +                entry->dict = posix_lookup_xattr_fill (THIS, real_path, &loc, +                                                       xdata, iabuf); +                loc_wipe (&loc); +        } + +        ret = 0; + +out: +        return ret; +} + +int +posix_make_ancestryfromgfid (xlator_t *this, char *path, int pathsize, +                             gf_dirent_t *head, int type, uuid_t gfid, +                             const size_t handle_size, +                             const char *priv_base_path, inode_table_t *itable, +                             inode_t **parent, dict_t *xdata) +{ +        char        *linkname   = NULL; /* "../../<gfid[0]>/<gfid[1]/" +                                         "<gfidstr>/<NAME_MAX>" */ +        char        *dir_handle = NULL; +        char        *dir_name   = NULL; +        char        *pgfidstr   = NULL; +        char        *saveptr    = NULL; +        ssize_t       len        = 0; +        inode_t     *inode      = NULL; +        struct iatt  iabuf      = {0, }; +        int          ret        = -1; +        uuid_t       tmp_gfid   = {0, }; + +        if (!path || !parent || !priv_base_path || uuid_is_null (gfid)) { +                goto out; +        } + +        if (__is_root_gfid (gfid)) { +                if (parent) { +                        if (*parent) { +                                inode_unref (*parent); +                        } + +                        *parent = inode_ref (itable->root); +                } + +                inode = itable->root; + +                memset (&iabuf, 0, sizeof (iabuf)); +                uuid_copy (iabuf.ia_gfid, inode->gfid); +                iabuf.ia_type = inode->ia_type; + +                ret = posix_make_ancestral_node (priv_base_path, path, pathsize, +                                                 head, "/", &iabuf, inode, type, +                                                 xdata); +                return ret; +        } + +        dir_handle = alloca (handle_size); +        linkname   = alloca (PATH_MAX); +        snprintf (dir_handle, handle_size, "%s/%s/%02x/%02x/%s", +                  priv_base_path, HANDLE_PFX, gfid[0], gfid[1], +                  uuid_utoa (gfid)); + +        len = readlink (dir_handle, linkname, PATH_MAX); +        if (len < 0) { +                gf_log (this->name, GF_LOG_ERROR, "could not read the link " +                        "from the gfid handle %s (%s)", dir_handle, +                        strerror (errno)); +                goto out; +        } + +        linkname[len] = '\0'; + +        pgfidstr = strtok_r (linkname + SLEN("../../00/00/"), "/", &saveptr); +        dir_name = strtok_r (NULL, "/", &saveptr); +        strcat (dir_name, "/"); -#define HANDLE_PFX ".glusterfs" -#define TRASH_DIR "landfill" +        uuid_parse (pgfidstr, tmp_gfid); + +        ret = posix_make_ancestryfromgfid (this, path, pathsize, head, type, +                                           tmp_gfid, handle_size, +                                           priv_base_path, itable, parent, +                                           xdata); +        if (ret < 0) { +                goto out; +        } -#define UUID0_STR "00000000-0000-0000-0000-000000000000" -#define SLEN(str) (sizeof(str) - 1) +        memset (&iabuf, 0, sizeof (iabuf)); +        inode = posix_resolve (this, itable, *parent, dir_name, &iabuf); + +        ret = posix_make_ancestral_node (priv_base_path, path, pathsize, head, +                                         dir_name, &iabuf, inode, type, xdata); +        if (*parent != NULL) { +                inode_unref (*parent); +        } + +        *parent = inode; + +out: +        return ret; +}  int  posix_handle_relpath (xlator_t *this, uuid_t gfid, const char *basename, diff --git a/xlators/storage/posix/src/posix-handle.h b/xlators/storage/posix/src/posix-handle.h index f1163b72795..8874ca2655f 100644 --- a/xlators/storage/posix/src/posix-handle.h +++ b/xlators/storage/posix/src/posix-handle.h @@ -17,9 +17,86 @@  #include <sys/types.h>  #include "xlator.h" +#include "gf-dirent.h" +#define HANDLE_PFX ".glusterfs" +#define TRASH_DIR "landfill" -#define LOC_HAS_ABSPATH(loc) ((loc) && (loc->path) && (loc->path[0] == '/')) +#define UUID0_STR "00000000-0000-0000-0000-000000000000" +#define SLEN(str) (sizeof(str) - 1) + +#define LOC_HAS_ABSPATH(loc) (loc && (loc->path) && (loc->path[0] == '/')) + +#define MAKE_PGFID_XATTR_KEY(var, prefix, pgfid) do {                   \ +        var = alloca (strlen (prefix) + UUID_CANONICAL_FORM_LEN + 1);   \ +        strcpy (var, prefix);                                           \ +        strcat (var, uuid_utoa (pgfid));                                \ +        } while (0) + +#define SET_PGFID_XATTR(path, key, value, flags, op_ret, this, label) do {    \ +        value = hton32 (value);                                         \ +        op_ret = sys_lsetxattr (path, key, &value, sizeof (value),      \ +                                flags);                                 \ +        if (op_ret == -1) {                                             \ +                op_errno = errno;                                       \ +                gf_log (this->name, GF_LOG_WARNING,                     \ +                        "setting xattr failed on %s: key = %s (%s)",    \ +                        path, key, strerror (op_errno));                \ +                goto label;                                             \ +        }                                                               \ +        } while (0) + + +#define REMOVE_PGFID_XATTR(path, key, op_ret, this, label) do {               \ +       op_ret = sys_lremovexattr (path, key);                           \ +       if (op_ret == -1) {                                              \ +               op_errno = errno;                                        \ +               gf_log (this->name, GF_LOG_WARNING, "removing xattr "    \ +                       "failed on %s: key = %s (%s)", path, key,        \ +                       strerror (op_errno));                            \ +               goto label;                                              \ +       }                                                                \ +       } while (0) + +/* should be invoked holding a lock */ +#define LINK_MODIFY_PGFID_XATTR(path, key, value, flags, op_ret, this, label) do { \ +       op_ret = sys_lgetxattr (path, key, &value, sizeof (value));  \ +       if (op_ret == -1) {                                              \ +               op_errno = errno;                                        \ +               if (op_errno == ENOATTR) {                               \ +                       value = 1;                                       \ +               } else {                                                 \ +                       gf_log (this->name, GF_LOG_WARNING,"getting xattr " \ +                               "failed on %s: key = %s (%s)", path, key, \ +                               strerror (op_errno));                    \ +                       goto label;                                      \ +               }                                                        \ +       } else {                                                         \ +               value = ntoh32 (value);                                  \ +               value++;                                                 \ +       }                                                                \ +       SET_PGFID_XATTR (path, key, value, flags, op_ret, this, label);  \ +       } while (0) + +/* should be invoked holding a lock */ +#define UNLINK_MODIFY_PGFID_XATTR(path, key, value, flags, op_ret, this, label) do { \ +       op_ret = sys_lgetxattr (path, key, &value, sizeof (value));  \ +       if (op_ret == -1) {                                              \ +               op_errno = errno;                                        \ +               gf_log (this->name, GF_LOG_WARNING, "getting xattr failed on " \ +                       "%s: key = %s (%s)", path, key, strerror (op_errno)); \ +               goto label;                                              \ +       } else {                                                         \ +               value = ntoh32 (value);                                  \ +               value--;                                                 \ +               if (value > 0) {                                         \ +                       SET_PGFID_XATTR (path, key, value, flags, op_ret, \ +                                        this, label);                   \ +               } else {                                                 \ +                       REMOVE_PGFID_XATTR (path, key, op_ret, this, label); \ +               }                                                        \ +       }                                                                \ +    } while (0)  #define MAKE_REAL_PATH(var, this, path) do {                            \          var = alloca (strlen (path) + POSIX_BASE_PATH_LEN(this) + 2);   \ @@ -27,7 +104,6 @@          strcpy (&var[POSIX_BASE_PATH_LEN(this)], path);                 \          } while (0) -  #define MAKE_HANDLE_PATH(var, this, gfid, base) do {                    \          int __len;                                                      \          __len = posix_handle_path (this, gfid, base, NULL, 0);          \ @@ -61,12 +137,12 @@  #define MAKE_INODE_HANDLE(rpath, this, loc, iatt_p) do {                \          if (uuid_is_null (loc->gfid)) {                                 \                  gf_log (this->name, GF_LOG_ERROR,                       \ -                        "null gfid for path %s", loc->path);            \ +                        "null gfid for path %s", (loc)->path);          \                  break;                                                  \          }                                                               \          if (LOC_HAS_ABSPATH (loc)) {                                    \ -                MAKE_REAL_PATH (rpath, this, loc->path);                \ -                op_ret = posix_pstat (this, loc->gfid, rpath, iatt_p);  \ +                MAKE_REAL_PATH (rpath, this, (loc)->path);              \ +                op_ret = posix_pstat (this, (loc)->gfid, rpath, iatt_p); \                  break;                                                  \          }                                                               \          errno = 0;                                                      \ @@ -107,10 +183,20 @@          } while (0) +#define POSIX_ANCESTRY_PATH (1 << 0) +#define POSIX_ANCESTRY_DENTRY (1 << 1)  int  posix_handle_path (xlator_t *this, uuid_t gfid, const char *basename, char *buf,                     size_t len); + +int +posix_make_ancestryfromgfid (xlator_t *this, char *path, int pathsize, +                             gf_dirent_t *head, int type, uuid_t gfid, +                             const size_t handle_size, +                             const char *priv_base_path, +                             inode_table_t *table, inode_t **parent, +                             dict_t *xdata);  int  posix_handle_path_safe (xlator_t *this, uuid_t gfid, const char *basename,                          char *buf, size_t len); diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c index e295f8850b4..4db15bf571c 100644 --- a/xlators/storage/posix/src/posix-helpers.c +++ b/xlators/storage/posix/src/posix-helpers.c @@ -102,14 +102,54 @@ out:  }  static int +_posix_xattr_get_set_from_backend (posix_xattr_filler_t *filler, char *key) +{ +        ssize_t  xattr_size = -1; +        int      ret        = 0; +        char    *value      = NULL; + +        xattr_size = sys_lgetxattr (filler->real_path, key, NULL, 0); + +        if (xattr_size > 0) { +                value = GF_CALLOC (1, xattr_size + 1, +                                   gf_posix_mt_char); +                if (!value) +                        goto out; + +                xattr_size = sys_lgetxattr (filler->real_path, key, value, +                                            xattr_size); +                if (xattr_size <= 0) { +                        gf_log (filler->this->name, GF_LOG_WARNING, +                                "getxattr failed. path: %s, key: %s", +                                filler->real_path, key); +                        GF_FREE (value); +                        goto out; +                } + +                value[xattr_size] = '\0'; +                ret = dict_set_bin (filler->xattr, key, +                                    value, xattr_size); +                if (ret < 0) { +                        gf_log (filler->this->name, GF_LOG_DEBUG, +                                "dict set failed. path: %s, key: %s", +                                filler->real_path, key); +                        GF_FREE (value); +                        goto out; +                } +        } +        ret = 0; +out: +        return ret; +} + + +static int  _posix_xattr_get_set (dict_t *xattr_req,                        char *key,                        data_t *data,                        void *xattrargs)  {          posix_xattr_filler_t *filler = xattrargs; -        char     *value      = NULL; -        ssize_t   xattr_size = -1;          int       ret      = -1;          char     *databuf  = NULL;          int       _fd      = -1; @@ -183,35 +223,24 @@ _posix_xattr_get_set (dict_t *xattr_req,                                          "Failed to set dictionary value for %s",                                          key);                  } -        } else { -                xattr_size = sys_lgetxattr (filler->real_path, key, NULL, 0); - -                if (xattr_size > 0) { -                        value = GF_CALLOC (1, xattr_size + 1, -                                           gf_posix_mt_char); -                        if (!value) -                                return -1; - -                        xattr_size = sys_lgetxattr (filler->real_path, key, value, -                                                    xattr_size); -                        if (xattr_size <= 0) { -                                gf_log (filler->this->name, GF_LOG_WARNING, -                                        "getxattr failed. path: %s, key: %s", -                                        filler->real_path, key); -                                GF_FREE (value); -                                return -1; -                        } +        } else if (!strcmp (key, GET_ANCESTRY_PATH_KEY)) { +                char *path = NULL; +                ret = posix_get_ancestry (filler->this, filler->loc->inode, +                                          NULL, &path, POSIX_ANCESTRY_PATH, +                                          &filler->op_errno, xattr_req); +                if (ret < 0) { +                        goto out; +                } -                        value[xattr_size] = '\0'; -                        ret = dict_set_bin (filler->xattr, key, -                                            value, xattr_size); -                        if (ret < 0) { -                                gf_log (filler->this->name, GF_LOG_DEBUG, -                                        "dict set failed. path: %s, key: %s", -                                        filler->real_path, key); -                                GF_FREE (value); -                        } +                ret = dict_set_dynstr (filler->xattr, GET_ANCESTRY_PATH_KEY, +                                       path); +                if (ret < 0) { +                        GF_FREE (path); +                        goto out;                  } + +        } else { +                ret = _posix_xattr_get_set_from_backend (filler, key);          }  out:          return 0; diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 1a344acbb5a..65b52a07cd5 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -79,7 +79,6 @@ extern char *marker_xattrs[];  #define SET_TO_OLD_FS_ID()  #endif -  int  posix_forget (xlator_t *this, inode_t *inode)  { @@ -105,15 +104,18 @@ posix_lookup (call_frame_t *frame, xlator_t *this,          char *      par_path           = NULL;          struct iatt postparent         = {0,};          int32_t     gfidless           = 0; +        struct  posix_private *priv    = NULL;          VALIDATE_OR_GOTO (frame, out);          VALIDATE_OR_GOTO (this, out);          VALIDATE_OR_GOTO (loc, out); +        priv = this->private; +          /* The Hidden directory should be for housekeeping purpose and it             should not get any gfid on it */ -        if (__is_root_gfid (loc->pargfid) && -            (strcmp (loc->name, GF_HIDDEN_PATH) == 0)) { +        if (__is_root_gfid (loc->pargfid) && loc->name +            && (strcmp (loc->name, GF_HIDDEN_PATH) == 0)) {                  gf_log (this->name, GF_LOG_WARNING,                          "Lookup issued on %s, which is not permitted",                          GF_HIDDEN_PATH); @@ -124,7 +126,7 @@ posix_lookup (call_frame_t *frame, xlator_t *this,          op_ret = dict_get_int32 (xdata, GF_GFIDLESS_LOOKUP, &gfidless);          op_ret = -1; -        if (uuid_is_null (loc->pargfid)) { +        if (uuid_is_null (loc->pargfid) || (loc->name == NULL)) {                  /* nameless lookup */                  MAKE_INODE_HANDLE (real_path, this, loc, &buf);          } else { @@ -1029,18 +1031,20 @@ int  posix_mknod (call_frame_t *frame, xlator_t *this,               loc_t *loc, mode_t mode, dev_t dev, mode_t umask, dict_t *xdata)  { -        int                   tmp_fd      = 0; -        int32_t               op_ret      = -1; -        int32_t               op_errno    = 0; -        char                 *real_path   = 0; -        char                 *par_path    = 0; -        struct iatt           stbuf       = { 0, }; -        char                  was_present = 1; -        struct posix_private *priv        = NULL; -        gid_t                 gid         = 0; -        struct iatt           preparent = {0,}; -        struct iatt           postparent = {0,}; -        void *                uuid_req  = NULL; +        int                   tmp_fd          = 0; +        int32_t               op_ret          = -1; +        int32_t               op_errno        = 0; +        char                 *real_path       = 0; +        char                 *par_path        = 0; +        struct iatt           stbuf           = { 0, }; +        char                  was_present     = 1; +        struct posix_private *priv            = NULL; +        gid_t                 gid             = 0; +        struct iatt           preparent       = {0,}; +        struct iatt           postparent      = {0,}; +        void *                uuid_req        = NULL; +        int32_t               nlink_samepgfid = 0; +        char                 *pgfid_xattr_key = NULL;          DECLARE_OLD_FS_ID_VAR; @@ -1143,6 +1147,16 @@ post_op:                          strerror (errno));          } +        if (priv->update_pgfid_nlinks) { +                MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX, +                                      loc->pargfid); +                nlink_samepgfid = 1; + +                SET_PGFID_XATTR (real_path, pgfid_xattr_key, nlink_samepgfid, +                                 XATTR_CREATE, op_ret, this, ignore); +        } + +ignore:          op_ret = posix_entry_create_xattr_set (this, real_path, xdata);          if (op_ret) {                  gf_log (this->name, GF_LOG_ERROR, @@ -1271,7 +1285,6 @@ posix_mkdir (call_frame_t *frame, xlator_t *this,                  goto out;          }  #endif -          op_ret = posix_acl_xattr_set (this, real_path, xdata);          if (op_ret) {                  gf_log (this->name, GF_LOG_ERROR, @@ -1325,15 +1338,17 @@ int32_t  posix_unlink (call_frame_t *frame, xlator_t *this,                loc_t *loc, int xflag, dict_t *xdata)  { -        int32_t               op_ret     = -1; -        int32_t               op_errno   = 0; -        char                 *real_path  = NULL; -        char                 *par_path   = NULL; -        int32_t               fd         = -1; -        struct iatt           stbuf      = {0,}; -        struct posix_private *priv       = NULL; -        struct iatt           preparent  = {0,}; -        struct iatt           postparent = {0,}; +        int32_t               op_ret          = -1; +        int32_t               op_errno        = 0; +        char                 *real_path       = NULL; +        char                 *par_path        = NULL; +        int32_t               fd              = -1; +        struct iatt           stbuf           = {0,}; +        struct posix_private *priv            = NULL; +        struct iatt           preparent       = {0,}; +        struct iatt           postparent      = {0,}; +        char                 *pgfid_xattr_key = NULL; +        int32_t               nlink_samepgfid = 0;          DECLARE_OLD_FS_ID_VAR; @@ -1371,6 +1386,26 @@ posix_unlink (call_frame_t *frame, xlator_t *this,                  }          } +        if (priv->update_pgfid_nlinks && (stbuf.ia_nlink > 1)) { +                MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX, +                                      loc->pargfid); +                LOCK (&loc->inode->lock); +                { +                        UNLINK_MODIFY_PGFID_XATTR (real_path, pgfid_xattr_key, +                                                   nlink_samepgfid, 0, op_ret, +                                                   this, unlock); +                } +        unlock: +                UNLOCK (&loc->inode->lock); + +                if (op_ret < 0) { +                        gf_log (this->name, GF_LOG_WARNING, "modification of " +                                "parent gfid xattr failed (path:%s gfid:%s)", +                                real_path, uuid_utoa (loc->inode->gfid)); +                        goto out; +                } +        } +          op_ret = sys_unlink (real_path);          if (op_ret == -1) {                  op_errno = errno; @@ -1512,16 +1547,18 @@ int  posix_symlink (call_frame_t *frame, xlator_t *this,                 const char *linkname, loc_t *loc, mode_t umask, dict_t *xdata)  { -        int32_t               op_ret      = -1; -        int32_t               op_errno    = 0; -        char *                real_path   = 0; -        char *                par_path   = 0; -        struct iatt           stbuf       = { 0, }; -        struct posix_private *priv        = NULL; -        gid_t                 gid         = 0; -        char                  was_present = 1; -        struct iatt           preparent = {0,}; -        struct iatt           postparent = {0,}; +        int32_t               op_ret          = -1; +        int32_t               op_errno        = 0; +        char *                real_path       = 0; +        char *                par_path        = 0; +        struct iatt           stbuf           = { 0, }; +        struct posix_private *priv            = NULL; +        gid_t                 gid             = 0; +        char                  was_present     = 1; +        struct iatt           preparent       = {0,}; +        struct iatt           postparent      = {0,}; +        char                 *pgfid_xattr_key = NULL; +        int32_t               nlink_samepgfid = 0;          DECLARE_OLD_FS_ID_VAR; @@ -1582,7 +1619,6 @@ posix_symlink (call_frame_t *frame, xlator_t *this,                  goto out;          }  #endif -          op_ret = posix_acl_xattr_set (this, real_path, xdata);          if (op_ret) {                  gf_log (this->name, GF_LOG_ERROR, @@ -1590,6 +1626,14 @@ posix_symlink (call_frame_t *frame, xlator_t *this,                          strerror (errno));          } +        if (priv->update_pgfid_nlinks) { +                MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX, +                                      loc->pargfid); +                nlink_samepgfid = 1; +                SET_PGFID_XATTR (real_path, pgfid_xattr_key, nlink_samepgfid, +                                 XATTR_CREATE, op_ret, this, ignore); +        } +ignore:          op_ret = posix_entry_create_xattr_set (this, real_path, xdata);          if (op_ret) {                  gf_log (this->name, GF_LOG_ERROR, @@ -1636,24 +1680,26 @@ int  posix_rename (call_frame_t *frame, xlator_t *this,                loc_t *oldloc, loc_t *newloc, dict_t *xdata)  { -        int32_t               op_ret       = -1; -        int32_t               op_errno     = 0; -        char                 *real_oldpath = NULL; -        char                 *real_newpath = NULL; -        char                 *par_oldpath = NULL; -        char                 *par_newpath = NULL; -        struct iatt           stbuf        = {0, }; -        struct posix_private *priv         = NULL; -        char                  was_present  = 1; -        struct iatt           preoldparent  = {0, }; -        struct iatt           postoldparent = {0, }; -        struct iatt           prenewparent  = {0, }; -        struct iatt           postnewparent = {0, }; +        int32_t               op_ret          = -1; +        int32_t               op_errno        = 0; +        char                 *real_oldpath    = NULL; +        char                 *real_newpath    = NULL; +        char                 *par_oldpath     = NULL; +        char                 *par_newpath     = NULL; +        struct iatt           stbuf           = {0, }; +        struct posix_private *priv            = NULL; +        char                  was_present     = 1; +        struct iatt           preoldparent    = {0, }; +        struct iatt           postoldparent   = {0, }; +        struct iatt           prenewparent    = {0, }; +        struct iatt           postnewparent   = {0, };          char                  olddirid[64];          char                  newdirid[64]; -        uuid_t                victim = {0}; -        int                   was_dir = 0; -        int                   nlink = 0; +        uuid_t                victim          = {0}; +        int                   was_dir         = 0; +        int                   nlink           = 0; +        char                 *pgfid_xattr_key = NULL; +        int32_t               nlink_samepgfid = 0;          DECLARE_OLD_FS_ID_VAR; @@ -1718,17 +1764,64 @@ posix_rename (call_frame_t *frame, xlator_t *this,                  goto out;          } -        if (IA_ISDIR (oldloc->inode->ia_type)) { +        if (IA_ISDIR (oldloc->inode->ia_type))                  posix_handle_unset (this, oldloc->inode->gfid, NULL); + +        LOCK (&oldloc->inode->lock); +        { +                if (!IA_ISDIR (oldloc->inode->ia_type) +                    && priv->update_pgfid_nlinks) { +                        MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, +                                              PGFID_XATTR_KEY_PREFIX, +                                              oldloc->pargfid); +                        UNLINK_MODIFY_PGFID_XATTR (real_oldpath, +                                                   pgfid_xattr_key, +                                                   nlink_samepgfid, 0, +                                                   op_ret, +                                                   this, unlock); +                } + +                op_ret = sys_rename (real_oldpath, real_newpath); +                if (op_ret == -1) { +                        op_errno = errno; +                        gf_log (this->name, +                                (op_errno == ENOTEMPTY ? GF_LOG_DEBUG +                                 : GF_LOG_ERROR), +                                "rename of %s to %s failed: %s", +                                real_oldpath, real_newpath, +                                strerror (op_errno)); + +                        if (priv->update_pgfid_nlinks +                            && !IA_ISDIR (oldloc->inode->ia_type)) { +                                LINK_MODIFY_PGFID_XATTR (real_oldpath, +                                                         pgfid_xattr_key, +                                                         nlink_samepgfid, 0, +                                                         op_ret, +                                                         this, unlock); +                        } + +                        goto unlock; +                } + +                if (!IA_ISDIR (oldloc->inode->ia_type) +                    && priv->update_pgfid_nlinks) { +                        MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, +                                              PGFID_XATTR_KEY_PREFIX, +                                              newloc->pargfid); +                        LINK_MODIFY_PGFID_XATTR (real_newpath, +                                                 pgfid_xattr_key, +                                                 nlink_samepgfid, 0, +                                                 op_ret, +                                                 this, unlock); +                }          } +unlock: +        UNLOCK (&oldloc->inode->lock); -        op_ret = sys_rename (real_oldpath, real_newpath); -        if (op_ret == -1) { -                op_errno = errno; -                gf_log (this->name, -                        (op_errno == ENOTEMPTY ? GF_LOG_DEBUG : GF_LOG_ERROR), -                        "rename of %s to %s failed: %s", -                        real_oldpath, real_newpath, strerror (op_errno)); +        if (op_ret < 0) { +                gf_log (this->name, GF_LOG_WARNING, "modification of " +                        "parent gfid xattr failed (gfid:%s)", +                        uuid_utoa (oldloc->inode->gfid));                  goto out;          } @@ -1792,16 +1885,18 @@ int  posix_link (call_frame_t *frame, xlator_t *this,              loc_t *oldloc, loc_t *newloc, dict_t *xdata)  { -        int32_t               op_ret       = -1; -        int32_t               op_errno     = 0; -        char                 *real_oldpath = 0; -        char                 *real_newpath = 0; -        char                 *par_newpath = 0; -        struct iatt           stbuf        = {0, }; -        struct posix_private *priv         = NULL; -        char                  was_present  = 1; -        struct iatt           preparent = {0,}; -        struct iatt           postparent = {0,}; +        int32_t               op_ret          = -1; +        int32_t               op_errno        = 0; +        char                 *real_oldpath    = 0; +        char                 *real_newpath    = 0; +        char                 *par_newpath     = 0; +        struct iatt           stbuf           = {0, }; +        struct posix_private *priv            = NULL; +        char                  was_present     = 1; +        struct iatt           preparent       = {0,}; +        struct iatt           postparent      = {0,}; +        int32_t               nlink_samepgfid = 0; +        char                 *pgfid_xattr_key = NULL;          DECLARE_OLD_FS_ID_VAR; @@ -1866,6 +1961,27 @@ posix_link (call_frame_t *frame, xlator_t *this,                  goto out;          } +        if (priv->update_pgfid_nlinks) { +                MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX, +                                      newloc->pargfid); + +                LOCK (&newloc->inode->lock); +                { +                        LINK_MODIFY_PGFID_XATTR (real_newpath, pgfid_xattr_key, +                                                 nlink_samepgfid, 0, op_ret, +                                                 this, unlock); +                } +        unlock: +                UNLOCK (&newloc->inode->lock); + +                if (op_ret < 0) { +                        gf_log (this->name, GF_LOG_WARNING, "modification of " +                                "parent gfid xattr failed (path:%s gfid:%s)", +                                real_newpath, uuid_utoa (newloc->inode->gfid)); +                        goto out; +                } +        } +          op_ret = 0;  out: @@ -1932,7 +2048,6 @@ posix_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset,          }          op_ret = 0; -  out:          SET_TO_OLD_FS_ID (); @@ -1948,20 +2063,23 @@ posix_create (call_frame_t *frame, xlator_t *this,                loc_t *loc, int32_t flags, mode_t mode,                mode_t umask, fd_t *fd, dict_t *xdata)  { -        int32_t                op_ret      = -1; -        int32_t                op_errno    = 0; -        int32_t                _fd         = -1; -        int                    _flags      = 0; -        char *                 real_path   = NULL; -        char *                 par_path   = NULL; -        struct iatt            stbuf       = {0, }; -        struct posix_fd *      pfd         = NULL; -        struct posix_private * priv        = NULL; -        char                   was_present = 1; - -        gid_t                  gid         = 0; -        struct iatt            preparent = {0,}; -        struct iatt            postparent = {0,}; +        int32_t                op_ret          = -1; +        int32_t                op_errno        = 0; +        int32_t                _fd             = -1; +        int                    _flags          = 0; +        char *                 real_path       = NULL; +        char *                 par_path        = NULL; +        struct iatt            stbuf           = {0, }; +        struct posix_fd *      pfd             = NULL; +        struct posix_private * priv            = NULL; +        char                   was_present     = 1; + +        gid_t                  gid             = 0; +        struct iatt            preparent       = {0,}; +        struct iatt            postparent      = {0,}; + +        int                    nlink_samepgfid = 0; +        char *                 pgfid_xattr_key = NULL;          DECLARE_OLD_FS_ID_VAR; @@ -2037,7 +2155,6 @@ posix_create (call_frame_t *frame, xlator_t *this,                          real_path, strerror (op_errno));          }  #endif -          op_ret = posix_acl_xattr_set (this, real_path, xdata);          if (op_ret) {                  gf_log (this->name, GF_LOG_ERROR, @@ -2045,6 +2162,14 @@ posix_create (call_frame_t *frame, xlator_t *this,                          strerror (errno));          } +        if (priv->update_pgfid_nlinks) { +                MAKE_PGFID_XATTR_KEY (pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX, +                                      loc->pargfid); +                nlink_samepgfid = 1; +                SET_PGFID_XATTR (real_path, pgfid_xattr_key, nlink_samepgfid, +                                 XATTR_CREATE, op_ret, this, ignore); +        } +ignore:          op_ret = posix_entry_create_xattr_set (this, real_path, xdata);          if (op_ret) {                  gf_log (this->name, GF_LOG_ERROR, @@ -2876,6 +3001,335 @@ posix_xattr_get_real_filename (call_frame_t *frame, xlator_t *this, loc_t *loc,  	return ret;  } +int +posix_get_ancestry_directory (xlator_t *this, inode_t *leaf_inode, +                              gf_dirent_t *head, char **path, int type, +                              int32_t *op_errno, dict_t *xdata) +{ +        ssize_t               handle_size = 0; +        struct posix_private *priv        = NULL; +        char    dirpath[PATH_MAX+1]       = {0,}; +        inode_t              *inode       = NULL; +        int                   ret         = -1; + +        priv = this->private; + +        handle_size = POSIX_GFID_HANDLE_SIZE(priv->base_path_length); + +        ret = posix_make_ancestryfromgfid (this, dirpath, PATH_MAX + 1, head, +                                           type | POSIX_ANCESTRY_PATH, +                                           leaf_inode->gfid, +                                           handle_size, priv->base_path, +                                           leaf_inode->table, &inode, xdata); +        if (ret < 0) +                goto out; + + +        /* there is already a reference in loc->inode */ +        inode_unref (inode); + +        if ((type & POSIX_ANCESTRY_PATH) && (path != NULL)) { +                if (strcmp (dirpath, "/")) +                        dirpath[strlen (dirpath) - 1] = '\0'; + +                *path = gf_strdup (dirpath); +        } + +out: +        return ret; +} + +int32_t +posix_links_in_same_directory (char *dirpath, int count, inode_t *leaf_inode, +                               inode_t *parent, uint64_t ino, +                               gf_dirent_t *head, char **path, +                               int type, dict_t *xdata, int32_t *op_errno) +{ +        DIR                  *dirp         = NULL; +        int                   op_ret       = -1; +        struct dirent        *entry        = NULL; +        struct dirent        *result       = NULL; +        inode_t              *linked_inode = NULL; +        gf_dirent_t          *gf_entry     = NULL; +        char    temppath[PATH_MAX+1]       = {0,}; +        xlator_t             *this         = NULL; +        struct posix_private *priv         = NULL; +        char                 *tempv        = NULL; + +        this = THIS; + +        priv = this->private; + +        dirp = opendir (dirpath); +        if (!dirp) { +                *op_errno = errno; +                gf_log (this->name, GF_LOG_WARNING, +                        "could not opendir %s: %s", dirpath, +                        strerror (*op_errno)); +                goto out; +        } + +        entry = alloca (offsetof(struct dirent, d_name) + NAME_MAX + 1); +        if (entry == NULL) +                goto out; + +        while (count > 0) { +                *op_errno = readdir_r (dirp, entry, &result); +                if ((result == NULL) || *op_errno) +                        break; + +                if (entry->d_ino != ino) +                        continue; + +                linked_inode = inode_link (leaf_inode, parent, +                                           entry->d_name, NULL); + +                GF_ASSERT (linked_inode == leaf_inode); +                inode_unref (linked_inode); + +                if (type & POSIX_ANCESTRY_DENTRY) { +                        loc_t loc = {0, }; + +                        loc.inode = inode_ref (leaf_inode); +                        uuid_copy (loc.gfid, leaf_inode->gfid); + +                        strcpy (temppath, dirpath); +                        strcat (temppath, "/"); +                        strcat (temppath, entry->d_name); + +                        gf_entry = gf_dirent_for_name (entry->d_name); +                        gf_entry->inode = inode_ref (leaf_inode); +                        gf_entry->dict +                                = posix_lookup_xattr_fill (this, +                                                           temppath, +                                                           &loc, xdata, +                                                           NULL); +                        list_add_tail (&gf_entry->list, &head->list); +                        loc_wipe (&loc); +                } + +                if (type & POSIX_ANCESTRY_PATH) { +                        strcpy (temppath, +                                &dirpath[priv->base_path_length]); +                        strcat (temppath, "/"); +                        strcat (temppath, entry->d_name); +                        if (!*path) { +                                *path = gf_strdup (temppath); +                        } else { +                                /* creating a colon separated */ +                                /* list of hard links */ +                                tempv  = GF_REALLOC (*path, strlen (*path) +                                                     + 1  // ':' +                                                     + strlen (temppath) + 1 ); +                                if (!tempv) { +                                        gf_log (this->name, GF_LOG_WARNING, +                                                "realloc failed on path"); +                                        GF_FREE (*path); +                                        op_ret = -1; +                                        *op_errno = ENOMEM; +                                        goto out; +                                } + +                                *path = tempv; +                                strcat (*path, ":"); +                                strcat (*path, temppath); +                        } +                } + +                count--; +        } + +out: +        if (dirp) { +                op_ret = closedir (dirp); +                if (op_ret == -1) { +                        *op_errno = errno; +                        gf_log (this->name, GF_LOG_WARNING, +                                "closedir failed: %s", +                                strerror (*op_errno)); +                } +        } + +        return op_ret; +} + +int +posix_get_ancestry_non_directory (xlator_t *this, inode_t *leaf_inode, +                                  gf_dirent_t *head, char **path, int type, +                                  int32_t *op_errno, dict_t *xdata) +{ +        size_t                remaining_size        = 0; +        char    dirpath[PATH_MAX+1]                 = {0,}, *leaf_path = NULL; +        int                   op_ret                = -1, pathlen = -1; +        ssize_t               handle_size           = 0; +        char    pgfidstr[UUID_CANONICAL_FORM_LEN+1] = {0,}; +        uuid_t                pgfid                 = {0, }; +        int                   nlink_samepgfid       = 0; +        struct stat           stbuf                 = {0,}; +        char                 *list                  = NULL; +        int32_t               list_offset           = 0; +        char     key[4096]                          = {0,}; +        struct posix_private *priv                  = NULL; +        ssize_t               size                  = 0; +        inode_t              *parent                = NULL; +        loc_t                *loc                   = NULL; + +        priv = this->private; + +        loc = GF_CALLOC (1, sizeof (*loc), gf_posix_mt_char); +        if (loc == NULL) { +                op_ret = -1; +                *op_errno = ENOMEM; +                goto out; +        } + +        uuid_copy (loc->gfid, leaf_inode->gfid); + +        MAKE_INODE_HANDLE (leaf_path, this, loc, NULL); + +        GF_FREE (loc); + +        size = sys_llistxattr (leaf_path, NULL, 0); +        if (size == -1) { +                *op_errno = errno; +                if ((errno == ENOTSUP) || (errno == ENOSYS)) { +                        GF_LOG_OCCASIONALLY (gf_posix_xattr_enotsup_log, +                                             this->name, GF_LOG_WARNING, +                                             "Extended attributes not " +                                             "supported (try remounting brick" +                                             " with 'user_xattr' flag)"); + +                } else { +                        gf_log (this->name, GF_LOG_WARNING, +                                "listxattr failed on %s: %s", +                                leaf_path, strerror (*op_errno)); + +                } + +                goto out; +        } + +        if (size == 0) { +                op_ret = 0; +                goto out; +        } + +        list = alloca (size + 1); +        if (!list) { +                *op_errno = errno; +                goto out; +        } + +        size = sys_llistxattr (leaf_path, list, size); +        remaining_size = size; +        list_offset = 0; + +        op_ret = sys_lstat (leaf_path, &stbuf); +        if (op_ret == -1) { +                *op_errno = errno; +                gf_log (this->name, GF_LOG_WARNING, "lstat failed" +                        " on %s: %s", leaf_path, +                        strerror (*op_errno)); +                goto out; +        } + +        while (remaining_size > 0) { +                if (*(list + list_offset) == '\0') +                        break; +                strcpy (key, list + list_offset); +                if (strncmp (key, PGFID_XATTR_KEY_PREFIX, +                             strlen (PGFID_XATTR_KEY_PREFIX)) != 0) +                        goto next; + +                op_ret = sys_lgetxattr (leaf_path, key, +                                        &nlink_samepgfid, +                                        sizeof(nlink_samepgfid)); +                if (op_ret == -1) { +                        *op_errno = errno; +                        gf_log (this->name, GF_LOG_ERROR, +                                "getxattr failed on " +                                "%s: key = %s (%s)", +                                leaf_path, +                                key, +                                strerror (*op_errno)); +                        goto out; +                } + +                nlink_samepgfid = ntoh32 (nlink_samepgfid); + +                strcpy (pgfidstr, key + strlen(PGFID_XATTR_KEY_PREFIX)); +                uuid_parse (pgfidstr, pgfid); + +                handle_size = POSIX_GFID_HANDLE_SIZE(priv->base_path_length); + +                /* constructing the absolute real path of parent dir */ +                strcpy (dirpath, priv->base_path); +                pathlen = PATH_MAX + 1 - priv->base_path_length; + +                op_ret = posix_make_ancestryfromgfid (this, +                                                      dirpath + priv->base_path_length, +                                                      pathlen, +                                                      head, +                                                      POSIX_ANCESTRY_PATH | POSIX_ANCESTRY_DENTRY, +                                                      pgfid, +                                                      handle_size, +                                                      priv->base_path, +                                                      leaf_inode->table, +                                                      &parent, xdata); +                if (op_ret < 0) { +                        goto next; +                } + +                dirpath[strlen (dirpath) - 1] = '\0'; + +                posix_links_in_same_directory (dirpath, nlink_samepgfid, +                                               leaf_inode, +                                               parent, stbuf.st_ino, head, +                                               path, type, xdata, op_errno); + +                if (parent != NULL) { +                        inode_unref (parent); +                        parent = NULL; +                } + +        next: +                remaining_size -= strlen (key) + 1; +                list_offset += strlen (key) + 1; +        } /* while (remaining_size > 0) */ + +        op_ret = 0; + +out: +        return op_ret; +} + +int +posix_get_ancestry (xlator_t *this, inode_t *leaf_inode, +                    gf_dirent_t *head, char **path, int type, int32_t *op_errno, +                    dict_t *xdata) +{ +        int                   ret  = -1; +        struct posix_private *priv = NULL; + +        priv = this->private; + +        if (!priv->update_pgfid_nlinks) +                goto out; + +        if (IA_ISDIR (leaf_inode->ia_type)) { +                ret = posix_get_ancestry_directory (this, leaf_inode, +                                                    head, path, type, op_errno, +                                                    xdata); +        } else  { +                ret = posix_get_ancestry_non_directory (this, leaf_inode, +                                                        head, path, type, +                                                        op_errno, xdata); +        } + +out: +        return ret; +} +  /**   * posix_getxattr - this function returns a dictionary with all the   *                  key:value pair present as xattr. used for @@ -2885,23 +3339,23 @@ int32_t  posix_getxattr (call_frame_t *frame, xlator_t *this,                  loc_t *loc, const char *name, dict_t *xdata)  { -        struct posix_private *priv           = NULL; -        int32_t               op_ret         = -1; -        int32_t               op_errno       = 0; -        int32_t               list_offset    = 0; -        ssize_t               size           = 0; -        size_t                remaining_size = 0; -        char     key[4096]                   = {0,}; -        char     host_buf[1024]              = {0,}; -        char                 *value          = NULL; -        char                 *list           = NULL; -        char                 *real_path      = NULL; -        dict_t               *dict           = NULL; -        char                 *file_contents  = NULL; -        int                   ret            = -1; -        char                 *path           = NULL; -        char                 *rpath          = NULL; -        char                 *dyn_rpath      = NULL; +        struct posix_private *priv                  = NULL; +        int32_t               op_ret                = -1; +        int32_t               op_errno              = 0; +        char     host_buf[1024]                     = {0,}; +        char                 *value                 = NULL; +        char                 *real_path             = NULL; +        dict_t               *dict                  = NULL; +        char                 *file_contents         = NULL; +        int                   ret                   = -1; +        char                 *path                  = NULL; +        char                 *rpath                 = NULL; +        char                 *dyn_rpath             = NULL; +        ssize_t               size                  = 0; +        char                 *list                  = NULL; +        int32_t               list_offset           = 0; +        size_t                remaining_size        = 0; +        char     key[4096]                          = {0,};          DECLARE_OLD_FS_ID_VAR; @@ -3045,6 +3499,31 @@ posix_getxattr (call_frame_t *frame, xlator_t *this,                  goto done;          } +        if (loc->inode && name +            && (strcmp (name, GET_ANCESTRY_PATH_KEY) == 0)) { +                int type = POSIX_ANCESTRY_PATH; + +                op_ret = posix_get_ancestry (this, loc->inode, NULL, +                                             &path, type, &op_errno, +                                             xdata); +                if (op_ret < 0) { +                        op_ret = -1; +                        op_errno = ENODATA; +                        goto out; +                } + +                op_ret = dict_set_dynstr (dict, GET_ANCESTRY_PATH_KEY, path); +                if (op_ret < 0) { +                        gf_log (this->name, GF_LOG_WARNING, "could not get " +                                "value for key (%s)", GET_ANCESTRY_PATH_KEY); +                        GF_FREE (path); +                        op_errno = -op_ret; +                        op_ret = -1; +                } + +                goto done; +        } +          if (name) {                  strcpy (key, name); @@ -3189,8 +3668,9 @@ out:          STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, dict, NULL); -        if (dict) +        if (dict) {                  dict_unref (dict); +        }          return 0;  } @@ -4322,15 +4802,14 @@ int32_t  posix_do_readdir (call_frame_t *frame, xlator_t *this,                    fd_t *fd, size_t size, off_t off, int whichop, dict_t *dict)  { -        struct posix_fd      *pfd            = NULL; -        DIR                  *dir            = NULL; -        int                   ret            = -1; -        int                   count          = 0; -        int32_t               op_ret         = -1; -        int32_t               op_errno       = 0; -        gf_dirent_t           entries; -        int32_t               skip_dirs      = 0; - +        struct posix_fd *pfd       = NULL; +        DIR             *dir       = NULL; +        int              ret       = -1; +        int              count     = 0; +        int32_t          op_ret    = -1; +        int32_t          op_errno  = 0; +        gf_dirent_t      entries; +        int32_t          skip_dirs = 0;          VALIDATE_OR_GOTO (frame, out);          VALIDATE_OR_GOTO (this, out); @@ -4409,6 +4888,32 @@ int32_t  posix_readdirp (call_frame_t *frame, xlator_t *this,                  fd_t *fd, size_t size, off_t off, dict_t *dict)  { +        gf_dirent_t entries; +        int32_t     op_ret = -1, op_errno = 0; +        gf_dirent_t     *entry     = NULL; + + +        if ((dict != NULL) && (dict_get (dict, GET_ANCESTRY_DENTRY_KEY))) { +                INIT_LIST_HEAD (&entries.list); + +                op_ret = posix_get_ancestry (this, fd->inode, &entries, NULL, +                                             POSIX_ANCESTRY_DENTRY, +                                             &op_errno, dict); +                if (op_ret >= 0) { +                        op_ret = 0; + +                        list_for_each_entry (entry, &entries.list, list) { +                                op_ret++; +                        } +                } + +                STACK_UNWIND_STRICT (readdir, frame, op_ret, op_errno, &entries, +                                     NULL); + +                gf_dirent_free (&entries); +                return 0; +        } +          posix_do_readdir (frame, this, fd, size, off, GF_FOP_READDIRP, dict);          return 0;  } @@ -4635,6 +5140,9 @@ reconfigure (xlator_t *this, dict_t *options)  	else  		posix_aio_off (this); +        GF_OPTION_RECONF ("update-link-count-parent", priv->update_pgfid_nlinks, +                          options, bool, out); +          GF_OPTION_RECONF ("node-uuid-pathinfo", priv->node_uuid_pathinfo,                            options, bool, out); @@ -4912,6 +5420,24 @@ init (xlator_t *this)                                  "for every open)");          } +        tmp_data = dict_get (this->options, "update-link-count-parent"); +        if (tmp_data) { +                if (gf_string2boolean (tmp_data->data, +                                       &_private->update_pgfid_nlinks) == -1) { +                        ret = -1; +                        gf_log (this->name, GF_LOG_ERROR, +                                "wrong value provided for " +                                "'update-link-count-parent'"); +                        goto out; +                } +                if (_private->update_pgfid_nlinks) +                        gf_log (this->name, GF_LOG_DEBUG, +                                "update-link-count-parent is enabled. Thus for each " +                                "file an extended attribute representing the " +                                "number of hardlinks for that file within the " +                                "same parent directory is set."); +        } +          ret = dict_get_str (this->options, "glusterd-uuid", &guuid);          if (!ret) {                  if (uuid_parse (guuid, _private->glusterd_uuid)) @@ -5203,5 +5729,10 @@ struct volume_options options[] = {  	  .description = "Num of usecs to wait for aggregating fsync"  	  " requests",  	}, +        { .key = {"update-link-count-parent"}, +          .type = GF_OPTION_TYPE_BOOL, +          .default_value = "false", +          .description = "Enable placeholders for gfid to path conversion" +        },          { .key  = {NULL} }  }; diff --git a/xlators/storage/posix/src/posix.h b/xlators/storage/posix/src/posix.h index 3121db2717e..d579bf673db 100644 --- a/xlators/storage/posix/src/posix.h +++ b/xlators/storage/posix/src/posix.h @@ -52,6 +52,12 @@  #define VECTOR_SIZE 64 * 1024 /* vector size 64KB*/  #define MAX_NO_VECT 1024 + +#define POSIX_GFID_HANDLE_SIZE(base_path_len) (base_path_len + SLEN("/") \ +                                               + SLEN(HANDLE_PFX) + SLEN("/") \ +                                               + SLEN("00/")            \ +                                               + SLEN("00/") + SLEN(UUID0_STR) + 1) /* '\0' */; +  /**   * posix_fd - internal structure common to file and directory fd's   */ @@ -146,6 +152,7 @@ struct posix_private {  	}               batch_fsync_mode;  	uint32_t        batch_fsync_delay_usec; +        gf_boolean_t    update_pgfid_nlinks;          /* seconds to sleep between health checks */          uint32_t        health_check_interval; @@ -205,4 +212,8 @@ __posix_fd_set_odirect (fd_t *fd, struct posix_fd *pfd, int opflags,  void posix_spawn_health_check_thread (xlator_t *this);  void *posix_fsyncer (void *); +int +posix_get_ancestry (xlator_t *this, inode_t *leaf_inode, +                    gf_dirent_t *head, char **path, int type, int32_t *op_errno, +                    dict_t *xdata);  #endif /* _POSIX_H */  | 
