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>
This commit is contained in:
parent
63b6df1413
commit
6192269444
5 changed files with 48 additions and 11 deletions
|
@ -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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
20
fs/readdir.c
20
fs/readdir.c
|
@ -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)
|
||||||
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 {
|
||||||
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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue