Commit 61922694 authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 63b6df14
......@@ -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.
......@@ -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)) {
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);
}
}
return ret;
}
/* Venus: we must read Venus dirents from a file */
......
......@@ -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;
......
......@@ -24,14 +24,20 @@
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;
if (shared)
inode_lock_shared(inode);
else
inode_lock(inode);
// res = mutex_lock_killable(&inode->i_mutex);
// if (res)
......@@ -40,11 +46,17 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
res = -ENOENT;
if (!IS_DEADDIR(inode)) {
ctx->pos = file->f_pos;
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);
}
if (shared)
inode_unlock_shared(inode);
else
inode_unlock(inode);
out:
return res;
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment