xref: /openbsd-src/sys/kern/kern_time.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: kern_time.c,v 1.38 2003/09/01 18:06:03 henning Exp $	*/
2 /*	$NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)kern_time.c	8.4 (Berkeley) 5/26/95
33  */
34 
35 #include <sys/param.h>
36 #include <sys/resourcevar.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39 #include <sys/proc.h>
40 #include <sys/vnode.h>
41 #include <sys/signalvar.h>
42 
43 #include <sys/mount.h>
44 #include <sys/syscallargs.h>
45 
46 #include <machine/cpu.h>
47 
48 int	settime(struct timeval *);
49 void	itimerround(struct timeval *);
50 
51 /*
52  * Time of day and interval timer support.
53  *
54  * These routines provide the kernel entry points to get and set
55  * the time-of-day and per-process interval timers.  Subroutines
56  * here provide support for adding and subtracting timeval structures
57  * and decrementing interval timers, optionally reloading the interval
58  * timers when they expire.
59  */
60 
61 /* This function is used by clock_settime and settimeofday */
62 int
63 settime(struct timeval *tv)
64 {
65 	struct timeval delta;
66 	int s;
67 
68 	/*
69 	 * Don't allow the time to be set forward so far it will wrap
70 	 * and become negative, thus allowing an attacker to bypass
71 	 * the next check below.  The cutoff is 1 year before rollover
72 	 * occurs, so even if the attacker uses adjtime(2) to move
73 	 * the time past the cutoff, it will take a very long time
74 	 * to get to the wrap point.
75 	 *
76 	 * XXX: we check against INT_MAX since on 64-bit
77 	 *	platforms, sizeof(int) != sizeof(long) and
78 	 *	time_t is 32 bits even when atv.tv_sec is 64 bits.
79 	 */
80 	if (tv->tv_sec > INT_MAX - 365*24*60*60) {
81 		printf("denied attempt to set clock forward to %ld\n",
82 		    tv->tv_sec);
83 		return (EPERM);
84 	}
85 	/*
86 	 * If the system is secure, we do not allow the time to be
87 	 * set to an earlier value (it may be slowed using adjtime,
88 	 * but not set back). This feature prevent interlopers from
89 	 * setting arbitrary time stamps on files.
90 	 */
91 	if (securelevel > 1 && timercmp(tv, &time, <)) {
92 		printf("denied attempt to set clock back %ld seconds\n",
93 		    time.tv_sec - tv->tv_sec);
94 		return (EPERM);
95 	}
96 
97 	/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
98 	s = splclock();
99 	timersub(tv, &time, &delta);
100 	time = *tv;
101 	timeradd(&boottime, &delta, &boottime);
102 	timeradd(&runtime, &delta, &runtime);
103 	splx(s);
104 	resettodr();
105 
106 	return (0);
107 }
108 
109 /* ARGSUSED */
110 int
111 sys_clock_gettime(p, v, retval)
112 	struct proc *p;
113 	void *v;
114 	register_t *retval;
115 {
116 	register struct sys_clock_gettime_args /* {
117 		syscallarg(clockid_t) clock_id;
118 		syscallarg(struct timespec *) tp;
119 	} */ *uap = v;
120 	clockid_t clock_id;
121 	struct timeval atv;
122 	struct timespec ats;
123 	int s;
124 
125 	clock_id = SCARG(uap, clock_id);
126 	switch (clock_id) {
127 	case CLOCK_REALTIME:
128 		microtime(&atv);
129 		break;
130 	case CLOCK_MONOTONIC:
131 		/* XXX "hz" granularity */
132 		s = splclock();
133 		atv = mono_time;
134 		splx(s);
135 		break;
136 	default:
137 		return (EINVAL);
138 	}
139 
140 	TIMEVAL_TO_TIMESPEC(&atv,&ats);
141 
142 	return copyout(&ats, SCARG(uap, tp), sizeof(ats));
143 }
144 
145 /* ARGSUSED */
146 int
147 sys_clock_settime(p, v, retval)
148 	struct proc *p;
149 	void *v;
150 	register_t *retval;
151 {
152 	register struct sys_clock_settime_args /* {
153 		syscallarg(clockid_t) clock_id;
154 		syscallarg(const struct timespec *) tp;
155 	} */ *uap = v;
156 	clockid_t clock_id;
157 	struct timeval atv;
158 	struct timespec ats;
159 	int error;
160 
161 	if ((error = suser(p, 0)) != 0)
162 		return (error);
163 
164 	if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)
165 		return (error);
166 
167 	clock_id = SCARG(uap, clock_id);
168 	switch (clock_id) {
169 	case CLOCK_REALTIME:
170 		TIMESPEC_TO_TIMEVAL(&atv, &ats);
171 		if ((error = settime(&atv)) != 0)
172 			return (error);
173 		break;
174 	case CLOCK_MONOTONIC:
175 		return (EINVAL);	/* read-only clock */
176 	default:
177 		return (EINVAL);
178 	}
179 
180 	return (0);
181 }
182 
183 int
184 sys_clock_getres(p, v, retval)
185 	struct proc *p;
186 	void *v;
187 	register_t *retval;
188 {
189 	register struct sys_clock_getres_args /* {
190 		syscallarg(clockid_t) clock_id;
191 		syscallarg(struct timespec *) tp;
192 	} */ *uap = v;
193 	clockid_t clock_id;
194 	struct timespec ts;
195 	int error = 0;
196 
197 	clock_id = SCARG(uap, clock_id);
198 	switch (clock_id) {
199 	case CLOCK_REALTIME:
200 	case CLOCK_MONOTONIC:
201 		ts.tv_sec = 0;
202 		ts.tv_nsec = 1000000000 / hz;
203 		break;
204 	default:
205 		return (EINVAL);
206 	}
207 
208 	if (SCARG(uap, tp))
209 		error = copyout(&ts, SCARG(uap, tp), sizeof (ts));
210 
211 	return error;
212 }
213 
214 /* ARGSUSED */
215 int
216 sys_nanosleep(p, v, retval)
217 	struct proc *p;
218 	void *v;
219 	register_t *retval;
220 {
221 	static int nanowait;
222 	struct sys_nanosleep_args/* {
223 		syscallarg(const struct timespec *) rqtp;
224 		syscallarg(struct timespec *) rmtp;
225 	} */ *uap = v;
226 	struct timespec rqt;
227 	struct timespec rmt;
228 	struct timeval stv, etv, atv;
229 	int error, s, timo;
230 
231 	error = copyin((const void *)SCARG(uap, rqtp), (void *)&rqt,
232 	    sizeof(struct timespec));
233 	if (error)
234 		return (error);
235 
236 	TIMESPEC_TO_TIMEVAL(&atv,&rqt)
237 	if (itimerfix(&atv))
238 		return (EINVAL);
239 
240 	if (SCARG(uap, rmtp)) {
241 		s = splclock();
242 		stv = mono_time;
243 		splx(s);
244 	}
245 
246 	timo = tvtohz(&atv);
247 
248 	/* Avoid sleeping forever. */
249 	if (timo <= 0)
250 		timo = 1;
251 
252 	error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
253 	if (error == ERESTART)
254 		error = EINTR;
255 	if (error == EWOULDBLOCK)
256 		error = 0;
257 
258 	if (SCARG(uap, rmtp)) {
259 		int error;
260 
261 		s = splclock();
262 		etv = mono_time;
263 		splx(s);
264 
265 		timersub(&etv, &stv, &stv);
266 		timersub(&atv, &stv, &atv);
267 
268 		if (atv.tv_sec < 0)
269 			timerclear(&atv);
270 
271 		TIMEVAL_TO_TIMESPEC(&atv, &rmt);
272 		error = copyout((void *)&rmt, (void *)SCARG(uap,rmtp),
273 		    sizeof(rmt));
274 		if (error)
275 			return (error);
276 	}
277 
278 	return error;
279 }
280 
281 /* ARGSUSED */
282 int
283 sys_gettimeofday(p, v, retval)
284 	struct proc *p;
285 	void *v;
286 	register_t *retval;
287 {
288 	register struct sys_gettimeofday_args /* {
289 		syscallarg(struct timeval *) tp;
290 		syscallarg(struct timezone *) tzp;
291 	} */ *uap = v;
292 	struct timeval atv;
293 	int error = 0;
294 
295 	if (SCARG(uap, tp)) {
296 		microtime(&atv);
297 		if ((error = copyout((void *)&atv, (void *)SCARG(uap, tp),
298 		    sizeof (atv))))
299 			return (error);
300 	}
301 	if (SCARG(uap, tzp))
302 		error = copyout((void *)&tz, (void *)SCARG(uap, tzp),
303 		    sizeof (tz));
304 	return (error);
305 }
306 
307 /* ARGSUSED */
308 int
309 sys_settimeofday(p, v, retval)
310 	struct proc *p;
311 	void *v;
312 	register_t *retval;
313 {
314 	struct sys_settimeofday_args /* {
315 		syscallarg(const struct timeval *) tv;
316 		syscallarg(const struct timezone *) tzp;
317 	} */ *uap = v;
318 	struct timeval atv;
319 	struct timezone atz;
320 	int error;
321 
322 	if ((error = suser(p, 0)))
323 		return (error);
324 	/* Verify all parameters before changing time. */
325 	if (SCARG(uap, tv) && (error = copyin((void *)SCARG(uap, tv),
326 	    (void *)&atv, sizeof(atv))))
327 		return (error);
328 	if (SCARG(uap, tzp) && (error = copyin((void *)SCARG(uap, tzp),
329 	    (void *)&atz, sizeof(atz))))
330 		return (error);
331 	if (SCARG(uap, tv)) {
332 		if ((error = settime(&atv)) != 0)
333 			return (error);
334 	}
335 	if (SCARG(uap, tzp))
336 		tz = atz;
337 	return (0);
338 }
339 
340 int	tickdelta;			/* current clock skew, us. per tick */
341 long	timedelta;			/* unapplied time correction, us. */
342 long	bigadj = 1000000;		/* use 10x skew above bigadj us. */
343 
344 /* ARGSUSED */
345 int
346 sys_adjtime(p, v, retval)
347 	struct proc *p;
348 	void *v;
349 	register_t *retval;
350 {
351 	register struct sys_adjtime_args /* {
352 		syscallarg(const struct timeval *) delta;
353 		syscallarg(struct timeval *) olddelta;
354 	} */ *uap = v;
355 	struct timeval atv;
356 	register long ndelta, ntickdelta, odelta;
357 	int s, error;
358 
359 	if ((error = suser(p, 0)))
360 		return (error);
361 	if ((error = copyin((void *)SCARG(uap, delta), (void *)&atv,
362 	    sizeof(struct timeval))))
363 		return (error);
364 
365 	/*
366 	 * Compute the total correction and the rate at which to apply it.
367 	 * Round the adjustment down to a whole multiple of the per-tick
368 	 * delta, so that after some number of incremental changes in
369 	 * hardclock(), tickdelta will become zero, lest the correction
370 	 * overshoot and start taking us away from the desired final time.
371 	 */
372 	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
373 	if (ndelta > bigadj)
374 		ntickdelta = 10 * tickadj;
375 	else
376 		ntickdelta = tickadj;
377 	if (ndelta % ntickdelta)
378 		ndelta = ndelta / ntickdelta * ntickdelta;
379 
380 	/*
381 	 * To make hardclock()'s job easier, make the per-tick delta negative
382 	 * if we want time to run slower; then hardclock can simply compute
383 	 * tick + tickdelta, and subtract tickdelta from timedelta.
384 	 */
385 	if (ndelta < 0)
386 		ntickdelta = -ntickdelta;
387 	s = splclock();
388 	odelta = timedelta;
389 	timedelta = ndelta;
390 	tickdelta = ntickdelta;
391 	splx(s);
392 
393 	if (SCARG(uap, olddelta)) {
394 		atv.tv_sec = odelta / 1000000;
395 		atv.tv_usec = odelta % 1000000;
396 		if ((error = copyout((void *)&atv, (void *)SCARG(uap, olddelta),
397 		    sizeof(struct timeval))))
398 			return (error);
399 	}
400 	return (0);
401 }
402 
403 /*
404  * Get value of an interval timer.  The process virtual and
405  * profiling virtual time timers are kept in the p_stats area, since
406  * they can be swapped out.  These are kept internally in the
407  * way they are specified externally: in time until they expire.
408  *
409  * The real time interval timer is kept in the process table slot
410  * for the process, and its value (it_value) is kept as an
411  * absolute time rather than as a delta, so that it is easy to keep
412  * periodic real-time signals from drifting.
413  *
414  * Virtual time timers are processed in the hardclock() routine of
415  * kern_clock.c.  The real time timer is processed by a timeout
416  * routine, called from the softclock() routine.  Since a callout
417  * may be delayed in real time due to interrupt processing in the system,
418  * it is possible for the real time timeout routine (realitexpire, given below),
419  * to be delayed in real time past when it is supposed to occur.  It
420  * does not suffice, therefore, to reload the real timer .it_value from the
421  * real time timers .it_interval.  Rather, we compute the next time in
422  * absolute time the timer should go off.
423  */
424 /* ARGSUSED */
425 int
426 sys_getitimer(p, v, retval)
427 	struct proc *p;
428 	void *v;
429 	register_t *retval;
430 {
431 	register struct sys_getitimer_args /* {
432 		syscallarg(int) which;
433 		syscallarg(struct itimerval *) itv;
434 	} */ *uap = v;
435 	struct itimerval aitv;
436 	int s;
437 
438 	if (SCARG(uap, which) < ITIMER_REAL || SCARG(uap, which) > ITIMER_PROF)
439 		return (EINVAL);
440 	s = splclock();
441 	if (SCARG(uap, which) == ITIMER_REAL) {
442 		/*
443 		 * Convert from absolute to relative time in .it_value
444 		 * part of real time timer.  If time for real time timer
445 		 * has passed return 0, else return difference between
446 		 * current time and time for the timer to go off.
447 		 */
448 		aitv = p->p_realtimer;
449 		if (timerisset(&aitv.it_value)) {
450 			if (timercmp(&aitv.it_value, &time, <))
451 				timerclear(&aitv.it_value);
452 			else
453 				timersub(&aitv.it_value, &time,
454 				    &aitv.it_value);
455 		}
456 	} else
457 		aitv = p->p_stats->p_timer[SCARG(uap, which)];
458 	splx(s);
459 	return (copyout((void *)&aitv, (void *)SCARG(uap, itv),
460 	    sizeof (struct itimerval)));
461 }
462 
463 /* ARGSUSED */
464 int
465 sys_setitimer(p, v, retval)
466 	struct proc *p;
467 	register void *v;
468 	register_t *retval;
469 {
470 	register struct sys_setitimer_args /* {
471 		syscallarg(int) which;
472 		syscallarg(const struct itimerval *) itv;
473 		syscallarg(struct itimerval *) oitv;
474 	} */ *uap = v;
475 	struct itimerval aitv;
476 	register const struct itimerval *itvp;
477 	int s, error;
478 	int timo;
479 
480 	if (SCARG(uap, which) < ITIMER_REAL || SCARG(uap, which) > ITIMER_PROF)
481 		return (EINVAL);
482 	itvp = SCARG(uap, itv);
483 	if (itvp && (error = copyin((void *)itvp, (void *)&aitv,
484 	    sizeof(struct itimerval))))
485 		return (error);
486 	if ((SCARG(uap, itv) = SCARG(uap, oitv)) &&
487 	    (error = sys_getitimer(p, uap, retval)))
488 		return (error);
489 	if (itvp == 0)
490 		return (0);
491 	if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
492 		return (EINVAL);
493 	s = splclock();
494 	if (SCARG(uap, which) == ITIMER_REAL) {
495 		timeout_del(&p->p_realit_to);
496 		if (timerisset(&aitv.it_value)) {
497 			timeradd(&aitv.it_value, &time, &aitv.it_value);
498 			timo = hzto(&aitv.it_value);
499 			if (timo <= 0)
500 				timo = 1;
501 			timeout_add(&p->p_realit_to, timo);
502 		}
503 		p->p_realtimer = aitv;
504 	} else {
505 		itimerround(&aitv.it_interval);
506 		p->p_stats->p_timer[SCARG(uap, which)] = aitv;
507 	}
508 	splx(s);
509 	return (0);
510 }
511 
512 /*
513  * Real interval timer expired:
514  * send process whose timer expired an alarm signal.
515  * If time is not set up to reload, then just return.
516  * Else compute next time timer should go off which is > current time.
517  * This is where delay in processing this timeout causes multiple
518  * SIGALRM calls to be compressed into one.
519  */
520 void
521 realitexpire(arg)
522 	void *arg;
523 {
524 	register struct proc *p;
525 	int s, timo;
526 
527 	p = (struct proc *)arg;
528 	psignal(p, SIGALRM);
529 	if (!timerisset(&p->p_realtimer.it_interval)) {
530 		timerclear(&p->p_realtimer.it_value);
531 		return;
532 	}
533 	for (;;) {
534 		s = splclock();
535 		timeradd(&p->p_realtimer.it_value,
536 		    &p->p_realtimer.it_interval, &p->p_realtimer.it_value);
537 		if (timercmp(&p->p_realtimer.it_value, &time, >)) {
538 			timo = hzto(&p->p_realtimer.it_value);
539 			if (timo <= 0)
540 				timo = 1;
541 			timeout_add(&p->p_realit_to, timo);
542 			splx(s);
543 			return;
544 		}
545 		splx(s);
546 	}
547 }
548 
549 /*
550  * Check that a proposed value to load into the .it_value or
551  * .it_interval part of an interval timer is acceptable.
552  */
553 int
554 itimerfix(tv)
555 	struct timeval *tv;
556 {
557 
558 	if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
559 	    tv->tv_usec < 0 || tv->tv_usec >= 1000000)
560 		return (EINVAL);
561 
562 	return (0);
563 }
564 
565 /*
566  * Timer interval smaller than the resolution of the system clock are
567  * rounded up.
568  */
569 void
570 itimerround(tv)
571 	struct timeval *tv;
572 {
573 	if (tv->tv_sec == 0 && tv->tv_usec < tick)
574 		tv->tv_usec = tick;
575 }
576 
577 /*
578  * Decrement an interval timer by a specified number
579  * of microseconds, which must be less than a second,
580  * i.e. < 1000000.  If the timer expires, then reload
581  * it.  In this case, carry over (usec - old value) to
582  * reduce the value reloaded into the timer so that
583  * the timer does not drift.  This routine assumes
584  * that it is called in a context where the timers
585  * on which it is operating cannot change in value.
586  */
587 int
588 itimerdecr(itp, usec)
589 	register struct itimerval *itp;
590 	int usec;
591 {
592 
593 	if (itp->it_value.tv_usec < usec) {
594 		if (itp->it_value.tv_sec == 0) {
595 			/* expired, and already in next interval */
596 			usec -= itp->it_value.tv_usec;
597 			goto expire;
598 		}
599 		itp->it_value.tv_usec += 1000000;
600 		itp->it_value.tv_sec--;
601 	}
602 	itp->it_value.tv_usec -= usec;
603 	usec = 0;
604 	if (timerisset(&itp->it_value))
605 		return (1);
606 	/* expired, exactly at end of interval */
607 expire:
608 	if (timerisset(&itp->it_interval)) {
609 		itp->it_value = itp->it_interval;
610 		itp->it_value.tv_usec -= usec;
611 		if (itp->it_value.tv_usec < 0) {
612 			itp->it_value.tv_usec += 1000000;
613 			itp->it_value.tv_sec--;
614 		}
615 	} else
616 		itp->it_value.tv_usec = 0;		/* sec is already 0 */
617 	return (0);
618 }
619 
620 /*
621  * ratecheck(): simple time-based rate-limit checking.  see ratecheck(9)
622  * for usage and rationale.
623  */
624 int
625 ratecheck(lasttime, mininterval)
626 	struct timeval *lasttime;
627 	const struct timeval *mininterval;
628 {
629 	struct timeval tv, delta;
630 	int s, rv = 0;
631 
632 	s = splclock();
633 	tv = mono_time;
634 	splx(s);
635 
636 	timersub(&tv, lasttime, &delta);
637 
638 	/*
639 	 * check for 0,0 is so that the message will be seen at least once,
640 	 * even if interval is huge.
641 	 */
642 	if (timercmp(&delta, mininterval, >=) ||
643 	    (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) {
644 		*lasttime = tv;
645 		rv = 1;
646 	}
647 
648 	return (rv);
649 }
650 
651 /*
652  * ppsratecheck(): packets (or events) per second limitation.
653  */
654 int
655 ppsratecheck(lasttime, curpps, maxpps)
656 	struct timeval *lasttime;
657 	int *curpps;
658 	int maxpps;	/* maximum pps allowed */
659 {
660 	struct timeval tv, delta;
661 	int s, rv;
662 
663 	s = splclock();
664 	tv = mono_time;
665 	splx(s);
666 
667 	timersub(&tv, lasttime, &delta);
668 
669 	/*
670 	 * check for 0,0 is so that the message will be seen at least once.
671 	 * if more than one second have passed since the last update of
672 	 * lasttime, reset the counter.
673 	 *
674 	 * we do increment *curpps even in *curpps < maxpps case, as some may
675 	 * try to use *curpps for stat purposes as well.
676 	 */
677 	if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
678 	    delta.tv_sec >= 1) {
679 		*lasttime = tv;
680 		*curpps = 0;
681 		rv = 1;
682 	} else if (maxpps < 0)
683 		rv = 1;
684 	else if (*curpps < maxpps)
685 		rv = 1;
686 	else
687 		rv = 0;
688 
689 #if 1 /*DIAGNOSTIC?*/
690 	/* be careful about wrap-around */
691 	if (*curpps + 1 > *curpps)
692 		*curpps = *curpps + 1;
693 #else
694 	/*
695 	 * assume that there's not too many calls to this function.
696 	 * not sure if the assumption holds, as it depends on *caller's*
697 	 * behavior, not the behavior of this function.
698 	 * IMHO it is wrong to make assumption on the caller's behavior,
699 	 * so the above #if is #if 1, not #ifdef DIAGNOSTIC.
700 	 */
701 	*curpps = *curpps + 1;
702 #endif
703 
704 	return (rv);
705 }
706