diff --git a/share/man/man9/osd.9 b/share/man/man9/osd.9 index e8260fe46338..c27b5d9fa4bb 100644 --- a/share/man/man9/osd.9 +++ b/share/man/man9/osd.9 @@ -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, diff --git a/sys/kern/kern_osd.c b/sys/kern/kern_osd.c index ce3c3b6eebec..41d518ff59dd 100644 --- a/sys/kern/kern_osd.c +++ b/sys/kern/kern_osd.c @@ -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) { diff --git a/sys/sys/osd.h b/sys/sys/osd.h index 14316ae30cdb..820e0f49ce96 100644 --- a/sys/sys/osd.h +++ b/sys/sys/osd.h @@ -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) \