Directory edits end with diskfs_file_update, both in ext2fs
(diskfs_direnter_hard, diskfs_dirremove_hard and
diskfs_dirrewrite_hard) and in libdiskfs (mkdir, rmdir, rename).  It
asks the kernel to write back every dirty page of the directory.  With
directory blocks journaled, those blocks are in the running
transaction, so each write is only intercepted and copied, after every
edit.  Over a large Debian upgrade, 84225 of 84505 intercepts were such
directory blocks.

With a journal, sync only a regular file's pages, which hold data that
is not journaled.  Do not sync the file's indirect blocks either: they
are journaled too.  And update the inode without WAIT: a caller that
needs the metadata durable commits its transaction (file_sync, io_sigio,
and the RPCs with diskfs_synchronous), and the one that waits without
committing, diskfs_truncate zeroing the end of the last block, needs
only that data on disk.  Without a journal nothing changes.

Over the same upgrade, intercepts dropped from 84505 to 294, of which 34
were directory blocks, with e2fsck clean.  The journal recovered cleanly
from kill -9 of the translator during rm -rf and tar -xf of a Linux
kernel tree, after a mix of directory creates, renames and unlinks, and
from qemu being killed during the upgrade.

With fewer intercepts, the intercept pool shrinks from 2048 to 1024
chunks: at most 127 were in use during the upgrade, and under 500
during tar -xf and rm -rf of a Linux kernel tree the remainder is left
as headroom.
---
 ext2fs/journal.c |  2 +-
 ext2fs/pager.c   | 42 ++++++++++++++++++++++++++++--------------
 2 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/ext2fs/journal.c b/ext2fs/journal.c
index 2993a76c1..d85e1374c 100644
--- a/ext2fs/journal.c
+++ b/ext2fs/journal.c
@@ -131,7 +131,7 @@
 #define IS_RUNNING_TID(j, tid) \
     ((j)->j_running_transaction && (j)->j_running_transaction->t_tid == (tid))
 
-#define JRNL_INTERCEPT_CAPACITY 2048
+#define JRNL_INTERCEPT_CAPACITY 1024
 
 static pthread_t kjournald_tid;
 
diff --git a/ext2fs/pager.c b/ext2fs/pager.c
index 2b3fb574d..71de4ebdc 100644
--- a/ext2fs/pager.c
+++ b/ext2fs/pager.c
@@ -910,24 +910,38 @@ diskfs_file_update (struct node *node, int wait)
 {
   struct pager *pager;
 
-  pthread_spin_lock (&node_to_page_lock);
-  pager = diskfs_node_disknode (node)->pager;
-  if (pager)
-    ports_port_ref (pager);
-  pthread_spin_unlock (&node_to_page_lock);
-
-  if (pager)
+  /* File data is not journaled, so a file's pages are written back here.
+     With a journal, a directory's blocks are: the commit makes its edits
+     durable, and checkpointing or the next writeback takes them home.
+     Syncing its pages would only send them to the journal again, to be
+     intercepted and copied, after every edit.  */
+  if (!ext2_journal || !S_ISDIR (node->dn_stat.st_mode))
     {
-      pager_sync (pager, wait);
-      ports_port_deref (pager);
+      pthread_spin_lock (&node_to_page_lock);
+      pager = diskfs_node_disknode (node)->pager;
+      if (pager)
+       ports_port_ref (pager);
+      pthread_spin_unlock (&node_to_page_lock);
+
+      if (pager)
+       {
+         pager_sync (pager, wait);
+         ports_port_deref (pager);
+       }
     }
 
-  /* If there is a journal present we will not sync metadata immediately
-     We will let the journal do it when its ready. */
-  int meta_wait = ext2_journal ? 0 : wait;
-  pokel_sync (&diskfs_node_disknode (node)->indir_pokel, meta_wait);
+  if (ext2_journal)
+    /* Indirect blocks and the inode are journaled too, so the same goes
+       for them.  A caller that needs them durable commits its
+       transaction.  The one that waits without committing,
+       diskfs_truncate zeroing the end of the last block, needs only the
+       data above on disk; waiting here would make the inode update force
+       a commit.  */
+    wait = 0;
+  else
+    pokel_sync (&diskfs_node_disknode (node)->indir_pokel, wait);
 
-  diskfs_node_update (node, meta_wait);
+  diskfs_node_update (node, wait);
 }
 
 /* Invalidate any pager data associated with NODE.  */
-- 
2.56.0


Reply via email to