12a457
From 02d93b001873689d5ff613fd1781582006c1b9cd Mon Sep 17 00:00:00 2001
12a457
From: vmallika <vmallika@redhat.com>
12a457
Date: Wed, 10 Feb 2016 06:39:22 +0530
12a457
Subject: [PATCH 27/80] uss/gluster: generate gfid for snapshot files from snapname and gfid
12a457
12a457
If 'a' and 'b' are hardlinks, we need to generate a virtual
12a457
gfid for these files so that the inode number for 'a' and 'b'
12a457
are same.
12a457
12a457
Generate gfid as below:
12a457
gfid_of_a = MD5(snapname + back_end_gfid(a))
12a457
if '/dir1/a' and '/dir2/b' are hardlinks, then inode number should be
12a457
same for
12a457
all below files:
12a457
/mnt/.snaps/snap1/dir1/a
12a457
/mnt/.snaps/snap1/dir2/b
12a457
/mnt/dir1/.snaps/snap1/a
12a457
/mnt/dir2/.snaps/snap1/b
12a457
12a457
Change-Id: Ifda793455610e554f3f1e4cbb90d44c02cda4b0f
12a457
BUG: 1303591
12a457
Signed-off-by: vmallika <vmallika@redhat.com>
12a457
Reviewed-on: http://review.gluster.org/9255
12a457
Smoke: Gluster Build System <jenkins@build.gluster.com>
12a457
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
12a457
CentOS-regression: Gluster Build System <jenkins@build.gluster.com>
12a457
Reviewed-by: Rajesh Joseph <rjoseph@redhat.com>
12a457
Reviewed-on: https://code.engineering.redhat.com/gerrit/70563
12a457
Tested-by: Rajesh Joseph <rjoseph@redhat.com>
12a457
---
12a457
 tests/basic/uss.t                                  |   32 +++++-
12a457
 tests/include.rc                                   |   10 ++
12a457
 .../snapview-server/src/snapview-server-helpers.c  |   15 +++
12a457
 .../features/snapview-server/src/snapview-server.c |  121 ++++++++++++++------
12a457
 .../features/snapview-server/src/snapview-server.h |   19 +++
12a457
 5 files changed, 162 insertions(+), 35 deletions(-)
12a457
12a457
diff --git a/tests/basic/uss.t b/tests/basic/uss.t
12a457
index 7a4f043..55fab66 100644
12a457
--- a/tests/basic/uss.t
12a457
+++ b/tests/basic/uss.t
12a457
@@ -41,7 +41,14 @@ TEST $GFS --volfile-server=$H0 --volfile-id=$V0 $M0;
12a457
 
12a457
 for i in {1..10} ; do echo "file" > $M0/file$i ; done
12a457
 
12a457
+# Create file and hard-links
12a457
+TEST touch $M0/f1
12a457
+TEST mkdir $M0/dir
12a457
+TEST ln $M0/f1 $M0/f2
12a457
+TEST ln $M0/f1 $M0/dir/f3
12a457
+
12a457
 TEST $CLI snapshot config activate-on-create enable
12a457
+TEST $CLI volume set $V0 features.uss enable;
12a457
 
12a457
 TEST $CLI snapshot create snap1 $V0 no-timestamp;
12a457
 
12a457
@@ -49,6 +56,29 @@ for i in {11..20} ; do echo "file" > $M0/file$i ; done
12a457
 
12a457
 TEST $CLI snapshot create snap2 $V0 no-timestamp;
12a457
 
12a457
+########### Test inode numbers ###########
12a457
+s1_f1_ino=$(STAT_INO $M0/.snaps/snap1/f1)
12a457
+TEST [ $s1_f1_ino != 0 ]
12a457
+
12a457
+# Inode number of f1 should be same as f2 f3 within snapshot
12a457
+EXPECT $s1_f1_ino STAT_INO $M0/.snaps/snap1/f2
12a457
+EXPECT $s1_f1_ino STAT_INO $M0/.snaps/snap1/dir/f3
12a457
+EXPECT $s1_f1_ino STAT_INO $M0/dir/.snaps/snap1/f3
12a457
+
12a457
+# Inode number of f1 in snap1 should be different from f1 in snap2
12a457
+tmp_ino=$(STAT_INO $M0/.snaps/snap2/f1)
12a457
+TEST [ $s1_f1_ino != $tmp_ino ]
12a457
+
12a457
+# Inode number of f1 in snap1 should be different from f1 in regular volume
12a457
+tmp_ino=$(STAT_INO $M0/f1)
12a457
+TEST [ $s1_f1_ino != $tmp_ino ]
12a457
+
12a457
+# Directory inode of snap1 should be different in each sub-dir
12a457
+s1_ino=$(STAT_INO $M0/.snaps/snap1)
12a457
+tmp_ino=$(STAT_INO $M0/dir/.snaps/snap1)
12a457
+TEST [ $s1_ino != $tmp_ino ]
12a457
+##########################################
12a457
+
12a457
 mkdir $M0/dir1;
12a457
 mkdir $M0/dir2;
12a457
 
12a457
@@ -80,8 +110,6 @@ TEST ! $CLI volume set $V0 features.snapshot-directory .
12a457
 TEST ! $CLI volume set $V0 features.snapshot-directory ..
12a457
 TEST ! $CLI volume set $V0 features.snapshot-directory .123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345
12a457
 
12a457
-TEST $CLI volume set $V0 features.uss enable;
12a457
-
12a457
 EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
12a457
 
12a457
 TEST $GFS --volfile-server=$H0 --volfile-id=$V0 $M0;
12a457
diff --git a/tests/include.rc b/tests/include.rc
12a457
index 495db1b..03c9f44 100644
12a457
--- a/tests/include.rc
12a457
+++ b/tests/include.rc
12a457
@@ -1068,3 +1068,13 @@ function STAT()
12a457
         stat $1
12a457
         echo $?
12a457
 }
12a457
+
12a457
+function STAT_INO()
12a457
+{
12a457
+        local ino=$(stat -c '%i' $1)
12a457
+        if [ $? -eq 0 ]; then
12a457
+                echo $ino
12a457
+        else
12a457
+                echo 0
12a457
+        fi
12a457
+}
12a457
diff --git a/xlators/features/snapview-server/src/snapview-server-helpers.c b/xlators/features/snapview-server/src/snapview-server-helpers.c
12a457
index 92ffdf5..0303f4d 100644
12a457
--- a/xlators/features/snapview-server/src/snapview-server-helpers.c
12a457
+++ b/xlators/features/snapview-server/src/snapview-server-helpers.c
12a457
@@ -335,6 +335,21 @@ out:
12a457
 }
12a457
 
12a457
 void
12a457
+svs_uuid_generate (uuid_t gfid, char *snapname, uuid_t origin_gfid)
12a457
+{
12a457
+        unsigned char md5_sum[MD5_DIGEST_LENGTH] = {0};
12a457
+        char          ino_string[NAME_MAX + 32]  = "";
12a457
+        int           ret                        = 0;
12a457
+
12a457
+        GF_ASSERT (snapname);
12a457
+
12a457
+        ret = snprintf (ino_string, sizeof (ino_string), "%s%s",
12a457
+                        snapname, uuid_utoa(origin_gfid));
12a457
+        MD5((unsigned char *)ino_string, strlen(ino_string), md5_sum);
12a457
+        gf_uuid_copy (gfid, md5_sum);
12a457
+}
12a457
+
12a457
+void
12a457
 svs_fill_ino_from_gfid (struct iatt *buf)
12a457
 {
12a457
         uint64_t  temp_ino = 0;
12a457
diff --git a/xlators/features/snapview-server/src/snapview-server.c b/xlators/features/snapview-server/src/snapview-server.c
12a457
index ed30cb8..95e8d3c 100644
12a457
--- a/xlators/features/snapview-server/src/snapview-server.c
12a457
+++ b/xlators/features/snapview-server/src/snapview-server.c
12a457
@@ -261,9 +261,23 @@ svs_lookup_snapshot (xlator_t *this, loc_t *loc, struct iatt *buf,
12a457
         memcpy (&inode_ctx->buf, buf, sizeof (*buf));
12a457
         svs_iatt_fill (parent->gfid, postparent);
12a457
 
12a457
+        SVS_STRDUP (inode_ctx->snapname, loc->name);
12a457
+        if (!inode_ctx->snapname) {
12a457
+                op_ret = -1;
12a457
+                *op_errno = ENOMEM;
12a457
+                goto out;
12a457
+        }
12a457
         op_ret = 0;
12a457
 
12a457
 out:
12a457
+        if (op_ret) {
12a457
+                if (object)
12a457
+                        glfs_h_close (object);
12a457
+
12a457
+                if (inode_ctx)
12a457
+                        inode_ctx->object = NULL;
12a457
+        }
12a457
+
12a457
         return op_ret;
12a457
 }
12a457
 
12a457
@@ -279,7 +293,7 @@ svs_lookup_entry (xlator_t *this, loc_t *loc, struct iatt *buf,
12a457
         struct stat     statbuf                         = {0, };
12a457
         svs_inode_t    *inode_ctx                       = NULL;
12a457
         glfs_object_t  *parent_object                   = NULL;
12a457
-        uuid_t          gfid;
12a457
+        uuid_t          gfid                            = {0, };
12a457
 
12a457
         GF_VALIDATE_OR_GOTO ("snapview-server", this, out);
12a457
         GF_VALIDATE_OR_GOTO (this->name, loc, out);
12a457
@@ -303,6 +317,14 @@ svs_lookup_entry (xlator_t *this, loc_t *loc, struct iatt *buf,
12a457
                 goto out;
12a457
         }
12a457
 
12a457
+        if (gf_uuid_is_null(object->gfid)) {
12a457
+                gf_log (this->name, GF_LOG_DEBUG, "gfid from glfs handle is "
12a457
+                        "NULL for entry %s (path: %s)", loc->name, loc->path);
12a457
+                op_ret = -1;
12a457
+                *op_errno = errno;
12a457
+                goto out;
12a457
+        }
12a457
+
12a457
         inode_ctx = svs_inode_ctx_get_or_new (this, loc->inode);
12a457
         if (!inode_ctx) {
12a457
                 gf_log (this->name, GF_LOG_ERROR, "failed to "
12a457
@@ -314,7 +336,7 @@ svs_lookup_entry (xlator_t *this, loc_t *loc, struct iatt *buf,
12a457
 
12a457
         if (gf_uuid_is_null (loc->gfid) &&
12a457
             gf_uuid_is_null (loc->inode->gfid))
12a457
-                gf_uuid_generate (gfid);
12a457
+                svs_uuid_generate (gfid, parent_ctx->snapname, object->gfid);
12a457
         else {
12a457
                 if (!gf_uuid_is_null (loc->inode->gfid))
12a457
                         gf_uuid_copy (gfid, loc->inode->gfid);
12a457
@@ -331,9 +353,26 @@ svs_lookup_entry (xlator_t *this, loc_t *loc, struct iatt *buf,
12a457
         memcpy (&inode_ctx->buf, buf, sizeof (*buf));
12a457
         svs_iatt_fill (parent->gfid, postparent);
12a457
 
12a457
+        if (IA_ISDIR (buf->ia_type)) {
12a457
+                SVS_STRDUP (inode_ctx->snapname, parent_ctx->snapname);
12a457
+                if (!inode_ctx->snapname) {
12a457
+                        op_ret = -1;
12a457
+                        *op_errno = ENOMEM;
12a457
+                        goto out;
12a457
+                }
12a457
+        }
12a457
+
12a457
         op_ret = 0;
12a457
 
12a457
 out:
12a457
+        if (op_ret) {
12a457
+                if (object)
12a457
+                        glfs_h_close (object);
12a457
+
12a457
+                if (inode_ctx)
12a457
+                        inode_ctx->object = NULL;
12a457
+        }
12a457
+
12a457
         return op_ret;
12a457
 }
12a457
 
12a457
@@ -812,9 +851,10 @@ svs_getxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, const char *name,
12a457
 
12a457
                 size = glfs_h_getxattrs (fs, object, name, NULL, 0);
12a457
                 if (size == -1) {
12a457
-                        gf_log (this->name, GF_LOG_ERROR, "getxattr "
12a457
-                                "on %s failed (key: %s)", loc->name,
12a457
-                                name);
12a457
+                        gf_log (this->name,
12a457
+                                errno == ENODATA?GF_LOG_DEBUG:GF_LOG_ERROR,
12a457
+                                "getxattr on %s failed (key: %s) with %s",
12a457
+                                loc->path, name, strerror(errno));
12a457
                         op_ret = -1;
12a457
                         op_errno = errno;
12a457
                         goto out;
12a457
@@ -1158,9 +1198,11 @@ svs_forget  (xlator_t *this, inode_t *inode)
12a457
         }
12a457
 
12a457
         inode_ctx = (svs_inode_t *)value;
12a457
+        if (!inode_ctx)
12a457
+                goto out;
12a457
 
12a457
-        if (inode_ctx->object)
12a457
-                glfs_h_close (inode_ctx->object);
12a457
+        if (inode_ctx->snapname)
12a457
+                GF_FREE (inode_ctx->snapname);
12a457
 
12a457
         GF_FREE (inode_ctx);
12a457
 
12a457
@@ -1358,38 +1400,51 @@ svs_readdirp_fill (xlator_t *this, inode_t *parent, svs_inode_t *parent_ctx,
12a457
                         gf_uuid_copy (entry->d_stat.ia_gfid, buf.ia_gfid);
12a457
                 }
12a457
         } else {
12a457
-                inode = inode_new (parent->table);
12a457
-                entry->inode = inode;
12a457
-                gf_uuid_generate (random_gfid);
12a457
-                gf_uuid_copy (buf.ia_gfid, random_gfid);
12a457
-                svs_fill_ino_from_gfid (&buf;;
12a457
-                entry->d_ino = buf.ia_ino;
12a457
-
12a457
-                /* If inode context allocation fails, then do not send the
12a457
-                   inode for that particular entry as part of readdirp
12a457
-                   response. Fuse and protocol/server will link the inodes
12a457
-                   in readdirp only if the entry contains inode in it.
12a457
-                */
12a457
-                inode_ctx = svs_inode_ctx_get_or_new (this, inode);
12a457
-                if (!inode_ctx) {
12a457
-                        gf_log (this->name, GF_LOG_ERROR, "failed to allocate "
12a457
-                                "inode context for %s", entry->d_name);
12a457
-                        inode_unref (entry->inode);
12a457
-                        entry->inode = NULL;
12a457
-                        goto out;
12a457
-                }
12a457
-
12a457
 
12a457
                 if (parent_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) {
12a457
+                        inode = inode_new (parent->table);
12a457
+                        entry->inode = inode;
12a457
+
12a457
+                        /* If inode context allocation fails, then do not send
12a457
+                         * the inode for that particular entry as part of
12a457
+                         * readdirp response. Fuse and protocol/server will link
12a457
+                         * the inodes in readdirp only if the entry contains
12a457
+                         * inode in it.
12a457
+                         */
12a457
+                        inode_ctx = svs_inode_ctx_get_or_new (this, inode);
12a457
+                        if (!inode_ctx) {
12a457
+                                gf_log (this->name, GF_LOG_ERROR, "failed to "
12a457
+                                        "allocate inode context for %s",
12a457
+                                        entry->d_name);
12a457
+                                inode_unref (entry->inode);
12a457
+                                entry->inode = NULL;
12a457
+                                goto out;
12a457
+                        }
12a457
+
12a457
+                        /* Generate virtual gfid for SNAPSHOT dir and
12a457
+                         * update the statbuf
12a457
+                         */
12a457
+                        gf_uuid_generate (random_gfid);
12a457
+                        gf_uuid_copy (buf.ia_gfid, random_gfid);
12a457
+                        svs_fill_ino_from_gfid (&buf;;
12a457
                         buf.ia_type = IA_IFDIR;
12a457
-                        inode_ctx->buf = buf;
12a457
+                        entry->d_ino = buf.ia_ino;
12a457
                         entry->d_stat = buf;
12a457
+                        inode_ctx->buf = buf;
12a457
                         inode_ctx->type = SNAP_VIEW_SNAPSHOT_INODE;
12a457
                 } else {
12a457
-                        gf_uuid_copy (entry->d_stat.ia_gfid, buf.ia_gfid);
12a457
-                        entry->d_stat.ia_ino = buf.ia_ino;
12a457
-                        inode_ctx->buf = entry->d_stat;
12a457
-                        inode_ctx->type = SNAP_VIEW_VIRTUAL_INODE;
12a457
+                        /* For files under snapshot world do not set
12a457
+                         * entry->inode and reset statbuf (except ia_ino),
12a457
+                         * so that FUSE/Kernel will send an explicit lookup.
12a457
+                         * entry->d_stat contains the statbuf information
12a457
+                         * of original file, so for NFS not to cache this
12a457
+                         * information and to send explicit lookup, it is
12a457
+                         * required to reset the statbuf.
12a457
+                         * Virtual gfid for these files will be generated in the
12a457
+                         * first lookup.
12a457
+                         */
12a457
+                        buf.ia_ino = entry->d_ino;
12a457
+                        entry->d_stat = buf;
12a457
                 }
12a457
         }
12a457
 
12a457
diff --git a/xlators/features/snapview-server/src/snapview-server.h b/xlators/features/snapview-server/src/snapview-server.h
12a457
index c80d345..f9249f9 100644
12a457
--- a/xlators/features/snapview-server/src/snapview-server.h
12a457
+++ b/xlators/features/snapview-server/src/snapview-server.h
12a457
@@ -105,6 +105,17 @@
12a457
                 }                                                       \
12a457
         } while(0);
12a457
 
12a457
+#define SVS_STRDUP(dst, src)                                            \
12a457
+        do {                                                            \
12a457
+                if (dst && strcmp (src, dst)) {                         \
12a457
+                        GF_FREE (dst);                                  \
12a457
+                        dst = NULL;                                     \
12a457
+                }                                                       \
12a457
+                                                                        \
12a457
+                if (!dst)                                               \
12a457
+                        dst = gf_strdup (src);                          \
12a457
+        } while (0)
12a457
+
12a457
 int
12a457
 svs_mgmt_submit_request (void *req, call_frame_t *frame,
12a457
                          glusterfs_ctx_t *ctx,
12a457
@@ -133,6 +144,11 @@ struct svs_inode {
12a457
            from where the entry point was entered is saved.
12a457
         */
12a457
         uuid_t pargfid;
12a457
+
12a457
+        /* This is used to generate gfid for all sub files/dirs under this
12a457
+         * snapshot
12a457
+         */
12a457
+        char *snapname;
12a457
         struct iatt buf;
12a457
 };
12a457
 typedef struct svs_inode svs_inode_t;
12a457
@@ -194,6 +210,9 @@ svs_fd_t *
12a457
 svs_fd_ctx_get_or_new (xlator_t *this, fd_t *fd);
12a457
 
12a457
 void
12a457
+svs_uuid_generate (uuid_t gfid, char *snapname, uuid_t origin_gfid);
12a457
+
12a457
+void
12a457
 svs_fill_ino_from_gfid (struct iatt *buf);
12a457
 
12a457
 void
12a457
-- 
12a457
1.7.1
12a457