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

Commit 8b19e341 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 5762482f
Loading
Loading
Loading
Loading
+12 −11
Original line number Diff line number Diff line
@@ -3015,15 +3015,16 @@ Elong:
	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)
{
	spin_lock(&fs->lock);
	unsigned seq;

	do {
		seq = read_seqcount_begin(&fs->seq);
		*root = fs->root;
	path_get(root);
		*pwd = fs->pwd;
	path_get(pwd);
	spin_unlock(&fs->lock);
	} while (read_seqcount_retry(&fs->seq, seq));
}

/*
@@ -3053,7 +3054,8 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
	if (!page)
		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;
	br_read_lock(&vfsmount_lock);
@@ -3088,8 +3090,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
	}

out:
	path_put(&pwd);
	path_put(&root);
	rcu_read_unlock();
	free_page((unsigned long) page);
	return error;
}