Now that we've removed bd_rdStart from the bpf_d struct, removing
ticks from bpf(4) itself is straightforward.

- bd_rtout becomes a timespec; update bpfioctl() accordingly.
  Cap it at MAXTSLP nanoseconds to avoid arithmetic overflow
  in bpfread().

- At the start of bpfread(), if a timeout is set, find the end
  of the read as an absolute uptime.  This is the point where
  we want to avoid overflow: if bd_rtout is only MAXTSLP
  nanoseconds the timespecadd(3) will effectively never overflow.

- Before going to sleep, if we have a timeout set, compute how
  much longer to sleep in nanoseconds.

  Here's a spot where an absolute timeout sleep would save a
  little code, but we don't have such an interface yet.  Worth
  keeping in mind for the future, though.

dlg@: You said you wanted to simplify this loop.  Unsure what shape
that cleanup would take.  Should we clean it up before this change?

Thoughts?  ok?

Index: bpf.c
===================================================================
RCS file: /cvs/src/sys/net/bpf.c,v
retrieving revision 1.199
diff -u -p -r1.199 bpf.c
--- bpf.c       26 Dec 2020 16:30:58 -0000      1.199
+++ bpf.c       26 Dec 2020 22:05:04 -0000
@@ -60,6 +60,7 @@
 #include <sys/selinfo.h>
 #include <sys/sigio.h>
 #include <sys/task.h>
+#include <sys/time.h>
 
 #include <net/if.h>
 #include <net/bpf.h>
@@ -77,9 +78,6 @@
 
 #define PRINET  26                     /* interruptible */
 
-/* from kern/kern_clock.c; incremented each clock tick. */
-extern int ticks;
-
 /*
  * The default read buffer size is patchable.
  */
@@ -380,7 +378,7 @@ bpfopen(dev_t dev, int flag, int mode, s
        smr_init(&bd->bd_smr);
        sigio_init(&bd->bd_sigio);
 
-       bd->bd_rtout = 0;       /* no timeout by default */
+       timespecclear(&bd->bd_rtout);   /* no timeout by default */
        bd->bd_rnonblock = ISSET(flag, FNONBLOCK);
 
        bpf_get(bd);
@@ -428,9 +426,11 @@ bpfclose(dev_t dev, int flag, int mode, 
 int
 bpfread(dev_t dev, struct uio *uio, int ioflag)
 {
+       struct timespec diff, end, now;
+       uint64_t nsecs;
        struct bpf_d *d;
        caddr_t hbuf;
-       int end, error, hlen, nticks;
+       int error, hlen, timeout;
 
        KERNEL_ASSERT_LOCKED();
 
@@ -453,8 +453,11 @@ bpfread(dev_t dev, struct uio *uio, int 
        /*
         * If there's a timeout, mark when the read should end.
         */
-       if (d->bd_rtout)
-               end = ticks + (int)d->bd_rtout;
+       timeout = timespecisset(&d->bd_rtout);
+       if (timeout) {
+               nanouptime(&now);
+               timespecadd(&now, &d->bd_rtout, &end);
+       }
 
        /*
         * If the hold buffer is empty, then do a timed sleep, which
@@ -483,21 +486,26 @@ bpfread(dev_t dev, struct uio *uio, int 
                if (d->bd_rnonblock) {
                        /* User requested non-blocking I/O */
                        error = EWOULDBLOCK;
-               } else if (d->bd_rtout == 0) {
+               } else if (timeout == 0) {
                        /* No read timeout set. */
                        d->bd_nreaders++;
                        error = msleep_nsec(d, &d->bd_mtx, PRINET|PCATCH,
                            "bpf", INFSLP);
                        d->bd_nreaders--;
-               } else if ((nticks = end - ticks) > 0) {
-                       /* Read timeout has not expired yet. */
-                       d->bd_nreaders++;
-                       error = msleep(d, &d->bd_mtx, PRINET|PCATCH, "bpf",
-                           nticks);
-                       d->bd_nreaders--;
                } else {
-                       /* Read timeout has expired. */
-                       error = EWOULDBLOCK;
+                       nanouptime(&now);
+                       if (timespeccmp(&now, &end, <)) {
+                               /* Read timeout has not expired yet. */
+                               timespecsub(&end, &now, &diff);
+                               nsecs = TIMESPEC_TO_NSEC(&diff);
+                               d->bd_nreaders++;
+                               error = msleep_nsec(d, &d->bd_mtx,
+                                   PRINET|PCATCH, "bpf", nsecs);
+                               d->bd_nreaders--;
+                       } else {
+                               /* Read timeout has expired. */
+                               error = EWOULDBLOCK;
+                       }
                }
                if (error == EINTR || error == ERESTART)
                        goto out;
@@ -861,27 +869,17 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t 
        case BIOCSRTIMEOUT:
                {
                        struct timeval *tv = (struct timeval *)addr;
-                       u_long rtout;
 
-                       /* Compute number of ticks. */
                        if (tv->tv_sec < 0 || !timerisvalid(tv)) {
                                error = EINVAL;
                                break;
                        }
-                       if (tv->tv_sec > INT_MAX / hz) {
-                               error = EOVERFLOW;
-                               break;
-                       }
-                       rtout = tv->tv_sec * hz;
-                       if (tv->tv_usec / tick > INT_MAX - rtout) {
+                       if (TIMEVAL_TO_NSEC(tv) > MAXTSLP) {
                                error = EOVERFLOW;
                                break;
                        }
-                       rtout += tv->tv_usec / tick;
                        mtx_enter(&d->bd_mtx);
-                       d->bd_rtout = rtout;
-                       if (d->bd_rtout == 0 && tv->tv_usec != 0)
-                               d->bd_rtout = 1;
+                       TIMEVAL_TO_TIMESPEC(tv, &d->bd_rtout);
                        mtx_leave(&d->bd_mtx);
                        break;
                }
@@ -893,9 +891,9 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t 
                {
                        struct timeval *tv = (struct timeval *)addr;
 
+                       memset(tv, 0, sizeof(*tv));
                        mtx_enter(&d->bd_mtx);
-                       tv->tv_sec = d->bd_rtout / hz;
-                       tv->tv_usec = (d->bd_rtout % hz) * tick;
+                       TIMESPEC_TO_TIMEVAL(tv, &d->bd_rtout);
                        mtx_leave(&d->bd_mtx);
                        break;
                }
Index: bpfdesc.h
===================================================================
RCS file: /cvs/src/sys/net/bpfdesc.h,v
retrieving revision 1.43
diff -u -p -r1.43 bpfdesc.h
--- bpfdesc.h   26 Dec 2020 16:30:58 -0000      1.43
+++ bpfdesc.h   26 Dec 2020 22:05:04 -0000
@@ -78,7 +78,7 @@ struct bpf_d {
        int             bd_in_uiomove;  /* for debugging purpose */
 
        struct bpf_if  *bd_bif;         /* interface descriptor */
-       u_long          bd_rtout;       /* [m] Read timeout in 'ticks' */
+       struct timespec bd_rtout;       /* [m] Read timeout if non-zero */
        u_long          bd_nreaders;    /* [m] # threads asleep in bpfread() */
        int             bd_rnonblock;   /* true if nonblocking reads are set */
        struct bpf_program_smr

Reply via email to