Add osd_reserve() and osd_set_reserved(), which allow M_WAITOK allocation

of an OSD array,
This commit is contained in:
Jamie Gritton 2016-03-30 16:57:28 +00:00
parent 30a0e024ee
commit 320d842101
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=297422
3 changed files with 130 additions and 29 deletions

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd January 5, 2011
.Dd March 30, 2016
.Dt OSD 9
.Os
.Sh NAME
@ -33,6 +33,9 @@
.Nm osd_register ,
.Nm osd_deregister ,
.Nm osd_set ,
.Nm osd_reserve ,
.Nm osd_set_reserved ,
.Nm osd_free_reserved ,
.Nm osd_get ,
.Nm osd_del ,
.Nm osd_call ,
@ -63,6 +66,22 @@
.Fa "void *value"
.Fc
.Ft void *
.Fo osd_reserve
.Fa "u_int slot"
.Fc
.Ft int
.Fo osd_set_reserved
.Fa "u_int type"
.Fa "struct osd *osd"
.Fa "u_int slot"
.Fa "void *rsv"
.Fa "void *value"
.Fc
.Ft void
.Fo osd_free_reserved
.Fa "void *rsv"
.Fc
.Ft void *
.Fo osd_get
.Fa "u_int type"
.Fa "struct osd *osd"
@ -198,6 +217,15 @@ argument points to a data object to associate with
.Fa osd .
.Pp
The
.Fn osd_set_reserved
function does the same as
.Fn osd_set ,
but with an extra argument
.Fa rsv
that is internal-use memory previously allocated via
.Fn osd_reserve .
.Pp
The
.Fn osd_get
function returns the data pointer associated with a kernel data structure's
.Vt struct osd
@ -324,6 +352,24 @@ will proceed without any
.Xr realloc 9
calls.
.Pp
It is possible for
.Fn osd_set
to fail to allocate this array. To ensure that such allocation succeeds,
.Fn osd_reserve
may be called (in a non-blocking context), and it will pre-allocate the
memory via
.Xr malloc 9
with M_WAITOK.
Then this pre-allocated memory is passed to
.Fn osd_set_reserved ,
which will use it if necessary or otherwise discard it.
The memory may also be explicitly discarded by calling
.Fn osd_free_reserved .
As this method always allocates memory whether or not it is ultimately needed,
it should be used only rarely, such as in the unlikely event that
.Fn osd_set
fails.
.Pp
The
.Nm
API is geared towards slot identifiers storing pointers to the same underlying
@ -359,15 +405,27 @@ the kernel including most fast paths.
returns the slot identifier for the newly registered data type.
.Pp
.Fn osd_set
returns zero on success or ENOMEM if the specified type/slot identifier pair
and
.Fn osd_set_reserved
return zero on success or ENOMEM if the specified type/slot identifier pair
triggered an internal
.Xr realloc 9
which failed.
which failed
.Fn ( osd_set_reserved
will always succeed when
.Fa rsv
is non-NULL).
.Pp
.Fn osd_get
returns the data pointer for the specified type/slot identifier pair, or NULL if
the slot has not been initialised yet.
.Pp
.Fn osd_reserve
returns a pointer suitable for passing to
.Fn osd_set_reserved
or
.Fn osd_free_reserved .
.Pp
.Fn osd_call
returns zero if no method is run or the method for each slot runs successfully.
If a method for a slot returns non-zero,

View File

@ -54,7 +54,7 @@ struct osd_master {
struct sx osd_module_lock;
struct rmlock osd_object_lock;
struct mtx osd_list_lock;
LIST_HEAD(, osd) osd_list; /* (m) */
LIST_HEAD(, osd) osd_list; /* (l) */
osd_destructor_t *osd_destructors; /* (o) */
osd_method_t *osd_methods; /* (m) */
u_int osd_ntslots; /* (m) */
@ -197,6 +197,24 @@ osd_deregister(u_int type, u_int slot)
int
osd_set(u_int type, struct osd *osd, u_int slot, void *value)
{
return (osd_set_reserved(type, osd, slot, NULL, value));
}
void *
osd_reserve(u_int slot)
{
KASSERT(slot > 0, ("Invalid slot."));
OSD_DEBUG("Reserving slot array (slot=%u).", slot);
return (malloc(sizeof(void *) * slot, M_OSD, M_WAITOK | M_ZERO));
}
int
osd_set_reserved(u_int type, struct osd *osd, u_int slot, void *rsv,
void *value)
{
struct rm_priotracker tracker;
@ -206,36 +224,34 @@ osd_set(u_int type, struct osd *osd, u_int slot, void *value)
rm_rlock(&osdm[type].osd_object_lock, &tracker);
if (slot > osd->osd_nslots) {
void *newptr;
if (value == NULL) {
OSD_DEBUG(
"Not allocating null slot (type=%u, slot=%u).",
type, slot);
rm_runlock(&osdm[type].osd_object_lock, &tracker);
if (rsv)
osd_free_reserved(rsv);
return (0);
} else if (osd->osd_nslots == 0) {
/*
* First OSD for this object, so we need to allocate
* space and put it onto the list.
*/
osd->osd_slots = malloc(sizeof(void *) * slot, M_OSD,
M_NOWAIT | M_ZERO);
if (osd->osd_slots == NULL) {
rm_runlock(&osdm[type].osd_object_lock,
&tracker);
return (ENOMEM);
}
osd->osd_nslots = slot;
mtx_lock(&osdm[type].osd_list_lock);
LIST_INSERT_HEAD(&osdm[type].osd_list, osd, osd_next);
mtx_unlock(&osdm[type].osd_list_lock);
OSD_DEBUG("Setting first slot (type=%u).", type);
} else {
void *newptr;
}
/*
* Too few slots allocated here, so we need to extend or create
* the array.
*/
if (rsv) {
/*
* Too few slots allocated here, needs to extend
* the array.
* Use the reserve passed in (assumed to be
* the right size).
*/
newptr = rsv;
if (osd->osd_nslots != 0) {
memcpy(newptr, osd->osd_slots,
sizeof(void *) * osd->osd_nslots);
free(osd->osd_slots, M_OSD);
}
} else {
newptr = realloc(osd->osd_slots, sizeof(void *) * slot,
M_OSD, M_NOWAIT | M_ZERO);
if (newptr == NULL) {
@ -243,11 +259,22 @@ osd_set(u_int type, struct osd *osd, u_int slot, void *value)
&tracker);
return (ENOMEM);
}
osd->osd_slots = newptr;
osd->osd_nslots = slot;
OSD_DEBUG("Growing slots array (type=%u).", type);
}
}
if (osd->osd_nslots == 0) {
/*
* First OSD for this object, so we need to put it
* onto the list.
*/
mtx_lock(&osdm[type].osd_list_lock);
LIST_INSERT_HEAD(&osdm[type].osd_list, osd, osd_next);
mtx_unlock(&osdm[type].osd_list_lock);
OSD_DEBUG("Setting first slot (type=%u).", type);
} else
OSD_DEBUG("Growing slots array (type=%u).", type);
osd->osd_slots = newptr;
osd->osd_nslots = slot;
} else if (rsv)
osd_free_reserved(rsv);
OSD_DEBUG("Setting slot value (type=%u, slot=%u, value=%p).", type,
slot, value);
osd->osd_slots[slot - 1] = value;
@ -255,6 +282,14 @@ osd_set(u_int type, struct osd *osd, u_int slot, void *value)
return (0);
}
void
osd_free_reserved(void *rsv)
{
OSD_DEBUG("Discarding reserved slot array.");
free(rsv, M_OSD);
}
void *
osd_get(u_int type, struct osd *osd, u_int slot)
{

View File

@ -59,6 +59,10 @@ int osd_register(u_int type, osd_destructor_t destructor,
void osd_deregister(u_int type, u_int slot);
int osd_set(u_int type, struct osd *osd, u_int slot, void *value);
void *osd_reserve(u_int slot);
int osd_set_reserved(u_int type, struct osd *osd, u_int slot, void *rsv,
void *value);
void osd_free_reserved(void *rsv);
void *osd_get(u_int type, struct osd *osd, u_int slot);
void osd_del(u_int type, struct osd *osd, u_int slot);
int osd_call(u_int type, u_int method, void *obj, void *data);
@ -71,6 +75,8 @@ void osd_exit(u_int type, struct osd *osd);
osd_deregister(OSD_THREAD, (slot))
#define osd_thread_set(td, slot, value) \
osd_set(OSD_THREAD, &(td)->td_osd, (slot), (value))
#define osd_thread_set_reserved(td, slot, rsv, value) \
osd_set_reserved(OSD_THREAD, &(td)->td_osd, (slot), (rsv), (value))
#define osd_thread_get(td, slot) \
osd_get(OSD_THREAD, &(td)->td_osd, (slot))
#define osd_thread_del(td, slot) do { \
@ -88,6 +94,8 @@ void osd_exit(u_int type, struct osd *osd);
osd_deregister(OSD_JAIL, (slot))
#define osd_jail_set(pr, slot, value) \
osd_set(OSD_JAIL, &(pr)->pr_osd, (slot), (value))
#define osd_jail_set_reserved(pr, slot, rsv, value) \
osd_set_reserved(OSD_JAIL, &(pr)->pr_osd, (slot), (rsv), (value))
#define osd_jail_get(pr, slot) \
osd_get(OSD_JAIL, &(pr)->pr_osd, (slot))
#define osd_jail_del(pr, slot) \