Use FUSE multi-threaded mode for read-only mounts
authorEric Biggers <ebiggers3@gmail.com>
Mon, 12 Nov 2012 18:42:31 +0000 (12:42 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 12 Nov 2012 18:42:31 +0000 (12:42 -0600)
src/dentry.c
src/dentry.h
src/lookup_table.c
src/mount.c
src/resource.c
src/util.h
src/wim.c

index 2fc42c6b6d55e35df425f7102f662af6d19dac10..a9db942f81168ac18ad86432ebd8122423662f10 100644 (file)
@@ -878,6 +878,11 @@ static struct inode *new_timeless_inode()
                inode->link_count = 1;
        #ifdef WITH_FUSE
                inode->next_stream_id = 1;
+               if (pthread_mutex_init(&inode->i_mutex, NULL) != 0) {
+                       ERROR_WITH_ERRNO("Error initializing mutex");
+                       FREE(inode);
+                       return NULL;
+               }
        #endif
                INIT_LIST_HEAD(&inode->dentry_list);
        }
@@ -983,6 +988,7 @@ void free_inode(struct inode *inode)
        #ifdef WITH_FUSE
                wimlib_assert(inode->num_opened_fds == 0);
                FREE(inode->fds);
+               pthread_mutex_destroy(&inode->i_mutex);
        #endif
                FREE(inode->extracted_file);
                FREE(inode);
index 733cb2eea36ed5a074df72df2f8c135531b6eeed..d30cb15985632af4746431375f6f79e0a9a69516 100644 (file)
@@ -8,6 +8,10 @@
 #include "rbtree.h"
 #include <string.h>
 
+#ifdef WITH_FUSE
+#include <pthread.h>
+#endif
+
 struct stat;
 struct lookup_table;
 struct WIMStruct;
@@ -295,6 +299,11 @@ struct inode {
 
        /* Next alternate data stream ID to be assigned */
        u32 next_stream_id;
+
+       /* This mutex protects the inode's file descriptors table during
+        * read-only mounts.  Read-write mounts are still restricted to 1
+        * thread. */
+       pthread_mutex_t i_mutex;
 #endif
 };
 
index e22bd4ed9bd6e6ab9cd893f41c2cb6ed3f66f755..36d2d13f69430518dcdafbf59b2649a75af25152 100644 (file)
@@ -219,8 +219,8 @@ static void finalize_lte(struct lookup_table_entry *lte)
 void lte_decrement_refcnt(struct lookup_table_entry *lte,
                          struct lookup_table *table)
 {
-       wimlib_assert(lte);
-       wimlib_assert(lte->refcnt);
+       wimlib_assert(lte != NULL);
+       wimlib_assert(lte->refcnt != 0);
        if (--lte->refcnt == 0) {
                lookup_table_unlink(table, lte);
        #ifdef WITH_FUSE
@@ -233,9 +233,9 @@ void lte_decrement_refcnt(struct lookup_table_entry *lte,
 #ifdef WITH_FUSE
 void lte_decrement_num_opened_fds(struct lookup_table_entry *lte)
 {
-       wimlib_assert(lte);
-       wimlib_assert(lte->num_opened_fds);
-       if (--lte->num_opened_fds == 0 && lte->refcnt == 0)
+       wimlib_assert(lte != NULL);
+       wimlib_assert(lte->num_opened_fds != 0);
+       if (atomic_dec(&lte->num_opened_fds) == 0 && lte->refcnt == 0)
                finalize_lte(lte);
 }
 #endif
index e10287a6f58aa918aaa06852ba31b9a3ab1d5e25..6bc1fdff0e2e2c110f0bdff031413d019b1aadf9 100644 (file)
@@ -146,6 +146,9 @@ static int alloc_wimlib_fd(struct inode *inode,
 {
        static const u16 fds_per_alloc = 8;
        static const u16 max_fds = 0xffff;
+       int ret;
+
+       pthread_mutex_lock(&inode->i_mutex);
 
        DEBUG("Allocating fd for stream ID %u from inode %lx (open = %u, allocated = %u)",
              stream_id, inode->ino, inode->num_opened_fds,
@@ -155,16 +158,20 @@ static int alloc_wimlib_fd(struct inode *inode,
                struct wimlib_fd **fds;
                u16 num_new_fds;
 
-               if (inode->num_allocated_fds == max_fds)
-                       return -EMFILE;
+               if (inode->num_allocated_fds == max_fds) {
+                       ret = -EMFILE;
+                       goto out;
+               }
                num_new_fds = min(fds_per_alloc,
                                  max_fds - inode->num_allocated_fds);
 
                fds = REALLOC(inode->fds,
                              (inode->num_allocated_fds + num_new_fds) *
                                sizeof(inode->fds[0]));
-               if (!fds)
-                       return -ENOMEM;
+               if (!fds) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
                memset(&fds[inode->num_allocated_fds], 0,
                       num_new_fds * sizeof(fds[0]));
                inode->fds = fds;
@@ -173,8 +180,10 @@ static int alloc_wimlib_fd(struct inode *inode,
        for (u16 i = 0; ; i++) {
                if (!inode->fds[i]) {
                        struct wimlib_fd *fd = CALLOC(1, sizeof(*fd));
-                       if (!fd)
-                               return -ENOMEM;
+                       if (!fd) {
+                               ret = -ENOMEM;
+                               break;
+                       }
                        fd->f_inode    = inode;
                        fd->f_lte      = lte;
                        fd->staging_fd = -1;
@@ -184,17 +193,24 @@ static int alloc_wimlib_fd(struct inode *inode,
                        inode->fds[i]  = fd;
                        inode->num_opened_fds++;
                        if (lte)
-                               lte->num_opened_fds++;
+                               atomic_inc(&lte->num_opened_fds);
                        DEBUG("Allocated fd (idx = %u)", fd->idx);
-                       return 0;
+                       ret = 0;
+                       break;
                }
        }
+out:
+       pthread_mutex_unlock(&inode->i_mutex);
+       return ret;
 }
 
 static void inode_put_fd(struct inode *inode, struct wimlib_fd *fd)
 {
        wimlib_assert(fd != NULL);
        wimlib_assert(inode != NULL);
+
+       pthread_mutex_lock(&inode->i_mutex);
+
        wimlib_assert(fd->f_inode == inode);
        wimlib_assert(inode->num_opened_fds != 0);
        wimlib_assert(fd->idx < inode->num_allocated_fds);
@@ -202,13 +218,17 @@ static void inode_put_fd(struct inode *inode, struct wimlib_fd *fd)
 
        inode->fds[fd->idx] = NULL;
        FREE(fd);
-       if (--inode->num_opened_fds == 0 && inode->link_count == 0)
+       if (--inode->num_opened_fds == 0 && inode->link_count == 0) {
+               pthread_mutex_unlock(&inode->i_mutex);
                free_inode(inode);
+       } else {
+               pthread_mutex_unlock(&inode->i_mutex);
+       }
 }
 
 static int lte_put_fd(struct lookup_table_entry *lte, struct wimlib_fd *fd)
 {
-       wimlib_assert(fd);
+       wimlib_assert(fd != NULL);
        wimlib_assert(fd->f_lte == lte);
 
        if (!lte) /* Empty stream with no lookup table entry */
@@ -232,7 +252,7 @@ static int lte_put_fd(struct lookup_table_entry *lte, struct wimlib_fd *fd)
 static int close_wimlib_fd(struct wimlib_fd *fd)
 {
        int ret;
-       wimlib_assert(fd);
+       wimlib_assert(fd != NULL);
        DEBUG("Closing fd (inode = %lu, opened = %u, allocated = %u)",
              fd->f_inode->ino, fd->f_inode->num_opened_fds,
              fd->f_inode->num_allocated_fds);
@@ -1893,7 +1913,10 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
 
        argv[argc++] = "imagex";
        argv[argc++] = dir_copy;
-       argv[argc++] = "-s"; /* disable multi-threaded operation */
+
+       /* disable multi-threaded operation for read-write mounts */
+       if (flags & WIMLIB_MOUNT_FLAG_READWRITE)
+               argv[argc++] = "-s";
 
        if (flags & WIMLIB_MOUNT_FLAG_DEBUG)
                argv[argc++] = "-d";
index f21fd5148355ab2c0920980a4e45306a66f9139e..43ecc0a8d252c3fbf7e66e836102574807e88f52 100644 (file)
@@ -27,6 +27,8 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
+#include "dentry.h"
+
 #ifdef WITH_NTFS_3G
 #include <ntfs-3g/attrib.h>
 #include <ntfs-3g/inode.h>
@@ -39,7 +41,6 @@
 #include "lzx.h"
 #include "xpress.h"
 #include "sha1.h"
-#include "dentry.h"
 #include <unistd.h>
 #include <errno.h>
 #ifdef HAVE_ALLOCA_H
index 3292a32eb9878890efd45d43845699d536f304c8..3dfd6030be08574686a3cbb6b1d8c790775746dc 100644 (file)
 #      define HOT
 #endif /* __GNUC__ */
 
+#ifdef WITH_FUSE
+/* 
+ * Compare-and-swap.  Equivalent to the folliwng, but executed
+ * atomically:
+ *
+ * Q tmp = *ptr;
+ * if (tmp == oval)
+ *     *ptr = nval;
+ * return tmp;
+ */
+#define atomic_inc(ptr) \
+       __sync_fetch_and_add(ptr, 1)
+
+#define atomic_dec(ptr) \
+       __sync_sub_and_fetch(ptr, 1)
+
+#define cas(ptr, oval, nval) \
+       __sync_val_compare_and_swap(ptr, oval, nval);
+
+#define cas_bool(ptr, oval, nval) \
+       __sync_bool_compare_and_swap(ptr, oval, nval);
+#endif
+
 #ifndef _NTFS_TYPES_H
 typedef uint8_t  u8;
 typedef uint16_t u16;
index 2883b6a7b93a00dbcb4c0dacca58ecc72c12ec03..d065a590424c6c07d6e9d8ae7e87515f4d640b9e 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -28,6 +28,8 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
+#include "dentry.h"
+
 #ifdef WITH_NTFS_3G
 #include <ntfs-3g/volume.h>
 #endif