Skip to content

Commit a683a5b

Browse files
Al Virobrauner
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/20250702053437.GC1880847@ZenIV Acked-by: Ahmed S. Darwish <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Christian Brauner <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 7a5b467 commit a683a5b

File tree

7 files changed

+35
-48
lines changed

7 files changed

+35
-48
lines changed

fs/d_path.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,9 @@ static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
241241
unsigned seq;
242242

243243
do {
244-
seq = read_seqcount_begin(&fs->seq);
244+
seq = read_seqbegin(&fs->seq);
245245
*root = fs->root;
246-
} while (read_seqcount_retry(&fs->seq, seq));
246+
} while (read_seqretry(&fs->seq, seq));
247247
}
248248

249249
/**
@@ -385,10 +385,10 @@ static void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root,
385385
unsigned seq;
386386

387387
do {
388-
seq = read_seqcount_begin(&fs->seq);
388+
seq = read_seqbegin(&fs->seq);
389389
*root = fs->root;
390390
*pwd = fs->pwd;
391-
} while (read_seqcount_retry(&fs->seq, seq));
391+
} while (read_seqretry(&fs->seq, seq));
392392
}
393393

394394
/*

fs/exec.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,7 +1510,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
15101510
* state is protected by cred_guard_mutex we hold.
15111511
*/
15121512
n_fs = 1;
1513-
spin_lock(&p->fs->lock);
1513+
read_seqlock_excl(&p->fs->seq);
15141514
rcu_read_lock();
15151515
for_other_threads(p, t) {
15161516
if (t->fs == p->fs)
@@ -1523,7 +1523,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
15231523
bprm->unsafe |= LSM_UNSAFE_SHARE;
15241524
else
15251525
p->fs->in_exec = 1;
1526-
spin_unlock(&p->fs->lock);
1526+
read_sequnlock_excl(&p->fs->seq);
15271527
}
15281528

15291529
static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)

fs/fhandle.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,7 @@ static int get_path_anchor(int fd, struct path *root)
180180
}
181181

182182
if (fd == AT_FDCWD) {
183-
struct fs_struct *fs = current->fs;
184-
spin_lock(&fs->lock);
185-
*root = fs->pwd;
186-
path_get(root);
187-
spin_unlock(&fs->lock);
183+
get_fs_pwd(current->fs, root);
188184
return 0;
189185
}
190186

fs/fs_struct.c

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@ void set_fs_root(struct fs_struct *fs, const struct path *path)
1717
struct path old_root;
1818

1919
path_get(path);
20-
spin_lock(&fs->lock);
21-
write_seqcount_begin(&fs->seq);
20+
write_seqlock(&fs->seq);
2221
old_root = fs->root;
2322
fs->root = *path;
24-
write_seqcount_end(&fs->seq);
25-
spin_unlock(&fs->lock);
23+
write_sequnlock(&fs->seq);
2624
if (old_root.dentry)
2725
path_put(&old_root);
2826
}
@@ -36,12 +34,10 @@ void set_fs_pwd(struct fs_struct *fs, const struct path *path)
3634
struct path old_pwd;
3735

3836
path_get(path);
39-
spin_lock(&fs->lock);
40-
write_seqcount_begin(&fs->seq);
37+
write_seqlock(&fs->seq);
4138
old_pwd = fs->pwd;
4239
fs->pwd = *path;
43-
write_seqcount_end(&fs->seq);
44-
spin_unlock(&fs->lock);
40+
write_sequnlock(&fs->seq);
4541

4642
if (old_pwd.dentry)
4743
path_put(&old_pwd);
@@ -67,16 +63,14 @@ void chroot_fs_refs(const struct path *old_root, const struct path *new_root)
6763
fs = p->fs;
6864
if (fs) {
6965
int hits = 0;
70-
spin_lock(&fs->lock);
71-
write_seqcount_begin(&fs->seq);
66+
write_seqlock(&fs->seq);
7267
hits += replace_path(&fs->root, old_root, new_root);
7368
hits += replace_path(&fs->pwd, old_root, new_root);
74-
write_seqcount_end(&fs->seq);
7569
while (hits--) {
7670
count++;
7771
path_get(new_root);
7872
}
79-
spin_unlock(&fs->lock);
73+
write_sequnlock(&fs->seq);
8074
}
8175
task_unlock(p);
8276
}
@@ -99,10 +93,10 @@ void exit_fs(struct task_struct *tsk)
9993
if (fs) {
10094
int kill;
10195
task_lock(tsk);
102-
spin_lock(&fs->lock);
96+
read_seqlock_excl(&fs->seq);
10397
tsk->fs = NULL;
10498
kill = !--fs->users;
105-
spin_unlock(&fs->lock);
99+
read_sequnlock_excl(&fs->seq);
106100
task_unlock(tsk);
107101
if (kill)
108102
free_fs_struct(fs);
@@ -116,16 +110,15 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
116110
if (fs) {
117111
fs->users = 1;
118112
fs->in_exec = 0;
119-
spin_lock_init(&fs->lock);
120-
seqcount_spinlock_init(&fs->seq, &fs->lock);
113+
seqlock_init(&fs->seq);
121114
fs->umask = old->umask;
122115

123-
spin_lock(&old->lock);
116+
read_seqlock_excl(&old->seq);
124117
fs->root = old->root;
125118
path_get(&fs->root);
126119
fs->pwd = old->pwd;
127120
path_get(&fs->pwd);
128-
spin_unlock(&old->lock);
121+
read_sequnlock_excl(&old->seq);
129122
}
130123
return fs;
131124
}
@@ -140,10 +133,10 @@ int unshare_fs_struct(void)
140133
return -ENOMEM;
141134

142135
task_lock(current);
143-
spin_lock(&fs->lock);
136+
read_seqlock_excl(&fs->seq);
144137
kill = !--fs->users;
145138
current->fs = new_fs;
146-
spin_unlock(&fs->lock);
139+
read_sequnlock_excl(&fs->seq);
147140
task_unlock(current);
148141

149142
if (kill)
@@ -162,7 +155,6 @@ EXPORT_SYMBOL(current_umask);
162155
/* to be mentioned only in INIT_TASK */
163156
struct fs_struct init_fs = {
164157
.users = 1,
165-
.lock = __SPIN_LOCK_UNLOCKED(init_fs.lock),
166-
.seq = SEQCNT_SPINLOCK_ZERO(init_fs.seq, &init_fs.lock),
158+
.seq = __SEQLOCK_UNLOCKED(init_fs.seq),
167159
.umask = 0022,
168160
};

fs/namei.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,10 +1012,10 @@ static int set_root(struct nameidata *nd)
10121012
unsigned seq;
10131013

10141014
do {
1015-
seq = read_seqcount_begin(&fs->seq);
1015+
seq = read_seqbegin(&fs->seq);
10161016
nd->root = fs->root;
10171017
nd->root_seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
1018-
} while (read_seqcount_retry(&fs->seq, seq));
1018+
} while (read_seqretry(&fs->seq, seq));
10191019
} else {
10201020
get_fs_root(fs, &nd->root);
10211021
nd->state |= ND_ROOT_GRABBED;
@@ -2580,11 +2580,11 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
25802580
unsigned seq;
25812581

25822582
do {
2583-
seq = read_seqcount_begin(&fs->seq);
2583+
seq = read_seqbegin(&fs->seq);
25842584
nd->path = fs->pwd;
25852585
nd->inode = nd->path.dentry->d_inode;
25862586
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
2587-
} while (read_seqcount_retry(&fs->seq, seq));
2587+
} while (read_seqretry(&fs->seq, seq));
25882588
} else {
25892589
get_fs_pwd(current->fs, &nd->path);
25902590
nd->inode = nd->path.dentry->d_inode;

include/linux/fs_struct.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88

99
struct fs_struct {
1010
int users;
11-
spinlock_t lock;
12-
seqcount_spinlock_t seq;
11+
seqlock_t seq;
1312
int umask;
1413
int in_exec;
1514
struct path root, pwd;
@@ -26,18 +25,18 @@ extern int unshare_fs_struct(void);
2625

2726
static inline void get_fs_root(struct fs_struct *fs, struct path *root)
2827
{
29-
spin_lock(&fs->lock);
28+
read_seqlock_excl(&fs->seq);
3029
*root = fs->root;
3130
path_get(root);
32-
spin_unlock(&fs->lock);
31+
read_sequnlock_excl(&fs->seq);
3332
}
3433

3534
static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd)
3635
{
37-
spin_lock(&fs->lock);
36+
read_seqlock_excl(&fs->seq);
3837
*pwd = fs->pwd;
3938
path_get(pwd);
40-
spin_unlock(&fs->lock);
39+
read_sequnlock_excl(&fs->seq);
4140
}
4241

4342
extern bool current_chrooted(void);

kernel/fork.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,14 +1542,14 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
15421542
struct fs_struct *fs = current->fs;
15431543
if (clone_flags & CLONE_FS) {
15441544
/* tsk->fs is already what we want */
1545-
spin_lock(&fs->lock);
1545+
read_seqlock_excl(&fs->seq);
15461546
/* "users" and "in_exec" locked for check_unsafe_exec() */
15471547
if (fs->in_exec) {
1548-
spin_unlock(&fs->lock);
1548+
read_sequnlock_excl(&fs->seq);
15491549
return -EAGAIN;
15501550
}
15511551
fs->users++;
1552-
spin_unlock(&fs->lock);
1552+
read_sequnlock_excl(&fs->seq);
15531553
return 0;
15541554
}
15551555
tsk->fs = copy_fs_struct(fs);
@@ -3149,13 +3149,13 @@ int ksys_unshare(unsigned long unshare_flags)
31493149

31503150
if (new_fs) {
31513151
fs = current->fs;
3152-
spin_lock(&fs->lock);
3152+
read_seqlock_excl(&fs->seq);
31533153
current->fs = new_fs;
31543154
if (--fs->users)
31553155
new_fs = NULL;
31563156
else
31573157
new_fs = fs;
3158-
spin_unlock(&fs->lock);
3158+
read_sequnlock_excl(&fs->seq);
31593159
}
31603160

31613161
if (new_fd)

0 commit comments

Comments
 (0)