diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index bc21dc641cb1..fb63e7874ab0 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -581,6 +581,9 @@ MLINKS+=condvar.9 cv_broadcast.9 \ MLINKS+=config_intrhook.9 config_intrhook_disestablish.9 \ config_intrhook.9 config_intrhook_establish.9 MLINKS+=contigmalloc.9 contigfree.9 +MLINKS+=casuword.9 casueword.9 \ + casuword.9 casueword32.9 \ + casuword.9 casuword32.9 MLINKS+=copy.9 copyin.9 \ copy.9 copyin_nofault.9 \ copy.9 copyinstr.9 \ @@ -688,7 +691,10 @@ MLINKS+=fetch.9 fubyte.9 \ fetch.9 fuword.9 \ fetch.9 fuword16.9 \ fetch.9 fuword32.9 \ - fetch.9 fuword64.9 + fetch.9 fuword64.9 \ + fetch.9 fueword.9 \ + fetch.9 fueword32.9 \ + fetch.9 fueword64.9 MLINKS+=firmware.9 firmware_get.9 \ firmware.9 firmware_put.9 \ firmware.9 firmware_register.9 \ diff --git a/share/man/man9/casuword.9 b/share/man/man9/casuword.9 new file mode 100644 index 000000000000..34a0f1dce6fd --- /dev/null +++ b/share/man/man9/casuword.9 @@ -0,0 +1,95 @@ +.\" Copyright (c) 2014 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" Part of this documentation was written by +.\" Konstantin Belousov under sponsorship +.\" from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 21, 2014 +.Dt CASU 9 +.Os +.Sh NAME +.Nm casueword , +.Nm casueword32 , +.Nm casuword , +.Nm casuword32 +.Nd fetch, compare and store data from user-space +.Sh SYNOPSIS +.In sys/types.h +.In sys/systm.h +.Ft int +.Fn casueword "volatile u_long *base" "u_long oldval" "u_long *oldvalp" "u_long newval" +.Ft int +.Fn casueword32 "volatile uint32_t *base" "uint32_t oldval" "uint32_t *oldvalp" "uint32_t newval" +.Ft u_long +.Fn casuword "volatile u_long *base" "u_long oldval" "u_long newval" +.Ft uint32_t +.Fn casuword32 "volatile uint32_t *base" "uint32_t oldval" "uint32_t newval" +.Sh DESCRIPTION +The +.Nm +functions are designed to perform atomic compare-and-swap operation on +the value in the usermode memory of the current process. +.Pp +The +.Nm +routines reads the value from user memory with address +.Pa base , +and compare the value read with +.Pa oldval . +If the values are equal, +.Pa newval +is written to the +.Pa *base . +In case of +.Fn casueword32 +and +.Fn casueword , +old value is stored into the (kernel-mode) variable pointed by +.Pa *oldvalp . +The userspace value must be naturally aligned. +.Pp +The callers of +.Fn casuword +and +.Fn casuword32 +functions cannot distinguish between -1 read from +userspace and function failure. +.Sh RETURN VALUES +The +.Fn casuword +and +.Fn casuword32 +functions return the data fetched or -1 on failure. +The +.Fn casueword +and +.Fn casueword32 +functions return 0 on success and -1 on failure. +.Sh SEE ALSO +.Xr atomic 9 , +.Xr fetch 9 , +.Xr store 9 diff --git a/share/man/man9/fetch.9 b/share/man/man9/fetch.9 index ccf68668d3d8..7e13cbc51c45 100644 --- a/share/man/man9/fetch.9 +++ b/share/man/man9/fetch.9 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 5, 2009 +.Dd October 21, 2014 .Dt FETCH 9 .Os .Sh NAME @@ -44,11 +44,13 @@ .Nm fuword , .Nm fuword16 , .Nm fuword32 , -.Nm fuword64 +.Nm fuword64 , +.Nm fueword , +.Nm fueword32 , +.Nm fueword64 .Nd fetch data from user-space .Sh SYNOPSIS .In sys/types.h -.In sys/time.h .In sys/systm.h .Ft int .Fn fubyte "const void *base" @@ -60,27 +62,38 @@ .Fn fuword32 "const void *base" .Ft int64_t .Fn fuword64 "const void *base" +.Ft long +.Fn fueword "const void *base" "long *val" +.Ft int32_t +.Fn fueword32 "const void *base" "int32_t *val" +.Ft int64_t +.Fn fueword64 "const void *base" "int64_t *val" .In sys/resourcevar.h .Ft int .Fn fuswintr "void *base" .Sh DESCRIPTION The .Nm -functions are designed to copy small amounts of data from user-space. +functions are designed to copy small amounts of data from user-space +of the current process. +If read is successful, it is performed atomically. +The data read must be naturally aligned. .Pp The .Nm routines provide the following functionality: -.Bl -tag -width "fuswintr()" +.Bl -tag -width "fueword32()" .It Fn fubyte Fetches a byte of data from the user-space address .Pa base . +The byte read is zero-extended into the results variable. .It Fn fuword -Fetches a word of data from the user-space address +Fetches a word of data (long) from the user-space address .Pa base . .It Fn fuword16 Fetches 16 bits of data from the user-space address .Pa base . +The half-word read is zero-extended into the results variable. .It Fn fuword32 Fetches 32 bits of data from the user-space address .Pa base . @@ -91,11 +104,46 @@ Fetches 64 bits of data from the user-space address Fetches a short word of data from the user-space address .Pa base . This function is safe to call during an interrupt context. +.It Fn fueword +Fetches a word of data (long) from the user-space address +.Pa base +and stores the result in the variable pointed by +.Pa val . +.It Fn fueword32 +Fetches 32 bits of data from the user-space address +.Pa base +and stores the result in the variable pointed by +.Pa val . +.It Fn fueword64 +Fetches 64 bits of data from the user-space address +.Pa base +and stores the result in the variable pointed by +.Pa val . .El +.Pp +The callers of +.Fn fuword , +.Fn fuword32 +and +.Fn fuword64 +functions cannot distinguish between -1 read from +userspace and function failure. .Sh RETURN VALUES The -.Nm +.Fn fubyte , +.Fn fuword , +.Fn fuword16 , +.Fn fuword32 , +.Fn fuword64 , +and +.Fn fuswintr functions return the data fetched or -1 on failure. +The +.Fn fueword , +.Fn fueword32 +and +.Fn fueword64 +functions return 0 on success and -1 on failure. .Sh SEE ALSO .Xr copy 9 , .Xr store 9 diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S index 489736757aba..50e653d8b414 100644 --- a/sys/amd64/amd64/support.S +++ b/sys/amd64/amd64/support.S @@ -312,12 +312,13 @@ copyin_fault: END(copyin) /* - * casuword32. Compare and set user integer. Returns -1 or the current value. - * dst = %rdi, old = %rsi, new = %rdx + * casueword32. Compare and set user integer. Returns -1 on fault, + * 0 if access was successful. Old value is written to *oldp. + * dst = %rdi, old = %esi, oldp = %rdx, new = %ecx */ -ENTRY(casuword32) - movq PCPU(CURPCB),%rcx - movq $fusufault,PCB_ONFAULT(%rcx) +ENTRY(casueword32) + movq PCPU(CURPCB),%r8 + movq $fusufault,PCB_ONFAULT(%r8) movq $VM_MAXUSER_ADDRESS-4,%rax cmpq %rax,%rdi /* verify address is valid */ @@ -327,26 +328,34 @@ ENTRY(casuword32) #ifdef SMP lock #endif - cmpxchgl %edx,(%rdi) /* new = %edx */ + cmpxchgl %ecx,(%rdi) /* new = %ecx */ /* * The old value is in %eax. If the store succeeded it will be the * value we expected (old) from before the store, otherwise it will - * be the current value. + * be the current value. Save %eax into %esi to prepare the return + * value. */ + movl %eax,%esi + xorl %eax,%eax + movq %rax,PCB_ONFAULT(%r8) - movq PCPU(CURPCB),%rcx - movq $0,PCB_ONFAULT(%rcx) + /* + * Access the oldp after the pcb_onfault is cleared, to correctly + * catch corrupted pointer. + */ + movl %esi,(%rdx) /* oldp = %rdx */ ret -END(casuword32) +END(casueword32) /* - * casuword. Compare and set user word. Returns -1 or the current value. - * dst = %rdi, old = %rsi, new = %rdx + * casueword. Compare and set user long. Returns -1 on fault, + * 0 if access was successful. Old value is written to *oldp. + * dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx */ -ENTRY(casuword) - movq PCPU(CURPCB),%rcx - movq $fusufault,PCB_ONFAULT(%rcx) +ENTRY(casueword) + movq PCPU(CURPCB),%r8 + movq $fusufault,PCB_ONFAULT(%r8) movq $VM_MAXUSER_ADDRESS-4,%rax cmpq %rax,%rdi /* verify address is valid */ @@ -356,28 +365,28 @@ ENTRY(casuword) #ifdef SMP lock #endif - cmpxchgq %rdx,(%rdi) /* new = %rdx */ + cmpxchgq %rcx,(%rdi) /* new = %rcx */ /* - * The old value is in %eax. If the store succeeded it will be the + * The old value is in %rax. If the store succeeded it will be the * value we expected (old) from before the store, otherwise it will * be the current value. */ - - movq PCPU(CURPCB),%rcx - movq $fusufault,PCB_ONFAULT(%rcx) - movq $0,PCB_ONFAULT(%rcx) + movq %rax,%rsi + xorl %eax,%eax + movq %rax,PCB_ONFAULT(%r8) + movq %rsi,(%rdx) ret -END(casuword) +END(casueword) /* * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit - * byte from user memory. All these functions are MPSAFE. - * addr = %rdi + * byte from user memory. + * addr = %rdi, valp = %rsi */ -ALTENTRY(fuword64) -ENTRY(fuword) +ALTENTRY(fueword64) +ENTRY(fueword) movq PCPU(CURPCB),%rcx movq $fusufault,PCB_ONFAULT(%rcx) @@ -385,13 +394,15 @@ ENTRY(fuword) cmpq %rax,%rdi /* verify address is valid */ ja fusufault - movq (%rdi),%rax - movq $0,PCB_ONFAULT(%rcx) + xorl %eax,%eax + movq (%rdi),%r11 + movq %rax,PCB_ONFAULT(%rcx) + movq %r11,(%rsi) ret END(fuword64) END(fuword) -ENTRY(fuword32) +ENTRY(fueword32) movq PCPU(CURPCB),%rcx movq $fusufault,PCB_ONFAULT(%rcx) @@ -399,10 +410,12 @@ ENTRY(fuword32) cmpq %rax,%rdi /* verify address is valid */ ja fusufault - movl (%rdi),%eax - movq $0,PCB_ONFAULT(%rcx) + xorl %eax,%eax + movl (%rdi),%r11d + movq %rax,PCB_ONFAULT(%rcx) + movl %r11d,(%rsi) ret -END(fuword32) +END(fueword32) /* * fuswintr() and suswintr() are specialized variants of fuword16() and diff --git a/sys/arm/include/param.h b/sys/arm/include/param.h index 4a64607c8f16..626715410f25 100644 --- a/sys/arm/include/param.h +++ b/sys/arm/include/param.h @@ -149,4 +149,8 @@ #define pgtok(x) ((x) * (PAGE_SIZE / 1024)) +#ifdef _KERNEL +#define NO_FUEWORD 1 +#endif + #endif /* !_ARM_INCLUDE_PARAM_H_ */ diff --git a/sys/i386/i386/support.s b/sys/i386/i386/support.s index c126f78f276e..0a08012e0ec0 100644 --- a/sys/i386/i386/support.s +++ b/sys/i386/i386/support.s @@ -389,16 +389,16 @@ copyin_fault: ret /* - * casuword. Compare and set user word. Returns -1 or the current value. + * casueword. Compare and set user word. Returns -1 on fault, + * 0 on non-faulting access. The current value is in *oldp. */ - -ALTENTRY(casuword32) -ENTRY(casuword) +ALTENTRY(casueword32) +ENTRY(casueword) movl PCPU(CURPCB),%ecx movl $fusufault,PCB_ONFAULT(%ecx) movl 4(%esp),%edx /* dst */ movl 8(%esp),%eax /* old */ - movl 12(%esp),%ecx /* new */ + movl 16(%esp),%ecx /* new */ cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */ ja fusufault @@ -416,17 +416,20 @@ ENTRY(casuword) movl PCPU(CURPCB),%ecx movl $0,PCB_ONFAULT(%ecx) + movl 12(%esp),%edx /* oldp */ + movl %eax,(%edx) + xorl %eax,%eax ret -END(casuword32) -END(casuword) +END(casueword32) +END(casueword) /* * Fetch (load) a 32-bit word, a 16-bit word, or an 8-bit byte from user - * memory. All these functions are MPSAFE. + * memory. */ -ALTENTRY(fuword32) -ENTRY(fuword) +ALTENTRY(fueword32) +ENTRY(fueword) movl PCPU(CURPCB),%ecx movl $fusufault,PCB_ONFAULT(%ecx) movl 4(%esp),%edx /* from */ @@ -436,9 +439,12 @@ ENTRY(fuword) movl (%edx),%eax movl $0,PCB_ONFAULT(%ecx) + movl 8(%esp),%edx + movl %eax,(%edx) + xorl %eax,%eax ret -END(fuword32) -END(fuword) +END(fueword32) +END(fueword) /* * fuswintr() and suswintr() are specialized variants of fuword16() and diff --git a/sys/kern/subr_uio.c b/sys/kern/subr_uio.c index f2e6e3275cd6..f2bbb0cdff12 100644 --- a/sys/kern/subr_uio.c +++ b/sys/kern/subr_uio.c @@ -7,6 +7,11 @@ * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * + * Copyright (c) 2014 The FreeBSD Foundation + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -438,3 +443,128 @@ copyout_unmap(struct thread *td, vm_offset_t addr, size_t sz) return (0); } + +#ifdef NO_FUEWORD +/* + * XXXKIB The temporal implementation of fue*() functions which do not + * handle usermode -1 properly, mixing it with the fault code. Keep + * this until MD code is written. Currently sparc64, mips and arm do + * not have proper implementation. + */ + +int +fueword(const void *base, long *val) +{ + long res; + + res = fuword(base); + if (res == -1) + return (-1); + *val = res; + return (0); +} + +int +fueword32(const void *base, int32_t *val) +{ + int32_t res; + + res = fuword32(base); + if (res == -1) + return (-1); + *val = res; + return (0); +} + +#ifdef _LP64 +int +fueword64(const void *base, int64_t *val) +{ + int32_t res; + + res = fuword64(base); + if (res == -1) + return (-1); + *val = res; + return (0); +} +#endif + +int +casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp, + uint32_t newval) +{ + int32_t ov; + + ov = casuword32(base, oldval, newval); + if (ov == -1) + return (-1); + *oldvalp = ov; + return (0); +} + +int +casueword(volatile u_long *p, u_long oldval, u_long *oldvalp, u_long newval) +{ + u_long ov; + + ov = casuword(p, oldval, newval); + if (ov == -1) + return (-1); + *oldvalp = ov; + return (0); +} +#else /* NO_FUEWORD */ +int32_t +fuword32(const void *addr) +{ + int rv; + int32_t val; + + rv = fueword32(addr, &val); + return (rv == -1 ? -1 : val); +} + +#ifdef _LP64 +int64_t +fuword64(const void *addr) +{ + int rv; + int64_t val; + + rv = fueword64(addr, &val); + return (rv == -1 ? -1 : val); +} +#endif /* _LP64 */ + +long +fuword(const void *addr) +{ + long val; + int rv; + + rv = fueword(addr, &val); + return (rv == -1 ? -1 : val); +} + +uint32_t +casuword32(volatile uint32_t *addr, uint32_t old, uint32_t new) +{ + int rv; + uint32_t val; + + rv = casueword32(addr, old, &val, new); + return (rv == -1 ? -1 : val); +} + +u_long +casuword(volatile u_long *addr, u_long old, u_long new) +{ + int rv; + u_long val; + + rv = casueword(addr, old, &val, new); + return (rv == -1 ? -1 : val); +} + +#endif /* NO_FUEWORD */ diff --git a/sys/mips/include/param.h b/sys/mips/include/param.h index 2d1d7f1a416c..90f3e6f4ec6c 100644 --- a/sys/mips/include/param.h +++ b/sys/mips/include/param.h @@ -178,4 +178,8 @@ #define pgtok(x) ((x) * (PAGE_SIZE / 1024)) +#ifdef _KERNEL +#define NO_FUEWORD 1 +#endif + #endif /* !_MIPS_INCLUDE_PARAM_H_ */ diff --git a/sys/powerpc/powerpc/copyinout.c b/sys/powerpc/powerpc/copyinout.c index dcfab809b250..a337c8b73495 100644 --- a/sys/powerpc/powerpc/copyinout.c +++ b/sys/powerpc/powerpc/copyinout.c @@ -405,14 +405,68 @@ fubyte(const void *addr) return (val); } +int +fuword16(const void *addr) +{ + struct thread *td; + pmap_t pm; + faultbuf env; + uint16_t *p, val; + + td = curthread; + pm = &td->td_proc->p_vmspace->vm_pmap; + + if (setfault(env)) { + td->td_pcb->pcb_onfault = NULL; + return (-1); + } + + if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { + td->td_pcb->pcb_onfault = NULL; + return (-1); + } + + val = *p; + + td->td_pcb->pcb_onfault = NULL; + return (val); +} + +int +fueword32(const void *addr, int32_t *val) +{ + struct thread *td; + pmap_t pm; + faultbuf env; + int32_t *p; + + td = curthread; + pm = &td->td_proc->p_vmspace->vm_pmap; + + if (setfault(env)) { + td->td_pcb->pcb_onfault = NULL; + return (-1); + } + + if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { + td->td_pcb->pcb_onfault = NULL; + return (-1); + } + + *val = *p; + + td->td_pcb->pcb_onfault = NULL; + return (0); +} + #ifdef __powerpc64__ -int32_t -fuword32(const void *addr) +int +fueword64(const void *addr, int64_t *val) { struct thread *td; pmap_t pm; faultbuf env; - int32_t *p, val; + int64_t *p; td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; @@ -427,20 +481,20 @@ fuword32(const void *addr) return (-1); } - val = *p; + *val = *p; td->td_pcb->pcb_onfault = NULL; - return (val); + return (0); } #endif -long -fuword(const void *addr) +int +fueword(const void *addr, long *val) { struct thread *td; pmap_t pm; faultbuf env; - long *p, val; + long *p; td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; @@ -455,22 +509,15 @@ fuword(const void *addr) return (-1); } - val = *p; + *val = *p; td->td_pcb->pcb_onfault = NULL; - return (val); + return (0); } -#ifndef __powerpc64__ -int32_t -fuword32(const void *addr) -{ - return ((int32_t)fuword(addr)); -} -#endif - -uint32_t -casuword32(volatile uint32_t *addr, uint32_t old, uint32_t new) +int +casueword32(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp, + uint32_t new) { struct thread *td; pmap_t pm; @@ -507,18 +554,21 @@ casuword32(volatile uint32_t *addr, uint32_t old, uint32_t new) td->td_pcb->pcb_onfault = NULL; - return (val); + *oldvalp = val; + return (0); } #ifndef __powerpc64__ -u_long -casuword(volatile u_long *addr, u_long old, u_long new) +int +casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new) { - return (casuword32((volatile uint32_t *)addr, old, new)); + + return (casueword32((volatile uint32_t *)addr, old, + (uint32_t *)oldvalp, new)); } #else -u_long -casuword(volatile u_long *addr, u_long old, u_long new) +int +casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new) { struct thread *td; pmap_t pm; @@ -555,7 +605,7 @@ casuword(volatile u_long *addr, u_long old, u_long new) td->td_pcb->pcb_onfault = NULL; - return (val); + *oldvalp = val; + return (0); } #endif - diff --git a/sys/sparc64/include/param.h b/sys/sparc64/include/param.h index e59f2c49b84b..46bacae360b3 100644 --- a/sys/sparc64/include/param.h +++ b/sys/sparc64/include/param.h @@ -146,4 +146,8 @@ #define pgtok(x) ((unsigned long)(x) * (PAGE_SIZE / 1024)) +#ifdef _KERNEL +#define NO_FUEWORD 1 +#endif + #endif /* !_SPARC64_INCLUDE_PARAM_H_ */ diff --git a/sys/sys/systm.h b/sys/sys/systm.h index f4eae5702cd2..6e5ee6175c24 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -254,16 +254,23 @@ int copyout_nofault(const void * __restrict kaddr, void * __restrict udaddr, int fubyte(const void *base); long fuword(const void *base); -int fuword16(void *base); +int fuword16(const void *base); int32_t fuword32(const void *base); int64_t fuword64(const void *base); +int fueword(const void *base, long *val); +int fueword32(const void *base, int32_t *val); +int fueword64(const void *base, int64_t *val); int subyte(void *base, int byte); int suword(void *base, long word); int suword16(void *base, int word); int suword32(void *base, int32_t word); int suword64(void *base, int64_t word); uint32_t casuword32(volatile uint32_t *base, uint32_t oldval, uint32_t newval); -u_long casuword(volatile u_long *p, u_long oldval, u_long newval); +u_long casuword(volatile u_long *p, u_long oldval, u_long newval); +int casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp, + uint32_t newval); +int casueword(volatile u_long *p, u_long oldval, u_long *oldvalp, + u_long newval); void realitexpire(void *);