[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
- [RFC PATCH tarfs 0/6] mmap support for tarfs, Sergey Bugaev, 2021/04/29
- [RFC PATCH tarfs 2/6] Link to libpager and initialize it on startup, Sergey Bugaev, 2021/04/29
- [RFC PATCH tarfs 4/6] Implement basic support for writable mappings, Sergey Bugaev, 2021/04/29
- [RFC PATCH tarfs 5/6] Attempt to implement mmap coherence,
Sergey Bugaev <=
- [RFC PATCH tarfs 3/6] Implement basic read-only mmap support, Sergey Bugaev, 2021/04/29
- [RFC PATCH tarfs 6/6] Update TODO and BUGS, Sergey Bugaev, 2021/04/29
- [RFC PATCH tarfs 1/6] Plumb io_map () through the backend layer, Sergey Bugaev, 2021/04/29