diff options
author | Guy Helmer <ghelmer@FreeBSD.org> | 2012-12-10 16:14:44 +0000 |
---|---|---|
committer | Guy Helmer <ghelmer@FreeBSD.org> | 2012-12-10 16:14:44 +0000 |
commit | 3b3b91e73619f2d77c3d626b7346396728ed1cf6 (patch) | |
tree | 05f79a3e8fd1361998dd0dc02f1088df035c8960 /sys/net/bpf.c | |
parent | f785f598617eac1bc8992b6393ba6853558f60d9 (diff) | |
download | src-test2-3b3b91e73619f2d77c3d626b7346396728ed1cf6.tar.gz src-test2-3b3b91e73619f2d77c3d626b7346396728ed1cf6.zip |
Notes
Diffstat (limited to 'sys/net/bpf.c')
-rw-r--r-- | sys/net/bpf.c | 41 |
1 files changed, 30 insertions, 11 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 6d9a917a8b91..9ee196416683 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -819,6 +819,7 @@ bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td) * particular buffer method. */ bpf_buffer_init(d); + d->bd_hbuf_in_use = 0; d->bd_bufmode = BPF_BUFMODE_BUFFER; d->bd_sig = SIGIO; d->bd_direction = BPF_D_INOUT; @@ -872,6 +873,9 @@ bpfread(struct cdev *dev, struct uio *uio, int ioflag) callout_stop(&d->bd_callout); timed_out = (d->bd_state == BPF_TIMED_OUT); d->bd_state = BPF_IDLE; + while (d->bd_hbuf_in_use) + mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, + PRINET|PCATCH, "bd_hbuf", 0); /* * If the hold buffer is empty, then do a timed sleep, which * ends when the timeout expires or when enough packets @@ -940,27 +944,27 @@ bpfread(struct cdev *dev, struct uio *uio, int ioflag) /* * At this point, we know we have something in the hold slot. */ + d->bd_hbuf_in_use = 1; BPFD_UNLOCK(d); /* * Move data from hold buffer into user space. * We know the entire buffer is transferred since * we checked above that the read buffer is bpf_bufsize bytes. - * - * XXXRW: More synchronization needed here: what if a second thread - * issues a read on the same fd at the same time? Don't want this - * getting invalidated. + * + * We do not have to worry about simultaneous reads because + * we waited for sole access to the hold buffer above. */ error = bpf_uiomove(d, d->bd_hbuf, d->bd_hlen, uio); BPFD_LOCK(d); - if (d->bd_hbuf != NULL) { - /* Free the hold buffer only if it is still valid. */ - d->bd_fbuf = d->bd_hbuf; - d->bd_hbuf = NULL; - d->bd_hlen = 0; - bpf_buf_reclaimed(d); - } + KASSERT(d->bd_hbuf != NULL, ("bpfread: lost bd_hbuf")); + d->bd_fbuf = d->bd_hbuf; + d->bd_hbuf = NULL; + d->bd_hlen = 0; + bpf_buf_reclaimed(d); + d->bd_hbuf_in_use = 0; + wakeup(&d->bd_hbuf_in_use); BPFD_UNLOCK(d); return (error); @@ -1114,6 +1118,9 @@ reset_d(struct bpf_d *d) BPFD_LOCK_ASSERT(d); + while (d->bd_hbuf_in_use) + mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, PRINET, + "bd_hbuf", 0); if ((d->bd_hbuf != NULL) && (d->bd_bufmode != BPF_BUFMODE_ZBUF || bpf_canfreebuf(d))) { /* Free the hold buffer. */ @@ -1254,6 +1261,9 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, BPFD_LOCK(d); n = d->bd_slen; + while (d->bd_hbuf_in_use) + mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, + PRINET, "bd_hbuf", 0); if (d->bd_hbuf) n += d->bd_hlen; BPFD_UNLOCK(d); @@ -1967,6 +1977,9 @@ filt_bpfread(struct knote *kn, long hint) ready = bpf_ready(d); if (ready) { kn->kn_data = d->bd_slen; + while (d->bd_hbuf_in_use) + mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, + PRINET, "bd_hbuf", 0); if (d->bd_hbuf) kn->kn_data += d->bd_hlen; } else if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { @@ -2299,6 +2312,9 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, * spot to do it. */ if (d->bd_fbuf == NULL && bpf_canfreebuf(d)) { + while (d->bd_hbuf_in_use) + mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, + PRINET, "bd_hbuf", 0); d->bd_fbuf = d->bd_hbuf; d->bd_hbuf = NULL; d->bd_hlen = 0; @@ -2341,6 +2357,9 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, ++d->bd_dcount; return; } + while (d->bd_hbuf_in_use) + mtx_sleep(&d->bd_hbuf_in_use, &d->bd_lock, + PRINET, "bd_hbuf", 0); ROTATE_BUFFERS(d); do_wakeup = 1; curlen = 0; |