Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

af_unix: Refactor unix_next_socket().

Currently, unix_next_socket() is overloaded depending on the 2nd argument.
If it is NULL, unix_next_socket() returns the first socket in the hash. If
not NULL, it returns the next socket in the same hash list or the first
socket in the next non-empty hash list.

This patch refactors unix_next_socket() into two functions unix_get_first()
and unix_get_next(). unix_get_first() newly acquires a lock and returns
the first socket in the list. unix_get_next() returns the next socket in a
list or releases a lock and falls back to unix_get_first().

In the following patch, bpf iter holds entire sockets in a list and always
releases the lock before .show(). It always calls unix_get_first() to
acquire a lock in each iteration. So, this patch makes the change easier
to follow.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.co.jp>
Link: https://lore.kernel.org/r/20220113002849.4384-2-kuniyu@amazon.co.jp
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Kuniyuki Iwashima and committed by
Alexei Starovoitov
4408d55a 2a1aff60

+30 -21
+30 -21
net/unix/af_unix.c
··· 3240 3240 return sk; 3241 3241 } 3242 3242 3243 - static struct sock *unix_next_socket(struct seq_file *seq, 3244 - struct sock *sk, 3245 - loff_t *pos) 3243 + static struct sock *unix_get_first(struct seq_file *seq, loff_t *pos) 3246 3244 { 3247 3245 unsigned long bucket = get_bucket(*pos); 3246 + struct sock *sk; 3248 3247 3249 - while (sk > (struct sock *)SEQ_START_TOKEN) { 3250 - sk = sk_next(sk); 3251 - if (!sk) 3252 - goto next_bucket; 3253 - if (sock_net(sk) == seq_file_net(seq)) 3254 - return sk; 3255 - } 3256 - 3257 - do { 3248 + while (bucket < ARRAY_SIZE(unix_socket_table)) { 3258 3249 spin_lock(&unix_table_locks[bucket]); 3250 + 3259 3251 sk = unix_from_bucket(seq, pos); 3260 3252 if (sk) 3261 3253 return sk; 3262 3254 3263 - next_bucket: 3264 - spin_unlock(&unix_table_locks[bucket++]); 3265 - *pos = set_bucket_offset(bucket, 1); 3266 - } while (bucket < ARRAY_SIZE(unix_socket_table)); 3255 + spin_unlock(&unix_table_locks[bucket]); 3256 + 3257 + *pos = set_bucket_offset(++bucket, 1); 3258 + } 3267 3259 3268 3260 return NULL; 3261 + } 3262 + 3263 + static struct sock *unix_get_next(struct seq_file *seq, struct sock *sk, 3264 + loff_t *pos) 3265 + { 3266 + unsigned long bucket = get_bucket(*pos); 3267 + 3268 + for (sk = sk_next(sk); sk; sk = sk_next(sk)) 3269 + if (sock_net(sk) == seq_file_net(seq)) 3270 + return sk; 3271 + 3272 + spin_unlock(&unix_table_locks[bucket]); 3273 + 3274 + *pos = set_bucket_offset(++bucket, 1); 3275 + 3276 + return unix_get_first(seq, pos); 3269 3277 } 3270 3278 3271 3279 static void *unix_seq_start(struct seq_file *seq, loff_t *pos) ··· 3281 3273 if (!*pos) 3282 3274 return SEQ_START_TOKEN; 3283 3275 3284 - if (get_bucket(*pos) >= ARRAY_SIZE(unix_socket_table)) 3285 - return NULL; 3286 - 3287 - return unix_next_socket(seq, NULL, pos); 3276 + return unix_get_first(seq, pos); 3288 3277 } 3289 3278 3290 3279 static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) 3291 3280 { 3292 3281 ++*pos; 3293 - return unix_next_socket(seq, v, pos); 3282 + 3283 + if (v == SEQ_START_TOKEN) 3284 + return unix_get_first(seq, pos); 3285 + 3286 + return unix_get_next(seq, v, pos); 3294 3287 } 3295 3288 3296 3289 static void unix_seq_stop(struct seq_file *seq, void *v)