Skip to content

Commit 6192269

Browse files
author
Al Viro
committed
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>
1 parent 63b6df1 commit 6192269

File tree

5 files changed

+48
-11
lines changed

5 files changed

+48
-11
lines changed

Documentation/filesystems/porting

+18
Original file line numberDiff line numberDiff line change
@@ -557,3 +557,21 @@ in your dentry operations instead.
557557
will not happen in parallel ("same" in the sense of your ->d_compare()).
558558
Lookups on different names in the same directory can and do happen in
559559
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.

fs/coda/dir.c

+12-6
Original file line numberDiff line numberDiff line change
@@ -424,16 +424,22 @@ static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
424424
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
425425
host_file = cfi->cfi_container;
426426

427-
if (host_file->f_op->iterate) {
427+
if (host_file->f_op->iterate || host_file->f_op->iterate_shared) {
428428
struct inode *host_inode = file_inode(host_file);
429-
430-
inode_lock(host_inode);
431429
ret = -ENOENT;
432430
if (!IS_DEADDIR(host_inode)) {
433-
ret = host_file->f_op->iterate(host_file, ctx);
434-
file_accessed(host_file);
431+
if (host_file->f_op->iterate_shared) {
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+
}
435442
}
436-
inode_unlock(host_inode);
437443
return ret;
438444
}
439445
/* Venus: we must read Venus dirents from a file */

fs/exportfs/expfs.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
312312
goto out;
313313

314314
error = -EINVAL;
315-
if (!file->f_op->iterate)
315+
if (!file->f_op->iterate && !file->f_op->iterate_shared)
316316
goto out_close;
317317

318318
buffer.sequence = 0;

fs/readdir.c

+16-4
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,40 @@
2424
int iterate_dir(struct file *file, struct dir_context *ctx)
2525
{
2626
struct inode *inode = file_inode(file);
27+
bool shared = false;
2728
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)
2932
goto out;
3033

3134
res = security_file_permission(file, MAY_READ);
3235
if (res)
3336
goto out;
3437

35-
inode_lock(inode);
38+
if (shared)
39+
inode_lock_shared(inode);
40+
else
41+
inode_lock(inode);
3642
// res = mutex_lock_killable(&inode->i_mutex);
3743
// if (res)
3844
// goto out;
3945

4046
res = -ENOENT;
4147
if (!IS_DEADDIR(inode)) {
4248
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);
4453
file->f_pos = ctx->pos;
4554
fsnotify_access(file);
4655
file_accessed(file);
4756
}
48-
inode_unlock(inode);
57+
if (shared)
58+
inode_unlock_shared(inode);
59+
else
60+
inode_unlock(inode);
4961
out:
5062
return res;
5163
}

include/linux/fs.h

+1
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,7 @@ struct file_operations {
16741674
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
16751675
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
16761676
int (*iterate) (struct file *, struct dir_context *);
1677+
int (*iterate_shared) (struct file *, struct dir_context *);
16771678
unsigned int (*poll) (struct file *, struct poll_table_struct *);
16781679
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
16791680
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

0 commit comments

Comments
 (0)