Do not clear KN_INFLUX when not owning influx state.

For notes in KN_INFLUX|KN_SCAN state, the influx bit is set by a
parallel scan.  When knote() reports event for the vnode filters,
which require kqueue unlocked, it unconditionally sets and then clears
influx to keep note around kqueue unlock.  There, do not clear influx
flag if a scan set it, since we do not own it, instead we prevent scan
from executing by holding knlist lock.

The knote_fork() function has somewhat similar problem, it might set
KN_INFLUX for scanned note, drop kqueue and list locks, and then clear
the flag after relock.  A solution there would be different enough, as
well as the test program, so close the reported issue first.

Reported and test case provided by:	yjh0502@gmail.com
PR:	214923
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
This commit is contained in:
kib 2016-12-19 22:18:36 +00:00
parent 4bb8b1319b
commit fa7aa12d7b

@ -2006,6 +2006,7 @@ knote(struct knlist *list, long hint, int lockflags)
struct kqueue *kq;
struct knote *kn, *tkn;
int error;
bool own_influx;
if (list == NULL)
return;
@ -2036,11 +2037,14 @@ knote(struct knlist *list, long hint, int lockflags)
*/
KQ_UNLOCK(kq);
} else if ((lockflags & KNF_NOKQLOCK) != 0) {
kn->kn_status |= KN_INFLUX;
own_influx = (kn->kn_status & KN_INFLUX) == 0;
if (own_influx)
kn->kn_status |= KN_INFLUX;
KQ_UNLOCK(kq);
error = kn->kn_fop->f_event(kn, hint);
KQ_LOCK(kq);
kn->kn_status &= ~KN_INFLUX;
if (own_influx)
kn->kn_status &= ~KN_INFLUX;
if (error)
KNOTE_ACTIVATE(kn, 1);
KQ_UNLOCK_FLUX(kq);