e3c68b
From 36b0bd86321436a951f225fcf2e921390ed8dc33 Mon Sep 17 00:00:00 2001
e3c68b
From: Michael Adam <obnox@samba.org>
e3c68b
Date: Thu, 20 Jun 2019 13:09:37 +0200
e3c68b
Subject: [PATCH 223/255] change get_real_filename implementation to use
e3c68b
 ENOATTR instead of ENOENT
e3c68b
e3c68b
get_real_filename is implemented as a virtual extended attribute to help
e3c68b
Samba implement the case-insensitive but case preserving SMB protocol
e3c68b
more efficiently. It is implemented as a getxattr call on the parent directory
e3c68b
with the virtual key of "get_real_filename:<entryname>" by looking for a
e3c68b
spelling with different case for the provided file/dir name (<entryname>)
e3c68b
and returning this correct spelling as a result if the entry is found.
e3c68b
Originally (05aaec645a6262d431486eb5ac7cd702646cfcfb), the
e3c68b
implementation used the ENOENT errno to return the authoritative answer
e3c68b
that <entryname> does not exist in any case folding.
e3c68b
e3c68b
Now this implementation is actually a violation or misuse of the defined
e3c68b
API for the getxattr call which returns ENOENT for the case that the dir
e3c68b
that the call is made against does not exist and ENOATTR (or the synonym
e3c68b
ENODATA) for the case that the xattr does not exist.
e3c68b
e3c68b
This was not a problem until the gluster fuse-bridge was changed
e3c68b
to do map ENOENT to ESTALE in 59629f1da9dca670d5dcc6425f7f89b3e96b46bf,
e3c68b
after which we the getxattr call for get_real_filename returned an
e3c68b
ESTALE instead of ENOENT breaking the expectation in Samba.
e3c68b
e3c68b
It is an independent problem that ESTALE should not leak out to user
e3c68b
space but is intended to trigger retries between fuse and gluster.
e3c68b
But nevertheless, the semantics seem to be incorrect here and should
e3c68b
be changed.
e3c68b
e3c68b
This patch changes the implementation of the get_real_filename virtual
e3c68b
xattr to correctly return ENOATTR instead of ENOENT if the file/directory
e3c68b
being looked up is not found.
e3c68b
e3c68b
The Samba glusterfs_fuse vfs module which takes advantage of the
e3c68b
get_real_filename over a fuse mount will receive a corresponding change
e3c68b
to map ENOATTR to ENOENT. Without this change, it will still work
e3c68b
correctly, but the performance optimization for nonexisting files is
e3c68b
lost. On the other hand side, this change removes the distinction
e3c68b
between the old not-implemented case and the implemented case.
e3c68b
So Samba changed to treat ENOATTR like ENOENT will not work correctly
e3c68b
any more against old servers that don't implement get_real_filename.
e3c68b
I.e. existing files will be reported as non-existing
e3c68b
e3c68b
Backport of https://review.gluster.org/c/glusterfs/+/22925
e3c68b
e3c68b
Change-Id: I971b427ab8410636d5d201157d9af70e0d075b67
e3c68b
fixes: bz#1724089
e3c68b
Signed-off-by: Michael Adam <obnox@samba.org>
e3c68b
Reviewed-on: https://code.engineering.redhat.com/gerrit/175012
e3c68b
Tested-by: RHGS Build Bot <nigelb@redhat.com>
e3c68b
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
e3c68b
---
e3c68b
 xlators/cluster/dht/src/dht-common.c           | 8 ++++----
e3c68b
 xlators/storage/posix/src/posix-inode-fd-ops.c | 4 ++--
e3c68b
 2 files changed, 6 insertions(+), 6 deletions(-)
e3c68b
e3c68b
diff --git a/xlators/cluster/dht/src/dht-common.c b/xlators/cluster/dht/src/dht-common.c
e3c68b
index 9a6ea5b..219b072 100644
e3c68b
--- a/xlators/cluster/dht/src/dht-common.c
e3c68b
+++ b/xlators/cluster/dht/src/dht-common.c
e3c68b
@@ -4618,7 +4618,7 @@ dht_getxattr_get_real_filename_cbk(call_frame_t *frame, void *cookie,
e3c68b
 
e3c68b
     LOCK(&frame->lock);
e3c68b
     {
e3c68b
-        if (local->op_errno == ENODATA || local->op_errno == EOPNOTSUPP) {
e3c68b
+        if (local->op_errno == EOPNOTSUPP) {
e3c68b
             /* Nothing to do here, we have already found
e3c68b
              * a subvol which does not have the get_real_filename
e3c68b
              * optimization. If condition is for simple logic.
e3c68b
@@ -4627,7 +4627,7 @@ dht_getxattr_get_real_filename_cbk(call_frame_t *frame, void *cookie,
e3c68b
         }
e3c68b
 
e3c68b
         if (op_ret == -1) {
e3c68b
-            if (op_errno == ENODATA || op_errno == EOPNOTSUPP) {
e3c68b
+            if (op_errno == EOPNOTSUPP) {
e3c68b
                 /* This subvol does not have the optimization.
e3c68b
                  * Better let the user know we don't support it.
e3c68b
                  * Remove previous results if any.
e3c68b
@@ -4655,7 +4655,7 @@ dht_getxattr_get_real_filename_cbk(call_frame_t *frame, void *cookie,
e3c68b
                 goto post_unlock;
e3c68b
             }
e3c68b
 
e3c68b
-            if (op_errno == ENOENT) {
e3c68b
+            if (op_errno == ENOATTR) {
e3c68b
                 /* Do nothing, our defaults are set to this.
e3c68b
                  */
e3c68b
                 goto unlock;
e3c68b
@@ -4723,7 +4723,7 @@ dht_getxattr_get_real_filename(call_frame_t *frame, xlator_t *this, loc_t *loc,
e3c68b
     cnt = local->call_cnt = layout->cnt;
e3c68b
 
e3c68b
     local->op_ret = -1;
e3c68b
-    local->op_errno = ENOENT;
e3c68b
+    local->op_errno = ENOATTR;
e3c68b
 
e3c68b
     for (i = 0; i < cnt; i++) {
e3c68b
         subvol = layout->list[i].xlator;
e3c68b
diff --git a/xlators/storage/posix/src/posix-inode-fd-ops.c b/xlators/storage/posix/src/posix-inode-fd-ops.c
e3c68b
index c949f68..ea3b69c 100644
e3c68b
--- a/xlators/storage/posix/src/posix-inode-fd-ops.c
e3c68b
+++ b/xlators/storage/posix/src/posix-inode-fd-ops.c
e3c68b
@@ -2954,7 +2954,7 @@ posix_xattr_get_real_filename(call_frame_t *frame, xlator_t *this, loc_t *loc,
e3c68b
     (void)sys_closedir(fd);
e3c68b
 
e3c68b
     if (!found)
e3c68b
-        return -ENOENT;
e3c68b
+        return -ENOATTR;
e3c68b
 
e3c68b
     ret = dict_set_dynstr(dict, (char *)key, found);
e3c68b
     if (ret) {
e3c68b
@@ -3422,7 +3422,7 @@ posix_getxattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
e3c68b
         if (ret < 0) {
e3c68b
             op_ret = -1;
e3c68b
             op_errno = -ret;
e3c68b
-            if (op_errno == ENOENT) {
e3c68b
+            if (op_errno == ENOATTR) {
e3c68b
                 gf_msg_debug(this->name, 0,
e3c68b
                              "Failed to get "
e3c68b
                              "real filename (%s, %s)",
e3c68b
-- 
e3c68b
1.8.3.1
e3c68b