diff options
| author | jwadams <none@none> | 2005-08-23 16:24:21 -0700 |
|---|---|---|
| committer | jwadams <none@none> | 2005-08-23 16:24:21 -0700 |
| commit | 8918dff3e162b85faa068f02fc6f2ca350150e71 (patch) | |
| tree | 99eb952e98259fb77ea5f24d198c409d2a76668a /usr/src/lib/libscf | |
| parent | f53a9c5408883906fbe75e40dff93747fb2089a0 (diff) | |
| download | illumos-joyent-8918dff3e162b85faa068f02fc6f2ca350150e71.tar.gz | |
6208709 scf_iter_handle_scopes always deadlocks in MT processes
6227387 /lib/svc/bin/restore_repository gives incorrect error when run as a non-root user
6255078 SMF shouldn't modify /etc files unnecessarily
6255593 svc.configd's per-client entity management is O(N)
6255609 libscf's entity id management handles overflow poorly
6256393 restore_repository's options should be more clear
6264601 svccfg's "repository" should use relative paths
6277017 svc.configd coredumps while trying to reboot on low memory condition
6305465 uu_list_t parent pointer confounded ::findleaks
Diffstat (limited to 'usr/src/lib/libscf')
| -rw-r--r-- | usr/src/lib/libscf/common/lowlevel.c | 156 | ||||
| -rw-r--r-- | usr/src/lib/libscf/common/lowlevel_impl.h | 8 |
2 files changed, 140 insertions, 24 deletions
diff --git a/usr/src/lib/libscf/common/lowlevel.c b/usr/src/lib/libscf/common/lowlevel.c index ae9108ab95..16c375d5e2 100644 --- a/usr/src/lib/libscf/common/lowlevel.c +++ b/usr/src/lib/libscf/common/lowlevel.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -177,7 +177,35 @@ transaction_entry_compare(const void *l_arg, const void *r_arg, void *private) ret = strcmp(l_prop, r_prop); if (ret > 0) return (1); - else if (ret < 0) + if (ret < 0) + return (-1); + return (0); +} + +static int +datael_compare(const void *l_arg, const void *r_arg, void *private) +{ + uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity; + uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity : + *(uint32_t *)private; + + if (l_id > r_id) + return (1); + if (l_id < r_id) + return (-1); + return (0); +} + +static int +iter_compare(const void *l_arg, const void *r_arg, void *private) +{ + uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id; + uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id : + *(uint32_t *)private; + + if (l_id > r_id) + return (1); + if (l_id < r_id) return (-1); return (0); } @@ -209,11 +237,11 @@ lowlevel_init(void) datael_pool = uu_list_pool_create("SUNW,libscf_datael", sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node), - NULL, UU_LIST_POOL_DEBUG); + datael_compare, UU_LIST_POOL_DEBUG); iter_pool = uu_list_pool_create("SUNW,libscf_iter", sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node), - NULL, UU_LIST_POOL_DEBUG); + iter_compare, UU_LIST_POOL_DEBUG); assert_nolint(offsetof(scf_transaction_entry_t, entry_property) == 0); @@ -506,14 +534,22 @@ handle_is_bound(scf_handle_t *h) } static int -handle_has_server(scf_handle_t *h) +handle_has_server_locked(scf_handle_t *h) { door_info_t i; + assert(MUTEX_HELD(&h->rh_lock)); + + return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 && + i.di_target != -1); +} + +static int +handle_has_server(scf_handle_t *h) +{ int ret; (void) pthread_mutex_lock(&h->rh_lock); - ret = (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 && - i.di_target != -1); + ret = handle_has_server_locked(h); (void) pthread_mutex_unlock(&h->rh_lock); return (ret); @@ -1267,24 +1303,91 @@ scf_myname(scf_handle_t *h, char *out, size_t len) } static uint32_t -handle_alloc_entityid(scf_handle_t *handle) +handle_alloc_entityid(scf_handle_t *h) { - assert(MUTEX_HELD(&handle->rh_lock)); - return (++handle->rh_nextentity); + uint32_t nextid; + + assert(MUTEX_HELD(&h->rh_lock)); + + if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX) + return (0); /* no ids available */ + + /* + * The following loop assumes that there are not a huge number of + * outstanding entities when we've wrapped. If that ends up not + * being the case, the O(N^2) nature of this search will hurt a lot, + * and the data structure should be switched to an AVL tree. + */ + nextid = h->rh_nextentity + 1; + for (;;) { + scf_datael_t *cur; + + if (nextid == 0) { + nextid++; + h->rh_flags |= HANDLE_WRAPPED_ENTITY; + } + if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY)) + break; + + cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL); + if (cur == NULL) + break; /* not in use */ + + if (nextid == h->rh_nextentity) + return (0); /* wrapped around; no ids available */ + nextid++; + } + + h->rh_nextentity = nextid; + return (nextid); } static uint32_t -handle_alloc_iterid(scf_handle_t *handle) +handle_alloc_iterid(scf_handle_t *h) { - assert(MUTEX_HELD(&handle->rh_lock)); - return (++handle->rh_nextiter); + uint32_t nextid; + + assert(MUTEX_HELD(&h->rh_lock)); + + if (uu_list_numnodes(h->rh_iters) == UINT32_MAX) + return (0); /* no ids available */ + + /* see the comment in handle_alloc_entityid */ + nextid = h->rh_nextiter + 1; + for (;;) { + scf_iter_t *cur; + + if (nextid == 0) { + nextid++; + h->rh_flags |= HANDLE_WRAPPED_ITER; + } + if (!(h->rh_flags & HANDLE_WRAPPED_ITER)) + break; /* not yet wrapped */ + + cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL); + if (cur == NULL) + break; /* not in use */ + + if (nextid == h->rh_nextiter) + return (0); /* wrapped around; no ids available */ + nextid++; + } + + h->rh_nextiter = nextid; + return (nextid); } static uint32_t -handle_alloc_changeid(scf_handle_t *handle) +handle_next_changeid(scf_handle_t *handle) { + uint32_t nextid; + assert(MUTEX_HELD(&handle->rh_lock)); - return (++handle->rh_nextchangeid); + + nextid = ++handle->rh_nextchangeid; + if (nextid == 0) + nextid = ++handle->rh_nextchangeid; + return (nextid); } /* @@ -1320,6 +1423,11 @@ datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type) return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED)); } dp->rd_entity = handle_alloc_entityid(h); + if (dp->rd_entity == 0) { + (void) pthread_mutex_unlock(&h->rh_lock); + uu_list_node_fini(dp, &dp->rd_node, datael_pool); + return (scf_set_error(SCF_ERROR_NO_MEMORY)); + } ret = datael_attach(dp); if (ret == 0) { @@ -1767,7 +1875,7 @@ datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type, request.rpr_childid = cp->rd_entity; datael_finish_reset(dp); - request.rpr_changeid = handle_alloc_changeid(h); + request.rpr_changeid = handle_next_changeid(h); r = make_door_call(h, &request, sizeof (request), &response, sizeof (response)); (void) pthread_mutex_unlock(&h->rh_lock); @@ -1831,7 +1939,7 @@ datael_add_pg(const scf_datael_t *dp, const char *name, const char *type, datael_finish_reset(dp); datael_finish_reset(cp); - request.rpr_changeid = handle_alloc_changeid(h); + request.rpr_changeid = handle_next_changeid(h); r = make_door_call(h, &request, sizeof (request), &response, sizeof (response)); (void) pthread_mutex_unlock(&h->rh_lock); @@ -1867,7 +1975,7 @@ datael_delete(const scf_datael_t *dp) request.rpr_entityid = dp->rd_entity; datael_finish_reset(dp); - request.rpr_changeid = handle_alloc_changeid(h); + request.rpr_changeid = handle_next_changeid(h); r = make_door_call(h, &request, sizeof (request), &response, sizeof (response)); (void) pthread_mutex_unlock(&h->rh_lock); @@ -1913,6 +2021,12 @@ scf_iter_create(scf_handle_t *h) (void) pthread_mutex_lock(&h->rh_lock); iter->iter_id = handle_alloc_iterid(h); + if (iter->iter_id == 0) { + (void) pthread_mutex_unlock(&h->rh_lock); + uu_list_node_fini(iter, &iter->iter_node, iter_pool); + (void) scf_set_error(SCF_ERROR_NO_MEMORY); + return (NULL); + } if (iter_attach(iter) == -1) { uu_list_node_fini(iter, &iter->iter_node, iter_pool); (void) pthread_mutex_unlock(&h->rh_lock); @@ -2030,7 +2144,7 @@ scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle) return (scf_set_error(SCF_ERROR_NOT_BOUND)); } - if (!handle_has_server(h)) { + if (!handle_has_server_locked(h)) { (void) pthread_mutex_unlock(&h->rh_lock); return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); } @@ -2894,7 +3008,7 @@ datael_update(scf_datael_t *dp) request.rpr_entityid = dp->rd_entity; datael_finish_reset(dp); - request.rpr_changeid = handle_alloc_changeid(h); + request.rpr_changeid = handle_next_changeid(h); r = make_door_call(h, &request, sizeof (request), &response, sizeof (response)); @@ -6606,7 +6720,7 @@ _scf_request_backup(scf_handle_t *h, const char *name) (void) pthread_mutex_lock(&h->rh_lock); request.rpr_request = REP_PROTOCOL_BACKUP; - request.rpr_changeid = handle_alloc_changeid(h); + request.rpr_changeid = handle_next_changeid(h); r = make_door_call(h, &request, sizeof (request), &response, sizeof (response)); diff --git a/usr/src/lib/libscf/common/lowlevel_impl.h b/usr/src/lib/libscf/common/lowlevel_impl.h index 5137eaf8ad..a3bc40aed9 100644 --- a/usr/src/lib/libscf/common/lowlevel_impl.h +++ b/usr/src/lib/libscf/common/lowlevel_impl.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -101,8 +101,10 @@ struct scf_handle { scf_property_t *rh_property; scf_value_t *rh_value; }; -#define HANDLE_DEAD 0x0001 -#define HANDLE_UNREFED 0x0002 +#define HANDLE_DEAD 0x0001 +#define HANDLE_UNREFED 0x0002 +#define HANDLE_WRAPPED_ENTITY 0x0004 +#define HANDLE_WRAPPED_ITER 0x0008 #define RH_HOLD_ITER 0x0001 #define RH_HOLD_SCOPE 0x0002 |
