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