- don't return ENOMEM for errors not related to memory
- don't overload return values (-error/+size) - don't allocate kernel memory from user supplied length.
This commit is contained in:
parent
8982bc4889
commit
96bd66bcf0
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: subr_interrupt.c,v 1.3 2018/01/13 13:53:36 reinoud Exp $ */
|
/* $NetBSD: subr_interrupt.c,v 1.4 2018/01/28 22:24:58 christos Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015 Internet Initiative Japan Inc.
|
* Copyright (c) 2015 Internet Initiative Japan Inc.
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: subr_interrupt.c,v 1.3 2018/01/13 13:53:36 reinoud Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: subr_interrupt.c,v 1.4 2018/01/28 22:24:58 christos Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
|
@ -133,7 +133,7 @@ interrupt_avert_intr(u_int cpu_idx)
|
||||||
|
|
||||||
ii_handler = interrupt_construct_intrids(cpuset);
|
ii_handler = interrupt_construct_intrids(cpuset);
|
||||||
if (ii_handler == NULL) {
|
if (ii_handler == NULL) {
|
||||||
error = ENOMEM;
|
error = EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
nids = ii_handler->iih_nids;
|
nids = ii_handler->iih_nids;
|
||||||
|
@ -180,25 +180,24 @@ interrupt_intrio_list_line_size(void)
|
||||||
* Return the size of interrupts list data on success.
|
* Return the size of interrupts list data on success.
|
||||||
* Reterun 0 on failed.
|
* Reterun 0 on failed.
|
||||||
*/
|
*/
|
||||||
static size_t
|
static int
|
||||||
interrupt_intrio_list_size(void)
|
interrupt_intrio_list_size(size_t *ilsize)
|
||||||
{
|
{
|
||||||
struct intrids_handler *ii_handler;
|
struct intrids_handler *ii_handler;
|
||||||
size_t ilsize;
|
|
||||||
|
|
||||||
ilsize = 0;
|
*ilsize = 0;
|
||||||
|
|
||||||
/* buffer header */
|
/* buffer header */
|
||||||
ilsize += sizeof(struct intrio_list);
|
*ilsize += sizeof(struct intrio_list);
|
||||||
|
|
||||||
/* il_line body */
|
/* il_line body */
|
||||||
ii_handler = interrupt_construct_intrids(kcpuset_running);
|
ii_handler = interrupt_construct_intrids(kcpuset_running);
|
||||||
if (ii_handler == NULL)
|
if (ii_handler == NULL)
|
||||||
return 0;
|
return EOPNOTSUPP;
|
||||||
ilsize += interrupt_intrio_list_line_size() * (ii_handler->iih_nids);
|
*ilsize += interrupt_intrio_list_line_size() * ii_handler->iih_nids;
|
||||||
|
|
||||||
interrupt_destruct_intrids(ii_handler);
|
interrupt_destruct_intrids(ii_handler);
|
||||||
return ilsize;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -207,28 +206,17 @@ interrupt_intrio_list_size(void)
|
||||||
* If "data" == NULL, simply return list structure bytes.
|
* If "data" == NULL, simply return list structure bytes.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
interrupt_intrio_list(struct intrio_list *il, int length)
|
interrupt_intrio_list(struct intrio_list *il, size_t ilsize)
|
||||||
{
|
{
|
||||||
struct intrio_list_line *illine;
|
struct intrio_list_line *illine;
|
||||||
kcpuset_t *assigned, *avail;
|
kcpuset_t *assigned, *avail;
|
||||||
struct intrids_handler *ii_handler;
|
struct intrids_handler *ii_handler;
|
||||||
intrid_t *ids;
|
intrid_t *ids;
|
||||||
size_t ilsize;
|
|
||||||
u_int cpu_idx;
|
u_int cpu_idx;
|
||||||
int nids, intr_idx, ret, line_size;
|
int nids, intr_idx, error, line_size;
|
||||||
|
|
||||||
ilsize = interrupt_intrio_list_size();
|
|
||||||
if (ilsize == 0)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
if (il == NULL)
|
|
||||||
return ilsize;
|
|
||||||
|
|
||||||
if (length < ilsize)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
illine = (struct intrio_list_line *)
|
illine = (struct intrio_list_line *)
|
||||||
((char *)il + sizeof(struct intrio_list));
|
((char *)il + sizeof(struct intrio_list));
|
||||||
il->il_lineoffset = (off_t)((uintptr_t)illine - (uintptr_t)il);
|
il->il_lineoffset = (off_t)((uintptr_t)illine - (uintptr_t)il);
|
||||||
|
|
||||||
kcpuset_create(&avail, true);
|
kcpuset_create(&avail, true);
|
||||||
|
@ -238,19 +226,19 @@ interrupt_intrio_list(struct intrio_list *il, int length)
|
||||||
ii_handler = interrupt_construct_intrids(kcpuset_running);
|
ii_handler = interrupt_construct_intrids(kcpuset_running);
|
||||||
if (ii_handler == NULL) {
|
if (ii_handler == NULL) {
|
||||||
DPRINTF(("%s: interrupt_construct_intrids() failed\n",
|
DPRINTF(("%s: interrupt_construct_intrids() failed\n",
|
||||||
__func__));
|
__func__));
|
||||||
ret = -ENOMEM;
|
error = EOPNOTSUPP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_size = interrupt_intrio_list_line_size();
|
line_size = interrupt_intrio_list_line_size();
|
||||||
/* ensure interrupts are not added after interrupt_intrio_list_size(). */
|
/* ensure interrupts are not added after interrupt_intrio_list_size() */
|
||||||
nids = ii_handler->iih_nids;
|
nids = ii_handler->iih_nids;
|
||||||
ids = ii_handler->iih_intrids;
|
ids = ii_handler->iih_intrids;
|
||||||
if (ilsize < sizeof(struct intrio_list) + line_size * nids) {
|
if (ilsize < sizeof(struct intrio_list) + line_size * nids) {
|
||||||
DPRINTF(("%s: interrupts are added during execution.\n",
|
DPRINTF(("%s: interrupts are added during execution.\n",
|
||||||
__func__));
|
__func__));
|
||||||
ret = -ENOMEM;
|
error = EAGAIN;
|
||||||
goto destruct_out;
|
goto destruct_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,19 +252,19 @@ interrupt_intrio_list(struct intrio_list *il, int length)
|
||||||
interrupt_get_assigned(ids[intr_idx], assigned);
|
interrupt_get_assigned(ids[intr_idx], assigned);
|
||||||
for (cpu_idx = 0; cpu_idx < ncpu; cpu_idx++) {
|
for (cpu_idx = 0; cpu_idx < ncpu; cpu_idx++) {
|
||||||
struct intrio_list_line_cpu *illcpu =
|
struct intrio_list_line_cpu *illcpu =
|
||||||
&illine->ill_cpu[cpu_idx];
|
&illine->ill_cpu[cpu_idx];
|
||||||
|
|
||||||
illcpu->illc_assigned =
|
illcpu->illc_assigned =
|
||||||
kcpuset_isset(assigned, cpu_idx) ? true : false;
|
kcpuset_isset(assigned, cpu_idx);
|
||||||
illcpu->illc_count =
|
illcpu->illc_count =
|
||||||
interrupt_get_count(ids[intr_idx], cpu_idx);
|
interrupt_get_count(ids[intr_idx], cpu_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
illine = (struct intrio_list_line *)
|
illine = (struct intrio_list_line *)
|
||||||
((char *)illine + line_size);
|
((char *)illine + line_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ilsize;
|
error = 0;
|
||||||
il->il_version = INTRIO_LIST_VERSION;
|
il->il_version = INTRIO_LIST_VERSION;
|
||||||
il->il_ncpus = ncpu;
|
il->il_ncpus = ncpu;
|
||||||
il->il_nintrs = nids;
|
il->il_nintrs = nids;
|
||||||
|
@ -289,7 +277,7 @@ interrupt_intrio_list(struct intrio_list *il, int length)
|
||||||
kcpuset_destroy(assigned);
|
kcpuset_destroy(assigned);
|
||||||
kcpuset_destroy(avail);
|
kcpuset_destroy(avail);
|
||||||
|
|
||||||
return ret;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -298,42 +286,39 @@ interrupt_intrio_list(struct intrio_list *il, int length)
|
||||||
static int
|
static int
|
||||||
interrupt_intrio_list_sysctl(SYSCTLFN_ARGS)
|
interrupt_intrio_list_sysctl(SYSCTLFN_ARGS)
|
||||||
{
|
{
|
||||||
int ret, error;
|
int error;
|
||||||
void *buf;
|
void *buf;
|
||||||
|
size_t ilsize;
|
||||||
|
|
||||||
if (oldlenp == NULL)
|
if (oldlenp == NULL)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
|
if ((error = interrupt_intrio_list_size(&ilsize)) != 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If oldp == NULL, the sysctl(8) caller process want to get the size of
|
* If oldp == NULL, the sysctl(8) caller process want to get the size of
|
||||||
* intrctl list data only.
|
* intrctl list data only.
|
||||||
*/
|
*/
|
||||||
if (oldp == NULL) {
|
if (oldp == NULL) {
|
||||||
ret = interrupt_intrio_list(NULL, 0);
|
*oldlenp = ilsize;
|
||||||
if (ret < 0)
|
|
||||||
return -ret;
|
|
||||||
|
|
||||||
*oldlenp = ret;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If oldp != NULL, the sysctl(8) caller process want to get both the size
|
* If oldp != NULL, the sysctl(8) caller process want to get both the
|
||||||
* and the contents of intrctl list data.
|
* size and the contents of intrctl list data.
|
||||||
*/
|
*/
|
||||||
if (*oldlenp == 0)
|
if (*oldlenp < ilsize)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
||||||
buf = kmem_zalloc(*oldlenp, KM_SLEEP);
|
buf = kmem_zalloc(ilsize, KM_SLEEP);
|
||||||
ret = interrupt_intrio_list(buf, *oldlenp);
|
if ((error = interrupt_intrio_list(buf, ilsize)) != 0)
|
||||||
if (ret < 0) {
|
|
||||||
error = -ret;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
error = copyout(buf, oldp, *oldlenp);
|
|
||||||
|
|
||||||
|
error = copyout(buf, oldp, ilsize);
|
||||||
out:
|
out:
|
||||||
kmem_free(buf, *oldlenp);
|
kmem_free(buf, ilsize);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue