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