Skip to content

Commit

Permalink
introduce a parallel variant of ->iterate()
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Al Viro committed May 2, 2016
1 parent 63b6df1 commit 6192269
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 11 deletions.
18 changes: 18 additions & 0 deletions Documentation/filesystems/porting
Original file line number Diff line number Diff line change
Expand Up @@ -557,3 +557,21 @@ in your dentry operations instead.
will not happen in parallel ("same" in the sense of your ->d_compare()).
Lookups on different names in the same directory can and do happen in
parallel now.
--
[recommended]
->iterate_shared() is added; it's a parallel variant of ->iterate().
Exclusion on struct file level is still provided (as well as that
between it and lseek on the same struct file), but if your directory
has been opened several times, you can get these called in parallel.
Exclusion between that method and all directory-modifying ones is
still provided, of course.

Often enough ->iterate() can serve as ->iterate_shared() without any
changes - it is a read-only operation, after all. If you have any
per-inode or per-dentry in-core data structures modified by ->iterate(),
you might need something to serialize the access to them. If you
do dcache pre-seeding, you'll need to switch to d_alloc_parallel() for
that; look for in-tree examples.

Old method is only used if the new one is absent; eventually it will
be removed. Switch while you still can; the old one won't stay.
18 changes: 12 additions & 6 deletions fs/coda/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,16 +424,22 @@ static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container;

if (host_file->f_op->iterate) {
if (host_file->f_op->iterate || host_file->f_op->iterate_shared) {
struct inode *host_inode = file_inode(host_file);

inode_lock(host_inode);
ret = -ENOENT;
if (!IS_DEADDIR(host_inode)) {
ret = host_file->f_op->iterate(host_file, ctx);
file_accessed(host_file);
if (host_file->f_op->iterate_shared) {
inode_lock_shared(host_inode);
ret = host_file->f_op->iterate_shared(host_file, ctx);
file_accessed(host_file);
inode_unlock_shared(host_inode);
} else {
inode_lock(host_inode);
ret = host_file->f_op->iterate(host_file, ctx);
file_accessed(host_file);
inode_unlock(host_inode);
}
}
inode_unlock(host_inode);
return ret;
}
/* Venus: we must read Venus dirents from a file */
Expand Down
2 changes: 1 addition & 1 deletion fs/exportfs/expfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
goto out;

error = -EINVAL;
if (!file->f_op->iterate)
if (!file->f_op->iterate && !file->f_op->iterate_shared)
goto out_close;

buffer.sequence = 0;
Expand Down
20 changes: 16 additions & 4 deletions fs/readdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,40 @@
int iterate_dir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(file);
bool shared = false;
int res = -ENOTDIR;
if (!file->f_op->iterate)
if (file->f_op->iterate_shared)
shared = true;
else if (!file->f_op->iterate)
goto out;

res = security_file_permission(file, MAY_READ);
if (res)
goto out;

inode_lock(inode);
if (shared)
inode_lock_shared(inode);
else
inode_lock(inode);
// res = mutex_lock_killable(&inode->i_mutex);
// if (res)
// goto out;

res = -ENOENT;
if (!IS_DEADDIR(inode)) {
ctx->pos = file->f_pos;
res = file->f_op->iterate(file, ctx);
if (shared)
res = file->f_op->iterate_shared(file, ctx);
else
res = file->f_op->iterate(file, ctx);
file->f_pos = ctx->pos;
fsnotify_access(file);
file_accessed(file);
}
inode_unlock(inode);
if (shared)
inode_unlock_shared(inode);
else
inode_unlock(inode);
out:
return res;
}
Expand Down
1 change: 1 addition & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,7 @@ struct file_operations {
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
int (*iterate_shared) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
Expand Down

0 comments on commit 6192269

Please sign in to comment.