d2787b
From 9bf6986f8ea3edd9de3d2629404f7ab11c1597de Mon Sep 17 00:00:00 2001
d2787b
From: Xavi Hernandez <xhernandez@redhat.com>
d2787b
Date: Tue, 9 Mar 2021 00:24:07 +0100
d2787b
Subject: [PATCH 558/584] afr: fix directory entry count
d2787b
d2787b
AFR may hide some existing entries from a directory when reading it
d2787b
because they are generated internally for private management. However
d2787b
the returned number of entries from readdir() function is not updated
d2787b
accordingly. So it may return a number higher than the real entries
d2787b
present in the gf_dirent list.
d2787b
d2787b
This may cause unexpected behavior of clients, including gfapi which
d2787b
incorrectly assumes that there was an entry when the list was actually
d2787b
empty.
d2787b
d2787b
This patch also makes the check in gfapi more robust to avoid similar
d2787b
issues that could appear in the future.
d2787b
d2787b
Backport of:
d2787b
> Upstream-patch: https://github.com/gluster/glusterfs/pull/2233
d2787b
> Fixes: #2232
d2787b
> Change-Id: I81ba3699248a53ebb0ee4e6e6231a4301436f763
d2787b
> Signed-off-by: Xavi Hernandez <xhernandez@redhat.com>
d2787b
d2787b
BUG: 1927411
d2787b
Change-Id: I81ba3699248a53ebb0ee4e6e6231a4301436f763
d2787b
Signed-off-by: Xavi Hernandez <xhernandez@redhat.com>
d2787b
Reviewed-on: https://code.engineering.redhat.com/gerrit/c/rhs-glusterfs/+/244535
d2787b
Tested-by: RHGS Build Bot <nigelb@redhat.com>
d2787b
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
d2787b
---
d2787b
 api/src/glfs-fops.c                    |  3 +-
d2787b
 tests/bugs/replicate/issue-2232.c      | 85 ++++++++++++++++++++++++++++++++++
d2787b
 tests/bugs/replicate/issue-2232.t      | 34 ++++++++++++++
d2787b
 xlators/cluster/afr/src/afr-dir-read.c | 11 +++--
d2787b
 4 files changed, 129 insertions(+), 4 deletions(-)
d2787b
 create mode 100644 tests/bugs/replicate/issue-2232.c
d2787b
 create mode 100644 tests/bugs/replicate/issue-2232.t
d2787b
d2787b
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
d2787b
index 6dc3b66..821d250 100644
d2787b
--- a/api/src/glfs-fops.c
d2787b
+++ b/api/src/glfs-fops.c
d2787b
@@ -3748,8 +3748,9 @@ glfd_entry_refresh(struct glfs_fd *glfd, int plus)
d2787b
         errno = 0;
d2787b
     }
d2787b
 
d2787b
-    if (ret > 0)
d2787b
+    if ((ret > 0) && !list_empty(&glfd->entries)) {
d2787b
         glfd->next = list_entry(glfd->entries.next, gf_dirent_t, list);
d2787b
+    }
d2787b
 
d2787b
     gf_dirent_free(&old;;
d2787b
 out:
d2787b
diff --git a/tests/bugs/replicate/issue-2232.c b/tests/bugs/replicate/issue-2232.c
d2787b
new file mode 100644
d2787b
index 0000000..df547c2
d2787b
--- /dev/null
d2787b
+++ b/tests/bugs/replicate/issue-2232.c
d2787b
@@ -0,0 +1,85 @@
d2787b
+
d2787b
+#include <stdio.h>
d2787b
+#include <errno.h>
d2787b
+#include <stdlib.h>
d2787b
+#include <errno.h>
d2787b
+#include <string.h>
d2787b
+#include <glusterfs/api/glfs.h>
d2787b
+
d2787b
+int main(int argc, char **argv)
d2787b
+{
d2787b
+    char log[128];
d2787b
+    struct dirent entry;
d2787b
+    struct dirent *ent;
d2787b
+    glfs_xreaddirp_stat_t *xstat;
d2787b
+    int ret, flags;
d2787b
+
d2787b
+    if (argc != 3) {
d2787b
+        fprintf(stderr, "Syntax: %s <hostname> <volume>\n", argv[0]);
d2787b
+        exit(1);
d2787b
+    }
d2787b
+    char *hostname = argv[1];
d2787b
+    char *volname = argv[2];
d2787b
+
d2787b
+    glfs_t *fs = glfs_new(volname);
d2787b
+    if (!fs) {
d2787b
+        fprintf(stderr, "glfs_new() failed\n");
d2787b
+        exit(1);
d2787b
+    }
d2787b
+
d2787b
+    ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007);
d2787b
+    if (ret < 0) {
d2787b
+        fprintf(stderr, "glfs_set_volfile_server() failed\n");
d2787b
+        return ret;
d2787b
+    }
d2787b
+
d2787b
+    sprintf(log, "/tmp/logs-%d.log", getpid());
d2787b
+    ret = glfs_set_logging(fs, log, 9);
d2787b
+    if (ret < 0) {
d2787b
+        fprintf(stderr, "glfs_set_logging() failed\n");
d2787b
+        return ret;
d2787b
+    }
d2787b
+
d2787b
+    ret = glfs_init(fs);
d2787b
+    if (ret < 0) {
d2787b
+        fprintf(stderr, "glfs_init() failed\n");
d2787b
+        return ret;
d2787b
+    }
d2787b
+
d2787b
+    glfs_fd_t *fd = glfs_opendir(fs, "/");
d2787b
+    if (fd == NULL) {
d2787b
+        fprintf(stderr, "glfs_opendir() failed\n");
d2787b
+        return 1;
d2787b
+    }
d2787b
+
d2787b
+    flags = GFAPI_XREADDIRP_STAT | GFAPI_XREADDIRP_HANDLE;
d2787b
+    xstat = NULL;
d2787b
+    while ((ret = glfs_xreaddirplus_r(fd, flags, &xstat, &entry, &ent)) > 0) {
d2787b
+        if (xstat != NULL) {
d2787b
+            glfs_free(xstat);
d2787b
+        }
d2787b
+        if ((strcmp(ent->d_name, ".") == 0) ||
d2787b
+            (strcmp(ent->d_name, "..") == 0)) {
d2787b
+            xstat = NULL;
d2787b
+            continue;
d2787b
+        }
d2787b
+        if ((xstat == NULL) || ((ret & GFAPI_XREADDIRP_HANDLE) == 0)) {
d2787b
+            fprintf(stderr, "glfs_xreaddirplus_r() failed: %s\n",
d2787b
+                    strerror(errno));
d2787b
+            return 1;
d2787b
+        }
d2787b
+
d2787b
+        xstat = NULL;
d2787b
+    }
d2787b
+
d2787b
+    if (ret < 0) {
d2787b
+        fprintf(stderr, "glfs_xreaddirplus_r() failed\n");
d2787b
+        return ret;
d2787b
+    }
d2787b
+
d2787b
+    glfs_close(fd);
d2787b
+
d2787b
+    glfs_fini(fs);
d2787b
+
d2787b
+    return ret;
d2787b
+}
d2787b
diff --git a/tests/bugs/replicate/issue-2232.t b/tests/bugs/replicate/issue-2232.t
d2787b
new file mode 100644
d2787b
index 0000000..66a41e0
d2787b
--- /dev/null
d2787b
+++ b/tests/bugs/replicate/issue-2232.t
d2787b
@@ -0,0 +1,34 @@
d2787b
+#!/bin/bash
d2787b
+
d2787b
+. $(dirname "${0}")/../../include.rc
d2787b
+. $(dirname "${0}")/../../volume.rc
d2787b
+
d2787b
+cleanup;
d2787b
+TEST gcc $(dirname "${0}")/issue-2232.c -o $(dirname "${0}")/issue-2232 -lgfapi
d2787b
+TEST glusterd
d2787b
+TEST pidof glusterd
d2787b
+
d2787b
+TEST $CLI volume create ${V0} replica 3 ${H0}:${B0}/${V0}{0..2}
d2787b
+
d2787b
+# Create a fake .glusterfs-anonymous-inode-... entry
d2787b
+ANONINO=".glusterfs-anonymous-inode-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
d2787b
+TEST mkdir ${B0}/${V0}{0..2}/${ANONINO}
d2787b
+gfid="$(uuidgen)"
d2787b
+hex="0x$(echo "${gfid}" | tr -d '-')"
d2787b
+TEST assign_gfid "${hex}" "${B0}/${V0}0/${ANONINO}"
d2787b
+TEST assign_gfid "${hex}" "${B0}/${V0}1/${ANONINO}"
d2787b
+TEST assign_gfid "${hex}" "${B0}/${V0}2/${ANONINO}"
d2787b
+TEST mkdir -p "${B0}/${V0}0/.glusterfs/${gfid:0:2}/${gfid:2:2}"
d2787b
+TEST mkdir -p "${B0}/${V0}1/.glusterfs/${gfid:0:2}/${gfid:2:2}"
d2787b
+TEST mkdir -p "${B0}/${V0}2/.glusterfs/${gfid:0:2}/${gfid:2:2}"
d2787b
+TEST ln -s "../../00/00/00000000-0000-0000-0000-000000000001/${ANONINO}" "${B0}/${V0}0/.glusterfs/${gfid:0:2}/${gfid:2:2}/${gfid}"
d2787b
+TEST ln -s "../../00/00/00000000-0000-0000-0000-000000000001/${ANONINO}" "${B0}/${V0}1/.glusterfs/${gfid:0:2}/${gfid:2:2}/${gfid}"
d2787b
+TEST ln -s "../../00/00/00000000-0000-0000-0000-000000000001/${ANONINO}" "${B0}/${V0}2/.glusterfs/${gfid:0:2}/${gfid:2:2}/${gfid}"
d2787b
+
d2787b
+TEST $CLI volume start ${V0}
d2787b
+
d2787b
+TEST $(dirname "${0}")/issue-2232 ${H0} ${V0}
d2787b
+
d2787b
+TEST rm -f $(dirname $0)/issue-2232
d2787b
+
d2787b
+cleanup
d2787b
diff --git a/xlators/cluster/afr/src/afr-dir-read.c b/xlators/cluster/afr/src/afr-dir-read.c
d2787b
index d64b6a9..a98f8df 100644
d2787b
--- a/xlators/cluster/afr/src/afr-dir-read.c
d2787b
+++ b/xlators/cluster/afr/src/afr-dir-read.c
d2787b
@@ -157,7 +157,7 @@ afr_validate_read_subvol(inode_t *inode, xlator_t *this, int par_read_subvol)
d2787b
     return 0;
d2787b
 }
d2787b
 
d2787b
-static void
d2787b
+static int32_t
d2787b
 afr_readdir_transform_entries(call_frame_t *frame, gf_dirent_t *subvol_entries,
d2787b
                               int subvol, gf_dirent_t *entries, fd_t *fd)
d2787b
 {
d2787b
@@ -168,6 +168,7 @@ afr_readdir_transform_entries(call_frame_t *frame, gf_dirent_t *subvol_entries,
d2787b
     afr_private_t *priv = NULL;
d2787b
     gf_boolean_t need_heal = _gf_false;
d2787b
     gf_boolean_t validate_subvol = _gf_false;
d2787b
+    int32_t count = 0;
d2787b
 
d2787b
     this = THIS;
d2787b
     priv = this->private;
d2787b
@@ -184,6 +185,7 @@ afr_readdir_transform_entries(call_frame_t *frame, gf_dirent_t *subvol_entries,
d2787b
 
d2787b
         list_del_init(&entry->list);
d2787b
         list_add_tail(&entry->list, &entries->list);
d2787b
+        count++;
d2787b
 
d2787b
         if (!validate_subvol)
d2787b
             continue;
d2787b
@@ -197,6 +199,8 @@ afr_readdir_transform_entries(call_frame_t *frame, gf_dirent_t *subvol_entries,
d2787b
             }
d2787b
         }
d2787b
     }
d2787b
+
d2787b
+    return count;
d2787b
 }
d2787b
 
d2787b
 int32_t
d2787b
@@ -222,8 +226,9 @@ afr_readdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
d2787b
     }
d2787b
 
d2787b
     if (op_ret >= 0)
d2787b
-        afr_readdir_transform_entries(frame, subvol_entries, (long)cookie,
d2787b
-                                      &entries, local->fd);
d2787b
+        op_ret = afr_readdir_transform_entries(frame, subvol_entries,
d2787b
+                                               (long)cookie, &entries,
d2787b
+                                               local->fd);
d2787b
 
d2787b
     AFR_STACK_UNWIND(readdir, frame, op_ret, op_errno, &entries, xdata);
d2787b
 
d2787b
-- 
d2787b
1.8.3.1
d2787b