Skip to content

Commit d04bccd

Browse files
committed
listmount: allow listing in reverse order
util-linux is about to implement listmount() and statmount() support. Karel requested the ability to scan the mount table in backwards order because that's what libmount currently does in order to get the latest mount first. We currently don't support this in listmount(). Add a new LISTMOUNT_REVERSE flag to allow listing mounts in reverse order. For example, listing all child mounts of /sys without LISTMOUNT_REVERSE gives: /sys/kernel/security @ mnt_id: 4294968369 /sys/fs/cgroup @ mnt_id: 4294968370 /sys/firmware/efi/efivars @ mnt_id: 4294968371 /sys/fs/bpf @ mnt_id: 4294968372 /sys/kernel/tracing @ mnt_id: 4294968373 /sys/kernel/debug @ mnt_id: 4294968374 /sys/fs/fuse/connections @ mnt_id: 4294968375 /sys/kernel/config @ mnt_id: 4294968376 whereas with LISTMOUNT_REVERSE it gives: /sys/kernel/config @ mnt_id: 4294968376 /sys/fs/fuse/connections @ mnt_id: 4294968375 /sys/kernel/debug @ mnt_id: 4294968374 /sys/kernel/tracing @ mnt_id: 4294968373 /sys/fs/bpf @ mnt_id: 4294968372 /sys/firmware/efi/efivars @ mnt_id: 4294968371 /sys/fs/cgroup @ mnt_id: 4294968370 /sys/kernel/security @ mnt_id: 4294968369 Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 17e7016 commit d04bccd

File tree

2 files changed

+50
-10
lines changed

2 files changed

+50
-10
lines changed

fs/namespace.c

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,6 +1448,30 @@ static struct mount *mnt_find_id_at(struct mnt_namespace *ns, u64 mnt_id)
14481448
return ret;
14491449
}
14501450

1451+
/*
1452+
* Returns the mount which either has the specified mnt_id, or has the next
1453+
* greater id before the specified one.
1454+
*/
1455+
static struct mount *mnt_find_id_at_reverse(struct mnt_namespace *ns, u64 mnt_id)
1456+
{
1457+
struct rb_node *node = ns->mounts.rb_node;
1458+
struct mount *ret = NULL;
1459+
1460+
while (node) {
1461+
struct mount *m = node_to_mount(node);
1462+
1463+
if (mnt_id >= m->mnt_id_unique) {
1464+
ret = node_to_mount(node);
1465+
if (mnt_id == m->mnt_id_unique)
1466+
break;
1467+
node = node->rb_right;
1468+
} else {
1469+
node = node->rb_left;
1470+
}
1471+
}
1472+
return ret;
1473+
}
1474+
14511475
#ifdef CONFIG_PROC_FS
14521476

14531477
/* iterator; we want it to have access to namespace_sem, thus here... */
@@ -5042,13 +5066,20 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
50425066
return ret;
50435067
}
50445068

5045-
static struct mount *listmnt_next(struct mount *curr)
5069+
static struct mount *listmnt_next(struct mount *curr, bool reverse)
50465070
{
5047-
return node_to_mount(rb_next(&curr->mnt_node));
5071+
struct rb_node *node;
5072+
5073+
if (reverse)
5074+
node = rb_prev(&curr->mnt_node);
5075+
else
5076+
node = rb_next(&curr->mnt_node);
5077+
5078+
return node_to_mount(node);
50485079
}
50495080

50505081
static ssize_t do_listmount(u64 mnt_parent_id, u64 last_mnt_id, u64 *mnt_ids,
5051-
size_t nr_mnt_ids)
5082+
size_t nr_mnt_ids, bool reverse)
50525083
{
50535084
struct path root __free(path_put) = {};
50545085
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
@@ -5080,12 +5111,19 @@ static ssize_t do_listmount(u64 mnt_parent_id, u64 last_mnt_id, u64 *mnt_ids,
50805111
if (ret)
50815112
return ret;
50825113

5083-
if (!last_mnt_id)
5084-
first = node_to_mount(rb_first(&ns->mounts));
5085-
else
5086-
first = mnt_find_id_at(ns, last_mnt_id + 1);
5114+
if (!last_mnt_id) {
5115+
if (reverse)
5116+
first = node_to_mount(rb_last(&ns->mounts));
5117+
else
5118+
first = node_to_mount(rb_first(&ns->mounts));
5119+
} else {
5120+
if (reverse)
5121+
first = mnt_find_id_at_reverse(ns, last_mnt_id - 1);
5122+
else
5123+
first = mnt_find_id_at(ns, last_mnt_id + 1);
5124+
}
50875125

5088-
for (ret = 0, r = first; r && nr_mnt_ids; r = listmnt_next(r)) {
5126+
for (ret = 0, r = first; r && nr_mnt_ids; r = listmnt_next(r, reverse)) {
50895127
if (r->mnt_id_unique == mnt_parent_id)
50905128
continue;
50915129
if (!is_path_reachable(r, r->mnt.mnt_root, &orig))
@@ -5106,7 +5144,7 @@ SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req,
51065144
struct mnt_id_req kreq;
51075145
ssize_t ret;
51085146

5109-
if (flags)
5147+
if (flags & ~LISTMOUNT_REVERSE)
51105148
return -EINVAL;
51115149

51125150
/*
@@ -5130,7 +5168,8 @@ SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req,
51305168
return -ENOMEM;
51315169

51325170
scoped_guard(rwsem_read, &namespace_sem)
5133-
ret = do_listmount(kreq.mnt_id, kreq.param, kmnt_ids, nr_mnt_ids);
5171+
ret = do_listmount(kreq.mnt_id, kreq.param, kmnt_ids,
5172+
nr_mnt_ids, (flags & LISTMOUNT_REVERSE));
51345173

51355174
if (copy_to_user(mnt_ids, kmnt_ids, ret * sizeof(*mnt_ids)))
51365175
return -EFAULT;

include/uapi/linux/mount.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,5 +207,6 @@ struct mnt_id_req {
207207
* Special @mnt_id values that can be passed to listmount
208208
*/
209209
#define LSMT_ROOT 0xffffffffffffffff /* root mount */
210+
#define LISTMOUNT_REVERSE (1 << 0) /* List later mounts first */
210211

211212
#endif /* _UAPI_LINUX_MOUNT_H */

0 commit comments

Comments
 (0)