]> wimlib.net Git - wimlib/blobdiff - src/mount.c
Use FUSE multi-threaded mode for read-only mounts
[wimlib] / src / mount.c
index e07a11c3fbcfdfbd761d846c255302da75a811dd..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,31 +193,42 @@ static int alloc_wimlib_fd(struct inode *inode,
                        inode->fds[i]  = fd;
                        inode->num_opened_fds++;
                        if (lte)
-                               lte->num_opened_fds++;
-                       DEBUG("Allocated fd");
-                       return 0;
+                               atomic_inc(&lte->num_opened_fds);
+                       DEBUG("Allocated fd (idx = %u)", fd->idx);
+                       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);
-       wimlib_assert(inode);
+       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);
-       wimlib_assert(fd->idx < inode->num_opened_fds);
+       wimlib_assert(inode->num_opened_fds != 0);
+       wimlib_assert(fd->idx < inode->num_allocated_fds);
        wimlib_assert(inode->fds[fd->idx] == 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);
@@ -746,6 +766,28 @@ static int wimfs_access(const char *path, int mask)
        return 0;
 }
 
+static int wimfs_chmod(const char *path, mode_t mask)
+{
+       struct dentry *dentry;
+       struct wimfs_context *ctx = wimfs_get_context();
+       struct inode *inode;
+       struct stat stbuf;
+       int ret;
+
+       ret = lookup_resource(ctx->wim, path,
+                             get_lookup_flags(ctx) | LOOKUP_FLAG_DIRECTORY_OK,
+                             &dentry, NULL, NULL);
+       if (ret != 0)
+               return ret;
+       inode = dentry->d_inode;
+       inode_to_stbuf(inode, NULL, &stbuf);
+       if (mask == stbuf.st_mode)
+               return 0;
+       else
+               return -EPERM;
+
+}
+
 static void inode_update_lte_ptr(struct inode *inode,
                                 struct lookup_table_entry *old_lte,
                                 struct lookup_table_entry *new_lte)
@@ -1064,7 +1106,7 @@ static int wimfs_link(const char *to, const char *from)
                        lte->refcnt++;
        }
 
-       link_dentry(from_dentry, from_dentry_parent);
+       dentry_add_child(from_dentry_parent, from_dentry);
        return 0;
 }
 
@@ -1130,7 +1172,7 @@ static int wimfs_mkdir(const char *path, mode_t mode)
        newdir->d_inode->attributes |= FILE_ATTRIBUTE_DIRECTORY;
        newdir->d_inode->resolved = true;
        newdir->d_inode->ino = ctx->next_ino++;
-       link_dentry(newdir, parent);
+       dentry_add_child(parent, newdir);
        return 0;
 }
 
@@ -1182,7 +1224,7 @@ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
                        return -ENOMEM;
                dentry->d_inode->resolved = true;
                dentry->d_inode->ino = ctx->next_ino++;
-               link_dentry(dentry, parent);
+               dentry_add_child(parent, dentry);
        }
        return 0;
 }
@@ -1308,6 +1350,18 @@ static int wimfs_read(const char *path, char *buf, size_t size,
        }
 }
 
+struct fill_params {
+       void *buf;
+       fuse_fill_dir_t filler;
+};
+
+static int dentry_fuse_fill(struct dentry *dentry, void *arg)
+{
+       struct fill_params *fill_params = arg;
+       return fill_params->filler(fill_params->buf, dentry->file_name_utf8,
+                                  NULL, 0);
+}
+
 /* Fills in the entries of the directory specified by @path using the
  * FUSE-provided function @filler.  */
 static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
@@ -1315,27 +1369,22 @@ static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 {
        struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
        struct inode *inode;
-       struct dentry *child;
 
        if (!fd)
                return -EBADF;
 
        inode = fd->f_inode;
 
+       struct fill_params fill_params = {
+               .buf = buf,
+               .filler = filler,
+       };
+
        filler(buf, ".", NULL, 0);
        filler(buf, "..", NULL, 0);
 
-       child = inode->children;
-
-       if (!child)
-               return 0;
-
-       do {
-               if (filler(buf, child->file_name_utf8, NULL, 0))
-                       return 0;
-               child = child->next;
-       } while (child != inode->children);
-       return 0;
+       return for_dentry_in_rbtree(inode->children.rb_node,
+                                   dentry_fuse_fill, &fill_params);
 }
 
 
@@ -1439,7 +1488,7 @@ static int wimfs_rename(const char *from, const char *to)
                         * directory */
                        if (!dentry_is_directory(dst))
                                return -ENOTDIR;
-                       if (dst->d_inode->children != NULL)
+                       if (inode_has_children(dst->d_inode))
                                return -ENOTEMPTY;
                }
                parent_of_dst = dst->parent;
@@ -1462,7 +1511,7 @@ static int wimfs_rename(const char *from, const char *to)
        src->file_name_utf8_len = file_name_utf8_len;
 
        unlink_dentry(src);
-       link_dentry(src, parent_of_dst);
+       dentry_add_child(parent_of_dst, src);
        return 0;
 }
 
@@ -1582,7 +1631,7 @@ static int wimfs_symlink(const char *to, const char *from)
        if (inode_set_symlink(inode, to, ctx->wim->lookup_table, NULL) != 0)
                goto out_free_dentry;
 
-       link_dentry(dentry, dentry_parent);
+       dentry_add_child(dentry_parent, dentry);
        return 0;
 out_free_dentry:
        free_dentry(dentry);
@@ -1692,6 +1741,8 @@ static int wimfs_utime(const char *path, struct utimbuf *times)
 {
        struct dentry *dentry;
        struct inode *inode;
+       WIMStruct *w = wimfs_get_WIMStruct();
+
        dentry = get_dentry(w, path);
        if (!dentry)
                return -ENOENT;
@@ -1738,6 +1789,7 @@ static int wimfs_write(const char *path, const char *buf, size_t size,
 
 static struct fuse_operations wimfs_operations = {
        .access      = wimfs_access,
+       .chmod       = wimfs_chmod,
        .destroy     = wimfs_destroy,
 #if 0
        .fallocate   = wimfs_fallocate,
@@ -1861,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";