fold fs_struct->{lock,seq} into a seqlock

The combination of spinlock_t lock and seqcount_spinlock_t seq
in struct fs_struct is an open-coded seqlock_t (see linux/seqlock_types.h).
	Combine and switch to equivalent seqlock_t primitives.  AFAICS,
that does end up with the same sequence of underlying operations in all
cases.
	While we are at it, get_fs_pwd() is open-coded verbatim in
get_path_from_fd(); rather than applying conversion to it, replace with
the call of get_fs_pwd() there.  Not worth splitting the commit for that,
IMO...

	A bit of historical background - conversion of seqlock_t to
use of seqcount_spinlock_t happened several months after the same
had been done to struct fs_struct; switching fs_struct to seqlock_t
could've been done immediately after that, but it looks like nobody
had gotten around to that until now.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Link: https://lore.kernel.org/20250702053437.GC1880847@ZenIV
Acked-by: Ahmed S. Darwish <darwi@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Al Viro 2025-07-02 06:34:37 +01:00 committed by Christian Brauner
parent 7a5b467e5d
commit a683a5b2ba
No known key found for this signature in database
GPG key ID: 91C61BC06578DCA2
7 changed files with 35 additions and 48 deletions

View file

@ -241,9 +241,9 @@ static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
unsigned seq;
do {
seq = read_seqcount_begin(&fs->seq);
seq = read_seqbegin(&fs->seq);
*root = fs->root;
} while (read_seqcount_retry(&fs->seq, seq));
} while (read_seqretry(&fs->seq, seq));
}
/**
@ -385,10 +385,10 @@ static void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root,
unsigned seq;
do {
seq = read_seqcount_begin(&fs->seq);
seq = read_seqbegin(&fs->seq);
*root = fs->root;
*pwd = fs->pwd;
} while (read_seqcount_retry(&fs->seq, seq));
} while (read_seqretry(&fs->seq, seq));
}
/*

View file

@ -1510,7 +1510,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
* state is protected by cred_guard_mutex we hold.
*/
n_fs = 1;
spin_lock(&p->fs->lock);
read_seqlock_excl(&p->fs->seq);
rcu_read_lock();
for_other_threads(p, t) {
if (t->fs == p->fs)
@ -1523,7 +1523,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
bprm->unsafe |= LSM_UNSAFE_SHARE;
else
p->fs->in_exec = 1;
spin_unlock(&p->fs->lock);
read_sequnlock_excl(&p->fs->seq);
}
static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)

View file

@ -180,11 +180,7 @@ static int get_path_anchor(int fd, struct path *root)
}
if (fd == AT_FDCWD) {
struct fs_struct *fs = current->fs;
spin_lock(&fs->lock);
*root = fs->pwd;
path_get(root);
spin_unlock(&fs->lock);
get_fs_pwd(current->fs, root);
return 0;
}

View file

@ -17,12 +17,10 @@ void set_fs_root(struct fs_struct *fs, const struct path *path)
struct path old_root;
path_get(path);
spin_lock(&fs->lock);
write_seqcount_begin(&fs->seq);
write_seqlock(&fs->seq);
old_root = fs->root;
fs->root = *path;
write_seqcount_end(&fs->seq);
spin_unlock(&fs->lock);
write_sequnlock(&fs->seq);
if (old_root.dentry)
path_put(&old_root);
}
@ -36,12 +34,10 @@ void set_fs_pwd(struct fs_struct *fs, const struct path *path)
struct path old_pwd;
path_get(path);
spin_lock(&fs->lock);
write_seqcount_begin(&fs->seq);
write_seqlock(&fs->seq);
old_pwd = fs->pwd;
fs->pwd = *path;
write_seqcount_end(&fs->seq);
spin_unlock(&fs->lock);
write_sequnlock(&fs->seq);
if (old_pwd.dentry)
path_put(&old_pwd);
@ -67,16 +63,14 @@ void chroot_fs_refs(const struct path *old_root, const struct path *new_root)
fs = p->fs;
if (fs) {
int hits = 0;
spin_lock(&fs->lock);
write_seqcount_begin(&fs->seq);
write_seqlock(&fs->seq);
hits += replace_path(&fs->root, old_root, new_root);
hits += replace_path(&fs->pwd, old_root, new_root);
write_seqcount_end(&fs->seq);
while (hits--) {
count++;
path_get(new_root);
}
spin_unlock(&fs->lock);
write_sequnlock(&fs->seq);
}
task_unlock(p);
}
@ -99,10 +93,10 @@ void exit_fs(struct task_struct *tsk)
if (fs) {
int kill;
task_lock(tsk);
spin_lock(&fs->lock);
read_seqlock_excl(&fs->seq);
tsk->fs = NULL;
kill = !--fs->users;
spin_unlock(&fs->lock);
read_sequnlock_excl(&fs->seq);
task_unlock(tsk);
if (kill)
free_fs_struct(fs);
@ -116,16 +110,15 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
if (fs) {
fs->users = 1;
fs->in_exec = 0;
spin_lock_init(&fs->lock);
seqcount_spinlock_init(&fs->seq, &fs->lock);
seqlock_init(&fs->seq);
fs->umask = old->umask;
spin_lock(&old->lock);
read_seqlock_excl(&old->seq);
fs->root = old->root;
path_get(&fs->root);
fs->pwd = old->pwd;
path_get(&fs->pwd);
spin_unlock(&old->lock);
read_sequnlock_excl(&old->seq);
}
return fs;
}
@ -140,10 +133,10 @@ int unshare_fs_struct(void)
return -ENOMEM;
task_lock(current);
spin_lock(&fs->lock);
read_seqlock_excl(&fs->seq);
kill = !--fs->users;
current->fs = new_fs;
spin_unlock(&fs->lock);
read_sequnlock_excl(&fs->seq);
task_unlock(current);
if (kill)
@ -162,7 +155,6 @@ EXPORT_SYMBOL(current_umask);
/* to be mentioned only in INIT_TASK */
struct fs_struct init_fs = {
.users = 1,
.lock = __SPIN_LOCK_UNLOCKED(init_fs.lock),
.seq = SEQCNT_SPINLOCK_ZERO(init_fs.seq, &init_fs.lock),
.seq = __SEQLOCK_UNLOCKED(init_fs.seq),
.umask = 0022,
};

View file

@ -1012,10 +1012,10 @@ static int set_root(struct nameidata *nd)
unsigned seq;
do {
seq = read_seqcount_begin(&fs->seq);
seq = read_seqbegin(&fs->seq);
nd->root = fs->root;
nd->root_seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
} while (read_seqcount_retry(&fs->seq, seq));
} while (read_seqretry(&fs->seq, seq));
} else {
get_fs_root(fs, &nd->root);
nd->state |= ND_ROOT_GRABBED;
@ -2580,11 +2580,11 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
unsigned seq;
do {
seq = read_seqcount_begin(&fs->seq);
seq = read_seqbegin(&fs->seq);
nd->path = fs->pwd;
nd->inode = nd->path.dentry->d_inode;
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
} while (read_seqcount_retry(&fs->seq, seq));
} while (read_seqretry(&fs->seq, seq));
} else {
get_fs_pwd(current->fs, &nd->path);
nd->inode = nd->path.dentry->d_inode;

View file

@ -8,8 +8,7 @@
struct fs_struct {
int users;
spinlock_t lock;
seqcount_spinlock_t seq;
seqlock_t seq;
int umask;
int in_exec;
struct path root, pwd;
@ -26,18 +25,18 @@ extern int unshare_fs_struct(void);
static inline void get_fs_root(struct fs_struct *fs, struct path *root)
{
spin_lock(&fs->lock);
read_seqlock_excl(&fs->seq);
*root = fs->root;
path_get(root);
spin_unlock(&fs->lock);
read_sequnlock_excl(&fs->seq);
}
static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd)
{
spin_lock(&fs->lock);
read_seqlock_excl(&fs->seq);
*pwd = fs->pwd;
path_get(pwd);
spin_unlock(&fs->lock);
read_sequnlock_excl(&fs->seq);
}
extern bool current_chrooted(void);

View file

@ -1542,14 +1542,14 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
struct fs_struct *fs = current->fs;
if (clone_flags & CLONE_FS) {
/* tsk->fs is already what we want */
spin_lock(&fs->lock);
read_seqlock_excl(&fs->seq);
/* "users" and "in_exec" locked for check_unsafe_exec() */
if (fs->in_exec) {
spin_unlock(&fs->lock);
read_sequnlock_excl(&fs->seq);
return -EAGAIN;
}
fs->users++;
spin_unlock(&fs->lock);
read_sequnlock_excl(&fs->seq);
return 0;
}
tsk->fs = copy_fs_struct(fs);
@ -3149,13 +3149,13 @@ int ksys_unshare(unsigned long unshare_flags)
if (new_fs) {
fs = current->fs;
spin_lock(&fs->lock);
read_seqlock_excl(&fs->seq);
current->fs = new_fs;
if (--fs->users)
new_fs = NULL;
else
new_fs = fs;
spin_unlock(&fs->lock);
read_sequnlock_excl(&fs->seq);
}
if (new_fd)