Blob Blame History Raw
From 4521520e2640f52ceb74cda8001c0e894d9b155c Mon Sep 17 00:00:00 2001
From: Amar Tumballi <amarts@redhat.com>
Date: Wed, 27 Sep 2017 12:37:59 +0530
Subject: [PATCH 621/622] glusterfsd: allow subdir mount

Changes:

1. Take subdir mount option in client (mount.gluster / glusterfsd)
2. Pass the subdir mount to server-handshake (from client-handshake)
3. Handle subdir-mount dir's lookup in server-first-lookup and handle
   all fops resolution accordingly with proper gfid of subdir
4. Change the auth/addr module to handle the multiple subdir entries
   in option, and valid parsing.

How to use the feature:

`# mount -t glusterfs $hostname:/$volname/$subdir /$mount_point`
Or
`# mount -t glusterfs $hostname:/$volname -osubdir_mount=$subdir /$mount_point`

Option can be set like:

`# gluster volume set <volname> auth.allow "/subdir1(192.168.1.*),/(192.168.10.*),/subdir2(192.168.8.*)"`

> Upstream:
> Reviewed-on: https://review.gluster.org/17141
> Updates #175
> Also includes fixes from: https://review.gluster.org/18184
> Also includes fixes from: https://review.gluster.org/18322

BUG: 1017362

Signed-Off-By: Amar Tumballi <amarts@redhat.com>
Change-Id: Ia722e9190064061bb46da45e467be2253b19c81b
Reviewed-on: https://code.engineering.redhat.com/gerrit/119138
Tested-by: RHGS Build Bot <nigelb@redhat.com>
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
---
 doc/glusterfs.8                                |   3 +
 doc/mount.glusterfs.8                          |   7 +-
 glusterfsd/src/glusterfsd.c                    |  10 ++
 glusterfsd/src/glusterfsd.h                    |   1 +
 libglusterfs/src/client_t.c                    |  15 +-
 libglusterfs/src/client_t.h                    |   8 +-
 libglusterfs/src/glusterfs.h                   |   3 +
 libglusterfs/src/options.c                     |  62 +++++++-
 tests/features/subdir-mount.t                  |  99 ++++++++++++
 xlators/mount/fuse/utils/mount.glusterfs.in    |  17 ++-
 xlators/protocol/auth/addr/src/addr.c          | 202 ++++++++++++++++++-------
 xlators/protocol/client/src/client-handshake.c |  21 ++-
 xlators/protocol/server/src/server-common.c    |  68 +++++++--
 xlators/protocol/server/src/server-common.h    |   6 +-
 xlators/protocol/server/src/server-handshake.c | 180 +++++++++++++++-------
 xlators/protocol/server/src/server-helpers.c   |  10 +-
 xlators/protocol/server/src/server-rpc-fops.c  | 107 ++++++++-----
 xlators/protocol/server/src/server.c           |   1 +
 xlators/protocol/server/src/server.h           |   3 +
 19 files changed, 650 insertions(+), 173 deletions(-)
 create mode 100644 tests/features/subdir-mount.t

diff --git a/doc/glusterfs.8 b/doc/glusterfs.8
index fc28ef6..6f180b1 100644
--- a/doc/glusterfs.8
+++ b/doc/glusterfs.8
@@ -98,6 +98,9 @@ Mount the filesystem in 'worm' mode.
 .TP
 \fB\-\-xlator\-option=VOLUME\-NAME.OPTION=VALUE\fR
 Add/Override a translator option for a volume with the specified value.
+.TP
+\fB\-\-subdir\-mount=SUBDIR\-MOUNT\-PATH\fR
+Mount subdirectory instead of the '/' of volume.
 
 .SS "Fuse options"
 .PP
diff --git a/doc/mount.glusterfs.8 b/doc/mount.glusterfs.8
index 4e82c2f..e16bbec 100644
--- a/doc/mount.glusterfs.8
+++ b/doc/mount.glusterfs.8
@@ -12,11 +12,11 @@
 .SH NAME
 .B mount.glusterfs - script to mount native GlusterFS volume
 .SH SYNOPSIS
-.B mount -t glusterfs [-o <options>] <volumeserver>:/<volume>
+.B mount -t glusterfs [-o <options>] <volumeserver>:/<volume>[/<subdir>]
 .B         <mountpoint>
 .TP
 .B mount -t glusterfs [-o <options>] <server1>,<server2>,
-.B        <server3>,..<serverN>:/<volname> <mount_point>
+.B        <server3>,..<serverN>:/<volname>[/<subdir>] <mount_point>
 .TP
 .TP
 .B mount -t glusterfs [-o <options>] <path/to/volumefile> <mountpoint>
@@ -95,6 +95,9 @@ Disable direct I/O mode in fuse kernel module
 \fBcongestion\-threshold=\fRN
 Set fuse module's congestion threshold to N [default: 48]
 .TP
+\fsubdir\-mount=\fRN
+Set the subdirectory mount option [default: NULL, ie, no subdirectory mount]
+.TP
 .TP
 \fBbackup\-volfile\-servers=\fRSERVERLIST
 Provide list of backup volfile servers in the following format [default: None]
diff --git a/glusterfsd/src/glusterfsd.c b/glusterfsd/src/glusterfsd.c
index 110cbb3..8782ba2 100644
--- a/glusterfsd/src/glusterfsd.c
+++ b/glusterfsd/src/glusterfsd.c
@@ -154,6 +154,8 @@ static struct argp_option gf_options[] = {
          "Enable SELinux label (extended attributes) support on inodes"},
         {"capability", ARGP_CAPABILITY_KEY, 0, 0,
          "Enable Capability (extended attributes) support on inodes"},
+        {"subdir-mount", ARGP_SUBDIR_MOUNT_KEY, "SUBDIR-PATH", 0,
+         "Mount subdirectory given [default: NULL]"},
 
         {"print-netgroups", ARGP_PRINT_NETGROUPS, "NETGROUP-FILE", 0,
          "Validate the netgroups file and print it out"},
@@ -1235,6 +1237,14 @@ parse_opts (int key, char *arg, struct argp_state *state)
                 argp_failure (state, -1, 0,
                               "unknown secure-mgmt setting \"%s\"", arg);
                 break;
+        case ARGP_SUBDIR_MOUNT_KEY:
+                if (arg[0] != '/') {
+                        argp_failure (state, -1, 0,
+                                      "expect '/%s', provided just \"%s\"", arg, arg);
+                        break;
+                }
+                cmd_args->subdir_mount = gf_strdup (arg);
+                break;
 	}
 
         return 0;
diff --git a/glusterfsd/src/glusterfsd.h b/glusterfsd/src/glusterfsd.h
index 4d697f3..938d422 100644
--- a/glusterfsd/src/glusterfsd.h
+++ b/glusterfsd/src/glusterfsd.h
@@ -98,6 +98,7 @@ enum argp_option_keys {
         ARGP_OOM_SCORE_ADJ_KEY            = 176,
 #endif
 #endif
+        ARGP_SUBDIR_MOUNT_KEY             = 177,
 };
 
 struct _gfd_vol_top_priv_t {
diff --git a/libglusterfs/src/client_t.c b/libglusterfs/src/client_t.c
index 97cf9f9..f4fdb52 100644
--- a/libglusterfs/src/client_t.c
+++ b/libglusterfs/src/client_t.c
@@ -159,7 +159,8 @@ gf_client_clienttable_destroy (clienttable_t *clienttable)
  * as long as ref.bind is > 0 client should be alive.
  */
 client_t *
-gf_client_get (xlator_t *this, struct rpcsvc_auth_data *cred, char *client_uid)
+gf_client_get (xlator_t *this, struct rpcsvc_auth_data *cred, char *client_uid,
+               char *subdir_mount)
 {
         client_t      *client      = NULL;
         cliententry_t *cliententry = NULL;
@@ -204,6 +205,8 @@ gf_client_get (xlator_t *this, struct rpcsvc_auth_data *cred, char *client_uid)
                 }
 
                 client->this = this;
+                if (subdir_mount != NULL)
+                        client->subdir_mount = gf_strdup (subdir_mount);
 
                 LOCK_INIT (&client->scratch_ctx.lock);
 
@@ -373,6 +376,10 @@ client_destroy (client_t *client)
         list_for_each_entry (gtrav, &client->this->ctx->graphs, list) {
                 gf_client_destroy_recursive (gtrav->top, client);
         }
+        if (client->subdir_inode)
+                inode_unref (client->subdir_inode);
+
+        GF_FREE (client->subdir_mount);
         GF_FREE (client->auth.data);
         GF_FREE (client->scratch_ctx.ctx);
         GF_FREE (client->client_uid);
@@ -776,6 +783,12 @@ gf_client_dump_fdtables (xlator_t *this)
                                                     client->client_uid);
                         }
 
+                        if (client->subdir_mount) {
+                                gf_proc_dump_build_key (key, "conn",
+                                                        "%d.subdir", count);
+                                gf_proc_dump_write (key, "%s",
+                                                    client->subdir_mount);
+                        }
                         gf_proc_dump_build_key (key, "conn", "%d.ref",
                                                         count);
                         gf_proc_dump_write (key, GF_PRI_ATOMIC,
diff --git a/libglusterfs/src/client_t.h b/libglusterfs/src/client_t.h
index 31f1bd0..cd9afa2 100644
--- a/libglusterfs/src/client_t.h
+++ b/libglusterfs/src/client_t.h
@@ -40,6 +40,11 @@ typedef struct _client_t {
                 char                *username;
                 char                *passwd;
         }            auth;
+
+        /* subdir_mount */
+        char    *subdir_mount;
+        inode_t *subdir_inode;
+        uuid_t   subdir_gfid;
 } client_t;
 
 #define GF_CLIENTCTX_INITIAL_SIZE 8
@@ -72,7 +77,8 @@ typedef struct clienttable clienttable_t;
 struct rpcsvc_auth_data;
 
 client_t *
-gf_client_get (xlator_t *this, struct rpcsvc_auth_data *cred, char *client_uid);
+gf_client_get (xlator_t *this, struct rpcsvc_auth_data *cred,
+               char *client_uid, char *subdir_mount);
 
 void
 gf_client_put (client_t *client, gf_boolean_t *detached);
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h
index c58cae1..d13e5bd 100644
--- a/libglusterfs/src/glusterfs.h
+++ b/libglusterfs/src/glusterfs.h
@@ -400,6 +400,9 @@ struct _cmd_args {
 
         /* Should management connections use SSL? */
         int             secure_mgmt;
+
+        /* For the subdir mount */
+        char           *subdir_mount;
 };
 typedef struct _cmd_args cmd_args_t;
 
diff --git a/libglusterfs/src/options.c b/libglusterfs/src/options.c
index 02928a9..0ad4e53 100644
--- a/libglusterfs/src/options.c
+++ b/libglusterfs/src/options.c
@@ -599,21 +599,70 @@ xlator_option_validate_addr_list (xlator_t *xl, const char *key,
         char         *dup_val = NULL;
         char         *addr_tok = NULL;
         char         *save_ptr = NULL;
+        char         *entry = NULL;
+        char         *entry_ptr = NULL;
+        char         *dir_and_addr = NULL;
+        char         *addr_ptr = NULL;
+        char         *addr_list = NULL;
+        char         *addr = NULL;
+        char         *dir = NULL;
         char         errstr[4096] = {0,};
 
         dup_val = gf_strdup (value);
         if (!dup_val)
                 goto out;
 
-        addr_tok = strtok_r (dup_val, ",", &save_ptr);
-        if (addr_tok == NULL)
+        if (dup_val[0] != '/' && !strchr (dup_val, '(')) {
+                /* Possible old format, handle it for back-ward compatibility */
+                addr_tok = strtok_r (dup_val, ",", &save_ptr);
+                while (addr_tok) {
+                        if (!valid_internet_address (addr_tok, _gf_true))
+                                goto out;
+
+                        addr_tok = strtok_r (NULL, ",", &save_ptr);
+                }
+                ret = 0;
                 goto out;
-        while (addr_tok) {
-                if (!valid_internet_address (addr_tok, _gf_true))
+        }
+
+        /* Lets handle the value with new format */
+        entry = strtok_r (dup_val, ",", &entry_ptr);
+        while (entry) {
+                dir_and_addr = gf_strdup (entry);
+                if (!dir_and_addr)
                         goto out;
 
-                addr_tok = strtok_r (NULL, ",", &save_ptr);
+                dir = strtok_r (dir_and_addr, "(", &addr_ptr);
+                if (dir[0] != '/') {
+                        /* Valid format should be starting from '/' */
+                        goto out;
+                }
+                /* dir = strtok_r (NULL, " =", &addr_tmp); */
+                addr = strtok_r (NULL, ")", &addr_ptr);
+                if (!addr)
+                        goto out;
+
+                addr_list = gf_strdup (addr);
+                if (!addr_list)
+                        goto out;
+
+                /* This format be separated by '|' */
+                addr_tok = strtok_r (addr_list, "|", &save_ptr);
+                if (addr_tok == NULL)
+                        goto out;
+                while (addr_tok) {
+                        if (!valid_internet_address (addr_tok, _gf_true))
+                                goto out;
+
+                        addr_tok = strtok_r (NULL, "|", &save_ptr);
+                }
+                entry = strtok_r (NULL, ",", &entry_ptr);
+                GF_FREE (dir_and_addr);
+                GF_FREE (addr_list);
+                addr_list = NULL;
+                dir_and_addr = NULL;
         }
+
         ret = 0;
 
 out:
@@ -626,7 +675,8 @@ out:
                         *op_errstr = gf_strdup (errstr);
         }
         GF_FREE (dup_val);
-
+        GF_FREE (dir_and_addr);
+        GF_FREE (addr_list);
         return ret;
 }
 
diff --git a/tests/features/subdir-mount.t b/tests/features/subdir-mount.t
new file mode 100644
index 0000000..2fb0be4
--- /dev/null
+++ b/tests/features/subdir-mount.t
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../nfs.rc
+
+cleanup;
+
+## Start and create a volume
+TEST glusterd
+TEST pidof glusterd
+TEST $CLI volume info;
+
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4};
+
+## Start volume and verify
+TEST $CLI volume start $V0;
+
+## Mount FUSE with caching disabled (read-write)
+TEST $GFS -s $H0 --volfile-id $V0 --volume-name ${V0}-dht $M0;
+
+TEST ! stat $M0/subdir1;
+TEST mkdir $M0/subdir1;
+TEST ! stat $M0/subdir2;
+TEST mkdir $M0/subdir2;
+TEST ! stat $M0/subdir1/subdir1.1;
+TEST mkdir $M0/subdir1/subdir1.1;
+TEST ! stat $M0/subdir1/subdir1.1/subdir1.2;
+TEST mkdir $M0/subdir1/subdir1.1/subdir1.2;
+
+# mount volume/subdir1
+TEST $GFS --subdir-mount /subdir1 -s $H0 --volfile-id $V0 --volume-name ${V0}-dht $M1;
+
+TEST touch $M0/topfile;
+TEST ! stat $M1/topfile;
+
+TEST touch $M1/subdir1_file;
+TEST ! stat $M0/subdir1_file;
+TEST stat $M0/subdir1/subdir1_file;
+
+# mount volume/subdir2
+TEST $GFS --subdir-mount /subdir2 -s $H0 --volfile-id $V0 $M2;
+
+TEST ! stat $M2/topfile;
+
+TEST touch $M2/subdir2_file;
+TEST ! stat $M0/subdir2_file;
+TEST ! stat $M1/subdir2_file;
+TEST stat $M0/subdir2/subdir2_file;
+
+# umount $M1 / $M2
+TEST umount $M1
+TEST umount $M2
+
+# mount non-existing subdir ; this works with mount.glusterfs,
+# but with glusterfs, the script doesn't returns error.
+#TEST ! $GFS --subdir-mount subdir_not_there -s $H0 --volfile-id $V0 $M1;
+
+# mount subdir with depth
+TEST $GFS --subdir-mount /subdir1/subdir1.1/subdir1.2 -s $H0 --volfile-id $V0 $M2;
+TEST ! stat $M2/topfile;
+TEST touch $M2/subdir1.2_file;
+TEST ! stat $M0/subdir1.2_file;
+TEST stat $M0/subdir1/subdir1.1/subdir1.2/subdir1.2_file;
+
+TEST umount $M2
+
+# Lets validate the options # Not having '*' in here as there was some
+# problem with option validation with this
+TEST $CLI volume set $V0 auth.allow 192.168.1.1
+
+TEST $CLI volume set $V0 auth.allow "192.168.1.1,10.10.\*.\*,::1"
+
+TEST $CLI volume set $V0 auth.allow "/subdir1\(1.2.3.4\),/\(192.168.10.2\|192.168.11.1\),/subdir2\(1.2.3.4\)"
+
+# directories should be absolute
+TEST ! $CLI volume set $V0 auth.allow "subdir2\(1.2.3.4\)"
+
+# support subdir inside subdir
+TEST $CLI volume set $V0 auth.allow '/subdir1/subdir1.1/subdir1.2/\(1.2.3.4\|::1\),/\(192.168.10.1\|192.168.11.1\),/subdir2\(1.2.3.4\)'
+
+# /subdir2 has not allowed IP
+TEST $GFS --subdir-mount /subdir2 -s $H0 --volfile-id $V0 $M1
+TEST stat $M1
+
+TEST $GFS --subdir-mount /subdir1/subdir1.1/subdir1.2 -s $H0 --volfile-id $V0 $M2
+TEST stat $M2
+
+# umount $M1 / $M2
+TEST umount $M0
+TEST umount $M1
+TEST umount $M2
+
+
+TEST $CLI volume stop $V0;
+TEST $CLI volume delete $V0;
+TEST ! $CLI volume info $V0;
+
+## This should clean the mountpoints
+cleanup;
diff --git a/xlators/mount/fuse/utils/mount.glusterfs.in b/xlators/mount/fuse/utils/mount.glusterfs.in
index 2c5e466..e294c5a 100755
--- a/xlators/mount/fuse/utils/mount.glusterfs.in
+++ b/xlators/mount/fuse/utils/mount.glusterfs.in
@@ -297,6 +297,10 @@ start_glusterfs ()
         cmd_line=$(echo "$cmd_line --fuse-mountopts=$fuse_mountopts");
     fi
 
+    if [ -n "$subdir_mount" ]; then
+        cmd_line=$(echo "$cmd_line --subdir-mount=/$subdir_mount");
+    fi
+
     cmd_line=$(echo "$cmd_line $mount_point");
     $cmd_line;
     if [ $? -ne 0 ]; then
@@ -415,6 +419,9 @@ with_options()
         "volume-id")
             volume_id=$value
             ;;
+        "subdir-mount")
+            subdir_mount=$value
+            ;;
         "volfile-check")
             volfile_check=$value
             ;;
@@ -631,7 +638,15 @@ main ()
         server_ip=$(echo "$volfile_loc" | sed -n 's/\([a-zA-Z0-9:%.\-]*\):.*/\1/p');
         volume_str=$(echo "$volfile_loc" | sed -n 's/.*:\([^ ]*\).*/\1/p');
         [ -n "$volume_str" ] && {
-            volume_id="$volume_str";
+            volume_id=$volume_str
+            volume_str_temp=$volume_str
+            first_char=$(echo "$volume_str" | cut -c 1);
+            [ ${first_char} = '/' ] && {
+                volume_str_temp=$(echo "$volume_str" | cut -c 2-);
+            [ $(echo $volume_str_temp | grep -c "/") -eq 1 ] && {
+                volume_id=$(echo "$volume_str_temp" | cut -f1 -d '/');
+                subdir_mount=$(echo "$volume_str_temp" | cut -f2- -d '/');
+            }
         }
         volfile_loc="";
         [ -z "$volume_id" -o -z "$server_ip" ] && {
diff --git a/xlators/protocol/auth/addr/src/addr.c b/xlators/protocol/auth/addr/src/addr.c
index 7ccbb57..eb933f8 100644
--- a/xlators/protocol/auth/addr/src/addr.c
+++ b/xlators/protocol/auth/addr/src/addr.c
@@ -16,13 +16,151 @@
 #include "dict.h"
 #include "rpc-transport.h"
 
-#define ADDR_DELIMITER " ,"
+#define ENTRY_DELIMITER     ","
+#define ADDR_DELIMITER      "|"
 #define PRIVILEGED_PORT_CEILING 1024
 
 #ifndef AF_INET_SDP
 #define AF_INET_SDP 27
 #endif
 
+/* An option for subdir validation be like below */
+
+/* 1. '*'
+   2. '192.168.*'
+   3. '
+   4. '!10.10.1*' (Today as per the code, if negate is set on one entry, its never reset)
+   5. '192.168.1.*, 10.1.10.*';168.168.2.* =/dir;* =/another-dir'
+
+*/
+
+int
+compare_addr_and_update (char *option_str, char *peer_addr, char *subvol,
+                         char *delimiter,
+                         auth_result_t *result, auth_result_t status)
+{
+        char          *addr_str       = NULL;
+        char          *tmp            = NULL;
+        char           negate         = 0;
+        char           match          = 0;
+        int            length         = 0;
+        int            ret            = 0;
+
+        addr_str = strtok_r (option_str, delimiter, &tmp);
+
+        while (addr_str) {
+                gf_log (subvol,  GF_LOG_INFO,
+                        "%s = \"%s\", received addr = \"%s\"",
+                        (status == AUTH_ACCEPT) ? "allowed" : "rejected",
+                        addr_str, peer_addr);
+                if (addr_str[0] == '!') {
+                        negate = 1;
+                        addr_str++;
+                }
+
+                length = strlen(addr_str);
+                if ((addr_str[0] != '*') &&
+                    valid_host_name (addr_str, length)) {
+                        match = gf_is_same_address(addr_str, peer_addr);
+                        if (match) {
+                                *result = status;
+                                goto out;
+                        }
+                } else {
+                        match = fnmatch (addr_str, peer_addr, 0);
+                        if (negate ? match : !match) {
+                                *result = status;
+                                goto out;
+                        }
+                }
+
+                addr_str = strtok_r (NULL, delimiter, &tmp);
+        }
+
+        ret = -1;
+out:
+        return ret;
+}
+
+
+void
+parse_entries_and_compare (char *option_str, char *peer_addr, char *subvol,
+                           char *subdir, auth_result_t *result, auth_result_t status)
+{
+        char *entry = NULL;
+        char *entry_cpy = NULL;
+        char *directory = NULL;
+        char *entries = NULL;
+        char *addr_str = NULL;
+        char *addr = NULL;
+        char *tmp = NULL;
+        char *tmpdir = NULL;
+        int   ret = 0;
+
+        if (!subdir) {
+                gf_log (subvol, GF_LOG_WARNING,
+                        "subdir entry not present, not performing any operation.");
+                goto out;
+        }
+
+        entries = gf_strdup (option_str);
+        if (!entries)
+                goto out;
+
+        if (entries[0] != '/' && !strchr (entries, '(')) {
+                /* Backward compatible option */
+                ret = compare_addr_and_update (entries, peer_addr, subvol,
+                                               ",", result, status);
+                goto out;
+        }
+
+        entry = strtok_r (entries, ENTRY_DELIMITER, &tmp);
+        while (entry) {
+                entry_cpy = gf_strdup (entry);
+                if (!entry_cpy) {
+                        goto out;
+                }
+
+                directory = strtok_r (entry_cpy, "(", &tmpdir);
+                if (directory[0] != '/')
+                        goto out;
+
+                /* send second portion, after ' =' if directory matches */
+                if (strcmp (subdir, directory))
+                        goto next_entry;
+
+                addr_str = strtok_r (NULL, ")", &tmpdir);
+                if (!addr_str)
+                        goto out;
+
+                addr = gf_strdup (addr_str);
+                if (!addr)
+                        goto out;
+
+                gf_log (subvol, GF_LOG_INFO, "Found an entry for dir %s (%s),"
+                        " performing validation", subdir, addr);
+
+                ret = compare_addr_and_update (addr, peer_addr, subvol,
+                                               ADDR_DELIMITER, result, status);
+                if (ret == 0) {
+                        break;
+                }
+
+                GF_FREE (addr);
+                addr = NULL;
+
+        next_entry:
+                entry = strtok_r (NULL, ENTRY_DELIMITER, &tmp);
+                GF_FREE (entry_cpy);
+                entry_cpy = NULL;
+        }
+
+out:
+        GF_FREE (entries);
+        GF_FREE (entry_cpy);
+        GF_FREE (addr);
+}
+
 auth_result_t
 gf_auth (dict_t *input_params, dict_t *config_params)
 {
@@ -35,15 +173,12 @@ gf_auth (dict_t *input_params, dict_t *config_params)
         data_t        *allow_addr     = NULL;
         data_t        *reject_addr    = NULL;
         char          *addr_str       = NULL;
-        char          *tmp            = NULL;
-        char          *addr_cpy       = NULL;
         char          *service        = NULL;
         uint16_t       peer_port      = 0;
-        char           negate         = 0;
-        char           match          = 0;
         char           peer_addr[UNIX_PATH_MAX] = {0,};
         char          *type           = NULL;
         gf_boolean_t   allow_insecure = _gf_false;
+        char          *subdir         = NULL;
 
         name = data_to_str (dict_get (input_params, "remote-subvolume"));
         if (!name) {
@@ -98,6 +233,12 @@ gf_auth (dict_t *input_params, dict_t *config_params)
                 goto out;
         }
 
+
+        ret = dict_get_str (input_params, "subdir-mount", &subdir);
+        if (ret) {
+                subdir = "/";
+        }
+
         peer_info = data_to_ptr (peer_info_data);
 
         switch (((struct sockaddr *) &peer_info->sockaddr)->sa_family) {
@@ -143,60 +284,19 @@ gf_auth (dict_t *input_params, dict_t *config_params)
         }
 
         if (reject_addr) {
-                addr_cpy = gf_strdup (reject_addr->data);
-                if (!addr_cpy)
+                parse_entries_and_compare (reject_addr->data, peer_addr, name,
+                                           subdir, &result, AUTH_REJECT);
+                if (result == AUTH_REJECT)
                         goto out;
 
-                addr_str = strtok_r (addr_cpy, ADDR_DELIMITER, &tmp);
-
-                while (addr_str) {
-                        gf_log (name,  GF_LOG_DEBUG,
-                                "rejected = \"%s\", received addr = \"%s\"",
-                                addr_str, peer_addr);
-                        if (addr_str[0] == '!') {
-                                negate = 1;
-                                addr_str++;
-                        }
-
-                        match = fnmatch (addr_str, peer_addr, 0);
-                        if (negate ? match : !match) {
-                                result = AUTH_REJECT;
-                                goto out;
-                        }
-                        addr_str = strtok_r (NULL, ADDR_DELIMITER, &tmp);
-                }
-                GF_FREE (addr_cpy);
-                addr_cpy = NULL;
         }
 
         if (allow_addr) {
-                addr_cpy = gf_strdup (allow_addr->data);
-                if (!addr_cpy)
-                        goto out;
-
-                addr_str = strtok_r (addr_cpy, ADDR_DELIMITER, &tmp);
-
-                while (addr_str) {
-                        gf_log (name,  GF_LOG_INFO,
-                                "allowed = \"%s\", received addr = \"%s\"",
-                                addr_str, peer_addr);
-                        if (addr_str[0] == '!') {
-                                negate = 1;
-                                addr_str++;
-                        }
-
-                        match = fnmatch (addr_str, peer_addr, 0);
-                        if (negate ? match : !match) {
-                                result = AUTH_ACCEPT;
-                                goto out;
-                        }
-                        addr_str = strtok_r (NULL, ADDR_DELIMITER, &tmp);
-                }
+                parse_entries_and_compare (allow_addr->data, peer_addr, name,
+                                           subdir, &result, AUTH_ACCEPT);
         }
 
 out:
-        GF_FREE (addr_cpy);
-
         return result;
 }
 
diff --git a/xlators/protocol/client/src/client-handshake.c b/xlators/protocol/client/src/client-handshake.c
index 5f55752..4e6ac74 100644
--- a/xlators/protocol/client/src/client-handshake.c
+++ b/xlators/protocol/client/src/client-handshake.c
@@ -1136,13 +1136,20 @@ client_setvolume_cbk (struct rpc_req *req, struct iovec *iov, int count, void *m
         if (op_ret < 0) {
                 gf_msg (this->name, GF_LOG_ERROR, op_errno,
                         PC_MSG_SETVOLUME_FAIL,
-                        "SETVOLUME on remote-host failed");
+                        "SETVOLUME on remote-host failed: %s", remote_error);
+
                 errno = op_errno;
                 if (remote_error &&
                     (strcmp ("Authentication failed", remote_error) == 0)) {
                         auth_fail = _gf_true;
                         op_ret = 0;
                 }
+                if ((op_errno == ENOENT) && this->ctx->cmd_args.subdir_mount) {
+                        /* A case of subdir not being present at the moment,
+                           ride on auth_fail framework to notify the error */
+                        auth_fail = _gf_true;
+                        op_ret = 0;
+                }
                 if (op_errno == ESTALE) {
                         ret = client_notify_dispatch (this,
                                                       GF_EVENT_VOLFILE_MODIFIED,
@@ -1376,6 +1383,18 @@ client_setvolume (xlator_t *this, struct rpc_clnt *rpc)
                                 "'volfile-checksum'");
         }
 
+        if (this->ctx->cmd_args.subdir_mount) {
+                ret = dict_set_str (options, "subdir-mount",
+                                    this->ctx->cmd_args.subdir_mount);
+                if (ret) {
+                        gf_log (THIS->name, GF_LOG_ERROR,
+                                "Failed to set subdir_mount");
+                        /* It makes sense to fail, as per the CLI, we
+                           should be doing a subdir_mount */
+                        goto fail;
+                }
+        }
+
         ret = dict_set_int16 (options, "clnt-lk-version",
                               client_get_lk_ver (conf));
         if (ret < 0) {
diff --git a/xlators/protocol/server/src/server-common.c b/xlators/protocol/server/src/server-common.c
index 2cabcf9..100b198 100644
--- a/xlators/protocol/server/src/server-common.c
+++ b/xlators/protocol/server/src/server-common.c
@@ -10,8 +10,24 @@
 #include "xdr-nfs3.h"
 
 void
-server_post_stat (gfs3_stat_rsp *rsp, struct iatt *stbuf)
+server_post_stat (server_state_t *state, gfs3_stat_rsp *rsp, struct iatt *stbuf)
 {
+        if (state->client->subdir_mount) {
+                if (gf_uuid_compare (stbuf->ia_gfid,
+                                     state->client->subdir_gfid)) {
+                        /* This is very important as when we send iatt of
+                           root-inode, fuse/client expect the gfid to be 1,
+                           along with inode number. As for subdirectory mount,
+                           we use inode table which is shared by everyone, but
+                           make sure we send fops only from subdir and below,
+                           we have to alter inode gfid and send it to client */
+                        uuid_t gfid = {0,};
+
+                        gfid[15] = 1;
+                        stbuf->ia_ino = 1;
+                        gf_uuid_copy (stbuf->ia_gfid, gfid);
+                }
+        }
         gf_stat_from_iatt (&rsp->stat, stbuf);
 }
 
@@ -166,8 +182,25 @@ server_post_ftruncate (gfs3_ftruncate_rsp *rsp, struct iatt *prebuf,
 }
 
 void
-server_post_fstat (gfs3_fstat_rsp *rsp, struct iatt *stbuf)
+server_post_fstat (server_state_t *state, gfs3_fstat_rsp *rsp,
+                   struct iatt *stbuf)
 {
+        if (state->client->subdir_mount) {
+                if (gf_uuid_compare (stbuf->ia_gfid,
+                                     state->client->subdir_gfid)) {
+                        /* This is very important as when we send iatt of
+                           root-inode, fuse/client expect the gfid to be 1,
+                           along with inode number. As for subdirectory mount,
+                           we use inode table which is shared by everyone, but
+                           make sure we send fops only from subdir and below,
+                           we have to alter inode gfid and send it to client */
+                        uuid_t gfid = {0,};
+
+                        gfid[15] = 1;
+                        stbuf->ia_ino = 1;
+                        gf_uuid_copy (stbuf->ia_gfid, gfid);
+                }
+        }
         gf_stat_from_iatt (&rsp->stat, stbuf);
 }
 
@@ -447,17 +480,6 @@ server_post_lookup (gfs3_lookup_rsp *rsp, call_frame_t *frame,
 
         root_inode = frame->root->client->bound_xl->itable->root;
 
-        if (inode == root_inode) {
-                /* we just looked up root ("/") */
-                stbuf->ia_ino = 1;
-                rootgfid[15]  = 1;
-                gf_uuid_copy (stbuf->ia_gfid, rootgfid);
-                if (inode->ia_type == 0)
-                        inode->ia_type = stbuf->ia_type;
-        }
-
-        gf_stat_from_iatt (&rsp->stat, stbuf);
-
         if (!__is_root_gfid (inode->gfid)) {
                 link_inode = inode_link (inode, state->loc.parent,
                                          state->loc.name, stbuf);
@@ -466,6 +488,26 @@ server_post_lookup (gfs3_lookup_rsp *rsp, call_frame_t *frame,
                         inode_unref (link_inode);
                 }
         }
+
+        if ((inode == root_inode) ||
+            (state->client->subdir_mount &&
+             (inode == state->client->subdir_inode))) {
+                /* we just looked up root ("/") OR
+                   subdir mount directory, which is root ('/') in client */
+                /* This is very important as when we send iatt of
+                   root-inode, fuse/client expect the gfid to be 1,
+                   along with inode number. As for subdirectory mount,
+                   we use inode table which is shared by everyone, but
+                   make sure we send fops only from subdir and below,
+                   we have to alter inode gfid and send it to client */
+                stbuf->ia_ino = 1;
+                rootgfid[15]  = 1;
+                gf_uuid_copy (stbuf->ia_gfid, rootgfid);
+                if (inode->ia_type == 0)
+                        inode->ia_type = stbuf->ia_type;
+        }
+
+        gf_stat_from_iatt (&rsp->stat, stbuf);
 }
 
 void
diff --git a/xlators/protocol/server/src/server-common.h b/xlators/protocol/server/src/server-common.h
index f3b9ced..3fa972e 100644
--- a/xlators/protocol/server/src/server-common.h
+++ b/xlators/protocol/server/src/server-common.h
@@ -9,7 +9,8 @@
 
 #include "xdr-nfs3.h"
 void
-server_post_stat (gfs3_stat_rsp *rsp, struct iatt *stbuf);
+server_post_stat (server_state_t *state,
+                  gfs3_stat_rsp *rsp, struct iatt *stbuf);
 
 void
 server_post_readlink (gfs3_readlink_rsp *rsp, struct iatt *stbuf,
@@ -61,7 +62,8 @@ server_post_ftruncate (gfs3_ftruncate_rsp *rsp, struct iatt *prebuf,
                       struct iatt *postbuf);
 
 void
-server_post_fstat (gfs3_fstat_rsp *rsp, struct iatt *stbuf);
+server_post_fstat (server_state_t *state,
+                   gfs3_fstat_rsp *rsp, struct iatt *stbuf);
 
 void
 server_post_lk (xlator_t *this, gfs3_lk_rsp *rsp, struct gf_flock *lock);
diff --git a/xlators/protocol/server/src/server-handshake.c b/xlators/protocol/server/src/server-handshake.c
index f8f8f99..ba5b11a 100644
--- a/xlators/protocol/server/src/server-handshake.c
+++ b/xlators/protocol/server/src/server-handshake.c
@@ -19,6 +19,7 @@
 #include "server-messages.h"
 #include "syscall.h"
 #include "events.h"
+#include "syncop.h"
 
 struct __get_xl_struct {
         const char *name;
@@ -303,7 +304,7 @@ fail:
         return 0;
 }
 
-void
+static void
 server_first_lookup_done (rpcsvc_request_t *req, gf_setvolume_rsp *rsp) {
 
         server_submit_reply (NULL, req, rsp, NULL, 0, NULL,
@@ -313,41 +314,64 @@ server_first_lookup_done (rpcsvc_request_t *req, gf_setvolume_rsp *rsp) {
         GF_FREE (rsp);
 }
 
-
-int
-server_first_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
-                       int32_t op_ret, int32_t op_errno,
-                       inode_t *inode, struct iatt *buf, dict_t *xattr,
-                       struct iatt *postparent)
+static inode_t *
+do_path_lookup (xlator_t *xl, dict_t *dict, inode_t *parinode, char *basename)
 {
-        rpcsvc_request_t     *req = NULL;
-        gf_setvolume_rsp     *rsp = NULL;
+        int ret = 0;
+        loc_t loc = {0,};
+        uuid_t gfid = {0,};
+        struct iatt iatt = {0,};
+        inode_t *inode = NULL;
+
+        loc.parent = parinode;
+        loc_touchup (&loc, basename);
+        loc.inode = inode_new (xl->itable);
+
+        gf_uuid_generate (gfid);
+        ret = dict_set_static_bin (dict, "gfid-req", gfid, 16);
+        if (ret) {
+                gf_log (xl->name, GF_LOG_ERROR,
+                        "failed to set 'gfid-req' for subdir");
+                goto out;
+        }
 
-        req = cookie;
-        rsp = frame->local;
-        frame->local = NULL;
+        ret = syncop_lookup (xl, &loc, &iatt, NULL, dict, NULL);
+        if (ret < 0) {
+                gf_log (xl->name, GF_LOG_ERROR,
+                        "first lookup on subdir (%s) failed: %s",
+                        basename, strerror (errno));
+        }
 
-        if (op_ret < 0 || buf == NULL)
-                gf_log (this->name, GF_LOG_WARNING, "server first lookup failed"
-                        " on root inode: %s", strerror (op_errno));
 
-        /* Ignore error from lookup, don't set
-         * failure in rsp->op_ret. lookup on a snapview-server
-         * can fail with ESTALE
-         */
-        server_first_lookup_done (req, rsp);
+        /* Inode linking is required so that the
+           resolution happens all fine for future fops */
+        inode = inode_link (loc.inode, loc.parent, loc.name, &iatt);
 
-        STACK_DESTROY (frame->root);
+        /* Extra ref so the pointer is valid till client is valid */
+        /* FIXME: not a priority, but this can lead to some inode
+           leaks if subdir is more than 1 level depth. Leak is only
+           per subdir entry, and not dependent on number of
+           connections, so it should be fine for now */
+        inode_ref (inode);
 
-        return 0;
+out:
+        return inode;
 }
 
 int
-server_first_lookup (xlator_t *this, xlator_t *xl, rpcsvc_request_t *req,
-                     gf_setvolume_rsp *rsp)
+server_first_lookup (xlator_t *this, client_t *client, dict_t *reply)
 {
-        call_frame_t       *frame  = NULL;
         loc_t               loc    = {0, };
+        struct iatt         iatt   = {0,};
+        dict_t             *dict   = NULL;
+        int                 ret    = 0;
+        xlator_t           *xl     = client->bound_xl;
+        char               *msg    = NULL;
+        inode_t *inode = NULL;
+        char *bname = NULL;
+        char *str = NULL;
+        char *tmp = NULL;
+        char *saveptr = NULL;
 
         loc.path = "/";
         loc.name = "";
@@ -355,31 +379,67 @@ server_first_lookup (xlator_t *this, xlator_t *xl, rpcsvc_request_t *req,
         loc.parent = NULL;
         gf_uuid_copy (loc.gfid, loc.inode->gfid);
 
-        frame = create_frame (this, this->ctx->pool);
-        if (!frame) {
-                gf_log ("fuse", GF_LOG_ERROR, "failed to create frame");
-                goto err;
+        ret = syncop_lookup (xl, &loc, &iatt, NULL, NULL, NULL);
+        if (ret < 0)
+                gf_log (xl->name, GF_LOG_ERROR, "lookup on root failed: %s",
+                        strerror (errno));
+        /* Ignore error from lookup, don't set
+         * failure in rsp->op_ret. lookup on a snapview-server
+         * can fail with ESTALE
+         */
+        /* TODO-SUBDIR-MOUNT: validate above comment with respect to subdir lookup */
+
+        if (client->subdir_mount) {
+                str = tmp = gf_strdup (client->subdir_mount);
+                dict = dict_new ();
+                inode = xl->itable->root;
+                bname = strtok_r (str, "/", &saveptr);
+                while (bname != NULL) {
+                        inode = do_path_lookup (xl, dict, inode, bname);
+                        if (inode == NULL) {
+                                gf_log (this->name, GF_LOG_ERROR,
+                                        "first lookup on subdir (%s) failed: %s",
+                                        client->subdir_mount, strerror (errno));
+                                ret = -1;
+                                goto fail;
+                        }
+                        bname = strtok_r (NULL, "/", &saveptr);
+                }
+
+                /* Can be used in server_resolve() */
+                gf_uuid_copy (client->subdir_gfid, inode->gfid);
+                client->subdir_inode = inode;
         }
 
-        frame->local = (void *)rsp;
-        frame->root->uid = frame->root->gid = 0;
-        frame->root->pid = -1;
-        frame->root->type = GF_OP_TYPE_FOP;
+        ret = 0;
+        goto out;
 
-        STACK_WIND_COOKIE (frame, server_first_lookup_cbk, (void *)req, xl,
-                           xl->fops->lookup, &loc, NULL);
+fail:
+        /* we should say to client, it is not possible
+           to connect */
+        ret = gf_asprintf (&msg, "subdirectory for mount \"%s\" is not found",
+                           client->subdir_mount);
+        if (-1 == ret) {
+                gf_msg (this->name, GF_LOG_ERROR, 0,
+                        PS_MSG_ASPRINTF_FAILED,
+                        "asprintf failed while setting error msg");
+        }
+        ret = dict_set_dynstr (reply, "ERROR", msg);
+        if (ret < 0)
+                gf_msg_debug (this->name, 0, "failed to set error "
+                              "msg");
 
-        return 0;
+        ret = -1;
+out:
+        if (dict)
+                dict_unref (dict);
 
-err:
-        rsp->op_ret = -1;
-        rsp->op_errno = ENOMEM;
-        server_first_lookup_done (req, rsp);
+        inode_unref (loc.inode);
 
-        frame->local = NULL;
-        STACK_DESTROY (frame->root);
+        if (tmp)
+                GF_FREE (tmp);
 
-        return -1;
+        return ret;
 }
 
 int
@@ -414,6 +474,7 @@ server_setvolume (rpcsvc_request_t *req)
         int32_t              mgmt_version  = 0;
         glusterfs_ctx_t     *ctx           = NULL;
         struct  _child_status *tmp         = NULL;
+        char                *subdir_mount  = NULL;
 
         params = dict_new ();
         reply  = dict_new ();
@@ -544,6 +605,11 @@ server_setvolume (rpcsvc_request_t *req)
                 goto fail;
         }
 
+        ret = dict_get_str (params, "subdir-mount", &subdir_mount);
+        if (ret < 0) {
+                /* Not a problem at all as the key is optional */
+        }
+
         /*lk_verion :: [1..2^31-1]*/
         ret = dict_get_uint32 (params, "clnt-lk-version", &lk_version);
         if (ret < 0) {
@@ -558,7 +624,7 @@ server_setvolume (rpcsvc_request_t *req)
                 goto fail;
         }
 
-        client = gf_client_get (this, &req->cred, client_uid);
+        client = gf_client_get (this, &req->cred, client_uid, subdir_mount);
         if (client == NULL) {
                 op_ret = -1;
                 op_errno = ENOMEM;
@@ -713,14 +779,18 @@ server_setvolume (rpcsvc_request_t *req)
 
                 gf_event (EVENT_CLIENT_CONNECT, "client_uid=%s;"
                           "client_identifier=%s;server_identifier=%s;"
-                          "brick_path=%s",
+                          "brick_path=%s;subdir_mount=%s",
                           client->client_uid,
                           req->trans->peerinfo.identifier,
                           req->trans->myinfo.identifier,
-                          name);
+                          name, subdir_mount);
 
                 op_ret = 0;
                 client->bound_xl = xl;
+
+                /* Don't be confused by the below line (like how ERROR can
+                   be Success), key checked on client is 'ERROR' and hence
+                   we send 'Success' in this key */
                 ret = dict_set_str (reply, "ERROR", "Success");
                 if (ret < 0)
                         gf_msg_debug (this->name, 0, "failed to set error "
@@ -796,6 +866,16 @@ server_setvolume (rpcsvc_request_t *req)
                 gf_msg_debug (this->name, 0, "failed to set 'transport-ptr'");
 
 fail:
+        /* It is important to validate the lookup on '/' as part of handshake,
+           because if lookup itself can't succeed, we should communicate this
+           to client. Very important in case of subdirectory mounts, where if
+           client is trying to mount a non-existing directory */
+        if (op_ret >= 0 && client->bound_xl->itable) {
+                op_ret = server_first_lookup (this, client, reply);
+                if (op_ret == -1)
+                        op_errno = ENOENT;
+        }
+
         rsp = GF_CALLOC (1, sizeof (gf_setvolume_rsp),
                          gf_server_mt_setvolume_rsp_t);
         GF_ASSERT (rsp);
@@ -842,10 +922,8 @@ fail:
                 req->trans->xl_private = NULL;
         }
 
-        if (op_ret >= 0 && client->bound_xl->itable)
-                server_first_lookup (this, client->bound_xl, req, rsp);
-        else
-                server_first_lookup_done (req, rsp);
+        /* Send the response properly */
+        server_first_lookup_done (req, rsp);
 
         free (args.dict.dict_val);
 
@@ -904,7 +982,7 @@ server_set_lk_version (rpcsvc_request_t *req)
                 goto fail;
         }
 
-        client = gf_client_get (this, &req->cred, args.uid);
+        client = gf_client_get (this, &req->cred, args.uid, NULL);
         serv_ctx = server_ctx_get (client, client->this);
         if (serv_ctx == NULL) {
                 gf_msg (this->name, GF_LOG_INFO, 0,
diff --git a/xlators/protocol/server/src/server-helpers.c b/xlators/protocol/server/src/server-helpers.c
index 3ad3d84..647f144 100644
--- a/xlators/protocol/server/src/server-helpers.c
+++ b/xlators/protocol/server/src/server-helpers.c
@@ -423,6 +423,7 @@ get_frame_from_request (rpcsvc_request_t *req)
         clienttable_t *clienttable = NULL;
         unsigned int   i           = 0;
         rpc_transport_t *trans = NULL;
+        server_state_t  *state = NULL;
 
         GF_VALIDATE_OR_GOTO ("server", req, out);
 
@@ -508,6 +509,9 @@ get_frame_from_request (rpcsvc_request_t *req)
 
 
         frame->local = req;
+
+        state = CALL_STATE (frame);
+        state->client = client;
 out:
         return frame;
 }
@@ -2226,7 +2230,7 @@ server_populate_compound_response (xlator_t *this, gfs3_compound_rsp *rsp,
                                             rsp_args->xdata.xdata_len,
                                             rsp_args->op_errno, out);
                 if (!this_args_cbk->op_ret) {
-                        server_post_stat (rsp_args,
+                        server_post_stat (state, rsp_args,
                                           &this_args_cbk->stat);
                 }
                 rsp_args->op_ret = this_args_cbk->op_ret;
@@ -2729,8 +2733,8 @@ server_populate_compound_response (xlator_t *this, gfs3_compound_rsp *rsp,
                                             rsp_args->xdata.xdata_len,
                                             rsp_args->op_errno, out);
                 if (!this_args_cbk->op_ret) {
-                        server_post_fstat (rsp_args,
-                                          &this_args_cbk->stat);
+                        server_post_fstat (state, rsp_args,
+                                           &this_args_cbk->stat);
                 }
                 rsp_args->op_ret = this_args_cbk->op_ret;
                 rsp_args->op_errno  = gf_errno_to_error
diff --git a/xlators/protocol/server/src/server-rpc-fops.c b/xlators/protocol/server/src/server-rpc-fops.c
index a9f5d86..bd7ec7a 100644
--- a/xlators/protocol/server/src/server-rpc-fops.c
+++ b/xlators/protocol/server/src/server-rpc-fops.c
@@ -41,6 +41,18 @@ forget_inode_if_no_dentry (inode_t *inode)
         return;
 }
 
+static void
+set_resolve_gfid (client_t *client, uuid_t resolve_gfid,
+                  char *on_wire_gfid)
+{
+        if (client->subdir_mount &&
+            __is_root_gfid ((unsigned char *)on_wire_gfid)) {
+                /* set the subdir_mount's gfid for proper resolution */
+                gf_uuid_copy (resolve_gfid, client->subdir_gfid);
+        } else {
+                memcpy (resolve_gfid, on_wire_gfid, 16);
+        }
+}
 
 /* Callback function section */
 int
@@ -1194,8 +1206,8 @@ server_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
         GF_PROTOCOL_DICT_SERIALIZE (this, xdata, &rsp.xdata.xdata_val,
                                     rsp.xdata.xdata_len, op_errno, out);
 
+        state = CALL_STATE (frame);
         if (op_ret) {
-                state = CALL_STATE (frame);
                 gf_msg (this->name, fop_log_level (GF_FOP_FSTAT, op_errno),
                         op_errno, PS_MSG_STAT_INFO,
                         "%"PRId64": FSTAT %"PRId64" (%s) ==> (%s)",
@@ -1204,7 +1216,7 @@ server_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
                 goto out;
         }
 
-        server_post_fstat (&rsp, stbuf);
+        server_post_fstat (state, &rsp, stbuf);
 
 out:
         rsp.op_ret    = op_ret;
@@ -1595,8 +1607,8 @@ server_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
         GF_PROTOCOL_DICT_SERIALIZE (this, xdata, &rsp.xdata.xdata_val,
                                     rsp.xdata.xdata_len, op_errno, out);
 
+        state  = CALL_STATE (frame);
         if (op_ret) {
-                state  = CALL_STATE (frame);
                 gf_msg (this->name, fop_log_level (GF_FOP_STAT, op_errno),
                         op_errno, PS_MSG_STAT_INFO,
                         "%"PRId64": STAT %s (%s) ==> (%s)",
@@ -1606,7 +1618,7 @@ server_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
                 goto out;
         }
 
-        server_post_stat (&rsp, stbuf);
+        server_post_stat (state, &rsp, stbuf);
 out:
         rsp.op_ret    = op_ret;
         rsp.op_errno  = gf_errno_to_error (op_errno);
@@ -3406,7 +3418,7 @@ server3_3_stat (rpcsvc_request_t *req)
         }
 
         state->resolve.type  = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       state->xdata,
@@ -3464,7 +3476,7 @@ server3_3_setattr (rpcsvc_request_t *req)
         }
 
         state->resolve.type  = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         gf_stat_to_iatt (&args.stbuf, &state->stbuf);
         state->valid = args.valid;
@@ -3947,7 +3959,9 @@ server3_3_create (rpcsvc_request_t *req)
         state->mode           = args.mode;
         state->umask          = args.umask;
         state->flags          = gf_flags_to_flags (args.flags);
-        memcpy (state->resolve.pargfid, args.pargfid, 16);
+
+        set_resolve_gfid (frame->root->client, state->resolve.pargfid,
+                          args.pargfid);
 
         if (state->flags & O_EXCL) {
                 state->resolve.type = RESOLVE_NOT;
@@ -4534,7 +4548,7 @@ server3_3_fstat (rpcsvc_request_t *req)
 
         state->resolve.type    = RESOLVE_MUST;
         state->resolve.fd_no   = args.fd;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       state->xdata,
@@ -4651,7 +4665,9 @@ server3_3_unlink (rpcsvc_request_t *req)
 
         state->resolve.type   = RESOLVE_MUST;
         state->resolve.bname  = gf_strdup (args.bname);
-        memcpy (state->resolve.pargfid, args.pargfid, 16);
+
+        set_resolve_gfid (frame->root->client, state->resolve.pargfid,
+                          args.pargfid);
 
         state->flags = args.xflags;
 
@@ -4713,7 +4729,7 @@ server3_3_setxattr (rpcsvc_request_t *req)
 
         state->resolve.type     = RESOLVE_MUST;
         state->flags            = args.flags;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       dict,
@@ -4792,7 +4808,7 @@ server3_3_fsetxattr (rpcsvc_request_t *req)
         state->resolve.type      = RESOLVE_MUST;
         state->resolve.fd_no     = args.fd;
         state->flags             = args.flags;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       dict,
@@ -4868,7 +4884,7 @@ server3_3_fxattrop (rpcsvc_request_t *req)
         state->resolve.type    = RESOLVE_MUST;
         state->resolve.fd_no   = args.fd;
         state->flags           = args.flags;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       dict,
@@ -4944,7 +4960,7 @@ server3_3_xattrop (rpcsvc_request_t *req)
 
         state->resolve.type    = RESOLVE_MUST;
         state->flags           = args.flags;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       dict,
@@ -5017,7 +5033,7 @@ server3_3_getxattr (rpcsvc_request_t *req)
         }
 
         state->resolve.type  = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         if (args.namelen) {
                 state->name = gf_strdup (args.name);
@@ -5081,8 +5097,7 @@ server3_3_fgetxattr (rpcsvc_request_t *req)
 
         state->resolve.type  = RESOLVE_MUST;
         state->resolve.fd_no = args.fd;
-        memcpy (state->resolve.gfid, args.gfid, 16);
-
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
         if (args.namelen)
                 state->name = gf_strdup (args.name);
 
@@ -5143,7 +5158,7 @@ server3_3_removexattr (rpcsvc_request_t *req)
         }
 
         state->resolve.type   = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
         state->name           = gf_strdup (args.name);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
@@ -5202,7 +5217,7 @@ server3_3_fremovexattr (rpcsvc_request_t *req)
 
         state->resolve.type   = RESOLVE_MUST;
         state->resolve.fd_no  = args.fd;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
         state->name           = gf_strdup (args.name);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
@@ -5261,7 +5276,7 @@ server3_3_opendir (rpcsvc_request_t *req)
         }
 
         state->resolve.type   = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       state->xdata,
@@ -5331,7 +5346,7 @@ server3_3_readdirp (rpcsvc_request_t *req)
         state->resolve.type = RESOLVE_MUST;
         state->resolve.fd_no = args.fd;
         state->offset = args.offset;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         /* here, dict itself works as xdata */
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
@@ -5402,7 +5417,7 @@ server3_3_readdir (rpcsvc_request_t *req)
         state->resolve.type = RESOLVE_MUST;
         state->resolve.fd_no = args.fd;
         state->offset = args.offset;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       state->xdata,
@@ -5459,7 +5474,7 @@ server3_3_fsyncdir (rpcsvc_request_t *req)
         state->resolve.type = RESOLVE_MUST;
         state->resolve.fd_no = args.fd;
         state->flags = args.data;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       state->xdata,
@@ -5518,7 +5533,8 @@ server3_3_mknod (rpcsvc_request_t *req)
         }
 
         state->resolve.type    = RESOLVE_NOT;
-        memcpy (state->resolve.pargfid, args.pargfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.pargfid,
+                          args.pargfid);
         state->resolve.bname   = gf_strdup (args.bname);
 
         state->mode  = args.mode;
@@ -5584,7 +5600,9 @@ server3_3_mkdir (rpcsvc_request_t *req)
         }
 
         state->resolve.type    = RESOLVE_NOT;
-        memcpy (state->resolve.pargfid, args.pargfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.pargfid,
+                          args.pargfid);
+
         state->resolve.bname   = gf_strdup (args.bname);
 
         state->mode  = args.mode;
@@ -5648,7 +5666,8 @@ server3_3_rmdir (rpcsvc_request_t *req)
         }
 
         state->resolve.type    = RESOLVE_MUST;
-        memcpy (state->resolve.pargfid, args.pargfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.pargfid,
+                          args.pargfid);
         state->resolve.bname   = gf_strdup (args.bname);
 
         state->flags = args.xflags;
@@ -5711,7 +5730,7 @@ server3_3_inodelk (rpcsvc_request_t *req)
         }
 
         state->resolve.type    = RESOLVE_EXACT;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         cmd = args.cmd;
         switch (cmd) {
@@ -5802,7 +5821,7 @@ server3_3_finodelk (rpcsvc_request_t *req)
         state->volume = gf_strdup (args.volume);
         state->resolve.fd_no = args.fd;
         state->cmd = args.cmd;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         switch (state->cmd) {
         case GF_LK_GETLK:
@@ -5891,7 +5910,7 @@ server3_3_entrylk (rpcsvc_request_t *req)
         }
 
         state->resolve.type   = RESOLVE_EXACT;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         if (args.namelen)
                 state->name   = gf_strdup (args.name);
@@ -5959,7 +5978,7 @@ server3_3_fentrylk (rpcsvc_request_t *req)
         state->resolve.fd_no = args.fd;
         state->cmd  = args.cmd;
         state->type = args.type;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         if (args.namelen)
                 state->name = gf_strdup (args.name);
@@ -6018,7 +6037,7 @@ server3_3_access (rpcsvc_request_t *req)
         }
 
         state->resolve.type  = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
         state->mask          = args.mask;
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
@@ -6079,7 +6098,8 @@ server3_3_symlink (rpcsvc_request_t *req)
         }
 
         state->resolve.type   = RESOLVE_NOT;
-        memcpy (state->resolve.pargfid, args.pargfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.pargfid,
+                          args.pargfid);
         state->resolve.bname  = gf_strdup (args.bname);
         state->name           = gf_strdup (args.linkname);
         state->umask          = args.umask;
@@ -6146,7 +6166,8 @@ server3_3_link (rpcsvc_request_t *req)
 
         state->resolve2.type   = RESOLVE_NOT;
         state->resolve2.bname  = gf_strdup (args.newbname);
-        memcpy (state->resolve2.pargfid, args.newgfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve2.pargfid,
+                          args.newgfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       state->xdata,
@@ -6206,11 +6227,13 @@ server3_3_rename (rpcsvc_request_t *req)
 
         state->resolve.type   = RESOLVE_MUST;
         state->resolve.bname  = gf_strdup (args.oldbname);
-        memcpy (state->resolve.pargfid, args.oldgfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.pargfid,
+                          args.oldgfid);
 
         state->resolve2.type  = RESOLVE_MAY;
         state->resolve2.bname = gf_strdup (args.newbname);
-        memcpy (state->resolve2.pargfid, args.newgfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve2.pargfid,
+                          args.newgfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       state->xdata,
@@ -6261,7 +6284,7 @@ server3_3_lease (rpcsvc_request_t *req)
         }
 
         state->resolve.type = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
         gf_proto_lease_to_lease (&args.lease, &state->lease);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
@@ -6318,7 +6341,7 @@ server3_3_lk (rpcsvc_request_t *req)
         state->resolve.fd_no = args.fd;
         state->cmd =  args.cmd;
         state->type = args.type;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         switch (state->cmd) {
         case GF_LK_GETLK:
@@ -6502,10 +6525,12 @@ server3_3_lookup (rpcsvc_request_t *req)
         state->resolve.type   = RESOLVE_DONTCARE;
 
         if (args.bname && strcmp (args.bname, "")) {
-                memcpy (state->resolve.pargfid, args.pargfid, 16);
+                set_resolve_gfid (frame->root->client, state->resolve.pargfid,
+                                  args.pargfid);
                 state->resolve.bname = gf_strdup (args.bname);
         } else {
-                memcpy (state->resolve.gfid, args.gfid, 16);
+                set_resolve_gfid (frame->root->client,
+                                  state->resolve.gfid, args.gfid);
         }
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
@@ -6563,7 +6588,7 @@ server3_3_statfs (rpcsvc_request_t *req)
         }
 
         state->resolve.type   = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
                                       state->xdata,
@@ -6616,7 +6641,7 @@ server3_3_getactivelk (rpcsvc_request_t *req)
         }
 
         state->resolve.type = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         /* here, dict itself works as xdata */
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
@@ -6673,7 +6698,7 @@ server3_3_setactivelk (rpcsvc_request_t *req)
         }
 
         state->resolve.type = RESOLVE_MUST;
-        memcpy (state->resolve.gfid, args.gfid, 16);
+        set_resolve_gfid (frame->root->client, state->resolve.gfid, args.gfid);
 
         /* here, dict itself works as xdata */
         GF_PROTOCOL_DICT_UNSERIALIZE (frame->root->client->bound_xl,
diff --git a/xlators/protocol/server/src/server.c b/xlators/protocol/server/src/server.c
index b3dc417..71b25bc 100644
--- a/xlators/protocol/server/src/server.c
+++ b/xlators/protocol/server/src/server.c
@@ -430,6 +430,7 @@ _check_for_auth_option (dict_t *d, char *k, data_t *v,
                         goto out;
                 }
 
+                /* TODO-SUBDIR-MOUNT: fix the format */
                 tmp_addr_list = gf_strdup (v->data);
                 addr = strtok_r (tmp_addr_list, ",", &tmp_str);
                 if (!addr)
diff --git a/xlators/protocol/server/src/server.h b/xlators/protocol/server/src/server.h
index b419b05..1be9a38 100644
--- a/xlators/protocol/server/src/server.h
+++ b/xlators/protocol/server/src/server.h
@@ -206,6 +206,9 @@ struct _server_state {
         struct iobuf     *rsp_iobuf;
         struct iobref    *rsp_iobref;
         compound_args_t  *args;
+
+        /* subdir mount */
+        client_t         *client;
 };
 
 
-- 
1.8.3.1