From 5ae34d8bf9cf02fe2b70abbf996caf94cf78e615 Mon Sep 17 00:00:00 2001 From: Kuan-Ying Lee Date: Fri, 18 Oct 2024 18:46:18 +0800 Subject: [PATCH 1/2] drgn.helpers.linux.kernfs: Add kernfs_children helper Add kernfs_children() to iterate all kernfs_node in children rb_tree. Signed-off-by: Kuan-Ying Lee --- drgn/helpers/linux/kernfs.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drgn/helpers/linux/kernfs.py b/drgn/helpers/linux/kernfs.py index b60c958f3..b2e4500f1 100644 --- a/drgn/helpers/linux/kernfs.py +++ b/drgn/helpers/linux/kernfs.py @@ -10,6 +10,7 @@ """ import os +from typing import Iterator from drgn import NULL, Object, Path from drgn.helpers.linux.rbtree import rbtree_inorder_for_each_entry @@ -18,6 +19,7 @@ "kernfs_name", "kernfs_path", "kernfs_walk", + "kernfs_children", ) @@ -86,3 +88,16 @@ def kernfs_walk(parent: Object, path: Path) -> Object: else: return NULL(parent.prog_, kernfs_nodep_type) return parent + + +def kernfs_children(kn: Object) -> Iterator[Object]: + """ + Iterate over the children of a directory in kernfs. + + :param parent: ``struct kernfs_node *`` + :return: Iterator of ``struct kernfs_node *``. + """ + for child in rbtree_inorder_for_each_entry( + "struct kernfs_node", kn.dir.children.address_of_(), "rb" + ): + yield child From b3c243542639e79942b517f70c1c6debbb1362ff Mon Sep 17 00:00:00 2001 From: Kuan-Ying Lee Date: Fri, 18 Oct 2024 18:53:41 +0800 Subject: [PATCH 2/2] drgn.helpers.linux.kernfs: Add follow_symlinks support Extend kernfs_walk() to support symlink. Signed-off-by: Kuan-Ying Lee --- drgn/helpers/linux/kernfs.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drgn/helpers/linux/kernfs.py b/drgn/helpers/linux/kernfs.py index b2e4500f1..8bce7ee3c 100644 --- a/drgn/helpers/linux/kernfs.py +++ b/drgn/helpers/linux/kernfs.py @@ -63,23 +63,24 @@ def kernfs_path(kn: Object) -> bytes: return b"/".join(names) -def kernfs_walk(parent: Object, path: Path) -> Object: +def kernfs_walk(parent: Object, path: Path, follow_symlinks: bool = False) -> Object: """ Find the kernfs node with the given path from the given parent kernfs node. :param parent: ``struct kernfs_node *`` :param path: Path name. + :param follow_symlinks: If follow_symlinks is ``False``, and the + last component of a path is a symlink, the function will + return ``struct kernfs_node *`` of the symbolic link. :return: ``struct kernfs_node *`` (``NULL`` if not found) """ kernfs_nodep_type = parent.type_ - kernfs_node_type = kernfs_nodep_type.type + link_flag = parent.prog_.constant("KERNFS_LINK") for name in os.fsencode(path).split(b"/"): if not name: continue - for parent in rbtree_inorder_for_each_entry( - kernfs_node_type, parent.dir.children.address_of_(), "rb" - ): + for parent in kernfs_children(parent): if ( parent.name.string_() == name and not parent.ns # For now, we don't bother with namespaced kernfs nodes. @@ -87,6 +88,8 @@ def kernfs_walk(parent: Object, path: Path) -> Object: break else: return NULL(parent.prog_, kernfs_nodep_type) + if parent.flags & link_flag and follow_symlinks: + parent = parent.symlink.target_kn return parent