[PATCH v2 05/23] nscd: Use a real read-write lock for the client mapping
Carlos O'Donell
carlos@redhat.com
Tue Mar 24 17:13:57 GMT 2026
On 3/20/26 4:41 PM, Florian Weimer wrote:
> The old code had half of an implementation of a rwlock, but did
> not have code to wait in case the mapping was used by another
> thread, so it performed busy waiting in some cases. Switch
> to a proper rwlock instead.
Agreed. This looks better.
> Simplify the memory management by pre-allocating the struct
> mapped_database structures. Consolidate all struct definitions
> in an array in nscd_helper.c. This will make it possible to add
> fork safety later, in a centralized fashion.
>
> Simplify the error reporting and consolidate the retry logic.
> There is still no proper software TM protocol, the code is just
> simplified while retaining the old (incorrect) GC checks.
OK.
> Assume that SCM_RIGHTS and MSG_CMSG_CLOEXEC are always available
> (Linux and Hurd have them).
>
> I converted nscd_getpw_r.c manually, and guided automation to
> update the other files. Adjusting __nscd_get_nl_timestamp required
> additional instructions (use __nscd_get_map_ref, despite
> the potential loss of efficiency). Auto-generation should be
> fine here because the changes are mechanical and they mostly delete
> code.
Agreed.
> The definition of MAPPED_DATABASE_INITIALIZER is a slight layering
> violation, but both htl and ntpl use pthread rwlocks directly.
LGTM.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
> ---
> include/set-freeres.h | 5 --
> malloc/set-freeres.c | 15 ----
> nscd/nscd-client.h | 90 ++++++----------------
> nscd/nscd_getai.c | 39 +++-------
> nscd/nscd_getgr_r.c | 52 +++----------
> nscd/nscd_gethst_r.c | 85 +++++---------------
> nscd/nscd_getpw_r.c | 46 ++---------
> nscd/nscd_getserv_r.c | 55 +++----------
> nscd/nscd_helper.c | 171 +++++++++++++++++++++++++----------------
> nscd/nscd_initgroups.c | 32 ++------
> nscd/nscd_netgroup.c | 72 ++++-------------
> 11 files changed, 208 insertions(+), 454 deletions(-)
>
> diff --git a/include/set-freeres.h b/include/set-freeres.h
> index 470ce00791..55093aa89d 100644
> --- a/include/set-freeres.h
> +++ b/include/set-freeres.h
> @@ -46,11 +46,6 @@ extern void __gconv_dl_freemem (void) attribute_hidden;
> extern void __intl_freemem (void) attribute_hidden;
> extern void __libio_freemem (void) attribute_hidden;
> extern void __libc_fstab_freemem (void) attribute_hidden;
> -extern void __nscd_gr_map_freemem (void) attribute_hidden;
> -extern void __nscd_hst_map_freemem (void) attribute_hidden;
> -extern void __nscd_pw_map_freemem (void) attribute_hidden;
> -extern void __nscd_serv_map_freemem (void) attribute_hidden;
> -extern void __nscd_group_map_freemem (void) attribute_hidden;
> extern void __libc_regcomp_freemem (void) attribute_hidden;
> extern void __libc_atfork_freemem (void) attribute_hidden;
> extern void __libc_resolv_conf_freemem (void) attribute_hidden;
> diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
> index ab2998db89..39fd7d4d27 100644
> --- a/malloc/set-freeres.c
> +++ b/malloc/set-freeres.c
> @@ -36,13 +36,6 @@
> # pragma weak __intl_freemem
> # pragma weak __libio_freemem
> # pragma weak __libc_fstab_freemem
> -#ifdef USE_NSCD
> -# pragma weak __nscd_gr_map_freemem
> -# pragma weak __nscd_hst_map_freemem
> -# pragma weak __nscd_pw_map_freemem
> -# pragma weak __nscd_serv_map_freemem
> -# pragma weak __nscd_group_map_freemem
> -#endif
> # pragma weak __libc_regcomp_freemem
> # pragma weak __libc_atfork_freemem
> # pragma weak __res_thread_freeres
> @@ -144,14 +137,6 @@ __libc_freeres (void)
> call_function_static_weak (__libio_freemem);
> call_function_static_weak (__libc_fstab_freemem);
>
> -#ifdef USE_NSCD
> - call_function_static_weak (__nscd_gr_map_freemem);
> - call_function_static_weak (__nscd_hst_map_freemem);
> - call_function_static_weak (__nscd_pw_map_freemem);
> - call_function_static_weak (__nscd_serv_map_freemem);
> - call_function_static_weak (__nscd_group_map_freemem);
> -#endif
> -
> call_function_static_weak (__libc_regcomp_freemem);
> call_function_static_weak (__libc_atfork_freemem);
> /* __res_thread_freeres deallocates the per-thread resolv_context);
> diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
> index 0906de2929..aff303b757 100644
> --- a/nscd/nscd-client.h
> +++ b/nscd/nscd-client.h
> @@ -29,7 +29,7 @@
> #include <atomic.h>
> #include <nscd-types.h>
> #include <sys/uio.h>
> -
> +#include <libc-lock.h>
>
> /* Version number of the daemon interface */
> #define NSCD_VERSION 2
> @@ -351,83 +351,43 @@ struct mapped_database
> {
> const struct database_pers_head *head;
> const char *data;
> - size_t mapsize;
> - int counter; /* > 0 indicates it is usable. */
> + size_t mapsize; /* Zero means not in use. */
OK. Drop local counter and use mapsize.
> size_t datasize;
> -};
> -#define NO_MAPPING ((struct mapped_database *) -1l)
>
> -struct locked_map_ptr
> -{
> - int lock;
> - struct mapped_database *mapped;
> + /* Use of the mapping must acquire a read lock. If the mapping is
> + changed, acquire a write lock. */
> + __libc_rwlock_define (, lock);
OK. Change the internal lock to an internal rwlock.
> };
> -#define libc_locked_map_ptr(class, name) class struct locked_map_ptr name
> -
> -/* Try acquiring lock for mapptr, returns true if it succeeds, false
> - if not. */
> -static inline bool
> -__nscd_acquire_maplock (volatile struct locked_map_ptr *mapptr)
> -{
> - int cnt = 0;
> - while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock,
> - 1, 0) != 0, 0))
> - {
> - // XXX Best number of rounds?
> - if (__glibc_unlikely (++cnt > 5))
> - return false;
> -
> - atomic_spin_nop ();
> - }
> -
> - return true;
> -}
> -
OK. Remove __nscd_acquire_lock.
>
> /* Open socket connection to nscd server. */
> extern int __nscd_open_socket (const char *key, size_t keylen,
> request_type type, void *response,
> size_t responselen) attribute_hidden;
>
> -/* Try to get a file descriptor for the shared memory segment
> - containing the database. */
> -extern struct mapped_database *__nscd_get_mapping (request_type type,
> - const char *key,
> - struct mapped_database **mappedp) attribute_hidden;
> -
> -/* Get reference of mapping. */
> -extern struct mapped_database *__nscd_get_map_ref (request_type type,
> - const char *name,
> - volatile struct locked_map_ptr *mapptr,
> - int *gc_cyclep)
> - attribute_hidden;
> +/* Acquire reference to the mapping for DB (see <nscd-dbtype.h>). On
> + success, return a pointer to the mapping descriptor, and lock the
> + mapping.
> +
> + Errors are not fatal (socket fallback should be used,
> + rather than reporting an error immediately to the caller).
>
> -/* Unmap database. */
> -extern void __nscd_unmap (struct mapped_database *mapped)
> + To release the map reference, call __nscd_map_ref_retry_or_drop below. */
> +struct mapped_database *__nscd_get_map_ref (unsigned int db, int *gc_cyclep)
> attribute_hidden;
>
> -/* Drop reference of mapping. */
> -static int
> -__attribute__ ((unused))
> -__nscd_drop_map_ref (struct mapped_database *map, int *gc_cycle)
> -{
> - if (map != NO_MAPPING)
> - {
> - int now_cycle = map->head->gc_cycle;
> - if (__glibc_unlikely (now_cycle != *gc_cycle))
> - {
> - /* We might have read inconsistent data. */
> - *gc_cycle = now_cycle;
> - return -1;
> - }
> -
> - if (atomic_fetch_add_relaxed (&map->counter, -1) == 1)
> - __nscd_unmap (map);
> - }
> -
> - return 0;
> -}
> +/* If *MAPPED is not null, check that *GC_CYCLE matches the current cycle in
> + **MAPPED. If not, the function may return true to indicate another
> + attempt, and increments *NRETRIES. If the retry counter is
> + exceeded, set *MAPPED to null, unlock the mapping, and return
> + true to retry once more without the mapping.
> +
> + If no retries are needed, unlock the mapping (for non-null *MAPPED), and
> + return false. This always happens if retval == -1.
>
> + Must be called after __nscd_get_map_ref. */
> +bool __nscd_map_ref_retry_or_drop (struct mapped_database **mapped,
> + int *gc_cycle, int *nretries, int retval)
> + attribute_hidden;
>
> /* Search the mapped database. */
> extern struct datahead *__nscd_cache_search (request_type type,
> diff --git a/nscd/nscd_getai.c b/nscd/nscd_getai.c
> index 4aca0a18c4..a2e5da6b1c 100644
> --- a/nscd/nscd_getai.c
> +++ b/nscd/nscd_getai.c
> @@ -24,16 +24,13 @@
> #include <not-cancel.h>
>
> #include "nscd-client.h"
> +#include "nscd-dbtype.h"
> #include "nscd_proto.h"
>
>
> /* Define in nscd_gethst_r.c. */
> extern int __nss_not_use_nscd_hosts;
>
> -
> -/* We use the mapping from nscd_gethst. */
> -libc_locked_map_ptr (extern, __hst_map_handle) attribute_hidden;
> -
> /* Defined in nscd_gethst_r.c. */
> extern int __nss_have_localdomain attribute_hidden;
>
> @@ -58,9 +55,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
>
> /* If the mapping is available, try to search there instead of
> communicating with the nscd. */
> - struct mapped_database *mapped;
> - mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle,
> - &gc_cycle);
> + struct mapped_database *map = __nscd_get_map_ref (hstdb, &gc_cycle);
>
> retry:;
> struct nscd_ai_result *resultbuf = NULL;
> @@ -70,10 +65,10 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
> int sock = -1;
> ai_response_header ai_resp;
>
> - if (mapped != NO_MAPPING)
> + if (map != NULL)
> {
> struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
> - mapped, sizeof ai_resp);
> + map, sizeof ai_resp);
> if (found != NULL)
> {
> respdata = (char *) (&found->data[0].aidata + 1);
> @@ -81,7 +76,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
> recend = (const char *) found->data + found->recsize;
> /* Now check if we can trust ai_resp fields. If GC is
> in progress, it can contain anything. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out;
> @@ -157,7 +152,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
> && resultbuf->canon[ai_resp.canonlen - 1] != '\0')
> /* We cannot use the database. */
> {
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> retval = -2;
> else
> free (resultbuf);
> @@ -190,25 +185,11 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
> if (sock != -1)
> __close_nocancel_nostatus (sock);
> out:
> - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
> + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval))
> {
> - /* When we come here this means there has been a GC cycle while we
> - were looking for the data. This means the data might have been
> - inconsistent. Retry if possible. */
> - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
> - {
> - /* nscd is just running gc now. Disable using the mapping. */
> - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
> - __nscd_unmap (mapped);
> - mapped = NO_MAPPING;
> - }
> -
> - if (retval != -1)
> - {
> - *result = NULL;
> - free (resultbuf);
> - goto retry;
> - }
> + *result = NULL;
> + free (resultbuf);
> + goto retry;
> }
>
> return retval;
> diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c
> index db3c0ab464..746b11d792 100644
> --- a/nscd/nscd_getgr_r.c
> +++ b/nscd/nscd_getgr_r.c
> @@ -33,6 +33,7 @@
> #include <scratch_buffer.h>
>
> #include "nscd-client.h"
> +#include "nscd-dbtype.h"
> #include "nscd_proto.h"
>
> int __nss_not_use_nscd_group;
> @@ -63,23 +64,6 @@ __nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer,
> buffer, buflen, result);
> }
>
> -
> -libc_locked_map_ptr (,__gr_map_handle) attribute_hidden;
> -/* Note that we only free the structure if necessary. The memory
> - mapping is not removed since it is not visible to the malloc
> - handling. */
> -void
> -__nscd_gr_map_freemem (void)
> -{
> - if (__gr_map_handle.mapped != NO_MAPPING)
> - {
> - void *p = __gr_map_handle.mapped;
> - __gr_map_handle.mapped = NO_MAPPING;
> - free (p);
> - }
> -}
> -
> -
> static int
> nscd_getgr_r (const char *key, size_t keylen, request_type type,
> struct group *resultbuf, char *buffer, size_t buflen,
> @@ -93,9 +77,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
>
> /* If the mapping is available, try to search there instead of
> communicating with the nscd. */
> - struct mapped_database *mapped = __nscd_get_map_ref (GETFDGR, "group",
> - &__gr_map_handle,
> - &gc_cycle);
> + struct mapped_database *map = __nscd_get_map_ref (grpdb, &gc_cycle);
> retry:;
> const char *gr_name = NULL;
> size_t gr_name_len = 0;
> @@ -103,9 +85,9 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
> const char *recend = (const char *) ~UINTMAX_C (0);
> gr_response_header gr_resp;
>
> - if (mapped != NO_MAPPING)
> + if (map != NULL)
> {
> - struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
> + struct datahead *found = __nscd_cache_search (type, key, keylen, map,
> sizeof gr_resp);
> if (found != NULL)
> {
> @@ -117,7 +99,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
> recend = (const char *) found->data + found->recsize;
> /* Now check if we can trust gr_resp fields. If GC is
> in progress, it can contain anything. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out;
> @@ -239,7 +221,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
> {
> /* len array might contain garbage during nscd GC cycle,
> retry rather than fail in that case. */
> - if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
> + if (gr_name != NULL && map->head->gc_cycle != gc_cycle)
> retval = -2;
> goto out_close;
> }
> @@ -247,7 +229,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
> {
> /* len array might contain garbage during nscd GC cycle,
> retry rather than fail in that case. */
> - if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
> + if (gr_name != NULL && map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out_close;
> @@ -286,7 +268,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
> cnt < gr_resp.gr_mem_cnt; }))
> {
> /* We cannot use the database. */
> - retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
> + retval = map != NULL && map->head->gc_cycle != gc_cycle ? -2 : -1;
> goto out_close;
> }
>
> @@ -305,22 +287,8 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
> if (sock != -1)
> __close_nocancel_nostatus (sock);
> out:
> - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
> - {
> - /* When we come here this means there has been a GC cycle while we
> - were looking for the data. This means the data might have been
> - inconsistent. Retry if possible. */
> - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
> - {
> - /* nscd is just running gc now. Disable using the mapping. */
> - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
> - __nscd_unmap (mapped);
> - mapped = NO_MAPPING;
> - }
> -
> - if (retval != -1)
> - goto retry;
> - }
> + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval))
> + goto retry;
>
> scratch_buffer_free (&lenbuf);
>
> diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c
> index 9291039008..15d747fc33 100644
> --- a/nscd/nscd_gethst_r.c
> +++ b/nscd/nscd_gethst_r.c
> @@ -24,6 +24,7 @@
> #include <not-cancel.h>
>
> #include "nscd-client.h"
> +#include "nscd-dbtype.h"
> #include "nscd_proto.h"
>
> int __nss_not_use_nscd_hosts;
> @@ -77,52 +78,22 @@ __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type,
> }
>
>
> -libc_locked_map_ptr (, __hst_map_handle) attribute_hidden;
> -/* Note that we only free the structure if necessary. The memory
> - mapping is not removed since it is not visible to the malloc
> - handling. */
> -void
> -__nscd_hst_map_freemem (void)
> -{
> - if (__hst_map_handle.mapped != NO_MAPPING)
> - {
> - void *p = __hst_map_handle.mapped;
> - __hst_map_handle.mapped = NO_MAPPING;
> - free (p);
> - }
> -}
> -
> -
> uint32_t
> __nscd_get_nl_timestamp (void)
> {
> - uint32_t retval;
> if (__nss_not_use_nscd_hosts != 0)
> return 0;
>
> - /* __nscd_get_mapping can change hst_map_handle.mapped to NO_MAPPING.
> - However, __nscd_get_mapping assumes the prior value was not NO_MAPPING.
> - Thus we have to acquire the lock to prevent this thread from changing
> - hst_map_handle.mapped to NO_MAPPING while another thread is inside
> - __nscd_get_mapping. */
> - if (!__nscd_acquire_maplock (&__hst_map_handle))
> - return 0;
> -
> - struct mapped_database *map = __hst_map_handle.mapped;
> -
> - if (map == NULL
> - || (map != NO_MAPPING
> - && map->head->nscd_certainly_running == 0
> - && map->head->timestamp + MAPPING_TIMEOUT < time64_now ()))
> - map = __nscd_get_mapping (GETFDHST, "hosts", &__hst_map_handle.mapped);
> -
> - if (map == NO_MAPPING)
> - retval = 0;
> + int gc_cycle;
> + uint32_t retval;
> + struct mapped_database *map = __nscd_get_map_ref (hstdb, &gc_cycle);
> + if (map != NULL)
> + {
> + retval = map->head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP];
> + __libc_rwlock_unlock (map->lock);
> + }
> else
> - retval = map->head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP];
> -
> - /* Release the lock. */
> - __hst_map_handle.lock = 0;
> + retval = 0;
>
> return retval;
> }
> @@ -151,9 +122,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
>
> /* If the mapping is available, try to search there instead of
> communicating with the nscd. */
> - struct mapped_database *mapped;
> - mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle,
> - &gc_cycle);
> + struct mapped_database *map = __nscd_get_map_ref (hstdb, &gc_cycle);
>
> retry:;
> const char *h_name = NULL;
> @@ -164,11 +133,11 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
> const char *recend = (const char *) ~UINTMAX_C (0);
> int sock = -1;
> hst_response_header hst_resp;
> - if (mapped != NO_MAPPING)
> + if (map != NULL)
> {
> /* No const qualifier, as it can change during garbage collection. */
> - struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
> - sizeof hst_resp);
> + struct datahead *found = __nscd_cache_search (type, key, keylen,
> + map, sizeof hst_resp);
> if (found != NULL)
> {
> h_name = (char *) (&found->data[0].hstdata + 1);
> @@ -180,7 +149,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
> recend = (const char *) found->data + found->recsize;
> /* Now check if we can trust hst_resp fields. If GC is
> in progress, it can contain anything. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out;
> @@ -364,7 +333,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
> {
> /* aliases_len array might contain garbage during nscd GC cycle,
> retry rather than fail in that case. */
> - if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
> + if (addr_list != NULL && map->head->gc_cycle != gc_cycle)
> retval = -2;
> goto out_close;
> }
> @@ -373,7 +342,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
> {
> /* aliases_len array might contain garbage during nscd GC cycle,
> retry rather than fail in that case. */
> - if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
> + if (addr_list != NULL && map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out_close;
> @@ -406,7 +375,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
> cnt < hst_resp.h_aliases_cnt; }))
> {
> /* We cannot use the database. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> retval = -2;
> goto out_close;
> }
> @@ -430,22 +399,8 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
> if (sock != -1)
> __close_nocancel_nostatus (sock);
> out:
> - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
> - {
> - /* When we come here this means there has been a GC cycle while we
> - were looking for the data. This means the data might have been
> - inconsistent. Retry if possible. */
> - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
> - {
> - /* nscd is just running gc now. Disable using the mapping. */
> - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
> - __nscd_unmap (mapped);
> - mapped = NO_MAPPING;
> - }
> -
> - if (retval != -1)
> - goto retry;
> - }
> + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval))
> + goto retry;
>
> return retval;
> }
> diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c
> index f19b7a271c..938eac9c70 100644
> --- a/nscd/nscd_getpw_r.c
> +++ b/nscd/nscd_getpw_r.c
> @@ -31,6 +31,7 @@
> #include <_itoa.h>
>
> #include "nscd-client.h"
> +#include "nscd-dbtype.h"
> #include "nscd_proto.h"
>
> int __nss_not_use_nscd_passwd;
> @@ -63,22 +64,6 @@ __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer,
> }
>
>
> -libc_locked_map_ptr (static, map_handle);
> -/* Note that we only free the structure if necessary. The memory
> - mapping is not removed since it is not visible to the malloc
> - handling. */
> -void
> -__nscd_pw_map_freemem (void)
> -{
> - if (map_handle.mapped != NO_MAPPING)
> - {
> - void *p = map_handle.mapped;
> - map_handle.mapped = NO_MAPPING;
> - free (p);
> - }
> -}
> -
> -
> static int
> nscd_getpw_r (const char *key, size_t keylen, request_type type,
> struct passwd *resultbuf, char *buffer, size_t buflen,
> @@ -89,8 +74,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
>
> /* If the mapping is available, try to search there instead of
> communicating with the nscd. */
> - struct mapped_database *mapped;
> - mapped = __nscd_get_map_ref (GETFDPW, "passwd", &map_handle, &gc_cycle);
> + struct mapped_database *map = __nscd_get_map_ref (pwddb, &gc_cycle);
>
> retry:;
> const char *pw_name = NULL;
> @@ -98,9 +82,9 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
> const char *recend = (const char *) ~UINTMAX_C (0);
> pw_response_header pw_resp;
>
> - if (mapped != NO_MAPPING)
> + if (map != NULL)
> {
> - struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
> + struct datahead *found = __nscd_cache_search (type, key, keylen, map,
> sizeof pw_resp);
> if (found != NULL)
> {
> @@ -109,7 +93,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
> recend = (const char *) found->data + found->recsize;
> /* Now check if we can trust pw_resp fields. If GC is
> in progress, it can contain anything. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out;
> @@ -199,7 +183,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
> || resultbuf->pw_shell[pw_resp.pw_shell_len - 1] != '\0')
> {
> /* We cannot use the database. */
> - retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
> + retval = map->head->gc_cycle != gc_cycle ? -2 : -1;
> goto out_close;
> }
>
> @@ -218,22 +202,8 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
> if (sock != -1)
> __close_nocancel_nostatus (sock);
> out:
> - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
> - {
> - /* When we come here this means there has been a GC cycle while we
> - were looking for the data. This means the data might have been
> - inconsistent. Retry if possible. */
> - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
> - {
> - /* nscd is just running gc now. Disable using the mapping. */
> - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
> - __nscd_unmap (mapped);
> - mapped = NO_MAPPING;
> - }
> -
> - if (retval != -1)
> - goto retry;
> - }
> + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval))
> + goto retry;
>
> return retval;
> }
> diff --git a/nscd/nscd_getserv_r.c b/nscd/nscd_getserv_r.c
> index 63cd6d5860..519078d8fe 100644
> --- a/nscd/nscd_getserv_r.c
> +++ b/nscd/nscd_getserv_r.c
> @@ -23,6 +23,7 @@
> #include <stdint.h>
>
> #include "nscd-client.h"
> +#include "nscd-dbtype.h"
> #include "nscd_proto.h"
>
>
> @@ -58,22 +59,6 @@ __nscd_getservbyport_r (int port, const char *proto,
> }
>
>
> -libc_locked_map_ptr (, __serv_map_handle) attribute_hidden;
> -/* Note that we only free the structure if necessary. The memory
> - mapping is not removed since it is not visible to the malloc
> - handling. */
> -void
> -__nscd_serv_map_freemem (void)
> -{
> - if (__serv_map_handle.mapped != NO_MAPPING)
> - {
> - void *p = __serv_map_handle.mapped;
> - __serv_map_handle.mapped = NO_MAPPING;
> - free (p);
> - }
> -}
> -
> -
> static int
> nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
> request_type type, struct servent *resultbuf,
> @@ -85,9 +70,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
>
> /* If the mapping is available, try to search there instead of
> communicating with the nscd. */
> - struct mapped_database *mapped;
> - mapped = __nscd_get_map_ref (GETFDSERV, "services", &__serv_map_handle,
> - &gc_cycle);
> + struct mapped_database *map = __nscd_get_map_ref (servdb, &gc_cycle);
> size_t protolen = proto == NULL ? 0 : strlen (proto);
> size_t keylen = critlen + 1 + protolen + 1;
> int alloca_key = __libc_use_alloca (keylen);
> @@ -114,9 +97,9 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
> int sock = -1;
> serv_response_header serv_resp;
>
> - if (mapped != NO_MAPPING)
> + if (map != NULL)
> {
> - struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
> + struct datahead *found = __nscd_cache_search (type, key, keylen, map,
> sizeof serv_resp);
>
> if (found != NULL)
> @@ -131,7 +114,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
> recend = (const char *) found->data + found->recsize;
> /* Now check if we can trust serv_resp fields. If GC is
> in progress, it can contain anything. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out;
> @@ -291,7 +274,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
> {
> /* aliases_len array might contain garbage during nscd GC cycle,
> retry rather than fail in that case. */
> - if (aliases_list != NULL && mapped->head->gc_cycle != gc_cycle)
> + if (aliases_list != NULL && map->head->gc_cycle != gc_cycle)
> retval = -2;
> goto out_close;
> }
> @@ -301,7 +284,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
> {
> /* aliases_len array might contain garbage during nscd GC cycle,
> retry rather than fail in that case. */
> - if (aliases_list != NULL && mapped->head->gc_cycle != gc_cycle)
> + if (aliases_list != NULL && map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out_close;
> @@ -334,7 +317,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
> cnt < serv_resp.s_aliases_cnt; }))
> {
> /* We cannot use the database. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> retval = -2;
> goto out_close;
> }
> @@ -355,25 +338,11 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
> if (sock != -1)
> __close_nocancel_nostatus (sock);
> out:
> - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
> + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval))
> {
> - /* When we come here this means there has been a GC cycle while we
> - were looking for the data. This means the data might have been
> - inconsistent. Retry if possible. */
> - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
> - {
> - /* nscd is just running gc now. Disable using the mapping. */
> - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
> - __nscd_unmap (mapped);
> - mapped = NO_MAPPING;
> - }
> -
> - if (retval != -1)
> - {
> - if (!alloca_aliases_len)
> - free ((void *) aliases_len);
> - goto retry;
> - }
> + if (!alloca_aliases_len)
> + free ((void *) aliases_len);
> + goto retry;
> }
>
> if (!alloca_aliases_len)
> diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
> index 6319fde6f2..d3bfc208ad 100644
> --- a/nscd/nscd_helper.c
> +++ b/nscd/nscd_helper.c
> @@ -39,6 +39,7 @@
> #include <struct___timespec64.h>
>
> #include "nscd-client.h"
> +#include "nscd-dbtype.h"
>
> /* Extra time we wait if the socket is still receiving data. This
> value is in milliseconds. Note that the other side is nscd on the
> @@ -241,32 +242,64 @@ open_socket (request_type type, const char *key, size_t keylen)
> return -1;
> }
>
> +#define MAPPED_DATABASE_INITIALIZER \
> + ((struct mapped_database) { .lock = PTHREAD_RWLOCK_INITIALIZER, })
>
> -void
> -__nscd_unmap (struct mapped_database *mapped)
> -{
> - assert (mapped->counter == 0);
> - __munmap ((void *) mapped->head, mapped->mapsize);
> - free (mapped);
> -}
> -
> +static struct mapped_database __nscd_mapped_databases[lastdb] =
> + {
> + [pwddb] = MAPPED_DATABASE_INITIALIZER,
> + [grpdb] = MAPPED_DATABASE_INITIALIZER,
> + [hstdb] = MAPPED_DATABASE_INITIALIZER,
> + [servdb] = MAPPED_DATABASE_INITIALIZER,
> + [netgrdb] = MAPPED_DATABASE_INITIALIZER,
> + };
>
> /* Try to get a file descriptor for the shared memory segment
> - containing the database. */
> -struct mapped_database *
> -__nscd_get_mapping (request_type type, const char *key,
> - struct mapped_database **mappedp)
> + containing the database. Lock the mapping, but mapsize might still
> + be 0 after return because there is no mapping. */
> +static void
> +__nscd_get_mapping (unsigned int db)
> {
> - struct mapped_database *result = NO_MAPPING;
> -#ifdef SCM_RIGHTS
> + struct mapped_database *mapped = &__nscd_mapped_databases[db];
> +
> + static const uint8_t requests[] =
> + {
> + [pwddb] = GETFDPW,
> + [grpdb] = GETFDGR,
> + [hstdb] = GETFDHST,
> + [servdb] = GETFDSERV,
> + [netgrdb] = GETFDNETGR,
> + };
> +
> + static const char keys[][9] =
> + {
> + [pwddb] = "passwd",
> + [grpdb] = "group",
> + [hstdb] = "hosts",
> + [servdb] = "services",
> + [netgrdb] = "netgroup"
> + };
> + const char *key = keys[db];
> const size_t keylen = strlen (key) + 1;
> +
> + __libc_rwlock_wrlock (mapped->lock);
> +
> + /* Remove any previously existing mapping. */
> + if (mapped->mapsize > 0)
> + {
> + __munmap ((void *) mapped->head, mapped->mapsize);
> + mapped->head = NULL;
> + mapped->data = NULL;
> + mapped->mapsize = 0;
> + }
> +
> int saved_errno = errno;
>
> int mapfd = -1;
> - char resdata[keylen];
> + char resdata[sizeof (keys[0])];
>
> /* Open a socket and send the request. */
> - int sock = open_socket (type, key, keylen);
> + int sock = open_socket (requests[db], key, keylen);
> if (sock < 0)
> goto out;
>
> @@ -302,9 +335,6 @@ __nscd_get_mapping (request_type type, const char *key,
> if (wait_on_socket (sock, 5 * 1000) <= 0)
> goto out_close2;
>
> -# ifndef MSG_CMSG_CLOEXEC
> -# define MSG_CMSG_CLOEXEC 0
> -# endif
> ssize_t n = TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, MSG_CMSG_CLOEXEC));
>
> if (__builtin_expect (CMSG_FIRSTHDR (&msg) == NULL
> @@ -362,21 +392,11 @@ __nscd_get_mapping (request_type type, const char *key,
> if (__glibc_unlikely (mapsize < size))
> goto out_unmap;
>
> - /* Allocate a record for the mapping. */
> - struct mapped_database *newp = malloc (sizeof (*newp));
> - if (newp == NULL)
> - /* Ugh, after all we went through the memory allocation failed. */
> - goto out_unmap;
> -
> - newp->head = mapping;
> - newp->data = ((char *) mapping + head->header_size
> + mapped->head = mapping;
> + mapped->data = ((char *) mapping + head->header_size
> + roundup (head->module * sizeof (ref_t), ALIGN));
> - newp->mapsize = size;
> - newp->datasize = head->data_size;
> - /* Set counter to 1 to show it is usable. */
> - newp->counter = 1;
> -
> - result = newp;
> + mapped->mapsize = size;
> + mapped->datasize = head->data_size;
> }
>
> out_close:
> @@ -385,56 +405,71 @@ __nscd_get_mapping (request_type type, const char *key,
> __close (sock);
> out:
> __set_errno (saved_errno);
> -#endif /* SCM_RIGHTS */
> -
> - struct mapped_database *oldval = *mappedp;
> - *mappedp = result;
>
> - if (oldval != NULL && atomic_fetch_add_relaxed (&oldval->counter, -1) == 1)
> - __nscd_unmap (oldval);
> -
> - return result;
> + /* Downgrade lock to a read lock. The mapping may go away between
> + the two calls, but the caller has to handle the no-mapping case
> + anyway. */
> + __libc_rwlock_unlock (mapped->lock);
> + __libc_rwlock_rdlock (mapped->lock);
> }
>
> struct mapped_database *
> -__nscd_get_map_ref (request_type type, const char *name,
> - volatile struct locked_map_ptr *mapptr, int *gc_cyclep)
> +__nscd_get_map_ref (unsigned int db, int *gc_cyclep)
> {
> - struct mapped_database *cur = mapptr->mapped;
> - if (cur == NO_MAPPING)
> - return cur;
> + assert (db < lastdb);
> + struct mapped_database *mapped = &__nscd_mapped_databases[db];
> +
> + __libc_rwlock_rdlock (mapped->lock);
OK. Lock.
> + if (mapped->mapsize == 0
> + || (mapped->head->nscd_certainly_running == 0
> + && mapped->head->timestamp + MAPPING_TIMEOUT < time_now ())
> + || mapped->head->data_size > mapped->datasize)
> + {
> + __libc_rwlock_unlock (mapped->lock);
OK. Unlock.
> + __nscd_get_mapping (db);
> + }
>
> - if (!__nscd_acquire_maplock (mapptr))
> - return NO_MAPPING;
> + if (mapped->mapsize > 0)
> + {
> + *gc_cyclep = mapped->head->gc_cycle;
> + if ((*gc_cyclep & 1) == 0)
> + return mapped;
> + }
>
> - cur = mapptr->mapped;
> + __libc_rwlock_unlock (mapped->lock);
OK. Unlock.
> + return NULL;
> +}
> +
> +bool
> +__nscd_map_ref_retry_or_drop (struct mapped_database **mapped,
> + int *gc_cycle, int *nretries, int retval)
> +{
> + if (*mapped == NULL)
> + return false;
>
> - if (__glibc_likely (cur != NO_MAPPING))
> + int now_cycle = (*mapped)->head->gc_cycle;
> + if (__glibc_unlikely (now_cycle != *gc_cycle))
> {
> - /* If not mapped or timestamp not updated, request new map. */
> - if (cur == NULL
> - || (cur->head->nscd_certainly_running == 0
> - && cur->head->timestamp + MAPPING_TIMEOUT < time_now ())
> - || cur->head->data_size > cur->datasize)
> - cur = __nscd_get_mapping (type, name,
> - (struct mapped_database **) &mapptr->mapped);
> -
> - if (__glibc_likely (cur != NO_MAPPING))
> + /* When we come here this means there has been a GC cycle while we
> + were looking for the data. This means the data might have been
> + inconsistent. Retry if possible. */
> +
> + *gc_cycle = now_cycle;
> + if ((*gc_cycle & 1) != 0 || ++*nretries == 5)
> {
> - if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0,
> - 0))
> - cur = NO_MAPPING;
> - else
> - atomic_fetch_add_relaxed (&cur->counter, 1);
> + __libc_rwlock_unlock ((*mapped)->lock);
> + *mapped = NULL;
> + return true;
> }
> - }
>
> - mapptr->lock = 0;
> + if (retval != -1)
> + return true;
> + }
>
> - return cur;
> + __libc_rwlock_unlock ((*mapped)->lock);
> + return false;
> }
>
> -
> /* Using sizeof (hashentry) is not always correct to determine the size of
> the data structure as found in the nscd cache. The program could be
> a 64-bit process and nscd could be a 32-bit process. In this case
> diff --git a/nscd/nscd_initgroups.c b/nscd/nscd_initgroups.c
> index 71ad7c7f96..f1e821b8d0 100644
> --- a/nscd/nscd_initgroups.c
> +++ b/nscd/nscd_initgroups.c
> @@ -24,13 +24,10 @@
> #include <not-cancel.h>
>
> #include "nscd-client.h"
> +#include "nscd-dbtype.h"
> #include "nscd_proto.h"
>
>
> -/* We use the same mapping as in nscd_getgr. */
> -libc_locked_map_ptr (extern, __gr_map_handle) attribute_hidden;
> -
> -
> int
> __nscd_getgrouplist (const char *user, gid_t group, long int *size,
> gid_t **groupsp, long int limit)
> @@ -41,8 +38,7 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
>
> /* If the mapping is available, try to search there instead of
> communicating with the nscd. */
> - struct mapped_database *mapped;
> - mapped = __nscd_get_map_ref (GETFDGR, "group", &__gr_map_handle, &gc_cycle);
> + struct mapped_database *map = __nscd_get_map_ref (grpdb, &gc_cycle);
>
> retry:;
> char *respdata = NULL;
> @@ -50,10 +46,10 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
> int sock = -1;
> initgr_response_header initgr_resp;
>
> - if (mapped != NO_MAPPING)
> + if (map != NULL)
> {
> struct datahead *found = __nscd_cache_search (INITGROUPS, user,
> - userlen, mapped,
> + userlen, map,
> sizeof initgr_resp);
> if (found != NULL)
> {
> @@ -63,7 +59,7 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
>
> /* Now check if we can trust initgr_resp fields. If GC is
> in progress, it can contain anything. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out;
> @@ -158,22 +154,8 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
> if (sock != -1)
> __close_nocancel_nostatus (sock);
> out:
> - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
> - {
> - /* When we come here this means there has been a GC cycle while we
> - were looking for the data. This means the data might have been
> - inconsistent. Retry if possible. */
> - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
> - {
> - /* nscd is just running gc now. Disable using the mapping. */
> - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
> - __nscd_unmap (mapped);
> - mapped = NO_MAPPING;
> - }
> -
> - if (retval != -1)
> - goto retry;
> - }
> + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval))
> + goto retry;
>
> return retval;
> }
> diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
> index 990d071cc0..53649adc82 100644
> --- a/nscd/nscd_netgroup.c
> +++ b/nscd/nscd_netgroup.c
> @@ -22,27 +22,11 @@
> #include <not-cancel.h>
>
> #include "nscd-client.h"
> +#include "nscd-dbtype.h"
> #include "nscd_proto.h"
>
> int __nss_not_use_nscd_netgroup;
>
> -
> -libc_locked_map_ptr (static, map_handle);
> -/* Note that we only free the structure if necessary. The memory
> - mapping is not removed since it is not visible to the malloc
> - handling. */
> -void
> -__nscd_group_map_freemem (void)
> -{
> - if (map_handle.mapped != NO_MAPPING)
> - {
> - void *p = map_handle.mapped;
> - map_handle.mapped = NO_MAPPING;
> - free (p);
> - }
> -}
> -
> -
> int
> __nscd_setnetgrent (const char *group, struct __netgrent *datap)
> {
> @@ -52,18 +36,17 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap)
>
> /* If the mapping is available, try to search there instead of
> communicating with the nscd. */
> - struct mapped_database *mapped;
> - mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
> + struct mapped_database *map = __nscd_get_map_ref (netgrdb, &gc_cycle);
>
> retry:;
> char *respdata = NULL;
> int retval = -1;
> netgroup_response_header netgroup_resp;
>
> - if (mapped != NO_MAPPING)
> + if (map != NULL)
> {
> struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
> - group_len, mapped,
> + group_len, map,
> sizeof netgroup_resp);
> if (found != NULL)
> {
> @@ -71,7 +54,7 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap)
> netgroup_resp = found->data[0].netgroupdata;
> /* Now check if we can trust pw_resp fields. If GC is
> in progress, it can contain anything. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out;
> @@ -141,22 +124,8 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap)
> if (sock != -1)
> __close_nocancel_nostatus (sock);
> out:
> - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
> - {
> - /* When we come here this means there has been a GC cycle while we
> - were looking for the data. This means the data might have been
> - inconsistent. Retry if possible. */
> - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
> - {
> - /* nscd is just running gc now. Disable using the mapping. */
> - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
> - __nscd_unmap (mapped);
> - mapped = NO_MAPPING;
> - }
> -
> - if (retval != -1)
> - goto retry;
> - }
> + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval))
> + goto retry;
>
> return retval;
> }
> @@ -206,25 +175,24 @@ __nscd_innetgr (const char *netgroup, const char *host, const char *user,
> communicating with the nscd. */
> int gc_cycle;
> int nretries = 0;
> - struct mapped_database *mapped;
> - mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
> + struct mapped_database *map = __nscd_get_map_ref (netgrdb, &gc_cycle);
>
> retry:;
> int retval = -1;
> innetgroup_response_header innetgroup_resp;
> int sock = -1;
>
> - if (mapped != NO_MAPPING)
> + if (map != NULL)
> {
> struct datahead *found = __nscd_cache_search (INNETGR, key,
> - key_len, mapped,
> + key_len, map,
> sizeof innetgroup_resp);
> if (found != NULL)
> {
> innetgroup_resp = found->data[0].innetgroupdata;
> /* Now check if we can trust pw_resp fields. If GC is
> in progress, it can contain anything. */
> - if (mapped->head->gc_cycle != gc_cycle)
> + if (map->head->gc_cycle != gc_cycle)
> {
> retval = -2;
> goto out;
> @@ -265,22 +233,8 @@ __nscd_innetgr (const char *netgroup, const char *host, const char *user,
> if (sock != -1)
> __close_nocancel_nostatus (sock);
> out:
> - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
> - {
> - /* When we come here this means there has been a GC cycle while we
> - were looking for the data. This means the data might have been
> - inconsistent. Retry if possible. */
> - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
> - {
> - /* nscd is just running gc now. Disable using the mapping. */
> - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
> - __nscd_unmap (mapped);
> - mapped = NO_MAPPING;
> - }
> -
> - if (retval != -1)
> - goto retry;
> - }
> + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval))
> + goto retry;
>
> if (! use_alloca)
> free (key);
--
Cheers,
Carlos.
More information about the Libc-alpha
mailing list