mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	vfs: make getcwd() get the root and pwd path under rcu
This allows us to skip all the crazy spinlocks and reference count updates, and instead use the fs sequence read-lock to get an atomic snapshot of the root and cwd information. We might want to make the rule that "prepend_path()" is always called with the RCU lock held, but the RCU lock nests fine and this is the minimal fix. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									5762482f54
								
							
						
					
					
						commit
						8b19e34188
					
				
					 1 changed files with 12 additions and 11 deletions
				
			
		
							
								
								
									
										23
									
								
								fs/dcache.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								fs/dcache.c
									
									
									
									
									
								
							| 
						 | 
					@ -3015,15 +3015,16 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen)
 | 
				
			||||||
	return ERR_PTR(-ENAMETOOLONG);
 | 
						return ERR_PTR(-ENAMETOOLONG);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void get_fs_root_and_pwd(struct fs_struct *fs, struct path *root,
 | 
					static void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root,
 | 
				
			||||||
				       struct path *pwd)
 | 
									    struct path *pwd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	spin_lock(&fs->lock);
 | 
						unsigned seq;
 | 
				
			||||||
	*root = fs->root;
 | 
					
 | 
				
			||||||
	path_get(root);
 | 
						do {
 | 
				
			||||||
	*pwd = fs->pwd;
 | 
							seq = read_seqcount_begin(&fs->seq);
 | 
				
			||||||
	path_get(pwd);
 | 
							*root = fs->root;
 | 
				
			||||||
	spin_unlock(&fs->lock);
 | 
							*pwd = fs->pwd;
 | 
				
			||||||
 | 
						} while (read_seqcount_retry(&fs->seq, seq));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -3053,7 +3054,8 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
 | 
				
			||||||
	if (!page)
 | 
						if (!page)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	get_fs_root_and_pwd(current->fs, &root, &pwd);
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
						get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = -ENOENT;
 | 
						error = -ENOENT;
 | 
				
			||||||
	br_read_lock(&vfsmount_lock);
 | 
						br_read_lock(&vfsmount_lock);
 | 
				
			||||||
| 
						 | 
					@ -3088,8 +3090,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	path_put(&pwd);
 | 
						rcu_read_unlock();
 | 
				
			||||||
	path_put(&root);
 | 
					 | 
				
			||||||
	free_page((unsigned long) page);
 | 
						free_page((unsigned long) page);
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue