patches for easier mirroring, to eliminate a special copy, to make www.freebsd.org/security a full copy of security.freebsd.org and be eventually be the same. For now files are just sitting there. The symlinks are missing. Discussed on: www (repository location) Discussed with: simon (so)
		
			
				
	
	
		
			355 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			355 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
Index: sys/kern/kern_event.c
 | 
						|
===================================================================
 | 
						|
--- sys/kern/kern_event.c	(revision 197652)
 | 
						|
+++ sys/kern/kern_event.c	(working copy)
 | 
						|
@@ -392,30 +392,82 @@ filt_proc(struct knote *kn, long hint)
 | 
						|
 		return (1);
 | 
						|
 	}
 | 
						|
 
 | 
						|
-	/*
 | 
						|
-	 * process forked, and user wants to track the new process,
 | 
						|
-	 * so attach a new knote to it, and immediately report an
 | 
						|
-	 * event with the parent's pid.
 | 
						|
-	 */
 | 
						|
-	if ((event == NOTE_FORK) && (kn->kn_sfflags & NOTE_TRACK)) {
 | 
						|
-		struct kevent kev;
 | 
						|
-		int error;
 | 
						|
+	return (kn->kn_fflags != 0);
 | 
						|
+}
 | 
						|
 
 | 
						|
+/*
 | 
						|
+ * Called when the process forked. It mostly does the same as the
 | 
						|
+ * knote(), activating all knotes registered to be activated when the
 | 
						|
+ * process forked. Additionally, for each knote attached to the
 | 
						|
+ * parent, check whether user wants to track the new process. If so
 | 
						|
+ * attach a new knote to it, and immediately report an event with the
 | 
						|
+ * child's pid.
 | 
						|
+ */
 | 
						|
+void
 | 
						|
+knote_fork(struct knlist *list, int pid)
 | 
						|
+{
 | 
						|
+	struct kqueue *kq;
 | 
						|
+	struct knote *kn;
 | 
						|
+	struct kevent kev;
 | 
						|
+	int error;
 | 
						|
+
 | 
						|
+	if (list == NULL)
 | 
						|
+		return;
 | 
						|
+	list->kl_lock(list->kl_lockarg);
 | 
						|
+
 | 
						|
+	SLIST_FOREACH(kn, &list->kl_list, kn_selnext) {
 | 
						|
+		if ((kn->kn_status & KN_INFLUX) == KN_INFLUX)
 | 
						|
+			continue;
 | 
						|
+		kq = kn->kn_kq;
 | 
						|
+		KQ_LOCK(kq);
 | 
						|
+		if ((kn->kn_status & KN_INFLUX) == KN_INFLUX) {
 | 
						|
+			KQ_UNLOCK(kq);
 | 
						|
+			continue;
 | 
						|
+		}
 | 
						|
+
 | 
						|
 		/*
 | 
						|
-		 * register knote with new process.
 | 
						|
+		 * The same as knote(), activate the event.
 | 
						|
 		 */
 | 
						|
-		kev.ident = hint & NOTE_PDATAMASK;	/* pid */
 | 
						|
+		if ((kn->kn_sfflags & NOTE_TRACK) == 0) {
 | 
						|
+			kn->kn_status |= KN_HASKQLOCK;
 | 
						|
+			if (kn->kn_fop->f_event(kn, NOTE_FORK | pid))
 | 
						|
+				KNOTE_ACTIVATE(kn, 1);
 | 
						|
+			kn->kn_status &= ~KN_HASKQLOCK;
 | 
						|
+			KQ_UNLOCK(kq);
 | 
						|
+			continue;
 | 
						|
+		}
 | 
						|
+
 | 
						|
+		/*
 | 
						|
+		 * The NOTE_TRACK case. In addition to the activation
 | 
						|
+		 * of the event, we need to register new event to
 | 
						|
+		 * track the child. Drop the locks in preparation for
 | 
						|
+		 * the call to kqueue_register().
 | 
						|
+		 */
 | 
						|
+		kn->kn_status |= KN_INFLUX;
 | 
						|
+		KQ_UNLOCK(kq);
 | 
						|
+		list->kl_unlock(list->kl_lockarg);
 | 
						|
+
 | 
						|
+		/*
 | 
						|
+		 * Activate existing knote and register a knote with
 | 
						|
+		 * new process.
 | 
						|
+		 */
 | 
						|
+		kev.ident = pid;
 | 
						|
 		kev.filter = kn->kn_filter;
 | 
						|
 		kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1;
 | 
						|
 		kev.fflags = kn->kn_sfflags;
 | 
						|
-		kev.data = kn->kn_id;			/* parent */
 | 
						|
-		kev.udata = kn->kn_kevent.udata;	/* preserve udata */
 | 
						|
-		error = kqueue_register(kn->kn_kq, &kev, NULL, 0);
 | 
						|
+		kev.data = kn->kn_id;		/* parent */
 | 
						|
+		kev.udata = kn->kn_kevent.udata;/* preserve udata */
 | 
						|
+		error = kqueue_register(kq, &kev, NULL, 0);
 | 
						|
+		if (kn->kn_fop->f_event(kn, NOTE_FORK | pid))
 | 
						|
+			KNOTE_ACTIVATE(kn, 0);
 | 
						|
 		if (error)
 | 
						|
 			kn->kn_fflags |= NOTE_TRACKERR;
 | 
						|
+		KQ_LOCK(kq);
 | 
						|
+		kn->kn_status &= ~KN_INFLUX;
 | 
						|
+		KQ_UNLOCK_FLUX(kq);
 | 
						|
+		list->kl_lock(list->kl_lockarg);
 | 
						|
 	}
 | 
						|
-
 | 
						|
-	return (kn->kn_fflags != 0);
 | 
						|
+	list->kl_unlock(list->kl_lockarg);
 | 
						|
 }
 | 
						|
 
 | 
						|
 static int
 | 
						|
@@ -1123,7 +1175,7 @@ kqueue_scan(struct kqueue *kq, int maxevents, stru
 | 
						|
 	struct kevent *kevp;
 | 
						|
 	struct timeval atv, rtv, ttv;
 | 
						|
 	struct knote *kn, *marker;
 | 
						|
-	int count, timeout, nkev, error;
 | 
						|
+	int count, timeout, nkev, error, influx;
 | 
						|
 	int haskqglobal;
 | 
						|
 
 | 
						|
 	count = maxevents;
 | 
						|
@@ -1193,12 +1245,17 @@ start:
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	TAILQ_INSERT_TAIL(&kq->kq_head, marker, kn_tqe);
 | 
						|
+	influx = 0;
 | 
						|
 	while (count) {
 | 
						|
 		KQ_OWNED(kq);
 | 
						|
 		kn = TAILQ_FIRST(&kq->kq_head);
 | 
						|
 
 | 
						|
 		if ((kn->kn_status == KN_MARKER && kn != marker) ||
 | 
						|
 		    (kn->kn_status & KN_INFLUX) == KN_INFLUX) {
 | 
						|
+			if (influx) {
 | 
						|
+				influx = 0;
 | 
						|
+				KQ_FLUX_WAKEUP(kq);
 | 
						|
+			}
 | 
						|
 			kq->kq_state |= KQ_FLUXWAIT;
 | 
						|
 			error = msleep(kq, &kq->kq_lock, PSOCK,
 | 
						|
 			    "kqflxwt", 0);
 | 
						|
@@ -1248,6 +1305,7 @@ start:
 | 
						|
 				    ~(KN_QUEUED | KN_ACTIVE | KN_INFLUX);
 | 
						|
 				kq->kq_count--;
 | 
						|
 				KN_LIST_UNLOCK(kn);
 | 
						|
+				influx = 1;
 | 
						|
 				continue;
 | 
						|
 			}
 | 
						|
 			*kevp = kn->kn_kevent;
 | 
						|
@@ -1263,6 +1321,7 @@ start:
 | 
						|
 			
 | 
						|
 			kn->kn_status &= ~(KN_INFLUX);
 | 
						|
 			KN_LIST_UNLOCK(kn);
 | 
						|
+			influx = 1;
 | 
						|
 		}
 | 
						|
 
 | 
						|
 		/* we are returning a copy to the user */
 | 
						|
@@ -1271,6 +1330,7 @@ start:
 | 
						|
 		count--;
 | 
						|
 
 | 
						|
 		if (nkev == KQ_NEVENTS) {
 | 
						|
+			influx = 0;
 | 
						|
 			KQ_UNLOCK_FLUX(kq);
 | 
						|
 			error = k_ops->k_copyout(k_ops->arg, keva, nkev);
 | 
						|
 			nkev = 0;
 | 
						|
@@ -1434,8 +1494,11 @@ kqueue_close(struct file *fp, struct thread *td)
 | 
						|
 
 | 
						|
 	for (i = 0; i < kq->kq_knlistsize; i++) {
 | 
						|
 		while ((kn = SLIST_FIRST(&kq->kq_knlist[i])) != NULL) {
 | 
						|
-			KASSERT((kn->kn_status & KN_INFLUX) == 0,
 | 
						|
-			    ("KN_INFLUX set when not suppose to be"));
 | 
						|
+			if ((kn->kn_status & KN_INFLUX) == KN_INFLUX) {
 | 
						|
+				kq->kq_state |= KQ_FLUXWAIT;
 | 
						|
+				msleep(kq, &kq->kq_lock, PSOCK, "kqclo1", 0);
 | 
						|
+				continue;
 | 
						|
+			}
 | 
						|
 			kn->kn_status |= KN_INFLUX;
 | 
						|
 			KQ_UNLOCK(kq);
 | 
						|
 			if (!(kn->kn_status & KN_DETACHED))
 | 
						|
@@ -1447,8 +1510,12 @@ kqueue_close(struct file *fp, struct thread *td)
 | 
						|
 	if (kq->kq_knhashmask != 0) {
 | 
						|
 		for (i = 0; i <= kq->kq_knhashmask; i++) {
 | 
						|
 			while ((kn = SLIST_FIRST(&kq->kq_knhash[i])) != NULL) {
 | 
						|
-				KASSERT((kn->kn_status & KN_INFLUX) == 0,
 | 
						|
-				    ("KN_INFLUX set when not suppose to be"));
 | 
						|
+				if ((kn->kn_status & KN_INFLUX) == KN_INFLUX) {
 | 
						|
+					kq->kq_state |= KQ_FLUXWAIT;
 | 
						|
+					msleep(kq, &kq->kq_lock, PSOCK,
 | 
						|
+					       "kqclo2", 0);
 | 
						|
+					continue;
 | 
						|
+				}
 | 
						|
 				kn->kn_status |= KN_INFLUX;
 | 
						|
 				KQ_UNLOCK(kq);
 | 
						|
 				if (!(kn->kn_status & KN_DETACHED))
 | 
						|
Index: sys/kern/kern_fork.c
 | 
						|
===================================================================
 | 
						|
--- sys/kern/kern_fork.c	(revision 197652)
 | 
						|
+++ sys/kern/kern_fork.c	(working copy)
 | 
						|
@@ -699,14 +699,12 @@ again:
 | 
						|
 	 */
 | 
						|
 	PROC_LOCK(p1);
 | 
						|
 	_PRELE(p1);
 | 
						|
+	PROC_UNLOCK(p1);
 | 
						|
 
 | 
						|
 	/*
 | 
						|
 	 * Tell any interested parties about the new process.
 | 
						|
 	 */
 | 
						|
-	KNOTE_LOCKED(&p1->p_klist, NOTE_FORK | p2->p_pid);
 | 
						|
-
 | 
						|
-	PROC_UNLOCK(p1);
 | 
						|
-
 | 
						|
+	knote_fork(&p1->p_klist, p2->p_pid);
 | 
						|
 	/*
 | 
						|
 	 * Preserve synchronization semantics of vfork.  If waiting for
 | 
						|
 	 * child to exec or exit, set P_PPWAIT on child, and sleep on our
 | 
						|
Index: sys/kern/sys_pipe.c
 | 
						|
===================================================================
 | 
						|
--- sys/kern/sys_pipe.c	(revision 197652)
 | 
						|
+++ sys/kern/sys_pipe.c	(working copy)
 | 
						|
@@ -268,8 +268,8 @@ pipe_zone_ctor(void *mem, int size, void *arg, int
 | 
						|
 	 * one at a time.  When both are free'd, then the whole pair
 | 
						|
 	 * is released.
 | 
						|
 	 */
 | 
						|
-	rpipe->pipe_present = 1;
 | 
						|
-	wpipe->pipe_present = 1;
 | 
						|
+	rpipe->pipe_present = PIPE_ACTIVE;
 | 
						|
+	wpipe->pipe_present = PIPE_ACTIVE;
 | 
						|
 
 | 
						|
 	/*
 | 
						|
 	 * Eventually, the MAC Framework may initialize the label
 | 
						|
@@ -1003,7 +1003,8 @@ pipe_write(fp, uio, active_cred, flags, td)
 | 
						|
 	/*
 | 
						|
 	 * detect loss of pipe read side, issue SIGPIPE if lost.
 | 
						|
 	 */
 | 
						|
-	if ((!wpipe->pipe_present) || (wpipe->pipe_state & PIPE_EOF)) {
 | 
						|
+	if (wpipe->pipe_present != PIPE_ACTIVE ||
 | 
						|
+	    (wpipe->pipe_state & PIPE_EOF)) {
 | 
						|
 		pipeunlock(wpipe);
 | 
						|
 		PIPE_UNLOCK(rpipe);
 | 
						|
 		return (EPIPE);
 | 
						|
@@ -1361,13 +1362,14 @@ pipe_poll(fp, events, active_cred, td)
 | 
						|
 			revents |= events & (POLLIN | POLLRDNORM);
 | 
						|
 
 | 
						|
 	if (events & (POLLOUT | POLLWRNORM))
 | 
						|
-		if (!wpipe->pipe_present || (wpipe->pipe_state & PIPE_EOF) ||
 | 
						|
+		if (wpipe->pipe_present != PIPE_ACTIVE ||
 | 
						|
+		    (wpipe->pipe_state & PIPE_EOF) ||
 | 
						|
 		    (((wpipe->pipe_state & PIPE_DIRECTW) == 0) &&
 | 
						|
 		     (wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_BUF))
 | 
						|
 			revents |= events & (POLLOUT | POLLWRNORM);
 | 
						|
 
 | 
						|
 	if ((rpipe->pipe_state & PIPE_EOF) ||
 | 
						|
-	    (!wpipe->pipe_present) ||
 | 
						|
+	    wpipe->pipe_present != PIPE_ACTIVE ||
 | 
						|
 	    (wpipe->pipe_state & PIPE_EOF))
 | 
						|
 		revents |= POLLHUP;
 | 
						|
 
 | 
						|
@@ -1506,7 +1508,7 @@ pipeclose(cpipe)
 | 
						|
 	 * Disconnect from peer, if any.
 | 
						|
 	 */
 | 
						|
 	ppipe = cpipe->pipe_peer;
 | 
						|
-	if (ppipe->pipe_present != 0) {
 | 
						|
+	if (ppipe->pipe_present == PIPE_ACTIVE) {
 | 
						|
 		pipeselwakeup(ppipe);
 | 
						|
 
 | 
						|
 		ppipe->pipe_state |= PIPE_EOF;
 | 
						|
@@ -1523,16 +1525,23 @@ pipeclose(cpipe)
 | 
						|
 	PIPE_UNLOCK(cpipe);
 | 
						|
 	pipe_free_kmem(cpipe);
 | 
						|
 	PIPE_LOCK(cpipe);
 | 
						|
-	cpipe->pipe_present = 0;
 | 
						|
+	cpipe->pipe_present = PIPE_CLOSING;
 | 
						|
 	pipeunlock(cpipe);
 | 
						|
+
 | 
						|
+	/*
 | 
						|
+	 * knlist_clear() may sleep dropping the PIPE_MTX. Set the
 | 
						|
+	 * PIPE_FINALIZED, that allows other end to free the
 | 
						|
+	 * pipe_pair, only after the knotes are completely dismantled.
 | 
						|
+	 */
 | 
						|
 	knlist_clear(&cpipe->pipe_sel.si_note, 1);
 | 
						|
+	cpipe->pipe_present = PIPE_FINALIZED;
 | 
						|
 	knlist_destroy(&cpipe->pipe_sel.si_note);
 | 
						|
 
 | 
						|
 	/*
 | 
						|
 	 * If both endpoints are now closed, release the memory for the
 | 
						|
 	 * pipe pair.  If not, unlock.
 | 
						|
 	 */
 | 
						|
-	if (ppipe->pipe_present == 0) {
 | 
						|
+	if (ppipe->pipe_present == PIPE_FINALIZED) {
 | 
						|
 		PIPE_UNLOCK(cpipe);
 | 
						|
 #ifdef MAC
 | 
						|
 		mac_destroy_pipe(pp);
 | 
						|
@@ -1556,7 +1565,7 @@ pipe_kqfilter(struct file *fp, struct knote *kn)
 | 
						|
 		break;
 | 
						|
 	case EVFILT_WRITE:
 | 
						|
 		kn->kn_fop = &pipe_wfiltops;
 | 
						|
-		if (!cpipe->pipe_peer->pipe_present) {
 | 
						|
+		if (cpipe->pipe_peer->pipe_present != PIPE_ACTIVE) {
 | 
						|
 			/* other end of pipe has been closed */
 | 
						|
 			PIPE_UNLOCK(cpipe);
 | 
						|
 			return (EPIPE);
 | 
						|
@@ -1579,13 +1588,8 @@ filt_pipedetach(struct knote *kn)
 | 
						|
 	struct pipe *cpipe = (struct pipe *)kn->kn_fp->f_data;
 | 
						|
 
 | 
						|
 	PIPE_LOCK(cpipe);
 | 
						|
-	if (kn->kn_filter == EVFILT_WRITE) {
 | 
						|
-		if (!cpipe->pipe_peer->pipe_present) {
 | 
						|
-			PIPE_UNLOCK(cpipe);
 | 
						|
-			return;
 | 
						|
-		}
 | 
						|
+	if (kn->kn_filter == EVFILT_WRITE)
 | 
						|
 		cpipe = cpipe->pipe_peer;
 | 
						|
-	}
 | 
						|
 	knlist_remove(&cpipe->pipe_sel.si_note, kn, 1);
 | 
						|
 	PIPE_UNLOCK(cpipe);
 | 
						|
 }
 | 
						|
@@ -1604,7 +1608,8 @@ filt_piperead(struct knote *kn, long hint)
 | 
						|
 		kn->kn_data = rpipe->pipe_map.cnt;
 | 
						|
 
 | 
						|
 	if ((rpipe->pipe_state & PIPE_EOF) ||
 | 
						|
-	    (!wpipe->pipe_present) || (wpipe->pipe_state & PIPE_EOF)) {
 | 
						|
+	    wpipe->pipe_present != PIPE_ACTIVE ||
 | 
						|
+	    (wpipe->pipe_state & PIPE_EOF)) {
 | 
						|
 		kn->kn_flags |= EV_EOF;
 | 
						|
 		PIPE_UNLOCK(rpipe);
 | 
						|
 		return (1);
 | 
						|
@@ -1622,7 +1627,8 @@ filt_pipewrite(struct knote *kn, long hint)
 | 
						|
 	struct pipe *wpipe = rpipe->pipe_peer;
 | 
						|
 
 | 
						|
 	PIPE_LOCK(rpipe);
 | 
						|
-	if ((!wpipe->pipe_present) || (wpipe->pipe_state & PIPE_EOF)) {
 | 
						|
+	if (wpipe->pipe_present != PIPE_ACTIVE ||
 | 
						|
+	    (wpipe->pipe_state & PIPE_EOF)) {
 | 
						|
 		kn->kn_data = 0;
 | 
						|
 		kn->kn_flags |= EV_EOF;
 | 
						|
 		PIPE_UNLOCK(rpipe);
 | 
						|
 | 
						|
Index: sys/sys/event.h
 | 
						|
===================================================================
 | 
						|
--- sys/sys/event.h	(revision 197652)
 | 
						|
+++ sys/sys/event.h	(working copy)
 | 
						|
@@ -208,6 +208,7 @@ struct proc;
 | 
						|
 struct knlist;
 | 
						|
 
 | 
						|
 extern void	knote(struct knlist *list, long hint, int islocked);
 | 
						|
+extern void	knote_fork(struct knlist *list, int pid);
 | 
						|
 extern void	knlist_add(struct knlist *knl, struct knote *kn, int islocked);
 | 
						|
 extern void	knlist_remove(struct knlist *knl, struct knote *kn, int islocked);
 | 
						|
 extern void	knlist_remove_inevent(struct knlist *knl, struct knote *kn);
 | 
						|
Index: sys/sys/pipe.h
 | 
						|
===================================================================
 | 
						|
--- sys/sys/pipe.h	(revision 197652)
 | 
						|
+++ sys/sys/pipe.h	(working copy)
 | 
						|
@@ -115,6 +115,13 @@ struct pipe {
 | 
						|
 };
 | 
						|
 
 | 
						|
 /*
 | 
						|
+ * Values for the pipe_present.
 | 
						|
+ */
 | 
						|
+#define PIPE_ACTIVE		1
 | 
						|
+#define	PIPE_CLOSING		2
 | 
						|
+#define	PIPE_FINALIZED		3
 | 
						|
+
 | 
						|
+/*
 | 
						|
  * Container structure to hold the two pipe endpoints, mutex, and label
 | 
						|
  * pointer.
 | 
						|
  */
 |