summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-04-20 23:08:32 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2016-05-02 19:49:29 -0400
commit6192269444ebfbfb42e23c7a6a93c76ffe4b5e51 (patch)
treeec40fbbad46725d88f2c16b11ff5976d87f497bb
parent63b6df14134ddd048984c8afadb46e721815bfc6 (diff)
introduce a parallel variant of ->iterate()
New method: ->iterate_shared(). Same arguments as in ->iterate(), called with the directory locked only shared. Once all filesystems switch, the old one will be gone. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--Documentation/filesystems/porting18
-rw-r--r--fs/coda/dir.c18
-rw-r--r--fs/exportfs/expfs.c2
-rw-r--r--fs/readdir.c20
-rw-r--r--include/linux/fs.h1
5 files changed, 48 insertions, 11 deletions
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 1567a53857bd..12c57abdaac9 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -557,3 +557,21 @@ in your dentry operations instead.
557 will not happen in parallel ("same" in the sense of your ->d_compare()). 557 will not happen in parallel ("same" in the sense of your ->d_compare()).
558 Lookups on different names in the same directory can and do happen in 558 Lookups on different names in the same directory can and do happen in
559 parallel now. 559 parallel now.
560--
561[recommended]
562 ->iterate_shared() is added; it's a parallel variant of ->iterate().
563 Exclusion on struct file level is still provided (as well as that
564 between it and lseek on the same struct file), but if your directory
565 has been opened several times, you can get these called in parallel.
566 Exclusion between that method and all directory-modifying ones is
567 still provided, of course.
568
569 Often enough ->iterate() can serve as ->iterate_shared() without any
570 changes - it is a read-only operation, after all. If you have any
571 per-inode or per-dentry in-core data structures modified by ->iterate(),
572 you might need something to serialize the access to them. If you
573 do dcache pre-seeding, you'll need to switch to d_alloc_parallel() for
574 that; look for in-tree examples.
575
576 Old method is only used if the new one is absent; eventually it will
577 be removed. Switch while you still can; the old one won't stay.
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 42e731b8c80a..6fb8672c0892 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -424,16 +424,22 @@ static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
424 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 424 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
425 host_file = cfi->cfi_container; 425 host_file = cfi->cfi_container;
426 426
427 if (host_file->f_op->iterate) { 427 if (host_file->f_op->iterate || host_file->f_op->iterate_shared) {
428 struct inode *host_inode = file_inode(host_file); 428 struct inode *host_inode = file_inode(host_file);
429
430 inode_lock(host_inode);
431 ret = -ENOENT; 429 ret = -ENOENT;
432 if (!IS_DEADDIR(host_inode)) { 430 if (!IS_DEADDIR(host_inode)) {
433 ret = host_file->f_op->iterate(host_file, ctx); 431 if (host_file->f_op->iterate_shared) {
434 file_accessed(host_file); 432 inode_lock_shared(host_inode);
433 ret = host_file->f_op->iterate_shared(host_file, ctx);
434 file_accessed(host_file);
435 inode_unlock_shared(host_inode);
436 } else {
437 inode_lock(host_inode);
438 ret = host_file->f_op->iterate(host_file, ctx);
439 file_accessed(host_file);
440 inode_unlock(host_inode);
441 }
435 } 442 }
436 inode_unlock(host_inode);
437 return ret; 443 return ret;
438 } 444 }
439 /* Venus: we must read Venus dirents from a file */ 445 /* Venus: we must read Venus dirents from a file */
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 402c5caab5ca..207ba8d627ca 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -312,7 +312,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
312 goto out; 312 goto out;
313 313
314 error = -EINVAL; 314 error = -EINVAL;
315 if (!file->f_op->iterate) 315 if (!file->f_op->iterate && !file->f_op->iterate_shared)
316 goto out_close; 316 goto out_close;
317 317
318 buffer.sequence = 0; 318 buffer.sequence = 0;
diff --git a/fs/readdir.c b/fs/readdir.c
index d7308b8f6cf7..a86c6c04b9bc 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -24,15 +24,21 @@
24int iterate_dir(struct file *file, struct dir_context *ctx) 24int iterate_dir(struct file *file, struct dir_context *ctx)
25{ 25{
26 struct inode *inode = file_inode(file); 26 struct inode *inode = file_inode(file);
27 bool shared = false;
27 int res = -ENOTDIR; 28 int res = -ENOTDIR;
28 if (!file->f_op->iterate) 29 if (file->f_op->iterate_shared)
30 shared = true;
31 else if (!file->f_op->iterate)
29 goto out; 32 goto out;
30 33
31 res = security_file_permission(file, MAY_READ); 34 res = security_file_permission(file, MAY_READ);
32 if (res) 35 if (res)
33 goto out; 36 goto out;
34 37
35 inode_lock(inode); 38 if (shared)
39 inode_lock_shared(inode);
40 else
41 inode_lock(inode);
36 // res = mutex_lock_killable(&inode->i_mutex); 42 // res = mutex_lock_killable(&inode->i_mutex);
37 // if (res) 43 // if (res)
38 // goto out; 44 // goto out;
@@ -40,12 +46,18 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
40 res = -ENOENT; 46 res = -ENOENT;
41 if (!IS_DEADDIR(inode)) { 47 if (!IS_DEADDIR(inode)) {
42 ctx->pos = file->f_pos; 48 ctx->pos = file->f_pos;
43 res = file->f_op->iterate(file, ctx); 49 if (shared)
50 res = file->f_op->iterate_shared(file, ctx);
51 else
52 res = file->f_op->iterate(file, ctx);
44 file->f_pos = ctx->pos; 53 file->f_pos = ctx->pos;
45 fsnotify_access(file); 54 fsnotify_access(file);
46 file_accessed(file); 55 file_accessed(file);
47 } 56 }
48 inode_unlock(inode); 57 if (shared)
58 inode_unlock_shared(inode);
59 else
60 inode_unlock(inode);
49out: 61out:
50 return res; 62 return res;
51} 63}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3018f31f7aa0..3dc0258a2b64 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1674,6 +1674,7 @@ struct file_operations {
1674 ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); 1674 ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
1675 ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); 1675 ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
1676 int (*iterate) (struct file *, struct dir_context *); 1676 int (*iterate) (struct file *, struct dir_context *);
1677 int (*iterate_shared) (struct file *, struct dir_context *);
1677 unsigned int (*poll) (struct file *, struct poll_table_struct *); 1678 unsigned int (*poll) (struct file *, struct poll_table_struct *);
1678 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); 1679 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
1679 long (*compat_ioctl) (struct file *, unsigned int, unsigned long); 1680 long (*compat_ioctl) (struct file *, unsigned int, unsigned long);