50dc83
From 2d7d9165c6a8619eef553859b4b7136b8e9ccb55 Mon Sep 17 00:00:00 2001
50dc83
From: Anoop C S <anoopcs@redhat.com>
50dc83
Date: Sat, 10 Aug 2019 10:30:26 +0530
50dc83
Subject: [PATCH 280/284] performance/md-cache: Do not skip caching of null
50dc83
 character xattr values
50dc83
50dc83
Null character string is a valid xattr value in file system. But for
50dc83
those xattrs processed by md-cache, it does not update its entries if
50dc83
value is null('\0'). This results in ENODATA when those xattrs are
50dc83
queried afterwards via getxattr() causing failures in basic operations
50dc83
like create, copy etc in a specially configured Samba setup for Mac OS
50dc83
clients.
50dc83
50dc83
On the other side snapview-server is internally setting empty string("")
50dc83
as value for xattrs received as part of listxattr() and are not intended
50dc83
to be cached. Therefore we try to maintain that behaviour using an
50dc83
additional dictionary key to prevent updation of entries in getxattr()
50dc83
and fgetxattr() callbacks in md-cache.
50dc83
50dc83
Credits: Poornima G <pgurusid@redhat.com>
50dc83
50dc83
Backport of https://review.gluster.org/c/glusterfs/+/23206
50dc83
50dc83
Change-Id: I7859cbad0a06ca6d788420c2a495e658699c6ff7
50dc83
Fixes: bz#1732376
50dc83
Signed-off-by: Anoop C S <anoopcs@redhat.com>
50dc83
Reviewed-on: https://code.engineering.redhat.com/gerrit/179048
50dc83
Tested-by: RHGS Build Bot <nigelb@redhat.com>
50dc83
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
50dc83
---
50dc83
 tests/bugs/md-cache/bug-1726205.t                  | 22 +++++++++++++++
50dc83
 .../features/snapview-server/src/snapview-server.c | 12 ++++++++-
50dc83
 xlators/performance/md-cache/src/md-cache.c        | 31 +++++++++-------------
50dc83
 3 files changed, 45 insertions(+), 20 deletions(-)
50dc83
 create mode 100644 tests/bugs/md-cache/bug-1726205.t
50dc83
50dc83
diff --git a/tests/bugs/md-cache/bug-1726205.t b/tests/bugs/md-cache/bug-1726205.t
50dc83
new file mode 100644
50dc83
index 0000000..795130e
50dc83
--- /dev/null
50dc83
+++ b/tests/bugs/md-cache/bug-1726205.t
50dc83
@@ -0,0 +1,22 @@
50dc83
+#!/bin/bash
50dc83
+
50dc83
+. $(dirname $0)/../../include.rc
50dc83
+. $(dirname $0)/../../volume.rc
50dc83
+
50dc83
+cleanup;
50dc83
+
50dc83
+TEST glusterd;
50dc83
+
50dc83
+TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2,3};
50dc83
+
50dc83
+TEST $CLI volume start $V0
50dc83
+
50dc83
+TEST $CLI volume set $V0 group samba
50dc83
+
50dc83
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0
50dc83
+
50dc83
+TEST touch $M0/file
50dc83
+TEST "setfattr -n "user.DosStream.Zone.Identifier:\$DATA" -v '\0' $M0/file"
50dc83
+TEST "getfattr -n "user.DosStream.Zone.Identifier:\$DATA" -e hex $M0/file | grep -q 0x00"
50dc83
+
50dc83
+cleanup;
50dc83
diff --git a/xlators/features/snapview-server/src/snapview-server.c b/xlators/features/snapview-server/src/snapview-server.c
50dc83
index b4998b8..1d6a5e5 100644
50dc83
--- a/xlators/features/snapview-server/src/snapview-server.c
50dc83
+++ b/xlators/features/snapview-server/src/snapview-server.c
50dc83
@@ -828,7 +828,8 @@ out:
50dc83
  * back into the dict. But to get the values for those xattrs it has to do the
50dc83
  * getxattr operation on each xattr which might turn out to be a costly
50dc83
  * operation. So for each of the xattrs present in the list, a 0 byte value
50dc83
- * ("") is set into the dict before unwinding. This can be treated as an
50dc83
+ * ("") is set into the dict before unwinding. Since ("") is also a valid xattr
50dc83
+ * value(in a file system) we use an extra key in the same dictionary as an
50dc83
  * indicator to other xlators which want to cache the xattrs (as of now,
50dc83
  * md-cache which caches acl and selinux related xattrs) to not to cache the
50dc83
  * values of the xattrs present in the dict.
50dc83
@@ -871,6 +872,15 @@ svs_add_xattrs_to_dict(xlator_t *this, dict_t *dict, char *list, ssize_t size)
50dc83
         list_offset += strlen(keybuffer) + 1;
50dc83
     } /* while (remaining_size > 0) */
50dc83
 
50dc83
+    /* Add an additional key to indicate that we don't need to cache these
50dc83
+     * xattrs(with value "") */
50dc83
+    ret = dict_set_str(dict, "glusterfs.skip-cache", "");
50dc83
+    if (ret < 0) {
50dc83
+        gf_msg(this->name, GF_LOG_ERROR, 0, SVS_MSG_DICT_SET_FAILED,
50dc83
+               "dict set operation for the key glusterfs.skip-cache failed.");
50dc83
+        goto out;
50dc83
+    }
50dc83
+
50dc83
     ret = 0;
50dc83
 
50dc83
 out:
50dc83
diff --git a/xlators/performance/md-cache/src/md-cache.c b/xlators/performance/md-cache/src/md-cache.c
50dc83
index 6e0468f..a6b363f 100644
50dc83
--- a/xlators/performance/md-cache/src/md-cache.c
50dc83
+++ b/xlators/performance/md-cache/src/md-cache.c
50dc83
@@ -698,25 +698,6 @@ updatefn(dict_t *dict, char *key, data_t *value, void *data)
50dc83
             }
50dc83
         }
50dc83
 
50dc83
-        /* posix xlator as part of listxattr will send both names
50dc83
-         * and values of the xattrs in the dict. But as per man page
50dc83
-         * listxattr is mainly supposed to send names of the all the
50dc83
-         * xattrs. gfapi, as of now will put all the keys it obtained
50dc83
-         * in the dict (sent by posix) into a buffer provided by the
50dc83
-         * caller (thus the values of those xattrs are lost). If some
50dc83
-         * xlator makes gfapi based calls (ex: snapview-server), then
50dc83
-         * it has to unwind the calls by putting those names it got
50dc83
-         * in the buffer again into the dict. But now it would not be
50dc83
-         * having the values for those xattrs. So it might just put
50dc83
-         * a 0 byte value ("") into the dict for each xattr and unwind
50dc83
-         * the call. So the xlators which cache the xattrs (as of now
50dc83
-         * md-cache caches the acl and selinux related xattrs), should
50dc83
-         * not update their cache if the value of a xattr is a 0 byte
50dc83
-         * data (i.e. "").
50dc83
-         */
50dc83
-        if (value->len == 1 && value->data[0] == '\0')
50dc83
-            return 0;
50dc83
-
50dc83
         if (dict_set(u->dict, key, value) < 0) {
50dc83
             u->ret = -1;
50dc83
             return -1;
50dc83
@@ -2406,6 +2387,12 @@ mdc_getxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
50dc83
         goto out;
50dc83
     }
50dc83
 
50dc83
+    if (dict_get(xattr, "glusterfs.skip-cache")) {
50dc83
+        gf_msg(this->name, GF_LOG_DEBUG, 0, 0,
50dc83
+               "Skipping xattr update due to empty value");
50dc83
+        goto out;
50dc83
+    }
50dc83
+
50dc83
     mdc_inode_xatt_set(this, local->loc.inode, xdata);
50dc83
 
50dc83
 out:
50dc83
@@ -2488,6 +2475,12 @@ mdc_fgetxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
50dc83
         goto out;
50dc83
     }
50dc83
 
50dc83
+    if (dict_get(xattr, "glusterfs.skip-cache")) {
50dc83
+        gf_msg(this->name, GF_LOG_DEBUG, 0, 0,
50dc83
+               "Skipping xattr update due to empty value");
50dc83
+        goto out;
50dc83
+    }
50dc83
+
50dc83
     mdc_inode_xatt_set(this, local->fd->inode, xdata);
50dc83
 
50dc83
 out:
50dc83
-- 
50dc83
1.8.3.1
50dc83