[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