diff options
author | melifaro <melifaro@FreeBSD.org> | 2012-05-21 22:19:19 +0000 |
---|---|---|
committer | melifaro <melifaro@FreeBSD.org> | 2012-05-21 22:19:19 +0000 |
commit | e5f61c6580ea0a76e8c43d0fa98f33e5623b639c (patch) | |
tree | a1fde4fc9d51ecf611705c4c685d911eacba3bb4 | |
parent | 34ec5c86502577f86de209389836d93646d78b9b (diff) | |
download | FreeBSD-src-e5f61c6580ea0a76e8c43d0fa98f33e5623b639c.zip FreeBSD-src-e5f61c6580ea0a76e8c43d0fa98f33e5623b639c.tar.gz |
Call bpf_jitter() before acquiring BPF global lock due to malloc() being used inside bpf_jitter.
Eliminate bpf_buffer_alloc() and allocate BPF buffers on descriptor creation and BIOCSBLEN ioctl.
This permits us not to allocate buffers inside bpf_attachd() which is protected by global lock.
Approved by: kib(mentor)
MFC in: 4 weeks
-rw-r--r-- | sys/net/bpf.c | 22 | ||||
-rw-r--r-- | sys/net/bpf_buffer.c | 49 | ||||
-rw-r--r-- | sys/net/bpf_buffer.h | 1 |
3 files changed, 43 insertions, 29 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c index aa40cc4..88d69aa 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -804,7 +804,7 @@ static int bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td) { struct bpf_d *d; - int error; + int error, size; d = malloc(sizeof(*d), M_BPF, M_WAITOK | M_ZERO); error = devfs_set_cdevpriv(d, bpf_dtor); @@ -831,6 +831,10 @@ bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td) callout_init_mtx(&d->bd_callout, &d->bd_lock, 0); knlist_init_mtx(&d->bd_sel.si_note, &d->bd_lock); + /* Allocate default buffers */ + size = d->bd_bufsize; + bpf_buffer_ioctl_sblen(d, &size); + return (0); } @@ -1664,7 +1668,7 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd) struct bpf_insn *fcode, *old; u_int wfilter, flen, size; #ifdef BPF_JITTER - bpf_jit_filter *ofunc; + bpf_jit_filter *ofunc, *jfunc; #endif int need_upgrade; #ifdef COMPAT_FREEBSD32 @@ -1695,6 +1699,13 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd) else fcode = NULL; /* Make compiler happy */ +#ifdef BPF_JITTER + if (fp->bf_insns != NULL) + jfunc = bpf_jitter(fcode, flen); + else + jfunc = NULL; /* Make compiler happy */ +#endif + BPF_LOCK(); if (cmd == BIOCSETWF) { @@ -1755,7 +1766,7 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd) else { d->bd_rfilter = fcode; #ifdef BPF_JITTER - d->bd_bfilter = bpf_jitter(fcode, flen); + d->bd_bfilter = jfunc; #endif if (cmd == BIOCSETF) reset_d(d); @@ -1827,11 +1838,6 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr) */ switch (d->bd_bufmode) { case BPF_BUFMODE_BUFFER: - if (d->bd_sbuf == NULL) - bpf_buffer_alloc(d); - KASSERT(d->bd_sbuf != NULL, ("bpf_setif: bd_sbuf NULL")); - break; - case BPF_BUFMODE_ZBUF: if (d->bd_sbuf == NULL) return (EINVAL); diff --git a/sys/net/bpf_buffer.c b/sys/net/bpf_buffer.c index d338fca..64bb982 100644 --- a/sys/net/bpf_buffer.c +++ b/sys/net/bpf_buffer.c @@ -93,21 +93,6 @@ static int bpf_maxbufsize = BPF_MAXBUFSIZE; SYSCTL_INT(_net_bpf, OID_AUTO, maxbufsize, CTLFLAG_RW, &bpf_maxbufsize, 0, "Maximum capture buffer in bytes"); -void -bpf_buffer_alloc(struct bpf_d *d) -{ - - KASSERT(d->bd_fbuf == NULL, ("bpf_buffer_alloc: bd_fbuf != NULL")); - KASSERT(d->bd_sbuf == NULL, ("bpf_buffer_alloc: bd_sbuf != NULL")); - KASSERT(d->bd_hbuf == NULL, ("bpf_buffer_alloc: bd_hbuf != NULL")); - - d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_BPF, M_WAITOK); - d->bd_sbuf = (caddr_t)malloc(d->bd_bufsize, M_BPF, M_WAITOK); - d->bd_hbuf = NULL; - d->bd_slen = 0; - d->bd_hlen = 0; -} - /* * Simple data copy to the current kernel buffer. */ @@ -183,18 +168,42 @@ int bpf_buffer_ioctl_sblen(struct bpf_d *d, u_int *i) { u_int size; + caddr_t fbuf, sbuf; - BPFD_LOCK(d); - if (d->bd_bif != NULL) { - BPFD_UNLOCK(d); - return (EINVAL); - } size = *i; if (size > bpf_maxbufsize) *i = size = bpf_maxbufsize; else if (size < BPF_MINBUFSIZE) *i = size = BPF_MINBUFSIZE; + + /* Allocate buffers immediately */ + fbuf = (caddr_t)malloc(size, M_BPF, M_WAITOK); + sbuf = (caddr_t)malloc(size, M_BPF, M_WAITOK); + + BPFD_LOCK(d); + if (d->bd_bif != NULL) { + /* Interface already attached, unable to change buffers */ + BPFD_UNLOCK(d); + free(fbuf, M_BPF); + free(sbuf, M_BPF); + return (EINVAL); + } + + /* Free old buffers if set */ + if (d->bd_fbuf != NULL) + free(d->bd_fbuf, M_BPF); + if (d->bd_sbuf != NULL) + free(d->bd_sbuf, M_BPF); + + /* Fill in new data */ d->bd_bufsize = size; + d->bd_fbuf = fbuf; + d->bd_sbuf = sbuf; + + d->bd_hbuf = NULL; + d->bd_slen = 0; + d->bd_hlen = 0; + BPFD_UNLOCK(d); return (0); } diff --git a/sys/net/bpf_buffer.h b/sys/net/bpf_buffer.h index 733137f..c1dc1f3 100644 --- a/sys/net/bpf_buffer.h +++ b/sys/net/bpf_buffer.h @@ -36,7 +36,6 @@ #error "no user-serviceable parts inside" #endif -void bpf_buffer_alloc(struct bpf_d *d); void bpf_buffer_append_bytes(struct bpf_d *d, caddr_t buf, u_int offset, void *src, u_int len); void bpf_buffer_append_mbuf(struct bpf_d *d, caddr_t buf, u_int offset, |