Date: Mon, 10 Aug 2026 16:15:15 +0000 From: "Alan Somers" <asomers@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: "Jitendra Bhati" <bhatijitendra2022@gmail.com> Subject: git: dd532ad13371 - main - fts: reduce fd usage by storing fts_dirfd on directory entries only Message-ID: <6a79f913.370c9.29e788fe@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=dd532ad13371dcabc07d05052a7a256fc83c6ead commit dd532ad13371dcabc07d05052a7a256fc83c6ead Author: Jitendra Bhati <bhatijitendra2022@gmail.com> AuthorDate: 2026-08-08 00:31:09 +0000 Commit: Alan Somers <asomers@FreeBSD.org> CommitDate: 2026-08-10 16:14:16 +0000 fts: reduce fd usage by storing fts_dirfd on directory entries only Previously fts_build() called _dup(_dirfd(dirp)) for every child entry, holding N simultaneous fds for a directory with N children. Redefine fts_dirfd: instead of a fd for the entry's parent directory, it is now a fd for the entry itself, set only for directory entries. One dup per directory in fts_build() instead of one per child. Close fts_dirfd during the directory post-order visit, before advancing to its sibling. To access a file using fd-relative operations, callers should use openat(ent->fts_parent->fts_dirfd, ent->fts_name, ...) instead of openat(ent->fts_dirfd, ent->fts_name, ...). The fd is valid until the directory's post-order visit (FTS_DP). Reported by: Mark Johnston <markj@FreeBSD.org> Fixes: 4bd01d6ae016 (fts: refactor to use fd-relative operations) Sponsored by: Google LLC (GSoC 2026) Reviewed by: asomers Pull Request: https://github.com/freebsd/freebsd-src/pull/2360 --- include/fts.h | 2 +- lib/libc/gen/fts.3 | 32 +++++++++++++++++++------------- lib/libc/gen/fts.c | 23 ++++++++++++++--------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/include/fts.h b/include/fts.h index 0308b8ff880b..7d01b7a195c7 100644 --- a/include/fts.h +++ b/include/fts.h @@ -92,7 +92,7 @@ struct _ftsent { char *fts_path; /* root path */ int fts_errno; /* errno for this node */ int fts_symfd; /* fd for symlink */ - int fts_dirfd; /* fd for parent directory */ + int fts_dirfd; /* fd for this directory, if a directory */ int __fts_reserved[3]; /* reserved for future use */ __size_t fts_pathlen; /* strlen(fts_path) */ __size_t fts_namelen; /* strlen(fts_name) */ diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3 index d24eb58bb438..eb204a0dd3ac 100644 --- a/lib/libc/gen/fts.3 +++ b/lib/libc/gen/fts.3 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 7, 2026 +.Dd August 9, 2026 .Dt FTS 3 .Os .Sh NAME @@ -316,9 +316,10 @@ file is a member. A parent structure for the initial entry point is provided as well, however, only the .Fa fts_level , -.Fa fts_number -and +.Fa fts_number , .Fa fts_pointer +and +.Fa fts_dirfd fields are guaranteed to be initialized. .It Fa fts_link Upon return from the @@ -350,19 +351,24 @@ A pointer to .Xr stat 2 information for the file. .It Fa fts_dirfd -A file descriptor open on the parent directory of this entry. -It may be used with +A file descriptor open on this directory entry. +It is set only for directory entries +.Pq Dv FTS_D +and is \-1 for all other entry types. +To access a file using fd-relative operations without relying +on path-based syscalls, required in +.Xr capsicum 4 +capability mode, use +.Fa fts_parent->fts_dirfd +with .Xr openat 2 and -.Fa fts_name -to access the file without relying on path-based operations, -which is required in -.Xr capsicum 4 -capability mode. -The descriptor is valid only until the next call to -.Fn fts_read +.Fa fts_name . +The descriptor is valid until the directory's post-order visit +.Pq Dv FTS_DP and must not be closed by the caller. -For root-level entries, +For root-level entries opened with +.Fn fts_open , .Fa fts_dirfd is \-1. .El diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index 5f56d169e076..e388fce550b9 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -443,8 +443,8 @@ fts_read(FTS *sp) (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { p->fts_info = fts_stat(sp, p, 1, -1); if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { - if ((p->fts_symfd = p->fts_dirfd >= 0 ? - _dup(p->fts_dirfd) : + if ((p->fts_symfd = p->fts_parent->fts_dirfd >= 0 ? + _dup(p->fts_parent->fts_dirfd) : _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) { p->fts_errno = errno; p->fts_info = FTS_ERR; @@ -509,6 +509,10 @@ fts_read(FTS *sp) /* Move to the next node on this level. */ next: tmp = p; + if (tmp->fts_dirfd >= 0 && tmp->fts_info == FTS_DP) { + (void)_close(tmp->fts_dirfd); + tmp->fts_dirfd = -1; + } if ((p = p->fts_link) != NULL) { /* * If reached the top, return to the original directory (or @@ -537,8 +541,8 @@ next: tmp = p; p->fts_info = fts_stat(sp, p, 1, -1); if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { if ((p->fts_symfd = - p->fts_dirfd >= 0 ? - _dup(p->fts_dirfd) : + p->fts_parent->fts_dirfd >= 0 ? + _dup(p->fts_parent->fts_dirfd) : _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) { p->fts_errno = errno; p->fts_info = FTS_ERR; @@ -680,8 +684,8 @@ fts_children(FTS *sp, int instr) ISSET(FTS_NOCHDIR)) return (sp->fts_child = fts_build(sp, instr)); - if ((fd = sp->fts_cur->fts_dirfd >= 0 ? - _dup(sp->fts_cur->fts_dirfd) : + if ((fd = sp->fts_cur->fts_parent->fts_dirfd >= 0 ? + _dup(sp->fts_cur->fts_parent->fts_dirfd) : _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) return (NULL); sp->fts_child = fts_build(sp, instr); @@ -783,6 +787,8 @@ fts_build(FTS *sp, int type) return (NULL); } + cur->fts_dirfd = _dup(_dirfd(dirp)); + /* * In the FTS_PHYSICAL | FTS_NOSTAT case, we want to avoid calling * fstat() unnecessarily, but we still need to call it for @@ -918,7 +924,6 @@ mem1: saved_errno = errno; } p->fts_level = level; - p->fts_dirfd = _dup(_dirfd(dirp)); p->fts_parent = sp->fts_cur; p->fts_pathlen = len + dnamlen; @@ -1337,8 +1342,8 @@ fts_ufslinks(FTS *sp, const FTSENT *ent) * avoidance. */ if (priv->ftsp_dev != ent->fts_dev) { - if ((ent->fts_dirfd >= 0 ? - _fstatfs(ent->fts_dirfd, &priv->ftsp_statfs) : + if ((ent->fts_parent->fts_dirfd >= 0 ? + _fstatfs(ent->fts_parent->fts_dirfd, &priv->ftsp_statfs) : statfs(ent->fts_path, &priv->ftsp_statfs)) != -1) { priv->ftsp_dev = ent->fts_dev; priv->ftsp_linksreliable = 0;home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a79f913.370c9.29e788fe>
