Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61922694 authored by Al Viro's avatar Al Viro
Browse files

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
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -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.
+12 −6
Original line number Diff line number Diff line
@@ -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 */
+1 −1
Original line number Diff line number Diff line
@@ -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;
+16 −4
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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);