14f8ab
From e2af9793014ad67859aa73088765a52307cbe466 Mon Sep 17 00:00:00 2001
14f8ab
From: Csaba Henk <csaba@redhat.com>
14f8ab
Date: Tue, 7 Jan 2020 19:43:05 +0100
14f8ab
Subject: [PATCH 346/346] fuse: degrade logging of write failure to fuse device
14f8ab
14f8ab
Problem:
14f8ab
14f8ab
FUSE uses failures of communicating with /dev/fuse with various
14f8ab
errnos to indicate in-kernel conditions to userspace. Some of these
14f8ab
shouldn't be handled as an application error. Also the standard
14f8ab
POSIX errno description should not be shown as they are misleading
14f8ab
in this context.
14f8ab
14f8ab
Solution:
14f8ab
14f8ab
When writing to the fuse device, the caller of the respective
14f8ab
convenience routine can mask those errnos which don't qualify to
14f8ab
be an error for the application in that context, so then those
14f8ab
shall be reported at DEBUG level.
14f8ab
14f8ab
The possible non-standard errnos are reported with their
14f8ab
POSIX name instead of their description to avoid confusion.
14f8ab
(Eg. for ENOENT we don't log "no such file or directory",
14f8ab
we log indeed literal "ENOENT".)
14f8ab
14f8ab
Upstream on https://review.gluster.org/23974
14f8ab
> Change-Id: I510158843e4b1d482bdc496c2e97b1860dc1ba93
14f8ab
> updates: bz#1193929
14f8ab
> Signed-off-by: Csaba Henk <csaba@redhat.com>
14f8ab
14f8ab
BUG: 1763208
14f8ab
Change-Id: Ib1676bb334ed153ce74ae1c0413fc0e58fb388c7
14f8ab
Signed-off-by: Csaba Henk <csaba@redhat.com>
14f8ab
Reviewed-on: https://code.engineering.redhat.com/gerrit/189056
14f8ab
Tested-by: RHGS Build Bot <nigelb@redhat.com>
14f8ab
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
14f8ab
---
14f8ab
 xlators/mount/fuse/src/fuse-bridge.c | 78 +++++++++++++++++++++++++++++++++---
14f8ab
 xlators/mount/fuse/src/fuse-bridge.h |  9 ++++-
14f8ab
 2 files changed, 80 insertions(+), 7 deletions(-)
14f8ab
14f8ab
diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c
14f8ab
index ebe5c28..6e99053 100644
14f8ab
--- a/xlators/mount/fuse/src/fuse-bridge.c
14f8ab
+++ b/xlators/mount/fuse/src/fuse-bridge.c
14f8ab
@@ -198,7 +198,7 @@ fusedump_setup_meta(struct iovec *iovs, char *dir,
14f8ab
 
14f8ab
 static int
14f8ab
 check_and_dump_fuse_W(fuse_private_t *priv, struct iovec *iov_out, int count,
14f8ab
-                      ssize_t res)
14f8ab
+                      ssize_t res, errnomask_t errnomask)
14f8ab
 {
14f8ab
     char w = 'W';
14f8ab
     struct iovec diov[4] = {
14f8ab
@@ -216,8 +216,59 @@ check_and_dump_fuse_W(fuse_private_t *priv, struct iovec *iov_out, int count,
14f8ab
     struct fuse_out_header *fouh = NULL;
14f8ab
 
14f8ab
     if (res == -1) {
14f8ab
-        gf_log_callingfn("glusterfs-fuse", GF_LOG_ERROR,
14f8ab
-                         "writing to fuse device failed: %s", strerror(errno));
14f8ab
+        const char *errdesc = NULL;
14f8ab
+        gf_loglevel_t loglevel = GF_LOG_ERROR;
14f8ab
+
14f8ab
+        /* If caller masked the errno, then it
14f8ab
+         * does not indicate an error at the application
14f8ab
+         * level, so we degrade the log severity to DEBUG.
14f8ab
+         */
14f8ab
+        if (errnomask && errno < ERRNOMASK_MAX &&
14f8ab
+            GET_ERRNO_MASK(errnomask, errno))
14f8ab
+            loglevel = GF_LOG_DEBUG;
14f8ab
+
14f8ab
+        switch (errno) {
14f8ab
+            /* The listed errnos are FUSE status indicators,
14f8ab
+             * not legit values according to POSIX (see write(3p)),
14f8ab
+             * so resolving them according to the standard
14f8ab
+             * POSIX interpretation would be misleading.
14f8ab
+             */
14f8ab
+            case ENOENT:
14f8ab
+                errdesc = "ENOENT";
14f8ab
+                break;
14f8ab
+            case ENOTDIR:
14f8ab
+                errdesc = "ENOTDIR";
14f8ab
+                break;
14f8ab
+            case ENODEV:
14f8ab
+                errdesc = "ENODEV";
14f8ab
+                break;
14f8ab
+            case EPERM:
14f8ab
+                errdesc = "EPERM";
14f8ab
+                break;
14f8ab
+            case ENOMEM:
14f8ab
+                errdesc = "ENOMEM";
14f8ab
+                break;
14f8ab
+            case ENOTCONN:
14f8ab
+                errdesc = "ENOTCONN";
14f8ab
+                break;
14f8ab
+            case ECONNREFUSED:
14f8ab
+                errdesc = "ECONNREFUSED";
14f8ab
+                break;
14f8ab
+            case EOVERFLOW:
14f8ab
+                errdesc = "EOVERFLOW";
14f8ab
+                break;
14f8ab
+            case EBUSY:
14f8ab
+                errdesc = "EBUSY";
14f8ab
+                break;
14f8ab
+            case ENOTEMPTY:
14f8ab
+                errdesc = "ENOTEMPTY";
14f8ab
+                break;
14f8ab
+            default:
14f8ab
+                errdesc = strerror(errno);
14f8ab
+        }
14f8ab
+
14f8ab
+        gf_log_callingfn("glusterfs-fuse", loglevel,
14f8ab
+                         "writing to fuse device failed: %s", errdesc);
14f8ab
         return errno;
14f8ab
     }
14f8ab
 
14f8ab
@@ -282,7 +333,7 @@ send_fuse_iov(xlator_t *this, fuse_in_header_t *finh, struct iovec *iov_out,
14f8ab
     gf_log("glusterfs-fuse", GF_LOG_TRACE, "writev() result %d/%d %s", res,
14f8ab
            fouh->len, res == -1 ? strerror(errno) : "");
14f8ab
 
14f8ab
-    return check_and_dump_fuse_W(priv, iov_out, count, res);
14f8ab
+    return check_and_dump_fuse_W(priv, iov_out, count, res, NULL);
14f8ab
 }
14f8ab
 
14f8ab
 static int
14f8ab
@@ -353,6 +404,15 @@ fuse_invalidate_entry(xlator_t *this, uint64_t fuse_ino)
14f8ab
         fouh->unique = 0;
14f8ab
         fouh->error = FUSE_NOTIFY_INVAL_ENTRY;
14f8ab
 
14f8ab
+        if (ENOENT < ERRNOMASK_MAX)
14f8ab
+            MASK_ERRNO(node->errnomask, ENOENT);
14f8ab
+        if (ENOTDIR < ERRNOMASK_MAX)
14f8ab
+            MASK_ERRNO(node->errnomask, ENOTDIR);
14f8ab
+        if (EBUSY < ERRNOMASK_MAX)
14f8ab
+            MASK_ERRNO(node->errnomask, EBUSY);
14f8ab
+        if (ENOTEMPTY < ERRNOMASK_MAX)
14f8ab
+            MASK_ERRNO(node->errnomask, ENOTEMPTY);
14f8ab
+
14f8ab
         if (dentry->name) {
14f8ab
             nlen = strlen(dentry->name);
14f8ab
             fouh->len = sizeof(*fouh) + sizeof(*fnieo) + nlen + 1;
14f8ab
@@ -437,6 +497,9 @@ fuse_invalidate_inode(xlator_t *this, uint64_t fuse_ino)
14f8ab
     fniio->off = 0;
14f8ab
     fniio->len = -1;
14f8ab
 
14f8ab
+    if (ENOENT < ERRNOMASK_MAX)
14f8ab
+        MASK_ERRNO(node->errnomask, ENOENT);
14f8ab
+
14f8ab
     fuse_log_eh(this, "Invalidated inode %" PRIu64 " (gfid: %s)", fuse_ino,
14f8ab
                 uuid_utoa(inode->gfid));
14f8ab
     gf_log("glusterfs-fuse", GF_LOG_TRACE,
14f8ab
@@ -482,6 +545,7 @@ fuse_timed_message_new(void)
14f8ab
     /* should be NULL if not set */
14f8ab
     dmsg->fuse_message_body = NULL;
14f8ab
     INIT_LIST_HEAD(&dmsg->next);
14f8ab
+    memset(dmsg->errnomask, 0, sizeof(dmsg->errnomask));
14f8ab
 
14f8ab
     return dmsg;
14f8ab
 }
14f8ab
@@ -680,6 +744,8 @@ fuse_interrupt(xlator_t *this, fuse_in_header_t *finh, void *msg,
14f8ab
         dmsg->fuse_out_header.unique = finh->unique;
14f8ab
         dmsg->fuse_out_header.len = sizeof(dmsg->fuse_out_header);
14f8ab
         dmsg->fuse_out_header.error = -EAGAIN;
14f8ab
+        if (ENOENT < ERRNOMASK_MAX)
14f8ab
+            MASK_ERRNO(dmsg->errnomask, ENOENT);
14f8ab
         timespec_now(&dmsg->scheduled_ts);
14f8ab
         timespec_adjust_delta(&dmsg->scheduled_ts,
14f8ab
                               (struct timespec){0, 10000000});
14f8ab
@@ -4848,7 +4914,7 @@ notify_kernel_loop(void *data)
14f8ab
         iov_out.iov_base = node->inval_buf;
14f8ab
         iov_out.iov_len = len;
14f8ab
         rv = sys_writev(priv->fd, &iov_out, 1);
14f8ab
-        check_and_dump_fuse_W(priv, &iov_out, 1, rv);
14f8ab
+        check_and_dump_fuse_W(priv, &iov_out, 1, rv, node->errnomask);
14f8ab
 
14f8ab
         GF_FREE(node);
14f8ab
 
14f8ab
@@ -4940,7 +5006,7 @@ timed_response_loop(void *data)
14f8ab
         iovs[1] = (struct iovec){dmsg->fuse_message_body,
14f8ab
                                  len - sizeof(struct fuse_out_header)};
14f8ab
         rv = sys_writev(priv->fd, iovs, 2);
14f8ab
-        check_and_dump_fuse_W(priv, iovs, 2, rv);
14f8ab
+        check_and_dump_fuse_W(priv, iovs, 2, rv, dmsg->errnomask);
14f8ab
 
14f8ab
         fuse_timed_message_free(dmsg);
14f8ab
 
14f8ab
diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h
14f8ab
index cf4479c..d2d462c 100644
14f8ab
--- a/xlators/mount/fuse/src/fuse-bridge.h
14f8ab
+++ b/xlators/mount/fuse/src/fuse-bridge.h
14f8ab
@@ -195,14 +195,20 @@ struct fuse_private {
14f8ab
 };
14f8ab
 typedef struct fuse_private fuse_private_t;
14f8ab
 
14f8ab
+typedef uint64_t errnomask_t[2];
14f8ab
+#define MASK_ERRNO(mask, n) ((mask)[(n) >> 6] |= ((uint64_t)1 << ((n)&63)))
14f8ab
+#define GET_ERRNO_MASK(mask, n) ((mask)[(n) >> 6] & ((uint64_t)1 << ((n)&63)))
14f8ab
+#define ERRNOMASK_MAX (64 * (sizeof(errnomask_t) / sizeof(uint64_t)))
14f8ab
+
14f8ab
 #define INVAL_BUF_SIZE                                                         \
14f8ab
     (sizeof(struct fuse_out_header) +                                          \
14f8ab
      max(sizeof(struct fuse_notify_inval_inode_out),                           \
14f8ab
          sizeof(struct fuse_notify_inval_entry_out) + NAME_MAX + 1))
14f8ab
 
14f8ab
 struct fuse_invalidate_node {
14f8ab
-    char inval_buf[INVAL_BUF_SIZE];
14f8ab
+    errnomask_t errnomask;
14f8ab
     struct list_head next;
14f8ab
+    char inval_buf[INVAL_BUF_SIZE];
14f8ab
 };
14f8ab
 typedef struct fuse_invalidate_node fuse_invalidate_node_t;
14f8ab
 
14f8ab
@@ -210,6 +216,7 @@ struct fuse_timed_message {
14f8ab
     struct fuse_out_header fuse_out_header;
14f8ab
     void *fuse_message_body;
14f8ab
     struct timespec scheduled_ts;
14f8ab
+    errnomask_t errnomask;
14f8ab
     struct list_head next;
14f8ab
 };
14f8ab
 typedef struct fuse_timed_message fuse_timed_message_t;
14f8ab
-- 
14f8ab
1.8.3.1
14f8ab