bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH tarfs 5/6] Attempt to implement mmap coherence


From: Sergey Bugaev
Subject: [RFC PATCH tarfs 5/6] Attempt to implement mmap coherence
Date: Thu, 29 Apr 2021 21:57:15 +0300

When reading from or writing to a node that has an attached pager,
use pager_memcpy () instead of accessing the cache directly. This
enables tarfs_read_node () and tarfs_write_node () too see and affect
the changes made to the file through the memory mapping.
---
 tarfs.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 76 insertions(+), 13 deletions(-)

diff --git a/tarfs.c b/tarfs.c
index 3b9bcf590..5195d5771 100644
--- a/tarfs.c
+++ b/tarfs.c
@@ -759,11 +759,43 @@ tarfs_lookup_node (struct node** node, struct node* dir, 
const char* name)
 error_t
 tarfs_read_node (struct node *node, off_t offset, size_t *len, void* data)
 {
+  struct pager *pager;
+  memory_object_t memobj;
+  error_t err;
+
   if (S_ISDIR (node->nn_stat.st_mode))
   {
     *len = 0;
     return EISDIR;
   }
+
+  if (node->nn->hardlink)
+    node = node->nn->hardlink;
+
+  if (node->nn_stat.st_size <= offset)
+    {
+      *len = 0;
+      return 0;
+    }
+  if (node->nn_stat.st_size - offset < *len)
+    *len = node->nn_stat.st_size - offset;
+
+  /* If we have a pager, always go through it.
+     The pager will call into the cache if needed. */
+  pager = NODE_INFO(node)->pager;
+  if (pager)
+    {
+      ports_port_ref (pager);
+      pthread_mutex_unlock (&node->lock);
+      memobj = pager_get_port (pager);
+      mach_port_insert_right (mach_task_self (), memobj, memobj,
+                              MACH_MSG_TYPE_MAKE_SEND);
+      err = pager_memcpy (pager, memobj, offset, data, len, VM_PROT_READ);
+      mach_port_deallocate (mach_task_self (), memobj);
+      pthread_mutex_lock (&node->lock);
+      ports_port_deref (pager);
+      return err;
+    }
   else
     return cache_read (node, offset, *len, data, len);
 }
@@ -774,27 +806,54 @@ error_t
 tarfs_write_node (struct node *node, off_t offset, size_t *len, void *data)
 {
   IF_RWFS;
+  struct node *original_node;
+  struct pager *pager;
+  memory_object_t memobj;
+  error_t err;
 
   if (S_ISDIR (node->nn_stat.st_mode))
   {
     *len = 0;
     return EISDIR;
   }
-  else
+
+  original_node = node;
+  if (node->nn->hardlink)
+    node = node->nn->hardlink;
+
+  /* First, grow the node if we need to. This would happen automatically
+     for the cache path below, but not for the pager path. */
+  if (offset + *len > node->nn_stat.st_size)
   {
-    error_t err;
-    /* Checks whether we need to actually write to another node.
-       (hard links are not handled by cache_write ()).  */
-    struct node *what = node->nn->hardlink ? node->nn->hardlink : node;
-    
+    err = cache_set_size (node, offset + *len);
+    if (err)
+      return err;
+  }
+
+  /* If we have a pager, always go through it.
+     The pager will call into the cache if needed. */
+  pager = NODE_INFO(node)->pager;
+  if (pager)
+    {
+      ports_port_ref (pager);
+      pthread_mutex_unlock (&node->lock);
+      memobj = pager_get_port (pager);
+      mach_port_insert_right (mach_task_self (), memobj, memobj,
+                              MACH_MSG_TYPE_MAKE_SEND);
+      err = pager_memcpy (pager, memobj, offset, data, len,
+                          VM_PROT_READ|VM_PROT_WRITE);
+      mach_port_deallocate (mach_task_self (), memobj);
+      pthread_mutex_lock (&node->lock);
+      ports_port_deref (pager);
+    }
+  else
     err = cache_write (node, offset, data, *len, len);
 
-    /* Synchronize stat with hard link's target.  */
-    if ((! err) && (what != node))
-      node->nn_stat.st_size = what->nn_stat.st_size;
+  /* Synchronize stat with hard link's target.  */
+  if ((! err) && (original_node != node))
+    original_node->nn_stat.st_size = node->nn_stat.st_size;
 
-    return err;
-  }
+  return err;
 }
 
 /* Update NODE stat structure and mark it as dirty.  */
@@ -1035,7 +1094,6 @@ tarfs_io_map (struct node *node, memory_object_t *rdobj, 
memory_object_t *wrobj)
   return 0;
 }
 
-
 
 /* Rounds SIZE to the upper RECORDSIZE.  */
 static inline size_t
@@ -1171,7 +1229,12 @@ tarfs_sync_fs (int wait)
       char *path;
       size_t size;
 
-      /* Lock the node first */
+      /* If the node has a pager, ask it to flush
+         its state back into the cache. Do this before
+         locking the node. */
+      if (NODE_INFO(node)->pager)
+        pager_sync (NODE_INFO(node)->pager, 1);
+
       pthread_mutex_lock (&node->lock);
       have_to_sync = (tar->offset != file_offs + RECORDSIZE);
       path = fs_get_path_from_root (netfs_root_node, node);
-- 
2.31.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]