[neon/backports-focal/xdg-desktop-portal/Neon/unstable] document-portal: document-portal: Fuse, try to keep down nr of open fds

Alexander Larsson null at kde.org
Wed Jan 13 06:32:42 GMT 2021


Git commit 5b243fc78ad703b93c9b56911217adcd1b52bfef by Alexander Larsson.
Committed on 02/04/2020 at 15:01.
Pushed by ash into branch 'Neon/unstable'.

document-portal: Fuse, try to keep down nr of open fds

To avoid wasting fds we queue a dentry invalidate after every
successful lookup operation inside a document dir. This will
cause all outstanding dentries to be freed, thereby making the
kernel emit FORGET for inodes not used other than in the dcache.

This makes the stress-test go from max ~4000 outstanding fds to ~1000
for me, which should be enough to pass on systems with a hard limit
of 4096 fds.

M  +38   -3    document-portal/document-portal-fuse.c

https://invent.kde.org/neon/backports-focal/xdg-desktop-portal/commit/5b243fc78ad703b93c9b56911217adcd1b52bfef

diff --git a/document-portal/document-portal-fuse.c b/document-portal/document-portal-fuse.c
index 8b88d31..55bf409 100644
--- a/document-portal/document-portal-fuse.c
+++ b/document-portal/document-portal-fuse.c
@@ -133,6 +133,9 @@ struct _XdpDomain {
   guint64 doc_dir_inode;
   guint32 doc_flags;
 
+  fuse_ino_t doc_parent_ino; /* ino nr of the parent of the document dir, used to invalidate entries */
+  int doc_queued_invalidate; /* Access atomically, 1 if queued invalidate */
+
   /* Below is mutable, protected by mutex */
   GMutex  tempfile_mutex;
   GHashTable *tempfiles; /* Name -> physical */
@@ -1544,11 +1547,12 @@ ensure_by_app_inode (XdpDomain *by_app_domain,
 }
 
 static XdpInode *
-ensure_doc_inode (XdpDomain *parent_domain,
+ensure_doc_inode (XdpInode *parent,
                   const char *doc_id)
 {
   g_autoptr(XdpInode) inode = NULL;
   g_autoptr(PermissionDbEntry) doc_entry = NULL;
+  XdpDomain *parent_domain = parent->domain;
 
   doc_entry = xdp_lookup_doc (doc_id);
 
@@ -1565,6 +1569,7 @@ ensure_doc_inode (XdpDomain *parent_domain,
     {
       g_autoptr(XdpDomain) doc_domain = xdp_domain_new_document (parent_domain, doc_id, doc_entry);
       inode = xdp_inode_new (doc_domain, NULL);
+      doc_domain->doc_parent_ino = xdp_inode_to_ino (parent);
       g_hash_table_insert (parent_domain->inodes, doc_domain->doc_id, inode);
     }
   G_UNLOCK(domain_inodes);
@@ -1572,6 +1577,34 @@ ensure_doc_inode (XdpDomain *parent_domain,
   return g_steal_pointer (&inode);
 }
 
+static gboolean
+invalidate_doc_domain (gpointer user_data)
+{
+  g_autoptr(XdpDomain) doc_domain = user_data;
+
+  g_atomic_int_set (&doc_domain->doc_queued_invalidate, 0);
+
+  fuse_lowlevel_notify_inval_entry (main_ch, doc_domain->doc_parent_ino, doc_domain->doc_id, strlen (doc_domain->doc_id));
+
+  return FALSE;
+}
+
+/* Queue an inval_entry call on this domain, thereby freeing all unused inodes
+ * in the dcache which will free up a bunch of O_PATH fds in the fuse implementation
+ */
+static void
+doc_domain_queue_entry_invalidate (XdpDomain *doc_domain)
+{
+  int old = g_atomic_int_get (&doc_domain->doc_queued_invalidate);
+  if (old != 0)
+    return;
+
+  if (!g_atomic_int_compare_and_exchange (&doc_domain->doc_queued_invalidate, old, 1))
+    return; // Someone else set it to 1, return
+
+  g_timeout_add (1000, invalidate_doc_domain, xdp_domain_ref (doc_domain));
+}
+
 static void
 xdp_fuse_lookup (fuse_req_t req,
                  fuse_ino_t parent_ino,
@@ -1603,13 +1636,13 @@ xdp_fuse_lookup (fuse_req_t req,
           if (strcmp (name, BY_APP_NAME) == 0)
             inode = xdp_inode_ref (by_app_inode);
           else
-            inode = ensure_doc_inode (parent_domain, name);
+            inode = ensure_doc_inode (parent,name);
           break;
         case XDP_DOMAIN_BY_APP:
           inode = ensure_by_app_inode (parent_domain, name);
           break;
         case XDP_DOMAIN_APP:
-          inode = ensure_doc_inode (parent_domain, name);
+          inode = ensure_doc_inode (parent, name);
           break;
         default:
           g_assert_not_reached ();
@@ -1631,6 +1664,8 @@ xdp_fuse_lookup (fuse_req_t req,
       res = ensure_docdir_inode (parent->domain, fd, &e); /* Takes ownershif of fd */
       if (res != 0)
         return xdp_reply_err (op, req, -res);
+
+      doc_domain_queue_entry_invalidate (parent_domain);
     }
 
   g_debug ("LOOKUP %lx:%s => %lx", parent_ino, name, e.ino);



More information about the Neon-commits mailing list