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. ...@@ -557,3 +557,21 @@ in your dentry operations instead.
will not happen in parallel ("same" in the sense of your ->d_compare()). 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 Lookups on different names in the same directory can and do happen in
parallel now. 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) ...@@ -424,16 +424,22 @@ static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container; 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); struct inode *host_inode = file_inode(host_file);
inode_lock(host_inode);
ret = -ENOENT; ret = -ENOENT;
if (!IS_DEADDIR(host_inode)) { if (!IS_DEADDIR(host_inode)) {
ret = host_file->f_op->iterate(host_file, ctx); if (host_file->f_op->iterate_shared) {
file_accessed(host_file); 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; return ret;
} }
/* Venus: we must read Venus dirents from a file */ /* 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) ...@@ -312,7 +312,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
goto out; goto out;
error = -EINVAL; error = -EINVAL;
if (!file->f_op->iterate) if (!file->f_op->iterate && !file->f_op->iterate_shared)
goto out_close; goto out_close;
buffer.sequence = 0; buffer.sequence = 0;
......
...@@ -24,15 +24,21 @@ ...@@ -24,15 +24,21 @@
int iterate_dir(struct file *file, struct dir_context *ctx) int iterate_dir(struct file *file, struct dir_context *ctx)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
bool shared = false;
int res = -ENOTDIR; int res = -ENOTDIR;
if (!file->f_op->iterate) if (file->f_op->iterate_shared)
shared = true;
else if (!file->f_op->iterate)
goto out; goto out;
res = security_file_permission(file, MAY_READ); res = security_file_permission(file, MAY_READ);
if (res) if (res)
goto out; goto out;
inode_lock(inode); if (shared)
inode_lock_shared(inode);
else
inode_lock(inode);
// res = mutex_lock_killable(&inode->i_mutex); // res = mutex_lock_killable(&inode->i_mutex);
// if (res) // if (res)
// goto out; // goto out;
...@@ -40,12 +46,18 @@ int iterate_dir(struct file *file, struct dir_context *ctx) ...@@ -40,12 +46,18 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
res = -ENOENT; res = -ENOENT;
if (!IS_DEADDIR(inode)) { if (!IS_DEADDIR(inode)) {
ctx->pos = file->f_pos; 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; file->f_pos = ctx->pos;
fsnotify_access(file); fsnotify_access(file);
file_accessed(file); file_accessed(file);
} }
inode_unlock(inode); if (shared)
inode_unlock_shared(inode);
else
inode_unlock(inode);
out: out:
return res; return res;
} }
......
...@@ -1674,6 +1674,7 @@ struct file_operations { ...@@ -1674,6 +1674,7 @@ struct file_operations {
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *); int (*iterate) (struct file *, struct dir_context *);
int (*iterate_shared) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *); unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_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