Hi Matthew,

Looking closely at the glibc implementation, it seems to be a different
implementation (or diverged a lot); glibc's implementation in
nss/nss_db/db-open.c:

```

/* Open the database stored in FILE.  If successful, store either a
   pointer to the mapped file or a file handle for the file in H and
   return NSS_STATUS_SUCCESS.  On failure, return the appropriate
   lookup status.  */
enum nss_status
internal_setent (const char *file, struct nss_db_map *mapping)
{
  enum nss_status status = NSS_STATUS_UNAVAIL;

  int fd = __open_nocancel (file, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
  if (fd != -1) 
    {   
      struct nss_db_header header;

      if (read (fd, &header, sizeof (header)) == sizeof (header))
    {   
      mapping->header = mmap (NULL, header.allocate, PROT_READ,
                  MAP_PRIVATE, fd, 0); 
      mapping->len = header.allocate;
      if (mapping->header != MAP_FAILED)
        status = NSS_STATUS_SUCCESS;
      else if (errno == ENOMEM)
        status = NSS_STATUS_TRYAGAIN;
    }   

      __close_nocancel_nostatus (fd);
    }   

  return status;
}
```

it mmap's the file and tracks the open status in variable `state` and
opens the file only if state.header is NULL in nss/nss_db/db-XXX.c:

```
/* Return the next entry from the database file, doing locking.  */
enum nss_status
CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
                   size_t buflen, int *errnop H_ERRNO_PROTO)
{
  /* Return next entry in host file.  */
  enum nss_status status;
  struct parser_data *data = (void *) buffer;

  if (buflen < sizeof *data)
    {   
      *errnop = ERANGE;
      H_ERRNO_SET (NETDB_INTERNAL);
      return NSS_STATUS_TRYAGAIN;
    }   

  __libc_lock_lock (lock);

  if (state.header == NULL)
    {   
      status = internal_setent (DBFILE, &state);
      if (status != NSS_STATUS_SUCCESS)
    {   
      *errnop = errno;
      H_ERRNO_SET (NETDB_INTERNAL);
      goto out;
    }   
      entidx = NULL;
    }   
   [..]
```


whereas the libnss-db doesn't maintain the state in such a way and thus needing 
the fix proposed here.

In src/db-open.c:

```
/* Open the database stored in FILE.  If succesful, store the database
   handle in *DBP and return NSS_STATUS_SUCCESS.  On failure, return
   the appropriate lookup status.  */
enum nss_status
internal_setent (const char *file, DB **dbp)
{
  DB *db;
  int err;
  int fd; 

  if (*dbp)
    return NSS_STATUS_SUCCESS;

  err = db_open (file, DB_BTREE, DB_RDONLY, 0, NULL, NULL, &db);
  if (err != 0)
    {   
      if (err > 0)
    __set_errno (err);
      return NSS_STATUS_UNAVAIL;
    }
    [..]
```

So I believe this is *not* a problem in upstream glibc at all.

I am not sure if glibc can even be considered "upstream" for libnss-db
anymore given they've diverged a lot and libnss-db appears to be an
orphan package in Debian.

Given this, can we proceed with the SRU now for Ubuntu?

Overall, my conclusions are:

 - glibc's nss implementation doesn't have this problem. glibc isn't even the 
"upstream" in the usual meaning of upstream (libnss-db is a fork that's been 
orphaned). Hence I think no glibc changes are required
 - No movement on the proposal for Debian: 
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1101371
 - We could SRU this for Ubuntu only if this is acceptable for the SRU team
 
If you agree with this. If so, I'll go ahead and provide debdiffs for stonking 
and resolute. Please let me know what you think.

Thanks,
Ponnuvel

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2121543

Title:
  [SRU] Poor performance of libnss-db on large db files

To manage notifications about this bug go to:
https://bugs.launchpad.net/libnss-db/+bug/2121543/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to