Download raw body.
sysctl(2): make sysctl_int{,_lower}() mp-safe and unlock KERN_HOSTID
Make sysctl_int() mp-safe in the sysctl_int_bounded() way and unlock
KERN_HOSTID. Except bootstrap called clockattach() of sparc64, `hostid'
never used outside kern_sysctl().
mp-safe sysctl_int() is meaningless for sysctl_int_lower(), so rework it
too. This time all affected paths are kernel locked, but this doesn't
make sysctl_int_lower() worse.
ok?
Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
diff -u -p -r1.437 kern_sysctl.c
--- sys/kern/kern_sysctl.c 11 Aug 2024 15:10:53 -0000 1.437
+++ sys/kern/kern_sysctl.c 13 Aug 2024 11:03:24 -0000
@@ -507,6 +507,10 @@ kern_sysctl(int *name, u_int namelen, vo
return (sysctl_rdstring(oldp, oldlenp, newp, version));
case KERN_NUMVNODES: /* XXX numvnodes is a long */
return (sysctl_rdint(oldp, oldlenp, newp, numvnodes));
+ case KERN_HOSTID:
+ /* XXX assumes sizeof long >= sizeof int */
+ return (sysctl_int(oldp, oldlenp, newp, newlen,
+ (int *)&hostid));
case KERN_CLOCKRATE:
return (sysctl_clockrate(oldp, oldlenp, newp));
case KERN_BOOTTIME: {
@@ -585,7 +589,7 @@ int
kern_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen, struct proc *p)
{
- int error, level, inthostid, stackgap;
+ int error, level, stackgap;
dev_t dev;
extern int pool_debug;
@@ -623,11 +627,6 @@ kern_sysctl_locked(int *name, u_int name
if (newp && !error)
domainnamelen = newlen;
return (error);
- case KERN_HOSTID:
- inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */
- error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
- hostid = inthostid;
- return (error);
case KERN_CONSBUF:
if ((error = suser(p)))
return (error);
@@ -1055,17 +1054,36 @@ int
sysctl_int_lower(void *oldp, size_t *oldlenp, void *newp, size_t newlen,
int *valp)
{
- unsigned int oval = *valp, val = *valp;
+ unsigned int oldval, newval;
int error;
- if (newp == NULL)
- return (sysctl_rdint(oldp, oldlenp, newp, val));
+ if (oldp && *oldlenp < sizeof(int))
+ return (ENOMEM);
+ if (newp && newlen != sizeof(int))
+ return (EINVAL);
+ *oldlenp = sizeof(int);
+
+ if (newp) {
+ if ((error = copyin(newp, &newval, sizeof(int))))
+ return (error);
+ do {
+ oldval = atomic_load_int(valp);
+ if (oldval < (unsigned int)newval)
+ return (EPERM); /* do not allow raising */
+ } while (atomic_cas_uint(valp, oldval, newval) != oldval);
+
+ if (oldp) {
+ /* new value has been set although user gets error */
+ if ((error = copyout(&oldval, oldp, sizeof(int))))
+ return (error);
+ }
+ } else if (oldp) {
+ oldval = atomic_load_int(valp);
+
+ if ((error = copyout(&oldval, oldp, sizeof(int))))
+ return (error);
+ }
- if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)))
- return (error);
- if (val > oval)
- return (EPERM); /* do not allow raising */
- *(unsigned int *)valp = val;
return (0);
}
@@ -1076,6 +1094,7 @@ sysctl_int_lower(void *oldp, size_t *old
int
sysctl_int(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int *valp)
{
+ int oldval, newval;
int error = 0;
if (oldp && *oldlenp < sizeof(int))
@@ -1083,11 +1102,25 @@ sysctl_int(void *oldp, size_t *oldlenp,
if (newp && newlen != sizeof(int))
return (EINVAL);
*oldlenp = sizeof(int);
- if (oldp)
- error = copyout(valp, oldp, sizeof(int));
- if (error == 0 && newp)
- error = copyin(newp, valp, sizeof(int));
- return (error);
+
+ /* copyin() may sleep, call it first */
+ if (newp) {
+ if ((error = copyin(newp, &newval, sizeof(int))))
+ return (error);
+ }
+ if (oldp) {
+ if (newp)
+ oldval = atomic_swap_uint(valp, newval);
+ else
+ oldval = atomic_load_int(valp);
+ if ((error = copyout(&oldval, oldp, sizeof(int)))) {
+ /* new value has been set although user gets error */
+ return (error);
+ }
+ } else if (newp)
+ atomic_store_int(valp, newval);
+
+ return (0);
}
/*
sysctl(2): make sysctl_int{,_lower}() mp-safe and unlock KERN_HOSTID