Blob Blame History Raw
From 02d93b001873689d5ff613fd1781582006c1b9cd Mon Sep 17 00:00:00 2001
From: vmallika <vmallika@redhat.com>
Date: Wed, 10 Feb 2016 06:39:22 +0530
Subject: [PATCH 27/80] uss/gluster: generate gfid for snapshot files from snapname and gfid

If 'a' and 'b' are hardlinks, we need to generate a virtual
gfid for these files so that the inode number for 'a' and 'b'
are same.

Generate gfid as below:
gfid_of_a = MD5(snapname + back_end_gfid(a))
if '/dir1/a' and '/dir2/b' are hardlinks, then inode number should be
same for
all below files:
/mnt/.snaps/snap1/dir1/a
/mnt/.snaps/snap1/dir2/b
/mnt/dir1/.snaps/snap1/a
/mnt/dir2/.snaps/snap1/b

Change-Id: Ifda793455610e554f3f1e4cbb90d44c02cda4b0f
BUG: 1303591
Signed-off-by: vmallika <vmallika@redhat.com>
Reviewed-on: http://review.gluster.org/9255
Smoke: Gluster Build System <jenkins@build.gluster.com>
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
CentOS-regression: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Rajesh Joseph <rjoseph@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/70563
Tested-by: Rajesh Joseph <rjoseph@redhat.com>
---
 tests/basic/uss.t                                  |   32 +++++-
 tests/include.rc                                   |   10 ++
 .../snapview-server/src/snapview-server-helpers.c  |   15 +++
 .../features/snapview-server/src/snapview-server.c |  121 ++++++++++++++------
 .../features/snapview-server/src/snapview-server.h |   19 +++
 5 files changed, 162 insertions(+), 35 deletions(-)

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