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:
Al Viro 2016-04-20 23:08:32 -04:00
Родитель 63b6df1413
Коммит 6192269444
5 изменённых файлов: 48 добавлений и 11 удалений

Просмотреть файл

@ -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)) {
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 */

Просмотреть файл

@ -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,15 +24,21 @@
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;
@ -40,12 +46,18 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
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;
}

Просмотреть файл

@ -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);