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