aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/dir.c4
-rw-r--r--fs/fuse/fuse_i.h9
-rw-r--r--fs/fuse/inode.c19
-rw-r--r--include/uapi/linux/fuse.h7
4 files changed, 37 insertions, 2 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index ccd4971cc6c1..264f07c7754e 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -341,8 +341,10 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
341 struct dentry *newent; 341 struct dentry *newent;
342 bool outarg_valid = true; 342 bool outarg_valid = true;
343 343
344 fuse_lock_inode(dir);
344 err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, 345 err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
345 &outarg, &inode); 346 &outarg, &inode);
347 fuse_unlock_inode(dir);
346 if (err == -ENOENT) { 348 if (err == -ENOENT) {
347 outarg_valid = false; 349 outarg_valid = false;
348 err = 0; 350 err = 0;
@@ -1341,7 +1343,9 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
1341 fuse_read_fill(req, file, ctx->pos, PAGE_SIZE, 1343 fuse_read_fill(req, file, ctx->pos, PAGE_SIZE,
1342 FUSE_READDIR); 1344 FUSE_READDIR);
1343 } 1345 }
1346 fuse_lock_inode(inode);
1344 fuse_request_send(fc, req); 1347 fuse_request_send(fc, req);
1348 fuse_unlock_inode(inode);
1345 nbytes = req->out.args[0].size; 1349 nbytes = req->out.args[0].size;
1346 err = req->out.h.error; 1350 err = req->out.h.error;
1347 fuse_put_request(fc, req); 1351 fuse_put_request(fc, req);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index eddbe02c4028..929c383432b0 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -110,6 +110,9 @@ struct fuse_inode {
110 110
111 /** Miscellaneous bits describing inode state */ 111 /** Miscellaneous bits describing inode state */
112 unsigned long state; 112 unsigned long state;
113
114 /** Lock for serializing lookup and readdir for back compatibility*/
115 struct mutex mutex;
113}; 116};
114 117
115/** FUSE inode state bits */ 118/** FUSE inode state bits */
@@ -540,6 +543,9 @@ struct fuse_conn {
540 /** write-back cache policy (default is write-through) */ 543 /** write-back cache policy (default is write-through) */
541 unsigned writeback_cache:1; 544 unsigned writeback_cache:1;
542 545
546 /** allow parallel lookups and readdir (default is serialized) */
547 unsigned parallel_dirops:1;
548
543 /* 549 /*
544 * The following bitfields are only for optimization purposes 550 * The following bitfields are only for optimization purposes
545 * and hence races in setting them will not cause malfunction 551 * and hence races in setting them will not cause malfunction
@@ -956,4 +962,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
956 962
957void fuse_set_initialized(struct fuse_conn *fc); 963void fuse_set_initialized(struct fuse_conn *fc);
958 964
965void fuse_unlock_inode(struct inode *inode);
966void fuse_lock_inode(struct inode *inode);
967
959#endif /* _FS_FUSE_I_H */ 968#endif /* _FS_FUSE_I_H */
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 1ce67668a8e1..9961d8432ce3 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -97,6 +97,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
97 INIT_LIST_HEAD(&fi->queued_writes); 97 INIT_LIST_HEAD(&fi->queued_writes);
98 INIT_LIST_HEAD(&fi->writepages); 98 INIT_LIST_HEAD(&fi->writepages);
99 init_waitqueue_head(&fi->page_waitq); 99 init_waitqueue_head(&fi->page_waitq);
100 mutex_init(&fi->mutex);
100 fi->forget = fuse_alloc_forget(); 101 fi->forget = fuse_alloc_forget();
101 if (!fi->forget) { 102 if (!fi->forget) {
102 kmem_cache_free(fuse_inode_cachep, inode); 103 kmem_cache_free(fuse_inode_cachep, inode);
@@ -117,6 +118,7 @@ static void fuse_destroy_inode(struct inode *inode)
117 struct fuse_inode *fi = get_fuse_inode(inode); 118 struct fuse_inode *fi = get_fuse_inode(inode);
118 BUG_ON(!list_empty(&fi->write_files)); 119 BUG_ON(!list_empty(&fi->write_files));
119 BUG_ON(!list_empty(&fi->queued_writes)); 120 BUG_ON(!list_empty(&fi->queued_writes));
121 mutex_destroy(&fi->mutex);
120 kfree(fi->forget); 122 kfree(fi->forget);
121 call_rcu(&inode->i_rcu, fuse_i_callback); 123 call_rcu(&inode->i_rcu, fuse_i_callback);
122} 124}
@@ -351,6 +353,18 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
351 return 0; 353 return 0;
352} 354}
353 355
356void fuse_lock_inode(struct inode *inode)
357{
358 if (!get_fuse_conn(inode)->parallel_dirops)
359 mutex_lock(&get_fuse_inode(inode)->mutex);
360}
361
362void fuse_unlock_inode(struct inode *inode)
363{
364 if (!get_fuse_conn(inode)->parallel_dirops)
365 mutex_unlock(&get_fuse_inode(inode)->mutex);
366}
367
354static void fuse_umount_begin(struct super_block *sb) 368static void fuse_umount_begin(struct super_block *sb)
355{ 369{
356 fuse_abort_conn(get_fuse_conn_super(sb)); 370 fuse_abort_conn(get_fuse_conn_super(sb));
@@ -898,6 +912,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
898 fc->async_dio = 1; 912 fc->async_dio = 1;
899 if (arg->flags & FUSE_WRITEBACK_CACHE) 913 if (arg->flags & FUSE_WRITEBACK_CACHE)
900 fc->writeback_cache = 1; 914 fc->writeback_cache = 1;
915 if (arg->flags & FUSE_PARALLEL_DIROPS)
916 fc->parallel_dirops = 1;
901 if (arg->time_gran && arg->time_gran <= 1000000000) 917 if (arg->time_gran && arg->time_gran <= 1000000000)
902 fc->sb->s_time_gran = arg->time_gran; 918 fc->sb->s_time_gran = arg->time_gran;
903 } else { 919 } else {
@@ -928,7 +944,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
928 FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ | 944 FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
929 FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA | 945 FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
930 FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO | 946 FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO |
931 FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT; 947 FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT |
948 FUSE_PARALLEL_DIROPS;
932 req->in.h.opcode = FUSE_INIT; 949 req->in.h.opcode = FUSE_INIT;
933 req->in.numargs = 1; 950 req->in.numargs = 1;
934 req->in.args[0].size = sizeof(*arg); 951 req->in.args[0].size = sizeof(*arg);
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 5974fae54e12..27e17363263a 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -105,6 +105,9 @@
105 * 105 *
106 * 7.24 106 * 7.24
107 * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support 107 * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
108 *
109 * 7.25
110 * - add FUSE_PARALLEL_DIROPS
108 */ 111 */
109 112
110#ifndef _LINUX_FUSE_H 113#ifndef _LINUX_FUSE_H
@@ -140,7 +143,7 @@
140#define FUSE_KERNEL_VERSION 7 143#define FUSE_KERNEL_VERSION 7
141 144
142/** Minor version number of this interface */ 145/** Minor version number of this interface */
143#define FUSE_KERNEL_MINOR_VERSION 24 146#define FUSE_KERNEL_MINOR_VERSION 25
144 147
145/** The node ID of the root inode */ 148/** The node ID of the root inode */
146#define FUSE_ROOT_ID 1 149#define FUSE_ROOT_ID 1
@@ -234,6 +237,7 @@ struct fuse_file_lock {
234 * FUSE_ASYNC_DIO: asynchronous direct I/O submission 237 * FUSE_ASYNC_DIO: asynchronous direct I/O submission
235 * FUSE_WRITEBACK_CACHE: use writeback cache for buffered writes 238 * FUSE_WRITEBACK_CACHE: use writeback cache for buffered writes
236 * FUSE_NO_OPEN_SUPPORT: kernel supports zero-message opens 239 * FUSE_NO_OPEN_SUPPORT: kernel supports zero-message opens
240 * FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir
237 */ 241 */
238#define FUSE_ASYNC_READ (1 << 0) 242#define FUSE_ASYNC_READ (1 << 0)
239#define FUSE_POSIX_LOCKS (1 << 1) 243#define FUSE_POSIX_LOCKS (1 << 1)
@@ -253,6 +257,7 @@ struct fuse_file_lock {
253#define FUSE_ASYNC_DIO (1 << 15) 257#define FUSE_ASYNC_DIO (1 << 15)
254#define FUSE_WRITEBACK_CACHE (1 << 16) 258#define FUSE_WRITEBACK_CACHE (1 << 16)
255#define FUSE_NO_OPEN_SUPPORT (1 << 17) 259#define FUSE_NO_OPEN_SUPPORT (1 << 17)
260#define FUSE_PARALLEL_DIROPS (1 << 18)
256 261
257/** 262/**
258 * CUSE INIT request/reply flags 263 * CUSE INIT request/reply flags