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.
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 */
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;
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;
}
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);