aboutsummaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/imgact_elf.c12
-rw-r--r--sys/kern/kern_descrip.c55
-rw-r--r--sys/kern/kern_devctl.c1
-rw-r--r--sys/kern/kern_event.c267
-rw-r--r--sys/kern/kern_exit.c2
-rw-r--r--sys/kern/kern_fork.c2
-rw-r--r--sys/kern/kern_jaildesc.c1
-rw-r--r--sys/kern/kern_malloc.c2
-rw-r--r--sys/kern/kern_sig.c1
-rw-r--r--sys/kern/subr_devstat.c2
-rw-r--r--sys/kern/subr_log.c1
-rw-r--r--sys/kern/subr_prf.c2
-rw-r--r--sys/kern/sys_eventfd.c7
-rw-r--r--sys/kern/sys_pipe.c5
-rw-r--r--sys/kern/sys_procdesc.c1
-rw-r--r--sys/kern/tty.c2
-rw-r--r--sys/kern/tty_pts.c2
-rw-r--r--sys/kern/uipc_mqueue.c2
-rw-r--r--sys/kern/uipc_socket.c3
-rw-r--r--sys/kern/uipc_usrreq.c22
-rw-r--r--sys/kern/vfs_aio.c4
-rw-r--r--sys/kern/vfs_inotify.c1
-rw-r--r--sys/kern/vfs_subr.c15
23 files changed, 355 insertions, 57 deletions
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index c53707a1286c..779158b41221 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -231,7 +231,7 @@ static const Elf_Brandinfo *elf_brand_list[MAX_BRANDS];
#define aligned(a, t) (rounddown2((u_long)(a), sizeof(t)) == (u_long)(a))
-Elf_Brandnote __elfN(freebsd_brandnote) = {
+const Elf_Brandnote __elfN(freebsd_brandnote) = {
.hdr.n_namesz = sizeof(FREEBSD_ABI_VENDOR),
.hdr.n_descsz = sizeof(int32_t),
.hdr.n_type = NT_FREEBSD_ABI_TAG,
@@ -254,7 +254,7 @@ __elfN(freebsd_trans_osrel)(const Elf_Note *note, int32_t *osrel)
static int GNU_KFREEBSD_ABI_DESC = 3;
-Elf_Brandnote __elfN(kfreebsd_brandnote) = {
+const Elf_Brandnote __elfN(kfreebsd_brandnote) = {
.hdr.n_namesz = sizeof(GNU_ABI_VENDOR),
.hdr.n_descsz = 16, /* XXX at least 16 */
.hdr.n_type = 1,
@@ -2831,7 +2831,7 @@ __elfN(parse_notes)(const struct image_params *imgp, const Elf_Note *checknote,
}
if ((const char *)note_end - (const char *)note <
sizeof(Elf_Note)) {
- uprintf("ELF note to short\n");
+ uprintf("ELF note too short\n");
goto retf;
}
if (note->n_namesz != checknote->n_namesz ||
@@ -2839,9 +2839,9 @@ __elfN(parse_notes)(const struct image_params *imgp, const Elf_Note *checknote,
note->n_type != checknote->n_type)
goto nextnote;
note_name = (const char *)(note + 1);
- if (note_name + checknote->n_namesz >=
- (const char *)note_end || strncmp(note_vendor,
- note_name, checknote->n_namesz) != 0)
+ if (note_name + roundup2(note->n_namesz, ELF_NOTE_ROUNDSIZE) +
+ note->n_descsz >= (const char *)note_end ||
+ strncmp(note_vendor, note_name, checknote->n_namesz) != 0)
goto nextnote;
if (cb(note, cb_arg, &res))
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 19118eb7f275..a71a601733e5 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -2486,7 +2486,7 @@ fdunshare(struct thread *td)
if (refcount_load(&p->p_fd->fd_refcnt) == 1)
return;
- tmp = fdcopy(p->p_fd);
+ tmp = fdcopy(p->p_fd, p);
fdescfree(td);
p->p_fd = tmp;
}
@@ -2515,14 +2515,17 @@ pdunshare(struct thread *td)
* this is to ease callers, not catch errors.
*/
struct filedesc *
-fdcopy(struct filedesc *fdp)
+fdcopy(struct filedesc *fdp, struct proc *p1)
{
struct filedesc *newfdp;
struct filedescent *nfde, *ofde;
+ struct file *fp;
int i, lastfile;
+ bool fork_pass;
MPASS(fdp != NULL);
+ fork_pass = false;
newfdp = fdinit();
FILEDESC_SLOCK(fdp);
for (;;) {
@@ -2533,10 +2536,35 @@ fdcopy(struct filedesc *fdp)
fdgrowtable(newfdp, lastfile + 1);
FILEDESC_SLOCK(fdp);
}
- /* copy all passable descriptors (i.e. not kqueue) */
+
+ /*
+ * Copy all passable descriptors (i.e. not kqueue), and
+ * prepare to handle copyable but not passable descriptors
+ * (kqueues).
+ *
+ * The pass to handle copying is performed after all passable
+ * files are installed into the new file descriptor's table,
+ * since kqueues need all referenced file descriptors already
+ * valid, including other kqueues. For the same reason the
+ * copying is done in two passes by itself, first installing
+ * not fully initialized ('empty') copyable files into the new
+ * fd table, and then giving the subsystems a second chance to
+ * really fill the copied file backing structure with the
+ * content.
+ */
newfdp->fd_freefile = fdp->fd_freefile;
FILEDESC_FOREACH_FDE(fdp, i, ofde) {
- if ((ofde->fde_file->f_ops->fo_flags & DFLAG_PASSABLE) == 0 ||
+ const struct fileops *ops;
+
+ ops = ofde->fde_file->f_ops;
+ fp = NULL;
+ if ((ops->fo_flags & DFLAG_FORK) != 0 &&
+ (ofde->fde_flags & UF_FOCLOSE) == 0) {
+ if (ops->fo_fork(newfdp, ofde->fde_file, &fp, p1,
+ curthread) != 0)
+ continue;
+ fork_pass = true;
+ } else if ((ops->fo_flags & DFLAG_PASSABLE) == 0 ||
(ofde->fde_flags & UF_FOCLOSE) != 0 ||
!fhold(ofde->fde_file)) {
if (newfdp->fd_freefile == fdp->fd_freefile)
@@ -2545,11 +2573,30 @@ fdcopy(struct filedesc *fdp)
}
nfde = &newfdp->fd_ofiles[i];
*nfde = *ofde;
+ if (fp != NULL)
+ nfde->fde_file = fp;
filecaps_copy(&ofde->fde_caps, &nfde->fde_caps, true);
fdused_init(newfdp, i);
}
MPASS(newfdp->fd_freefile != -1);
FILEDESC_SUNLOCK(fdp);
+
+ /*
+ * Now handle copying kqueues, since all fds, including
+ * kqueues, are in place.
+ */
+ if (__predict_false(fork_pass)) {
+ FILEDESC_FOREACH_FDE(newfdp, i, nfde) {
+ const struct fileops *ops;
+
+ ops = nfde->fde_file->f_ops;
+ if ((ops->fo_flags & DFLAG_FORK) == 0 ||
+ nfde->fde_file == NULL)
+ continue;
+ ops->fo_fork(newfdp, NULL, &nfde->fde_file, p1,
+ curthread);
+ }
+ }
return (newfdp);
}
diff --git a/sys/kern/kern_devctl.c b/sys/kern/kern_devctl.c
index a1696225df32..a37cb23efed8 100644
--- a/sys/kern/kern_devctl.c
+++ b/sys/kern/kern_devctl.c
@@ -130,6 +130,7 @@ static const struct filterops devctl_rfiltops = {
.f_isfd = 1,
.f_detach = filt_devctl_detach,
.f_event = filt_devctl_read,
+ .f_copy = knote_triv_copy,
};
static struct cdev *devctl_dev;
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index a6333d8011b1..1baa24d278bf 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -134,6 +134,7 @@ static fo_kqfilter_t kqueue_kqfilter;
static fo_stat_t kqueue_stat;
static fo_close_t kqueue_close;
static fo_fill_kinfo_t kqueue_fill_kinfo;
+static fo_fork_t kqueue_fork;
static const struct fileops kqueueops = {
.fo_read = invfo_rdwr,
@@ -148,7 +149,9 @@ static const struct fileops kqueueops = {
.fo_chown = invfo_chown,
.fo_sendfile = invfo_sendfile,
.fo_cmp = file_kcmp_generic,
+ .fo_fork = kqueue_fork,
.fo_fill_kinfo = kqueue_fill_kinfo,
+ .fo_flags = DFLAG_FORK,
};
static int knote_attach(struct knote *kn, struct kqueue *kq);
@@ -176,6 +179,7 @@ static void filt_timerdetach(struct knote *kn);
static void filt_timerstart(struct knote *kn, sbintime_t to);
static void filt_timertouch(struct knote *kn, struct kevent *kev,
u_long type);
+static int filt_timercopy(struct knote *kn, struct proc *p1);
static int filt_timervalidate(struct knote *kn, sbintime_t *to);
static int filt_timer(struct knote *kn, long hint);
static int filt_userattach(struct knote *kn);
@@ -187,11 +191,13 @@ static void filt_usertouch(struct knote *kn, struct kevent *kev,
static const struct filterops file_filtops = {
.f_isfd = 1,
.f_attach = filt_fileattach,
+ .f_copy = knote_triv_copy,
};
static const struct filterops kqread_filtops = {
.f_isfd = 1,
.f_detach = filt_kqdetach,
.f_event = filt_kqueue,
+ .f_copy = knote_triv_copy,
};
/* XXX - move to kern_proc.c? */
static const struct filterops proc_filtops = {
@@ -199,12 +205,14 @@ static const struct filterops proc_filtops = {
.f_attach = filt_procattach,
.f_detach = filt_procdetach,
.f_event = filt_proc,
+ .f_copy = knote_triv_copy,
};
static const struct filterops jail_filtops = {
.f_isfd = 0,
.f_attach = filt_jailattach,
.f_detach = filt_jaildetach,
.f_event = filt_jail,
+ .f_copy = knote_triv_copy,
};
static const struct filterops timer_filtops = {
.f_isfd = 0,
@@ -212,12 +220,14 @@ static const struct filterops timer_filtops = {
.f_detach = filt_timerdetach,
.f_event = filt_timer,
.f_touch = filt_timertouch,
+ .f_copy = filt_timercopy,
};
static const struct filterops user_filtops = {
.f_attach = filt_userattach,
.f_detach = filt_userdetach,
.f_event = filt_user,
.f_touch = filt_usertouch,
+ .f_copy = knote_triv_copy,
};
static uma_zone_t knote_zone;
@@ -347,6 +357,7 @@ filt_nullattach(struct knote *kn)
static const struct filterops null_filtops = {
.f_isfd = 0,
.f_attach = filt_nullattach,
+ .f_copy = knote_triv_copy,
};
/* XXX - make SYSINIT to add these, and move into respective modules. */
@@ -940,6 +951,30 @@ filt_timerattach(struct knote *kn)
return (0);
}
+static int
+filt_timercopy(struct knote *kn, struct proc *p)
+{
+ struct kq_timer_cb_data *kc_src, *kc;
+
+ if (atomic_fetchadd_int(&kq_ncallouts, 1) + 1 > kq_calloutmax) {
+ atomic_subtract_int(&kq_ncallouts, 1);
+ return (ENOMEM);
+ }
+
+ kn->kn_status &= ~KN_DETACHED;
+ kc_src = kn->kn_ptr.p_v;
+ kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK);
+ kc->kn = kn;
+ kc->p = p;
+ kc->flags = kc_src->flags & ~KQ_TIMER_CB_ENQUEUED;
+ kc->next = kc_src->next;
+ kc->to = kc_src->to;
+ kc->cpuid = PCPU_GET(cpuid);
+ callout_init(&kc->c, 1);
+ kqtimer_sched_callout(kc);
+ return (0);
+}
+
static void
filt_timerstart(struct knote *kn, sbintime_t to)
{
@@ -1151,7 +1186,7 @@ int
sys_kqueue(struct thread *td, struct kqueue_args *uap)
{
- return (kern_kqueue(td, 0, NULL));
+ return (kern_kqueue(td, 0, false, NULL));
}
int
@@ -1159,55 +1194,76 @@ sys_kqueuex(struct thread *td, struct kqueuex_args *uap)
{
int flags;
- if ((uap->flags & ~(KQUEUE_CLOEXEC)) != 0)
+ if ((uap->flags & ~(KQUEUE_CLOEXEC | KQUEUE_CPONFORK)) != 0)
return (EINVAL);
flags = 0;
if ((uap->flags & KQUEUE_CLOEXEC) != 0)
flags |= O_CLOEXEC;
- return (kern_kqueue(td, flags, NULL));
+ return (kern_kqueue(td, flags, (uap->flags & KQUEUE_CPONFORK) != 0,
+ NULL));
}
static void
-kqueue_init(struct kqueue *kq)
+kqueue_init(struct kqueue *kq, bool cponfork)
{
mtx_init(&kq->kq_lock, "kqueue", NULL, MTX_DEF | MTX_DUPOK);
TAILQ_INIT(&kq->kq_head);
knlist_init_mtx(&kq->kq_sel.si_note, &kq->kq_lock);
TASK_INIT(&kq->kq_task, 0, kqueue_task, kq);
+ if (cponfork)
+ kq->kq_state |= KQ_CPONFORK;
}
-int
-kern_kqueue(struct thread *td, int flags, struct filecaps *fcaps)
+static int
+kern_kqueue_alloc(struct thread *td, struct filedesc *fdp, int *fdip,
+ struct file **fpp, int flags, struct filecaps *fcaps, bool cponfork,
+ struct kqueue **kqp)
{
- struct filedesc *fdp;
- struct kqueue *kq;
- struct file *fp;
struct ucred *cred;
- int fd, error;
+ struct kqueue *kq;
+ int error;
- fdp = td->td_proc->p_fd;
cred = td->td_ucred;
if (!chgkqcnt(cred->cr_ruidinfo, 1, lim_cur(td, RLIMIT_KQUEUES)))
return (ENOMEM);
- error = falloc_caps(td, &fp, &fd, flags, fcaps);
+ error = fdip != NULL ? falloc_caps(td, fpp, fdip, flags, fcaps) :
+ _falloc_noinstall(td, fpp, 1);
if (error != 0) {
chgkqcnt(cred->cr_ruidinfo, -1, 0);
return (error);
}
/* An extra reference on `fp' has been held for us by falloc(). */
- kq = malloc(sizeof *kq, M_KQUEUE, M_WAITOK | M_ZERO);
- kqueue_init(kq);
+ kq = malloc(sizeof(*kq), M_KQUEUE, M_WAITOK | M_ZERO);
+ kqueue_init(kq, cponfork);
kq->kq_fdp = fdp;
kq->kq_cred = crhold(cred);
- FILEDESC_XLOCK(fdp);
+ if (fdip != NULL)
+ FILEDESC_XLOCK(fdp);
TAILQ_INSERT_HEAD(&fdp->fd_kqlist, kq, kq_list);
- FILEDESC_XUNLOCK(fdp);
+ if (fdip != NULL)
+ FILEDESC_XUNLOCK(fdp);
+
+ finit(*fpp, FREAD | FWRITE, DTYPE_KQUEUE, kq, &kqueueops);
+ *kqp = kq;
+ return (0);
+}
+
+int
+kern_kqueue(struct thread *td, int flags, bool cponfork, struct filecaps *fcaps)
+{
+ struct kqueue *kq;
+ struct file *fp;
+ int fd, error;
+
+ error = kern_kqueue_alloc(td, td->td_proc->p_fd, &fd, &fp, flags,
+ fcaps, cponfork, &kq);
+ if (error != 0)
+ return (error);
- finit(fp, FREAD | FWRITE, DTYPE_KQUEUE, kq, &kqueueops);
fdrop(fp, td);
td->td_retval[0] = fd;
@@ -1488,7 +1544,7 @@ kern_kevent_anonymous(struct thread *td, int nevents,
struct kqueue kq = {};
int error;
- kqueue_init(&kq);
+ kqueue_init(&kq, false);
kq.kq_refcnt = 1;
error = kqueue_kevent(&kq, td, nevents, nevents, k_ops, NULL);
kqueue_drain(&kq, td);
@@ -1576,7 +1632,7 @@ kqueue_fo_release(int filt)
mtx_lock(&filterops_lock);
KASSERT(sysfilt_ops[~filt].for_refcnt > 0,
- ("filter object refcount not valid on release"));
+ ("filter object %d refcount not valid on release", filt));
sysfilt_ops[~filt].for_refcnt--;
mtx_unlock(&filterops_lock);
}
@@ -1855,17 +1911,8 @@ done:
}
static int
-kqueue_acquire(struct file *fp, struct kqueue **kqp)
+kqueue_acquire_ref(struct kqueue *kq)
{
- int error;
- struct kqueue *kq;
-
- error = 0;
-
- kq = fp->f_data;
- if (fp->f_type != DTYPE_KQUEUE || kq == NULL)
- return (EINVAL);
- *kqp = kq;
KQ_LOCK(kq);
if ((kq->kq_state & KQ_CLOSING) == KQ_CLOSING) {
KQ_UNLOCK(kq);
@@ -1873,8 +1920,22 @@ kqueue_acquire(struct file *fp, struct kqueue **kqp)
}
kq->kq_refcnt++;
KQ_UNLOCK(kq);
+ return (0);
+}
- return error;
+static int
+kqueue_acquire(struct file *fp, struct kqueue **kqp)
+{
+ struct kqueue *kq;
+ int error;
+
+ kq = fp->f_data;
+ if (fp->f_type != DTYPE_KQUEUE || kq == NULL)
+ return (EINVAL);
+ error = kqueue_acquire_ref(kq);
+ if (error == 0)
+ *kqp = kq;
+ return (error);
}
static void
@@ -2937,6 +2998,152 @@ noacquire:
return (error);
}
+static int
+kqueue_fork_alloc(struct filedesc *fdp, struct file *fp, struct file **fp1,
+ struct thread *td)
+{
+ struct kqueue *kq, *kq1;
+ int error;
+
+ MPASS(fp->f_type == DTYPE_KQUEUE);
+ kq = fp->f_data;
+ if ((kq->kq_state & KQ_CPONFORK) == 0)
+ return (EOPNOTSUPP);
+ error = kqueue_acquire_ref(kq);
+ if (error != 0)
+ return (error);
+ error = kern_kqueue_alloc(td, fdp, NULL, fp1, 0, NULL, true, &kq1);
+ if (error == 0) {
+ kq1->kq_forksrc = kq;
+ (*fp1)->f_flag = fp->f_flag & (FREAD | FWRITE | FEXEC |
+ O_CLOEXEC | O_CLOFORK);
+ } else {
+ kqueue_release(kq, 0);
+ }
+ return (error);
+}
+
+static void
+kqueue_fork_copy_knote(struct kqueue *kq1, struct knote *kn, struct proc *p1,
+ struct filedesc *fdp)
+{
+ struct knote *kn1;
+ const struct filterops *fop;
+ int error;
+
+ fop = kn->kn_fop;
+ if (fop->f_copy == NULL || (fop->f_isfd &&
+ fdp->fd_files->fdt_ofiles[kn->kn_kevent.ident].fde_file == NULL))
+ return;
+ error = kqueue_expand(kq1, fop, kn->kn_kevent.ident, M_WAITOK);
+ if (error != 0)
+ return;
+
+ kn1 = knote_alloc(M_WAITOK);
+ *kn1 = *kn;
+ kn1->kn_status |= KN_DETACHED;
+ kn1->kn_status &= ~KN_QUEUED;
+ kn1->kn_kq = kq1;
+ error = fop->f_copy(kn1, p1);
+ if (error != 0) {
+ knote_free(kn1);
+ return;
+ }
+ (void)kqueue_fo_find(kn->kn_kevent.filter);
+ if (fop->f_isfd && !fhold(kn1->kn_fp)) {
+ fop->f_detach(kn1);
+ kqueue_fo_release(kn->kn_kevent.filter);
+ knote_free(kn1);
+ return;
+ }
+ if (kn->kn_knlist != NULL)
+ knlist_add(kn->kn_knlist, kn1, 0);
+ KQ_LOCK(kq1);
+ knote_attach(kn1, kq1);
+ kn1->kn_influx = 0;
+ if ((kn->kn_status & KN_QUEUED) != 0)
+ knote_enqueue(kn1);
+ KQ_UNLOCK(kq1);
+}
+
+static void
+kqueue_fork_copy_list(struct klist *knlist, struct knote *marker,
+ struct kqueue *kq, struct kqueue *kq1, struct proc *p1,
+ struct filedesc *fdp)
+{
+ struct knote *kn;
+
+ KQ_OWNED(kq);
+ kn = SLIST_FIRST(knlist);
+ while (kn != NULL) {
+ if ((kn->kn_status & KN_DETACHED) != 0 ||
+ (kn_in_flux(kn) && (kn->kn_status & KN_SCAN) == 0)) {
+ kn = SLIST_NEXT(kn, kn_link);
+ continue;
+ }
+ kn_enter_flux(kn);
+ SLIST_INSERT_AFTER(kn, marker, kn_link);
+ KQ_UNLOCK(kq);
+ kqueue_fork_copy_knote(kq1, kn, p1, fdp);
+ KQ_LOCK(kq);
+ kn_leave_flux(kn);
+ kn = SLIST_NEXT(marker, kn_link);
+ /* XXXKIB switch kn_link to LIST? */
+ SLIST_REMOVE(knlist, marker, knote, kn_link);
+ }
+}
+
+static int
+kqueue_fork_copy(struct filedesc *fdp, struct file *fp, struct file *fp1,
+ struct proc *p1, struct thread *td)
+{
+ struct kqueue *kq, *kq1;
+ struct knote *marker;
+ int error, i;
+
+ error = 0;
+ MPASS(fp == NULL);
+ MPASS(fp1->f_type == DTYPE_KQUEUE);
+
+ kq1 = fp1->f_data;
+ kq = kq1->kq_forksrc;
+ marker = knote_alloc(M_WAITOK);
+ marker->kn_status = KN_MARKER;
+
+ KQ_LOCK(kq);
+ for (i = 0; i < kq->kq_knlistsize; i++) {
+ kqueue_fork_copy_list(&kq->kq_knlist[i], marker, kq, kq1,
+ p1, fdp);
+ }
+ if (kq->kq_knhashmask != 0) {
+ for (i = 0; i <= kq->kq_knhashmask; i++) {
+ kqueue_fork_copy_list(&kq->kq_knhash[i], marker, kq,
+ kq1, p1, fdp);
+ }
+ }
+ kqueue_release(kq, 1);
+ kq1->kq_forksrc = NULL;
+ KQ_UNLOCK(kq);
+
+ knote_free(marker);
+ return (error);
+}
+
+static int
+kqueue_fork(struct filedesc *fdp, struct file *fp, struct file **fp1,
+ struct proc *p1, struct thread *td)
+{
+ if (*fp1 == NULL)
+ return (kqueue_fork_alloc(fdp, fp, fp1, td));
+ return (kqueue_fork_copy(fdp, fp, *fp1, p1, td));
+}
+
+int
+knote_triv_copy(struct knote *kn __unused, struct proc *p1 __unused)
+{
+ return (0);
+}
+
struct knote_status_export_bit {
int kn_status_bit;
int knt_status_bit;
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index ab8ed32ad189..c4b1c8201ff2 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -807,7 +807,7 @@ kern_abort2(struct thread *td, const char *why, int nargs, void **uargs)
}
if (nargs > 0) {
sbuf_putc(sb, '(');
- for (i = 0;i < nargs; i++)
+ for (i = 0; i < nargs; i++)
sbuf_printf(sb, "%s%p", i == 0 ? "" : ", ", uargs[i]);
sbuf_putc(sb, ')');
}
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 7f6abae187b3..8b237b6dbd17 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -423,7 +423,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread *
pd = pdshare(p1->p_pd);
else
pd = pdcopy(p1->p_pd);
- fd = fdcopy(p1->p_fd);
+ fd = fdcopy(p1->p_fd, p2);
fdtol = NULL;
} else {
if (fr->fr_flags2 & FR2_SHARE_PATHS)
diff --git a/sys/kern/kern_jaildesc.c b/sys/kern/kern_jaildesc.c
index 3f322b271400..a564393d3366 100644
--- a/sys/kern/kern_jaildesc.c
+++ b/sys/kern/kern_jaildesc.c
@@ -344,6 +344,7 @@ static const struct filterops jaildesc_kqops = {
.f_isfd = 1,
.f_detach = jaildesc_kqops_detach,
.f_event = jaildesc_kqops_event,
+ .f_copy = knote_triv_copy,
};
static int
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c
index e919b15543b2..fcbfbe64f854 100644
--- a/sys/kern/kern_malloc.c
+++ b/sys/kern/kern_malloc.c
@@ -1302,7 +1302,7 @@ mallocinit(void *dummy)
#endif
align, UMA_ZONE_MALLOC);
}
- for (;i <= size; i+= KMEM_ZBASE)
+ for (; i <= size; i+= KMEM_ZBASE)
kmemsize[i >> KMEM_ZSHIFT] = indx;
}
}
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 21f765b17f62..a55f3c761449 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -124,6 +124,7 @@ const struct filterops sig_filtops = {
.f_attach = filt_sigattach,
.f_detach = filt_sigdetach,
.f_event = filt_signal,
+ .f_copy = knote_triv_copy,
};
static int kern_forcesigexit = 1;
diff --git a/sys/kern/subr_devstat.c b/sys/kern/subr_devstat.c
index 07a9cc0f57be..c4d0223d484f 100644
--- a/sys/kern/subr_devstat.c
+++ b/sys/kern/subr_devstat.c
@@ -415,7 +415,7 @@ sysctl_devstat(SYSCTL_HANDLER_ARGS)
if (error != 0)
return (error);
- for (;nds != NULL;) {
+ while (nds != NULL) {
error = SYSCTL_OUT(req, nds, sizeof(struct devstat));
if (error != 0)
return (error);
diff --git a/sys/kern/subr_log.c b/sys/kern/subr_log.c
index 5380902e602f..aac35a56130e 100644
--- a/sys/kern/subr_log.c
+++ b/sys/kern/subr_log.c
@@ -79,6 +79,7 @@ static const struct filterops log_read_filterops = {
.f_attach = NULL,
.f_detach = logkqdetach,
.f_event = logkqread,
+ .f_copy = knote_triv_copy,
};
static struct logsoftc {
diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c
index db0ceb17b9f0..e2070ae3f865 100644
--- a/sys/kern/subr_prf.c
+++ b/sys/kern/subr_prf.c
@@ -766,7 +766,7 @@ reswitch: switch (ch = (u_char)*fmt++) {
PCHAR(hex2ascii(*up & 0x0f));
up++;
if (width)
- for (q=p;*q;q++)
+ for (q = p; *q; q++)
PCHAR(*q);
}
break;
diff --git a/sys/kern/sys_eventfd.c b/sys/kern/sys_eventfd.c
index c2a0f67cae85..04ed107c933d 100644
--- a/sys/kern/sys_eventfd.c
+++ b/sys/kern/sys_eventfd.c
@@ -85,13 +85,16 @@ static int filt_eventfdwrite(struct knote *kn, long hint);
static const struct filterops eventfd_rfiltops = {
.f_isfd = 1,
.f_detach = filt_eventfddetach,
- .f_event = filt_eventfdread
+ .f_event = filt_eventfdread,
+ .f_copy = knote_triv_copy,
};
+
static const struct filterops eventfd_wfiltops = {
.f_isfd = 1,
.f_detach = filt_eventfddetach,
- .f_event = filt_eventfdwrite
+ .f_event = filt_eventfdwrite,
+ .f_copy = knote_triv_copy,
};
struct eventfd {
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index 57ebe8dc85f0..6531cea31423 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -181,20 +181,23 @@ static int filt_pipedump(struct proc *p, struct knote *kn,
static const struct filterops pipe_nfiltops = {
.f_isfd = 1,
.f_detach = filt_pipedetach_notsup,
- .f_event = filt_pipenotsup
+ .f_event = filt_pipenotsup,
/* no userdump */
+ .f_copy = knote_triv_copy,
};
static const struct filterops pipe_rfiltops = {
.f_isfd = 1,
.f_detach = filt_pipedetach,
.f_event = filt_piperead,
.f_userdump = filt_pipedump,
+ .f_copy = knote_triv_copy,
};
static const struct filterops pipe_wfiltops = {
.f_isfd = 1,
.f_detach = filt_pipedetach,
.f_event = filt_pipewrite,
.f_userdump = filt_pipedump,
+ .f_copy = knote_triv_copy,
};
/*
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index acaf1241cb2e..c5db21544b0f 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -486,6 +486,7 @@ static const struct filterops procdesc_kqops = {
.f_isfd = 1,
.f_detach = procdesc_kqops_detach,
.f_event = procdesc_kqops_event,
+ .f_copy = knote_triv_copy,
};
static int
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index c8e2c561b7cf..067471eb949a 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -754,12 +754,14 @@ static const struct filterops tty_kqops_read = {
.f_isfd = 1,
.f_detach = tty_kqops_read_detach,
.f_event = tty_kqops_read_event,
+ .f_copy = knote_triv_copy,
};
static const struct filterops tty_kqops_write = {
.f_isfd = 1,
.f_detach = tty_kqops_write_detach,
.f_event = tty_kqops_write_event,
+ .f_copy = knote_triv_copy,
};
static int
diff --git a/sys/kern/tty_pts.c b/sys/kern/tty_pts.c
index 1291770a9ccb..2672935c2d89 100644
--- a/sys/kern/tty_pts.c
+++ b/sys/kern/tty_pts.c
@@ -491,11 +491,13 @@ static const struct filterops pts_kqops_read = {
.f_isfd = 1,
.f_detach = pts_kqops_read_detach,
.f_event = pts_kqops_read_event,
+ .f_copy = knote_triv_copy,
};
static const struct filterops pts_kqops_write = {
.f_isfd = 1,
.f_detach = pts_kqops_write_detach,
.f_event = pts_kqops_write_event,
+ .f_copy = knote_triv_copy,
};
static int
diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c
index a8aec397b352..4c1bb1ff228e 100644
--- a/sys/kern/uipc_mqueue.c
+++ b/sys/kern/uipc_mqueue.c
@@ -281,11 +281,13 @@ static const struct filterops mq_rfiltops = {
.f_isfd = 1,
.f_detach = filt_mqdetach,
.f_event = filt_mqread,
+ .f_copy = knote_triv_copy,
};
static const struct filterops mq_wfiltops = {
.f_isfd = 1,
.f_detach = filt_mqdetach,
.f_event = filt_mqwrite,
+ .f_copy = knote_triv_copy,
};
/*
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index fe2d8d056062..eb9544628137 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -191,16 +191,19 @@ static const struct filterops soread_filtops = {
.f_isfd = 1,
.f_detach = filt_sordetach,
.f_event = filt_soread,
+ .f_copy = knote_triv_copy,
};
static const struct filterops sowrite_filtops = {
.f_isfd = 1,
.f_detach = filt_sowdetach,
.f_event = filt_sowrite,
+ .f_copy = knote_triv_copy,
};
static const struct filterops soempty_filtops = {
.f_isfd = 1,
.f_detach = filt_sowdetach,
.f_event = filt_soempty,
+ .f_copy = knote_triv_copy,
};
so_gen_t so_gencnt; /* generation count for sockets */
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index c5fc1e84ce3f..807271488af2 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1559,15 +1559,19 @@ restart:
mc_init_m(&cmc, control);
SOCK_RECVBUF_LOCK(so);
- MPASS(!(sb->sb_state & SBS_CANTRCVMORE));
-
- if (__predict_false(cmc.mc_len + sb->sb_ccc +
- sb->sb_ctl > sb->sb_hiwat)) {
+ if (__predict_false(
+ (sb->sb_state & SBS_CANTRCVMORE) ||
+ cmc.mc_len + sb->sb_ccc + sb->sb_ctl >
+ sb->sb_hiwat)) {
/*
- * Too bad, while unp_externalize() was
- * failing, the other side had filled
- * the buffer and we can't prepend data
- * back. Losing data!
+ * While the lock was dropped and we
+ * were failing in unp_externalize(),
+ * the peer could has a) disconnected,
+ * b) filled the buffer so that we
+ * can't prepend data back.
+ * These are two edge conditions that
+ * we just can't handle, so lose the
+ * data and return the error.
*/
SOCK_RECVBUF_UNLOCK(so);
SOCK_IO_RECV_UNLOCK(so);
@@ -1851,11 +1855,13 @@ static const struct filterops uipc_write_filtops = {
.f_isfd = 1,
.f_detach = uipc_filt_sowdetach,
.f_event = uipc_filt_sowrite,
+ .f_copy = knote_triv_copy,
};
static const struct filterops uipc_empty_filtops = {
.f_isfd = 1,
.f_detach = uipc_filt_sowdetach,
.f_event = uipc_filt_soempty,
+ .f_copy = knote_triv_copy,
};
static int
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index e63fa4c01434..60916a9fbd32 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -345,12 +345,14 @@ static const struct filterops aio_filtops = {
.f_attach = filt_aioattach,
.f_detach = filt_aiodetach,
.f_event = filt_aio,
+ .f_copy = knote_triv_copy,
};
static const struct filterops lio_filtops = {
.f_isfd = 0,
.f_attach = filt_lioattach,
.f_detach = filt_liodetach,
- .f_event = filt_lio
+ .f_event = filt_lio,
+ .f_copy = knote_triv_copy,
};
static eventhandler_tag exit_tag, exec_tag;
diff --git a/sys/kern/vfs_inotify.c b/sys/kern/vfs_inotify.c
index b265a5ff3a62..e60d8426ee42 100644
--- a/sys/kern/vfs_inotify.c
+++ b/sys/kern/vfs_inotify.c
@@ -111,6 +111,7 @@ static const struct filterops inotify_rfiltops = {
.f_isfd = 1,
.f_detach = filt_inotifydetach,
.f_event = filt_inotifyevent,
+ .f_copy = knote_triv_copy,
};
static MALLOC_DEFINE(M_INOTIFY, "inotify", "inotify data structures");
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 73e110c05bc1..58975f7ac932 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -6545,6 +6545,7 @@ const struct filterops fs_filtops = {
.f_attach = filt_fsattach,
.f_detach = filt_fsdetach,
.f_event = filt_fsevent,
+ .f_copy = knote_triv_copy,
};
static int
@@ -6624,24 +6625,28 @@ static int filt_vfsvnode(struct knote *kn, long hint);
static void filt_vfsdetach(struct knote *kn);
static int filt_vfsdump(struct proc *p, struct knote *kn,
struct kinfo_knote *kin);
+static int filt_vfscopy(struct knote *kn, struct proc *p1);
static const struct filterops vfsread_filtops = {
.f_isfd = 1,
.f_detach = filt_vfsdetach,
.f_event = filt_vfsread,
.f_userdump = filt_vfsdump,
+ .f_copy = filt_vfscopy,
};
static const struct filterops vfswrite_filtops = {
.f_isfd = 1,
.f_detach = filt_vfsdetach,
.f_event = filt_vfswrite,
.f_userdump = filt_vfsdump,
+ .f_copy = filt_vfscopy,
};
static const struct filterops vfsvnode_filtops = {
.f_isfd = 1,
.f_detach = filt_vfsdetach,
.f_event = filt_vfsvnode,
.f_userdump = filt_vfsdump,
+ .f_copy = filt_vfscopy,
};
static void
@@ -6825,6 +6830,16 @@ filt_vfsdump(struct proc *p, struct knote *kn, struct kinfo_knote *kin)
return (0);
}
+static int
+filt_vfscopy(struct knote *kn, struct proc *p1)
+{
+ struct vnode *vp;
+
+ vp = (struct vnode *)kn->kn_hook;
+ vhold(vp);
+ return (0);
+}
+
int
vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off)
{