mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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()).
 | 
			
		||||
	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)) {
 | 
			
		||||
			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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								fs/readdir.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								fs/readdir.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue