Deleted Added
full compact
11c11
< __FBSDID("$FreeBSD: head/sys/kern/kern_jail.c 168399 2007-04-05 21:34:54Z pjd $");
---
> __FBSDID("$FreeBSD: head/sys/kern/kern_jail.c 168401 2007-04-05 23:19:13Z pjd $");
27a28
> #include <sys/sx.h>
80c81
< /* allprison, lastprid, and prisoncount are protected by allprison_mtx. */
---
> /* allprison, lastprid, and prisoncount are protected by allprison_lock. */
82c83
< struct mtx allprison_mtx;
---
> struct sx allprison_lock;
85a87,102
> /*
> * List of jail services. Protected by allprison_lock.
> */
> TAILQ_HEAD(prison_services_head, prison_service);
> static struct prison_services_head prison_services =
> TAILQ_HEAD_INITIALIZER(prison_services);
> static int prison_service_slots = 0;
>
> struct prison_service {
> prison_create_t ps_create;
> prison_destroy_t ps_destroy;
> int ps_slotno;
> TAILQ_ENTRY(prison_service) ps_next;
> char ps_name[0];
> };
>
94c111
< mtx_init(&allprison_mtx, "allprison", NULL, MTX_DEF);
---
> sx_init(&allprison_lock, "allprison");
109a127
> struct prison_service *psrv;
141a160,165
> if (prison_service_slots == 0)
> pr->pr_slots = NULL;
> else {
> pr->pr_slots = malloc(sizeof(*pr->pr_slots) * prison_service_slots,
> M_PRISON, M_ZERO | M_WAITOK);
> }
144c168
< mtx_lock(&allprison_mtx);
---
> sx_xlock(&allprison_lock);
153c177
< mtx_unlock(&allprison_mtx);
---
> sx_xunlock(&allprison_lock);
163c187,191
< mtx_unlock(&allprison_mtx);
---
> sx_downgrade(&allprison_lock);
> TAILQ_FOREACH(psrv, &prison_services, ps_next) {
> psrv->ps_create(psrv, pr);
> }
> sx_sunlock(&allprison_lock);
174c202
< mtx_lock(&allprison_mtx);
---
> sx_xlock(&allprison_lock);
177c205,209
< mtx_unlock(&allprison_mtx);
---
> sx_downgrade(&allprison_lock);
> TAILQ_FOREACH(psrv, &prison_services, ps_next) {
> psrv->ps_destroy(psrv, pr);
> }
> sx_sunlock(&allprison_lock);
214c246
< mtx_lock(&allprison_mtx);
---
> sx_slock(&allprison_lock);
217c249
< mtx_unlock(&allprison_mtx);
---
> sx_sunlock(&allprison_lock);
222c254
< mtx_unlock(&allprison_mtx);
---
> sx_sunlock(&allprison_lock);
263c295
< mtx_assert(&allprison_mtx, MA_OWNED);
---
> sx_assert(&allprison_lock, SX_LOCKED);
275a308
> struct prison_service *psrv;
277c310
< mtx_lock(&allprison_mtx);
---
> sx_xlock(&allprison_lock);
284c317,321
< mtx_unlock(&allprison_mtx);
---
> sx_downgrade(&allprison_lock);
> TAILQ_FOREACH(psrv, &prison_services, ps_next) {
> psrv->ps_destroy(psrv, pr);
> }
> sx_sunlock(&allprison_lock);
291c328
< mtx_unlock(&allprison_mtx);
---
> sx_xunlock(&allprison_lock);
702a740,926
> /*
> * Register jail service. Provides 'create' and 'destroy' methods.
> * 'create' method will be called for every existing jail and all
> * jails in the future as they beeing created.
> * 'destroy' method will be called for every jail going away and
> * for all existing jails at the time of service deregistration.
> */
> struct prison_service *
> prison_service_register(const char *name, prison_create_t create,
> prison_destroy_t destroy)
> {
> struct prison_service *psrv, *psrv2;
> struct prison *pr;
> int reallocate = 1, slotno = 0;
> void **slots, **oldslots;
>
> psrv = malloc(sizeof(*psrv) + strlen(name) + 1, M_PRISON,
> M_WAITOK | M_ZERO);
> psrv->ps_create = create;
> psrv->ps_destroy = destroy;
> strcpy(psrv->ps_name, name);
> /*
> * Grab the allprison_lock here, so we won't miss any jail
> * creation/destruction.
> */
> sx_xlock(&allprison_lock);
> #ifdef INVARIANTS
> /*
> * Verify if service is not already registered.
> */
> TAILQ_FOREACH(psrv2, &prison_services, ps_next) {
> KASSERT(strcmp(psrv2->ps_name, name) != 0,
> ("jail service %s already registered", name));
> }
> #endif
> /*
> * Find free slot. When there is no existing free slot available,
> * allocate one at the end.
> */
> TAILQ_FOREACH(psrv2, &prison_services, ps_next) {
> if (psrv2->ps_slotno != slotno) {
> KASSERT(slotno < psrv2->ps_slotno,
> ("Invalid slotno (slotno=%d >= ps_slotno=%d",
> slotno, psrv2->ps_slotno));
> /* We found free slot. */
> reallocate = 0;
> break;
> }
> slotno++;
> }
> psrv->ps_slotno = slotno;
> /*
> * Keep the list sorted by slot number.
> */
> if (psrv2 != NULL) {
> KASSERT(reallocate == 0, ("psrv2 != NULL && reallocate != 0"));
> TAILQ_INSERT_BEFORE(psrv2, psrv, ps_next);
> } else {
> KASSERT(reallocate == 1, ("psrv2 == NULL && reallocate == 0"));
> TAILQ_INSERT_TAIL(&prison_services, psrv, ps_next);
> }
> prison_service_slots++;
> sx_downgrade(&allprison_lock);
> /*
> * Allocate memory for new slot if we didn't found empty one.
> * Do not use realloc(9), because pr_slots is protected with a mutex,
> * so we can't sleep.
> */
> LIST_FOREACH(pr, &allprison, pr_list) {
> if (reallocate) {
> /* First allocate memory with M_WAITOK. */
> slots = malloc(sizeof(*slots) * prison_service_slots,
> M_PRISON, M_WAITOK);
> /* Now grab the mutex and replace pr_slots. */
> mtx_lock(&pr->pr_mtx);
> oldslots = pr->pr_slots;
> if (psrv->ps_slotno > 0) {
> bcopy(oldslots, slots,
> sizeof(*slots) * (prison_service_slots - 1));
> }
> slots[psrv->ps_slotno] = NULL;
> pr->pr_slots = slots;
> mtx_unlock(&pr->pr_mtx);
> if (oldslots != NULL)
> free(oldslots, M_PRISON);
> }
> /*
> * Call 'create' method for each existing jail.
> */
> psrv->ps_create(psrv, pr);
> }
> sx_sunlock(&allprison_lock);
>
> return (psrv);
> }
>
> void
> prison_service_deregister(struct prison_service *psrv)
> {
> struct prison *pr;
> void **slots, **oldslots;
> int last = 0;
>
> sx_xlock(&allprison_lock);
> if (TAILQ_LAST(&prison_services, prison_services_head) == psrv)
> last = 1;
> TAILQ_REMOVE(&prison_services, psrv, ps_next);
> prison_service_slots--;
> sx_downgrade(&allprison_lock);
> LIST_FOREACH(pr, &allprison, pr_list) {
> /*
> * Call 'destroy' method for every currently existing jail.
> */
> psrv->ps_destroy(psrv, pr);
> /*
> * If this is the last slot, free the memory allocated for it.
> */
> if (last) {
> if (prison_service_slots == 0)
> slots = NULL;
> else {
> slots = malloc(sizeof(*slots) * prison_service_slots,
> M_PRISON, M_WAITOK);
> }
> mtx_lock(&pr->pr_mtx);
> oldslots = pr->pr_slots;
> /*
> * We require setting slot to NULL after freeing it,
> * this way we can check for memory leaks here.
> */
> KASSERT(oldslots[psrv->ps_slotno] == NULL,
> ("Slot %d (service %s, jailid=%d) still contains data?",
> psrv->ps_slotno, psrv->ps_name, pr->pr_id));
> if (psrv->ps_slotno > 0) {
> bcopy(oldslots, slots,
> sizeof(*slots) * prison_service_slots);
> }
> pr->pr_slots = slots;
> mtx_unlock(&pr->pr_mtx);
> KASSERT(oldslots != NULL, ("oldslots == NULL"));
> free(oldslots, M_PRISON);
> }
> }
> sx_sunlock(&allprison_lock);
> free(psrv, M_PRISON);
> }
>
> /*
> * Function sets data for the given jail in slot assigned for the given
> * jail service.
> */
> void
> prison_service_data_set(struct prison_service *psrv, struct prison *pr,
> void *data)
> {
>
> mtx_assert(&pr->pr_mtx, MA_OWNED);
> pr->pr_slots[psrv->ps_slotno] = data;
> }
>
> /*
> * Function clears slots assigned for the given jail service in the given
> * prison structure and returns current slot data.
> */
> void *
> prison_service_data_del(struct prison_service *psrv, struct prison *pr)
> {
> void *data;
>
> mtx_assert(&pr->pr_mtx, MA_OWNED);
> data = pr->pr_slots[psrv->ps_slotno];
> pr->pr_slots[psrv->ps_slotno] = NULL;
> return (data);
> }
>
> /*
> * Function returns current data from the slot assigned to the given jail
> * service for the given jail.
> */
> void *
> prison_service_data_get(struct prison_service *psrv, struct prison *pr)
> {
>
> mtx_assert(&pr->pr_mtx, MA_OWNED);
> return (pr->pr_slots[psrv->ps_slotno]);
> }
>
712,715d935
< retry:
< mtx_lock(&allprison_mtx);
< count = prisoncount;
< mtx_unlock(&allprison_mtx);
717c937,939
< if (count == 0)
---
> sx_slock(&allprison_lock);
> if ((count = prisoncount) == 0) {
> sx_sunlock(&allprison_lock);
718a941
> }
721,726d943
< mtx_lock(&allprison_mtx);
< if (count != prisoncount) {
< mtx_unlock(&allprison_mtx);
< free(sxp, M_TEMP);
< goto retry;
< }
738c955
< mtx_unlock(&allprison_mtx);
---
> sx_sunlock(&allprison_lock);