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