diff options
-rw-r--r-- | contrib/kyua/utils/fs/directory.cpp | 18 | ||||
-rw-r--r-- | crypto/krb5/src/lib/crypto/builtin/aes/aestab.h | 17 | ||||
-rw-r--r-- | include/dirent.h | 3 | ||||
-rw-r--r-- | lib/libarchive/config_freebsd.h | 1 | ||||
-rw-r--r-- | lib/libc/gen/readdir.c | 2 | ||||
-rw-r--r-- | libexec/rc/rc.subr | 4 | ||||
-rw-r--r-- | libexec/rc/tests/rc_subr_test.sh | 29 | ||||
-rw-r--r-- | sys/kern/vfs_inotify.c | 71 | ||||
-rw-r--r-- | usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c | 2 |
9 files changed, 101 insertions, 46 deletions
diff --git a/contrib/kyua/utils/fs/directory.cpp b/contrib/kyua/utils/fs/directory.cpp index f82fe88f86dc..b73741aa544d 100644 --- a/contrib/kyua/utils/fs/directory.cpp +++ b/contrib/kyua/utils/fs/directory.cpp @@ -127,16 +127,9 @@ struct utils::fs::detail::directory_iterator::impl : utils::noncopyable { /// not. A null pointer means an invalid iterator. ::DIR* _dirp; - /// Raw representation of the system directory entry. - /// - /// We need to keep this at the class level so that we can use the - /// readdir_r(3) function. - ::dirent _dirent; - /// Custom representation of the directory entry. /// - /// This is separate from _dirent because this is the type we return to the - /// user. We must keep this as a pointer so that we can support the common + /// We must keep this as a pointer so that we can support the common /// operators (* and ->) over iterators. std::unique_ptr< directory_entry > _entry; @@ -192,22 +185,23 @@ struct utils::fs::detail::directory_iterator::impl : utils::noncopyable { /// It is possible to use this function on a new directory_entry object to /// initialize the first entry. /// - /// \throw system_error If the call to readdir_r fails. + /// \throw system_error If the call to readdir fails. void next(void) { ::dirent* result; - if (::readdir_r(_dirp, &_dirent, &result) == -1) { + errno = 0; + if ((result = ::readdir(_dirp)) == NULL && errno != 0) { const int original_errno = errno; - throw fs::system_error(F("readdir_r(%s) failed") % _path, + throw fs::system_error(F("readdir(%s) failed") % _path, original_errno); } if (result == NULL) { _entry.reset(); close(); } else { - _entry.reset(new directory_entry(_dirent.d_name)); + _entry.reset(new directory_entry(result->d_name)); } } }; diff --git a/crypto/krb5/src/lib/crypto/builtin/aes/aestab.h b/crypto/krb5/src/lib/crypto/builtin/aes/aestab.h index 8fe32d1800d6..87d7097ba0ec 100644 --- a/crypto/krb5/src/lib/crypto/builtin/aes/aestab.h +++ b/crypto/krb5/src/lib/crypto/builtin/aes/aestab.h @@ -86,10 +86,11 @@ extern "C" { # define EXTERN extern #endif +/* Renamed from ALIGN in MIT source to avoid a conflict with machine/param.h */ #if defined(_MSC_VER) && defined(TABLE_ALIGN) -#define ALIGN __declspec(align(TABLE_ALIGN)) +#define AES_ALIGN __declspec(align(TABLE_ALIGN)) #else -#define ALIGN +#define AES_ALIGN #endif #if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) @@ -99,13 +100,13 @@ extern "C" { #endif #if defined(DO_TABLES) && defined(STATIC_TABLES) -#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) -#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } -EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH] = rc_data(w0); +#define d_1(t,n,b,e) EXTERN AES_ALIGN CONST XP_DIR t n[256] = b(e) +#define d_4(t,n,b,e,f,g,h) EXTERN AES_ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } +EXTERN AES_ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH] = rc_data(w0); #else -#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] -#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] -EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH]; +#define d_1(t,n,b,e) EXTERN AES_ALIGN CONST XP_DIR t n[256] +#define d_4(t,n,b,e,f,g,h) EXTERN AES_ALIGN CONST XP_DIR t n[4][256] +EXTERN AES_ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH]; #endif #if defined( SBX_SET ) diff --git a/include/dirent.h b/include/dirent.h index dff0e8675722..7fcdceb10b23 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -116,7 +116,8 @@ DIR *fdopendir(int); struct dirent * readdir(DIR *); #if __POSIX_VISIBLE >= 199506 || __XSI_VISIBLE >= 500 -int readdir_r(DIR *, struct dirent *, struct dirent **); +int readdir_r(DIR *, struct dirent *, struct dirent **) + __deprecated1("Does not take variable {NAME_MAX} into account"); #endif void rewinddir(DIR *); #if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 700 diff --git a/lib/libarchive/config_freebsd.h b/lib/libarchive/config_freebsd.h index a3a0216169bf..1601adddd0de 100644 --- a/lib/libarchive/config_freebsd.h +++ b/lib/libarchive/config_freebsd.h @@ -165,7 +165,6 @@ #define HAVE_POSIX_SPAWNP 1 #define HAVE_PTHREAD_H 1 #define HAVE_PWD_H 1 -#define HAVE_READDIR_R 1 #define HAVE_READLINK 1 #define HAVE_READLINKAT 1 #ifndef __linux__ diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c index b70102954df1..94d2b2e8d877 100644 --- a/lib/libc/gen/readdir.c +++ b/lib/libc/gen/readdir.c @@ -134,3 +134,5 @@ __readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) } __strong_reference(__readdir_r, readdir_r); +__warn_references(readdir_r, + "warning: this program uses readdir_r(), which is unsafe."); diff --git a/libexec/rc/rc.subr b/libexec/rc/rc.subr index a2e2e98a5087..06b1bd51384c 100644 --- a/libexec/rc/rc.subr +++ b/libexec/rc/rc.subr @@ -800,7 +800,7 @@ wait_for_pids() fi _prefix= while true; do - _nlist=""; + _nlist="" for _j in $_list; do if kill -0 $_j 2>/dev/null; then _nlist="${_nlist}${_nlist:+ }$_j" @@ -813,7 +813,7 @@ wait_for_pids() _list=$_nlist echo -n ${_prefix:-"Waiting for PIDS: "}$_list _prefix=", " - pwait $_list 2>/dev/null + pwait -o $_list 2>/dev/null done if [ -n "$_prefix" ]; then echo "." diff --git a/libexec/rc/tests/rc_subr_test.sh b/libexec/rc/tests/rc_subr_test.sh index 9931389e7a02..fe6d3b8264c9 100644 --- a/libexec/rc/tests/rc_subr_test.sh +++ b/libexec/rc/tests/rc_subr_test.sh @@ -1,7 +1,8 @@ +#- +# SPDX-License-Identifier: BSD-2-Clause # # Copyright 2022 Mateusz Piotrowski <0mp@FreeBSD.org> -# -# SPDX-License-Identifier: BSD-2-Clause +# Copyright (c) 2025 Klara, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -104,8 +105,32 @@ oomprotect_yes_body() /bin/sh "$__script" "$__name" "$__pidfile" onestop } +atf_test_case wait_for_pids_progress +wait_for_pids_progress_head() +{ + atf_set "descr" "Verify that wait_for_pids prints progress updates" +} +wait_for_pids_progress_body() +{ + cat >>script <<'EOF' +. /etc/rc.subr +sleep 15 & +a=$! +sleep 10 & +b=$! +sleep 5 & +c=$! +wait_for_pids $a $b $c +EOF + re="^Waiting for PIDS: [0-9]+ [0-9]+ [0-9]+" + re="${re}, [0-9]+ [0-9]+" + re="${re}, [0-9]+\.$" + atf_check -s exit:0 -o match:"${re}" /bin/sh script +} + atf_init_test_cases() { atf_add_test_case oomprotect_all atf_add_test_case oomprotect_yes + atf_add_test_case wait_for_pids_progress } diff --git a/sys/kern/vfs_inotify.c b/sys/kern/vfs_inotify.c index d3cd0d1f9832..746a5a39208e 100644 --- a/sys/kern/vfs_inotify.c +++ b/sys/kern/vfs_inotify.c @@ -34,6 +34,7 @@ #include <sys/sysent.h> #include <sys/syslimits.h> #include <sys/sysproto.h> +#include <sys/taskqueue.h> #include <sys/tree.h> #include <sys/user.h> #include <sys/vnode.h> @@ -168,6 +169,8 @@ struct inotify_softc { size_t nbpending; /* bytes available to read */ uint64_t ino; /* unique identifier */ struct inotify_watch_tree watches; /* active watches */ + TAILQ_HEAD(, inotify_watch) deadwatches; /* watches pending vrele() */ + struct task reaptask; /* task to reap dead watches */ struct selinfo sel; /* select/poll/kevent info */ struct ucred *cred; /* credential ref */ }; @@ -374,6 +377,13 @@ inotify_unlink_watch_locked(struct inotify_softc *sc, struct inotify_watch *watc vn_irflag_unset(vp, VIRF_INOTIFY); } +static void +inotify_free_watch(struct inotify_watch *watch) +{ + vrele(watch->vp); + free(watch, M_INOTIFY); +} + /* * Assumes that the watch has already been removed from its softc. */ @@ -389,9 +399,24 @@ inotify_remove_watch(struct inotify_watch *watch) mtx_lock(&vp->v_pollinfo->vpi_lock); inotify_unlink_watch_locked(sc, watch); mtx_unlock(&vp->v_pollinfo->vpi_lock); + inotify_free_watch(watch); +} - vrele(vp); - free(watch, M_INOTIFY); +static void +inotify_reap(void *arg, int pending) +{ + struct inotify_softc *sc; + struct inotify_watch *watch; + + sc = arg; + mtx_lock(&sc->lock); + while ((watch = TAILQ_FIRST(&sc->deadwatches)) != NULL) { + TAILQ_REMOVE(&sc->deadwatches, watch, vlink); + mtx_unlock(&sc->lock); + inotify_free_watch(watch); + mtx_lock(&sc->lock); + } + mtx_unlock(&sc->lock); } static int @@ -403,6 +428,7 @@ inotify_close(struct file *fp, struct thread *td) sc = fp->f_data; + /* Detach watches from their vnodes. */ mtx_lock(&sc->lock); (void)chginotifycnt(sc->cred->cr_ruidinfo, -1, 0); while ((watch = RB_MIN(inotify_watch_tree, &sc->watches)) != NULL) { @@ -411,6 +437,17 @@ inotify_close(struct file *fp, struct thread *td) inotify_remove_watch(watch); mtx_lock(&sc->lock); } + + /* Make sure that any asynchronous vrele() calls are done. */ + mtx_unlock(&sc->lock); + taskqueue_drain(taskqueue_thread, &sc->reaptask); + mtx_lock(&sc->lock); + KASSERT(RB_EMPTY(&sc->watches), + ("%s: watches not empty in %p", __func__, sc)); + KASSERT(TAILQ_EMPTY(&sc->deadwatches), + ("%s: deadwatches not empty in %p", __func__, sc)); + + /* Drop pending events. */ while (!STAILQ_EMPTY(&sc->pending)) { rec = inotify_dequeue(sc); if (rec != &sc->overflow) @@ -456,6 +493,8 @@ inotify_create_file(struct thread *td, struct file *fp, int flags, int *fflagsp) sc->nextwatch = 1; /* Required for compatibility. */ STAILQ_INIT(&sc->pending); RB_INIT(&sc->watches); + TAILQ_INIT(&sc->deadwatches); + TASK_INIT(&sc->reaptask, 0, inotify_reap, sc); mtx_init(&sc->lock, "inotify", NULL, MTX_DEF); knlist_init_mtx(&sc->sel.si_note, &sc->lock); sc->cred = crhold(td->td_ucred); @@ -560,17 +599,16 @@ inotify_queue_record(struct inotify_softc *sc, struct inotify_record *rec) return (true); } -static int +static void inotify_log_one(struct inotify_watch *watch, const char *name, size_t namelen, int event, uint32_t cookie) { struct inotify_watch key; struct inotify_softc *sc; struct inotify_record *rec; - int relecount; bool allocfail; - relecount = 0; + mtx_assert(&watch->vp->v_pollinfo->vpi_lock, MA_OWNED); sc = watch->sc; rec = inotify_alloc_record(watch->wd, name, namelen, event, cookie, @@ -599,20 +637,22 @@ inotify_log_one(struct inotify_watch *watch, const char *name, size_t namelen, /* * Remove the watch, taking care to handle races with - * inotify_close(). + * inotify_close(). The thread that removes the watch is + * responsible for freeing it. */ key.wd = watch->wd; if (RB_FIND(inotify_watch_tree, &sc->watches, &key) != NULL) { RB_REMOVE(inotify_watch_tree, &sc->watches, watch); inotify_unlink_watch_locked(sc, watch); - free(watch, M_INOTIFY); - /* Defer vrele() to until locks are dropped. */ - relecount++; + /* + * Defer the vrele() to a sleepable thread context. + */ + TAILQ_INSERT_TAIL(&sc->deadwatches, watch, vlink); + taskqueue_enqueue(taskqueue_thread, &sc->reaptask); } } mtx_unlock(&sc->lock); - return (relecount); } void @@ -620,25 +660,18 @@ inotify_log(struct vnode *vp, const char *name, size_t namelen, int event, uint32_t cookie) { struct inotify_watch *watch, *tmp; - int relecount; KASSERT((event & ~(IN_ALL_EVENTS | IN_ISDIR | IN_UNMOUNT)) == 0, ("inotify_log: invalid event %#x", event)); - relecount = 0; mtx_lock(&vp->v_pollinfo->vpi_lock); TAILQ_FOREACH_SAFE(watch, &vp->v_pollinfo->vpi_inotify, vlink, tmp) { KASSERT(watch->vp == vp, ("inotify_log: watch %p vp != vp", watch)); - if ((watch->mask & event) != 0 || event == IN_UNMOUNT) { - relecount += inotify_log_one(watch, name, namelen, event, - cookie); - } + if ((watch->mask & event) != 0 || event == IN_UNMOUNT) + inotify_log_one(watch, name, namelen, event, cookie); } mtx_unlock(&vp->v_pollinfo->vpi_lock); - - for (int i = 0; i < relecount; i++) - vrele(vp); } /* diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c index 8b7e4608d673..f7484e90189b 100644 --- a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c +++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c @@ -372,7 +372,7 @@ swins_get_packages(void) } if (errno != 0) { - syslog(LOG_ERR, "hrSWInstalledTable: readdir_r(\"%s\") failed:" + syslog(LOG_ERR, "hrSWInstalledTable: readdir(\"%s\") failed:" " %m", pkg_dir); ret = -1; } else { |