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

kernfs: Implement kernfs_show()

Currently, kernfs nodes can be created hidden and activated later by calling
kernfs_activate() to allow creation of multiple nodes to succeed or fail as
a unit. This is an one-way one-time-only transition. This patch introduces
kernfs_show() which can toggle visibility dynamically.

As the currently proposed use - toggling the cgroup pressure files - only
requires operating on leaf nodes, for the sake of simplicity, restrict it as
such for now.

Hiding uses the same mechanism as deactivation and likewise guarantees that
there are no in-flight operations on completion. KERNFS_ACTIVATED and
KERNFS_HIDDEN are used to manage the interactions between activations and
show/hide operations. A node is visible iff both activated & !hidden.

Cc: Chengming Zhou <zhouchengming@bytedance.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Tested-by: Chengming Zhou <zhouchengming@bytedance.com>
Reviewed-by: Chengming Zhou <zhouchengming@bytedance.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Link: https://lore.kernel.org/r/20220828050440.734579-9-tj@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Tejun Heo and committed by
Greg Kroah-Hartman
783bd07d f8eb145e

+38 -1
+36 -1
fs/kernfs/dir.c
··· 1311 1311 1312 1312 kn->flags |= KERNFS_ACTIVATED; 1313 1313 1314 - if (kernfs_active(kn) || (kn->flags & KERNFS_REMOVING)) 1314 + if (kernfs_active(kn) || (kn->flags & (KERNFS_HIDDEN | KERNFS_REMOVING))) 1315 1315 return; 1316 1316 1317 1317 WARN_ON_ONCE(kn->parent && RB_EMPTY_NODE(&kn->rb)); ··· 1343 1343 pos = NULL; 1344 1344 while ((pos = kernfs_next_descendant_post(pos, kn))) 1345 1345 kernfs_activate_one(pos); 1346 + 1347 + up_write(&root->kernfs_rwsem); 1348 + } 1349 + 1350 + /** 1351 + * kernfs_show - show or hide a node 1352 + * @kn: kernfs_node to show or hide 1353 + * @show: whether to show or hide 1354 + * 1355 + * If @show is %false, @kn is marked hidden and deactivated. A hidden node is 1356 + * ignored in future activaitons. If %true, the mark is removed and activation 1357 + * state is restored. This function won't implicitly activate a new node in a 1358 + * %KERNFS_ROOT_CREATE_DEACTIVATED root which hasn't been activated yet. 1359 + * 1360 + * To avoid recursion complexities, directories aren't supported for now. 1361 + */ 1362 + void kernfs_show(struct kernfs_node *kn, bool show) 1363 + { 1364 + struct kernfs_root *root = kernfs_root(kn); 1365 + 1366 + if (WARN_ON_ONCE(kernfs_type(kn) == KERNFS_DIR)) 1367 + return; 1368 + 1369 + down_write(&root->kernfs_rwsem); 1370 + 1371 + if (show) { 1372 + kn->flags &= ~KERNFS_HIDDEN; 1373 + if (kn->flags & KERNFS_ACTIVATED) 1374 + kernfs_activate_one(kn); 1375 + } else { 1376 + kn->flags |= KERNFS_HIDDEN; 1377 + if (kernfs_active(kn)) 1378 + atomic_add(KN_DEACTIVATED_BIAS, &kn->active); 1379 + kernfs_drain(kn); 1380 + } 1346 1381 1347 1382 up_write(&root->kernfs_rwsem); 1348 1383 }
+2
include/linux/kernfs.h
··· 108 108 KERNFS_HAS_SEQ_SHOW = 0x0040, 109 109 KERNFS_HAS_MMAP = 0x0080, 110 110 KERNFS_LOCKDEP = 0x0100, 111 + KERNFS_HIDDEN = 0x0200, 111 112 KERNFS_SUICIDAL = 0x0400, 112 113 KERNFS_SUICIDED = 0x0800, 113 114 KERNFS_EMPTY_DIR = 0x1000, ··· 431 430 const char *name, 432 431 struct kernfs_node *target); 433 432 void kernfs_activate(struct kernfs_node *kn); 433 + void kernfs_show(struct kernfs_node *kn, bool show); 434 434 void kernfs_remove(struct kernfs_node *kn); 435 435 void kernfs_break_active_protection(struct kernfs_node *kn); 436 436 void kernfs_unbreak_active_protection(struct kernfs_node *kn);