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