From b2fc3c686b2af26bd983ffc8f9b09df05bd937e9 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Sun, 22 Feb 2026 14:41:12 -0800 Subject: [PATCH] libfrog: add a function to grab the path from an open fd and a file handle handle_walk_paths operates on a file handle, but requires that the fs has been registered with libhandle via path_to_fshandle. For a normal libhandle client this is the desirable behavior because the application *should* maintain an open fd to the filesystem mount. However for xfs_healer this isn't going to work well because the healer mustn't pin the mount while it's running. It's smart enough to know how to find and reconnect to the mountpoint, but libhandle doesn't have any such concept. Therefore, alter the libfrog getparents code so that xfs_healer can pass in the mountpoint and reconnected fd without needing libhandle. All we're really doing here is trying to obtain a user-visible path for a file that encountered problems for logging purposes; if it fails, we'll fall back to logging the inode number. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- libfrog/getparents.c | 93 +++++++++++++++++++++++++++++++++++++------- libfrog/getparents.h | 4 ++ 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/libfrog/getparents.c b/libfrog/getparents.c index 9118b0ff..e8f54539 100644 --- a/libfrog/getparents.c +++ b/libfrog/getparents.c @@ -112,9 +112,13 @@ out_buf: return ret; } -/* Walk all parent pointers of this handle. Returns 0 or positive errno. */ -int -handle_walk_parents( +/* + * Walk all parent pointers of this handle using the given fd to query the + * filesystem. Returns 0 or positive errno. + */ +static int +handle_walk_parents_fd( + int fd, const void *hanp, size_t hlen, size_t bufsize, @@ -123,21 +127,11 @@ handle_walk_parents( { struct xfs_getparents_by_handle gph = { }; void *buf; - char *mntpt; - int fd; int ret; if (hlen != sizeof(struct xfs_handle)) return EINVAL; - /* - * This function doesn't modify the handle, but we don't want to have - * to bump the libhandle major version just to change that. - */ - fd = handle_to_fsfd((void *)hanp, &mntpt); - if (fd < 0) - return errno; - buf = alloc_records(&gph.gph_request, bufsize); if (!buf) return errno; @@ -158,6 +152,29 @@ out_buf: return ret; } +/* Walk all parent pointers of this handle. Returns 0 or positive errno. */ +int +handle_walk_parents( + const void *hanp, + size_t hlen, + size_t bufsize, + walk_parent_fn fn, + void *arg) +{ + char *mntpt; + int fd; + + /* + * This function doesn't modify the handle, but we don't want to have + * to bump the libhandle major version just to change that. + */ + fd = handle_to_fsfd((void *)hanp, &mntpt); + if (fd < 0) + return errno; + + return handle_walk_parents_fd(fd, hanp, hlen, bufsize, fn, arg); +} + struct walk_ppaths_info { /* Callback */ walk_path_fn fn; @@ -169,7 +186,11 @@ struct walk_ppaths_info { /* Path that we're constructing. */ struct path_list *path; + /* Use this much memory per call. */ size_t ioctl_bufsize; + + /* Use this fd for calling the getparents ioctl. */ + int mntfd; }; /* @@ -200,8 +221,14 @@ find_parent_component( return errno; path_list_add_parent_component(wpi->path, pc); - ret = handle_walk_parents(&rec->p_handle, sizeof(rec->p_handle), - wpi->ioctl_bufsize, find_parent_component, wpi); + if (wpi->mntfd >= 0) + ret = handle_walk_parents_fd(wpi->mntfd, &rec->p_handle, + sizeof(rec->p_handle), wpi->ioctl_bufsize, + find_parent_component, wpi); + else + ret = handle_walk_parents(&rec->p_handle, + sizeof(rec->p_handle), wpi->ioctl_bufsize, + find_parent_component, wpi); path_list_del_component(wpi->path, pc); path_component_free(pc); @@ -222,6 +249,7 @@ handle_walk_paths( { struct walk_ppaths_info wpi = { .ioctl_bufsize = ioctl_bufsize, + .mntfd = -1, }; int ret; @@ -246,6 +274,41 @@ handle_walk_paths( return ret; } +/* + * Call the given function on all known paths from the vfs root to the inode + * described in the handle using an already open mountpoint and fd. Returns 0 + * for success or positive errno. + */ +int +handle_walk_paths_fd( + const char *mntpt, + int mntfd, + const void *hanp, + size_t hlen, + size_t ioctl_bufsize, + walk_path_fn fn, + void *arg) +{ + struct walk_ppaths_info wpi = { + .ioctl_bufsize = ioctl_bufsize, + .mntfd = mntfd, + .mntpt = (char *)mntpt, + }; + int ret; + + wpi.path = path_list_init(); + if (!wpi.path) + return errno; + wpi.fn = fn; + wpi.arg = arg; + + ret = handle_walk_parents_fd(mntfd, hanp, hlen, ioctl_bufsize, + find_parent_component, &wpi); + + path_list_free(wpi.path); + return ret; +} + /* * Call the given function on all known paths from the vfs root to the inode * referred to by the file description. Returns 0 or positive errno. diff --git a/libfrog/getparents.h b/libfrog/getparents.h index 8098d594..e1df3088 100644 --- a/libfrog/getparents.h +++ b/libfrog/getparents.h @@ -39,4 +39,8 @@ int fd_to_path(int fd, size_t ioctl_bufsize, char *path, size_t pathlen); int handle_to_path(const void *hanp, size_t hlen, size_t ioctl_bufsize, char *path, size_t pathlen); +int handle_walk_paths_fd(const char *mntpt, int mntfd, const void *hanp, + size_t hanlen, size_t ioctl_bufsize, walk_path_fn fn, + void *arg); + #endif /* __LIBFROG_GETPARENTS_H_ */ -- 2.47.3