From: Eric Biggers Date: Mon, 12 Nov 2012 18:42:31 +0000 (-0600) Subject: Use FUSE multi-threaded mode for read-only mounts X-Git-Tag: v1.1.0~25 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=9b25b1a8e4c01e57f2872fe9e825f0dc81329008 Use FUSE multi-threaded mode for read-only mounts --- diff --git a/src/dentry.c b/src/dentry.c index 2fc42c6b..a9db942f 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -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); diff --git a/src/dentry.h b/src/dentry.h index 733cb2ee..d30cb159 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -8,6 +8,10 @@ #include "rbtree.h" #include +#ifdef WITH_FUSE +#include +#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 }; diff --git a/src/lookup_table.c b/src/lookup_table.c index e22bd4ed..36d2d13f 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -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(<e->num_opened_fds) == 0 && lte->refcnt == 0) finalize_lte(lte); } #endif diff --git a/src/mount.c b/src/mount.c index e10287a6..6bc1fdff 100644 --- a/src/mount.c +++ b/src/mount.c @@ -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(<e->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"; diff --git a/src/resource.c b/src/resource.c index f21fd514..43ecc0a8 100644 --- a/src/resource.c +++ b/src/resource.c @@ -27,6 +27,8 @@ #include #include +#include "dentry.h" + #ifdef WITH_NTFS_3G #include #include @@ -39,7 +41,6 @@ #include "lzx.h" #include "xpress.h" #include "sha1.h" -#include "dentry.h" #include #include #ifdef HAVE_ALLOCA_H diff --git a/src/util.h b/src/util.h index 3292a32e..3dfd6030 100644 --- a/src/util.h +++ b/src/util.h @@ -30,6 +30,29 @@ # 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; diff --git a/src/wim.c b/src/wim.c index 2883b6a7..d065a590 100644 --- a/src/wim.c +++ b/src/wim.c @@ -28,6 +28,8 @@ #include #include +#include "dentry.h" + #ifdef WITH_NTFS_3G #include #endif