From nobody Mon Aug 10 16:15:15 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hJfx130Vqz6p1Cy for ; Mon, 10 Aug 2026 16:15:17 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hJfx03hNbz3sll for ; Mon, 10 Aug 2026 16:15:16 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786378516; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=UYVLXGt1oHOUFOEApsoNFF493OPiBegQGtM7zE9uFwM=; b=w8M1o7WJQWiQBdHZQ37+ILjSotTvuZhfh5XS51RkkMDTabLezBs2n7xlNSxBKH3p3ToEoa L/0OAKXfXtw/SxyDwbJ/R4rpfoXwMS3YeZ3oipvjSxmr+LMuKCmqsD4fdbB7KYx1aZrppn EQIKbs1EAGrrq5yXf81vd1bEgiX6NcDibYDBzrF7vyP54wU+rvKkK83a3FyBhTPvsJd4n2 Idw3jnjhV8bcDBVQZaTjLE2wNwSkP7FAV68rgifUnErBQ5c+haXMNY8103ROBORnld6BRd Sru8Nq0YcW5QO1xhM+A5L3gh9iLtJkykW3js9wWj4mbrxvqpTb8lRYrrzgyQ5A== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1786378516; a=rsa-sha256; cv=none; b=KIDME2BEjc5M+/h8BwnjwQsZSvtS+2obtElUDBjglLtadsZ8fLC45VHnYDF+XbVinTH7BL 3gshlh4X5AUH2Vxulfe/1xF2t8GjcryUuohBGzLrIwkSQMj25PNG7JK9s4DHlUlPRPvUFr DSDhplA2ZuKXGMMAt0JwRBn/voeyw4efFaJE9vpwqMBjL0u0P+jUOyrEOYiZOoYOGe2qu1 W2S+PEOBCKRudgf2PQQZzSGSOGiSMkdetAtlwcEV7tRxDhjnCWP3fyF3peDic1vrPst7i2 cNxXe6Tc5ZD3lTvAr1xmxMtcUb5XgRI6S57JK2+sInnomW6BdYBedLb/Jep3hg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786378516; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=UYVLXGt1oHOUFOEApsoNFF493OPiBegQGtM7zE9uFwM=; b=Zjyc4abyJ+JXdwDt2aK5WLNeiZVUnZDwnp4c4IQKko35OGeCZQ7GPKgQWi0VQfIu9l9fHr 9E9xDzRyJJeBIULTadQu5Nprz27ewVE1/2RtjcZugkdSRz2ln5DDVfyxsWkuDaqwdchRq6 +ZTX2xrX86Vz/DgFm+RfIhDKIjqt6lBfAV+qCzFXbHslTz3vv7IzXYLTgajM9YZYAtQTX4 /J/wFhCOlZiyLOiB5ei5/DrOkmVGxBWhurnVt5xl1yIiPpjJHyk/NOUc+hAoFsqoaqauiI x8wtX+vprpENOvFMPK7aMv2slKBNboN8SbbGgnDD/3r7JyFjmlgYcyP3YPbHog== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hJfwz6tjjz1yJ for ; Mon, 10 Aug 2026 16:15:15 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 370c9 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 10 Aug 2026 16:15:15 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Jitendra Bhati From: Alan Somers Subject: git: dd532ad13371 - main - fts: reduce fd usage by storing fts_dirfd on directory entries only List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: asomers X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: dd532ad13371dcabc07d05052a7a256fc83c6ead Auto-Submitted: auto-generated Date: Mon, 10 Aug 2026 16:15:15 +0000 Message-Id: <6a79f913.370c9.29e788fe@gitrepo.freebsd.org> The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=dd532ad13371dcabc07d05052a7a256fc83c6ead commit dd532ad13371dcabc07d05052a7a256fc83c6ead Author: Jitendra Bhati AuthorDate: 2026-08-08 00:31:09 +0000 Commit: Alan Somers 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 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;