diff options
author | Florian Weimer <fweimer@redhat.com> | 2021-07-07 18:33:52 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2021-07-07 18:33:52 +0200 |
commit | 36861a968ad143f662db489cd8f859186ee375c2 (patch) | |
tree | a12995bb4eda7c1e6822b13a3e38efcb27dd1678 /nss/nss_files_data.c | |
parent | f0c28504a9877be5da3ed1215f2da2d5914bbb0b (diff) | |
download | glibc-36861a968ad143f662db489cd8f859186ee375c2.zip glibc-36861a968ad143f662db489cd8f859186ee375c2.tar.gz glibc-36861a968ad143f662db489cd8f859186ee375c2.tar.bz2 |
nss_files: Add generic code for set*ent, end*ent and file open
This reduces RSS usage if nss_files is not actually used, and can
be used later to make NSS data thread-specific. It also results in
a small code size reduction.
Before:
text data bss dec hex filename
2288 0 72 2360 938 nss/files-alias.os
1807 0 72 1879 757 nss/files-ethers.os
1371 0 72 1443 5a3 nss/files-grp.os
6246 0 72 6318 18ae nss/files-hosts.os
869 0 0 869 365 nss/files-initgroups.os
666 0 0 666 29a nss/files-init.os
1934 0 0 1934 78e nss/files-netgrp.os
2353 0 72 2425 979 nss/files-network.os
2130 0 72 2202 89a nss/files-proto.os
1372 0 72 1444 5a4 nss/files-pwd.os
2124 0 72 2196 894 nss/files-rpc.os
2265 0 72 2337 921 nss/files-service.os
1125 0 72 1197 4ad nss/files-sgrp.os
1124 0 72 1196 4ac nss/files-spwd.os
After:
text data bss dec hex filename
2040 0 0 2040 7f8 nss/files-alias.os
1599 0 0 1599 63f nss/files-ethers.os
1155 0 0 1155 483 nss/files-grp.os
6010 0 0 6010 177a nss/files-hosts.os
869 0 0 869 365 nss/files-initgroups.os
666 0 0 666 29a nss/files-init.os
1934 0 0 1934 78e nss/files-netgrp.os
2129 0 0 2129 851 nss/files-network.os
1914 0 0 1914 77a nss/files-proto.os
1156 0 0 1156 484 nss/files-pwd.os
1908 0 0 1908 774 nss/files-rpc.os
2057 0 0 2057 809 nss/files-service.os
909 0 0 909 38d nss/files-sgrp.os
908 0 0 908 38c nss/files-spwd.os
1090 0 8 1098 44a nss/nss_files_data.os
27674 code bytes before, 26344 code bytes after, so it is an overall
win despite the extra initialization code.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Diffstat (limited to 'nss/nss_files_data.c')
-rw-r--r-- | nss/nss_files_data.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/nss/nss_files_data.c b/nss/nss_files_data.c new file mode 100644 index 0000000..80fbfe5 --- /dev/null +++ b/nss/nss_files_data.c @@ -0,0 +1,161 @@ +/* Returns a pointer to the global nss_files data structure. + Copyright (C) 2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <nss_files.h> + +#include <allocate_once.h> +#include <errno.h> +#include <netdb.h> +#include <nss.h> +#include <stdlib.h> + +/* This collects all per file-data. */ +struct nss_files_data +{ + struct nss_files_per_file_data files[nss_file_count]; +}; + +/* For use with allocate_once. */ +static void *nss_files_global; +static void * +nss_files_global_allocate (void *closure) +{ + struct nss_files_data *result = malloc (sizeof (*result)); + if (result != NULL) + { + for (int i = 0; i < nss_file_count; ++i) + { + result->files[i].stream = NULL; + __libc_lock_init (result->files[i].lock); + } + } + return result; +} +/* Like __nss_files_data_open, but does not perform the open call. */ +static enum nss_status +__nss_files_data_get (struct nss_files_per_file_data **pdata, + enum nss_files_file file, int *errnop, int *herrnop) +{ + struct nss_files_data *data = allocate_once (&nss_files_global, + nss_files_global_allocate, + NULL, NULL); + if (data == NULL) + { + if (errnop != NULL) + *errnop = errno; + if (herrnop != NULL) + { + __set_h_errno (NETDB_INTERNAL); + *herrnop = NETDB_INTERNAL; + } + return NSS_STATUS_TRYAGAIN; + } + + *pdata = &data->files[file]; + __libc_lock_lock ((*pdata)->lock); + return NSS_STATUS_SUCCESS; +} + +/* Helper function for opening the backing file at PATH. */ +static enum nss_status +__nss_files_data_internal_open (struct nss_files_per_file_data *data, + const char *path) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (data->stream == NULL) + { + data->stream = __nss_files_fopen (path); + + if (data->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + } + + return status; +} + + +enum nss_status +__nss_files_data_open (struct nss_files_per_file_data **pdata, + enum nss_files_file file, const char *path, + int *errnop, int *herrnop) +{ + enum nss_status status = __nss_files_data_get (pdata, file, errnop, herrnop); + if (status != NSS_STATUS_SUCCESS) + return status; + + /* Be prepared that the set*ent function was not called before. */ + if ((*pdata)->stream == NULL) + { + int saved_errno = errno; + status = __nss_files_data_internal_open (*pdata, path); + __set_errno (saved_errno); + if (status != NSS_STATUS_SUCCESS) + __nss_files_data_put (*pdata); + } + + return status; +} + +libc_hidden_def (__nss_files_data_open) + +void +__nss_files_data_put (struct nss_files_per_file_data *data) +{ + __libc_lock_unlock (data->lock); +} +libc_hidden_def (__nss_files_data_put) + +enum nss_status +__nss_files_data_setent (enum nss_files_file file, const char *path) +{ + struct nss_files_per_file_data *data; + enum nss_status status = __nss_files_data_get (&data, file, NULL, NULL); + if (status != NSS_STATUS_SUCCESS) + return status; + + if (data->stream == NULL) + status = __nss_files_data_internal_open (data, path); + else + rewind (data->stream); + + __nss_files_data_put (data); + return status; +} +libc_hidden_def (__nss_files_data_setent) + +enum nss_status +__nss_files_data_endent (enum nss_files_file file) +{ + /* No cleanup is necessary if not initialized. */ + struct nss_files_data *data = atomic_load_acquire (&nss_files_global); + if (data == NULL) + return NSS_STATUS_SUCCESS; + + struct nss_files_per_file_data *fdata = &data->files[file]; + __libc_lock_lock (fdata->lock); + if (fdata->stream != NULL) + { + fclose (fdata->stream); + fdata->stream = NULL; + } + __libc_lock_unlock (fdata->lock); + + return NSS_STATUS_SUCCESS; +} +libc_hidden_def (__nss_files_data_endent) |