mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00: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