change fs_struct.lock from rwlock to spinlock
PATCH 1/1 change fs_struct.lock from rwlock to spinlock
struct fs_struct.lock is an rwlock with the read-side used to protect root and pwd members while taking references to them. Taking a reference to a path typically requires just 2 atomic ops, so the critical section is very small. Parallel read-side operations would have cacheline contention on the lock, the dentry, and the vfsmount cachelines, so the rwlock is unlikely to ever give a real parallelism increase.
Replace it with a spinlock to avoid one or two atomic operations in typical path lookup fastpath.
Signed-off-by Nick Piggin <[email protected]>
--- drivers/staging/pohmelfs/path_entry.c | 8 +++---- fs/cachefiles/daemon.c | 8 +++---- fs/dcache.c | 8 +++---- fs/exec.c | 4 +-- fs/fs_struct.c | 36 +++++++++++++++++----------------- fs/namei.c | 8 +++---- fs/namespace.c | 4 +-- fs/proc/base.c | 4 +-- include/linux/fs_struct.h | 2 - kernel/auditsc.c | 4 +-- kernel/fork.c | 10 ++++----- 11 files changed, 48 insertions(+), 48 deletions(-)
fs/dcache.c +4 -4
@@ -2010,10 +2010,10 @@ char *d_path(const struct path *path, chif (path->dentry->d_op && path->dentry->d_op->d_dname)return path->dentry->d_op->d_dname (path->dentry, buf, buflen); -read_lock (¤t->fs->lock); +spin_lock (¤t->fs->lock); root = current->fs->root;path_get (&root); -read_unlock (¤t->fs->lock); +spin_unlock (¤t->fs->lock);spin_lock (&dcache_lock); tmp = root; res =__d_path (path, &tmp, buf, buflen);
@@ -2108,12 +2108,12 @@ SYSCALL_DEFINE2(getcwd, char __user *, bif (!page)return -ENOMEM ; -read_lock (¤t->fs->lock); +spin_lock (¤t->fs->lock); pwd = current->fs->pwd;path_get (&pwd); root = current->fs->root;path_get (&root); -read_unlock (¤t->fs->lock); +spin_unlock (¤t->fs->lock); error = -ENOENT ;spin_lock (&dcache_lock);
fs/fs_struct.c +18 -18
@@ -13,11 +13,11 @@ void set_fs_root(struct fs_struct *fs, s {struct path old_root; -write_lock (&fs->lock); +spin_lock (&fs->lock); old_root = fs->root; fs->root = *path;path_get (path); -write_unlock (&fs->lock); +spin_unlock (&fs->lock);if (old_root.dentry)path_put (&old_root); }
@@ -30,11 +30,11 @@ void set_fs_pwd(struct fs_struct *fs, st {struct path old_pwd; -write_lock (&fs->lock); +spin_lock (&fs->lock); old_pwd = fs->pwd; fs->pwd = *path;path_get (path); -write_unlock (&fs->lock); +spin_unlock (&fs->lock);if (old_pwd.dentry)path_put (&old_pwd);
@@ -51,7 +51,7 @@ void chroot_fs_refs(struct path *old_rootask_lock (p); fs = p->fs;if (fs) { -write_lock (&fs->lock); +spin_lock (&fs->lock);if (fs->root.dentry == old_root->dentry && fs->root.mnt == old_root->mnt) {path_get (new_root);
@@ -64,7 +64,7 @@ void chroot_fs_refs(struct path *old_roo fs->pwd = *new_root; count++; } -write_unlock (&fs->lock); +spin_unlock (&fs->lock); }task_unlock (p); }while_each_thread (g, p);
@@ -87,10 +87,10 @@ void exit_fs(struct task_struct *tsk)if (fs) {int kill;task_lock (tsk); -write_lock (&fs->lock); +spin_lock (&fs->lock); tsk->fs =NULL ; kill = !--fs->users; -write_unlock (&fs->lock); +spin_unlock (&fs->lock);task_unlock (tsk);if (kill)free_fs_struct (fs);
@@ -104,14 +104,14 @@ struct fs_struct *copy_fs_struct(structif (fs) { fs->users =1 ; fs->in_exec =0 ; -rwlock_init (&fs->lock); +spin_lock_init (&fs->lock); fs->umask = old->umask; -read_lock (&old->lock); +spin_lock (&old->lock); fs->root = old->root;path_get (&old->root); fs->pwd = old->pwd;path_get (&old->pwd); -read_unlock (&old->lock); +spin_unlock (&old->lock); }return fs; }
@@ -126,10 +126,10 @@ int unshare_fs_struct(void)return -ENOMEM ;task_lock (current); -write_lock (&fs->lock); +spin_lock (&fs->lock); kill = !--fs->users; current->fs = new_fs; -write_unlock (&fs->lock); +spin_unlock (&fs->lock);task_unlock (current);if (kill)
@@ -148,7 +148,7 @@ EXPORT_SYMBOL(current_umask);/* to be mentioned only in INIT_TASK */ struct fs_struct init_fs = { .users =1 , - .lock =__RW_LOCK_UNLOCKED (init_fs.lock), + .lock =__SPIN_LOCK_UNLOCKED (init_fs.lock), .umask =0022 , };
@@ -161,14 +161,14 @@ void daemonize_fs_struct(void)task_lock (current); -write_lock (&init_fs.lock); +spin_lock (&init_fs.lock); init_fs.users++; -write_unlock (&init_fs.lock); +spin_unlock (&init_fs.lock); -write_lock (&fs->lock); +spin_lock (&fs->lock); current->fs = &init_fs; kill = !--fs->users; -write_unlock (&fs->lock); +spin_unlock (&fs->lock);task_unlock (current);if (kill)
fs/namei.c +4 -4
@@ -486,10 +486,10 @@ static __always_inline void set_root(str {if (!nd->root.mnt) {struct fs_struct *fs = current->fs; -read_lock (&fs->lock); +spin_lock (&fs->lock); nd->root = fs->root;path_get (&nd->root); -read_unlock (&fs->lock); +spin_unlock (&fs->lock); } }
@@ -1017,10 +1017,10 @@ static int path_init(int dfd, const charpath_get (&nd->root); }else if (dfd ==AT_FDCWD ) {struct fs_struct *fs = current->fs; -read_lock (&fs->lock); +spin_lock (&fs->lock); nd->path = fs->pwd;path_get (&fs->pwd); -read_unlock (&fs->lock); +spin_unlock (&fs->lock); }else {struct dentry *dentry;
fs/namespace.c +2 -2
@@ -2208,10 +2208,10 @@ SYSCALL_DEFINE2(pivot_root, const char _ goto out1; } -read_lock (¤t->fs->lock); +spin_lock (¤t->fs->lock); root = current->fs->root;path_get (¤t->fs->root); -read_unlock (¤t->fs->lock); +spin_unlock (¤t->fs->lock);down_write (&namespace_sem);mutex_lock (&old.dentry->d_inode->i_mutex); error = -EINVAL ;
include/linux/fs_struct.h +1 -1
@@ -5,7 +5,7 @@struct fs_struct {int users; -rwlock_t lock; +spinlock_t lock;int umask;int in_exec;struct path root, pwd;
fs/exec.c +2 -2
@@ -1117,7 +1117,7 @@ int check_unsafe_exec(struct linux_binpr bprm->unsafe =tracehook_unsafe_exec (p); n_fs =1 ; -write_lock (&p->fs->lock); +spin_lock (&p->fs->lock);rcu_read_lock ();for (t =next_thread (p); t != p; t =next_thread (t)) {if (t->fs == p->fs)
@@ -1134,7 +1134,7 @@ int check_unsafe_exec(struct linux_binpr res =1 ; } } -write_unlock (&p->fs->lock); +spin_unlock (&p->fs->lock);return res; }
fs/proc/base.c +2 -2
@@ -156,10 +156,10 @@ static int get_fs_path(struct task_structask_lock (task); fs = task->fs;if (fs) { -read_lock (&fs->lock); +spin_lock (&fs->lock); *path = root ? fs->root : fs->pwd;path_get (path); -read_unlock (&fs->lock); +spin_unlock (&fs->lock); result =0 ; }task_unlock (task);
kernel/fork.c +5 -5
@@ -752,13 +752,13 @@ static int copy_fs(unsigned long clone_fstruct fs_struct *fs = current->fs;if (clone_flags &CLONE_FS ) {/* tsk->fs is already what we want */ -write_lock (&fs->lock); +spin_lock (&fs->lock);if (fs->in_exec) { -write_unlock (&fs->lock); +spin_unlock (&fs->lock);return -EAGAIN ; } fs->users++; -write_unlock (&fs->lock); +spin_unlock (&fs->lock);return 0 ; } tsk->fs =copy_fs_struct (fs);
@@ -1675,13 +1675,13 @@ SYSCALL_DEFINE1(unshare, unsigned long,if (new_fs) { fs = current->fs; -write_lock (&fs->lock); +spin_lock (&fs->lock); current->fs = new_fs;if (--fs->users) new_fs =NULL ;else new_fs = fs; -write_unlock (&fs->lock); +spin_unlock (&fs->lock); }if (new_mm) {
drivers/staging/pohmelfs/path_entry.c +4 -4
@@ -44,9 +44,9 @@ int pohmelfs_construct_path_string(strucreturn -ENOENT ; } -read_lock (¤t->fs->lock); +spin_lock (¤t->fs->lock); path.mnt =mntget (current->fs->root.mnt); -read_unlock (¤t->fs->lock); +spin_unlock (¤t->fs->lock); path.dentry = d;
@@ -91,9 +91,9 @@ int pohmelfs_path_length(struct pohmelfsreturn -ENOENT ; } -read_lock (¤t->fs->lock); +spin_lock (¤t->fs->lock); root =dget (current->fs->root.dentry); -read_unlock (¤t->fs->lock); +spin_unlock (¤t->fs->lock);spin_lock (&dcache_lock);
fs/cachefiles/daemon.c +4 -4
@@ -574,9 +574,9 @@ static int cachefiles_daemon_cull(struct/* extract the directory dentry from the cwd */ fs = current->fs; -read_lock (&fs->lock); +spin_lock (&fs->lock); dir =dget (fs->pwd.dentry); -read_unlock (&fs->lock); +spin_unlock (&fs->lock);if (!S_ISDIR (dir->d_inode->i_mode)) goto notdir;
@@ -650,9 +650,9 @@ static int cachefiles_daemon_inuse(struc/* extract the directory dentry from the cwd */ fs = current->fs; -read_lock (&fs->lock); +spin_lock (&fs->lock); dir =dget (fs->pwd.dentry); -read_unlock (&fs->lock); +spin_unlock (&fs->lock);if (!S_ISDIR (dir->d_inode->i_mode)) goto notdir;
kernel/auditsc.c +2 -2
@@ -1838,10 +1838,10 @@ void __audit_getname(const char *name) context->names[context->name_count].osid =0 ; ++context->name_count;if (!context->pwd.dentry) { -read_lock (¤t->fs->lock); +spin_lock (¤t->fs->lock); context->pwd = current->fs->pwd;path_get (¤t->fs->pwd); -read_unlock (¤t->fs->lock); +spin_unlock (¤t->fs->lock); } }