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