From 2c210d1eb88d4ab44bfce576b8fbac8e89a946f4 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Tue, 23 Aug 2005 23:21:53 +0000 Subject: * nscd/connection.c (DEFAULT_DATASIZE_PER_BUCKET): Move to nscd.h. (dbs): Initialize max_db_size fields. (nscd_init): When mapping the database, use max_db_size as the mapping size even if it is bigger than the file size. * nscd/mem.c (mempool_alloc): When resizing the file make sure the limit in max_db_size is not exceeded. Don't use mremap, just posix_fallocate is enough (according to Linus). Use posix_fallocate correctly. * nscd/nscd.conf: Add max-db-size parameters. * nscd/nscd.h (struct database_dyn): Add max_db_size field. Define DEFAULT_MAX_DB_SIZE and DEFAULT_DATASIZE_PER_BUCKET. Temporarily define TEMP_FAILURE_RETRY_VAL here. * nscd/nscd_conf.c (nscd_parse_file): Parse max-db-size parameter and add sanity checks for it. * nscd/aicache.c (addhstaiX): Use send with MSG_NOSIGNAL not write to send reply. * nscd/connection.c (writeall): Likewise. (handle_request): Likewise. * nscd/grpcache.c (cache_addgr): Likewise. * nscd/hstcache.c (cache_addhst): Likewise. * nscd/initgrcache.c (addinitgroupsX): Likewise. * nscd/nscd.c (parse_opt): Likewise. * nscd/nscd_stat.c (send_stats): Likewise. (receive_print_stats): Likewise. * nscd/pwdcache.c (cache_addpw): Likewise. --- nscd/aicache.c | 2 +- nscd/connections.c | 32 +++++++++++++++++++++----------- nscd/grpcache.c | 3 ++- nscd/hstcache.c | 3 ++- nscd/initgrcache.c | 3 ++- nscd/mem.c | 18 +++++++++++++----- nscd/nscd.c | 5 +++-- nscd/nscd.conf | 4 ++++ nscd/nscd.h | 17 +++++++++++++++++ nscd/nscd_conf.c | 29 ++++++++++++++++++++++++++++- nscd/nscd_stat.c | 6 ++++-- nscd/pwdcache.c | 3 ++- 12 files changed, 99 insertions(+), 26 deletions(-) (limited to 'nscd') diff --git a/nscd/aicache.c b/nscd/aicache.c index fb75dc1..992c6ef 100644 --- a/nscd/aicache.c +++ b/nscd/aicache.c @@ -399,7 +399,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, total = sizeof (notfound); if (fd != -1) - TEMP_FAILURE_RETRY (write (fd, ¬found, total)); + TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL)); dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len); /* If we cannot permanently store the result, so be it. */ diff --git a/nscd/connections.c b/nscd/connections.c index 0a0654d..ce1348b 100644 --- a/nscd/connections.c +++ b/nscd/connections.c @@ -48,10 +48,6 @@ #include "selinux.h" -/* Number of bytes of data we initially reserve for each hash table bucket. */ -#define DEFAULT_DATASIZE_PER_BUCKET 1024 - - /* Wrapper functions with error checking for standard functions. */ extern void *xmalloc (size_t n); extern void *xcalloc (size_t n, size_t s); @@ -104,6 +100,7 @@ struct database_dyn dbs[lastdb] = .check_file = 1, .persistent = 0, .shared = 0, + .max_db_size = DEFAULT_MAX_DB_SIZE, .filename = "/etc/passwd", .db_filename = _PATH_NSCD_PASSWD_DB, .disabled_iov = &pwd_iov_disabled, @@ -119,6 +116,7 @@ struct database_dyn dbs[lastdb] = .check_file = 1, .persistent = 0, .shared = 0, + .max_db_size = DEFAULT_MAX_DB_SIZE, .filename = "/etc/group", .db_filename = _PATH_NSCD_GROUP_DB, .disabled_iov = &grp_iov_disabled, @@ -134,6 +132,7 @@ struct database_dyn dbs[lastdb] = .check_file = 1, .persistent = 0, .shared = 0, + .max_db_size = DEFAULT_MAX_DB_SIZE, .filename = "/etc/hosts", .db_filename = _PATH_NSCD_HOSTS_DB, .disabled_iov = &hst_iov_disabled, @@ -188,7 +187,7 @@ writeall (int fd, const void *buf, size_t len) ssize_t ret; do { - ret = TEMP_FAILURE_RETRY (write (fd, buf, n)); + ret = TEMP_FAILURE_RETRY (send (fd, buf, n, MSG_NOSIGNAL)); if (ret <= 0) break; buf = (const char *) buf + ret; @@ -473,8 +472,16 @@ nscd_init (void) _("file size does not match")); unlink (dbs[cnt].db_filename); } - else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0)) == MAP_FAILED) + /* Note we map with the maximum size allowed for the + database. This is likely much larger than the + actual file size. This is OK on most OSes since + extensions of the underlying file will + automatically translate more pages available for + memory access. */ + else if ((mem = mmap (NULL, dbs[cnt].max_db_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0)) + == MAP_FAILED) goto fail_db; else if (!verify_persistent_db (mem, &head, cnt)) { @@ -638,8 +645,10 @@ cannot create read-only descriptor for \"%s\"; no mmap"), if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head))) != sizeof (head)) - || posix_fallocate (fd, 0, total) != 0 - || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE, + || (TEMP_FAILURE_RETRY_VAL (posix_fallocate (fd, 0, total)) + != 0) + || (mem = mmap (NULL, dbs[cnt].max_db_size, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { write_fail: @@ -901,8 +910,9 @@ cannot handle old request version %d; current version is %d"), if (!db->enabled) { /* No, sent the prepared record. */ - if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base, - db->disabled_iov->iov_len)) + if (TEMP_FAILURE_RETRY (send (fd, db->disabled_iov->iov_base, + db->disabled_iov->iov_len, + MSG_NOSIGNAL)) != (ssize_t) db->disabled_iov->iov_len && __builtin_expect (debug_level, 0) > 0) { diff --git a/nscd/grpcache.c b/nscd/grpcache.c index c938554..6543ef3 100644 --- a/nscd/grpcache.c +++ b/nscd/grpcache.c @@ -107,7 +107,8 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req, case. */ total = sizeof (notfound); - written = TEMP_FAILURE_RETRY (write (fd, ¬found, total)); + written = TEMP_FAILURE_RETRY (send (fd, ¬found, total, + MSG_NOSIGNAL)); dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len); /* If we cannot permanently store the result, so be it. */ diff --git a/nscd/hstcache.c b/nscd/hstcache.c index 377f023..29bce99 100644 --- a/nscd/hstcache.c +++ b/nscd/hstcache.c @@ -115,7 +115,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, written = total = sizeof (notfound); if (fd != -1) - written = TEMP_FAILURE_RETRY (write (fd, ¬found, total)); + written = TEMP_FAILURE_RETRY (send (fd, ¬found, total, + MSG_NOSIGNAL)); dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len); /* If we cannot permanently store the result, so be it. */ diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c index db01f1b..bb6dee2 100644 --- a/nscd/initgrcache.c +++ b/nscd/initgrcache.c @@ -188,7 +188,8 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, /* We have no data. This means we send the standard reply for this case. */ if (fd != -1) - written = TEMP_FAILURE_RETRY (write (fd, ¬found, total)); + written = TEMP_FAILURE_RETRY (send (fd, ¬found, total, + MSG_NOSIGNAL)); dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len); /* If we cannot permanently store the result, so be it. */ diff --git a/nscd/mem.c b/nscd/mem.c index 823eda1..96f0170 100644 --- a/nscd/mem.c +++ b/nscd/mem.c @@ -481,18 +481,26 @@ mempool_alloc (struct database_dyn *db, size_t len) if (! tried_resize) { /* Try to resize the database. Grow size of 1/8th. */ - size_t new_data_size = db->head->data_size + db->head->data_size / 8; size_t oldtotal = (sizeof (struct database_pers_head) + db->head->module * sizeof (ref_t) + db->head->data_size); + size_t new_data_size = (db->head->data_size + + MAX (2 * len, db->head->data_size / 8)); size_t newtotal = (sizeof (struct database_pers_head) + db->head->module * sizeof (ref_t) + new_data_size); + if (newtotal > db->max_db_size) + { + new_data_size -= newtotal - db->max_db_size; + newtotal = db->max_db_size; + } - if ((!db->mmap_used - || posix_fallocate (db->wr_fd, oldtotal, newtotal) != 0) - /* Try to resize the mapping. Note: no MREMAP_MAYMOVE. */ - && mremap (db->head, oldtotal, newtotal, 0) == 0) + if (db->mmap_used && newtotal > oldtotal + /* We only have to adjust the file size. The new pages + become magically available. */ + && TEMP_FAILURE_RETRY_VAL (posix_fallocate (db->wr_fd, oldtotal, + newtotal + - oldtotal)) == 0) { db->head->data_size = new_data_size; tried_resize = true; diff --git a/nscd/nscd.c b/nscd/nscd.c index a7aa964..c16152c 100644 --- a/nscd/nscd.c +++ b/nscd/nscd.c @@ -315,8 +315,9 @@ parse_opt (int key, char *arg, struct argp_state *state) req.version = NSCD_VERSION; req.type = SHUTDOWN; req.key_len = 0; - nbytes = TEMP_FAILURE_RETRY (write (sock, &req, - sizeof (request_header))); + nbytes = TEMP_FAILURE_RETRY (send (sock, &req, + sizeof (request_header), + MSG_NOSIGNAL)); close (sock); exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS); } diff --git a/nscd/nscd.conf b/nscd/nscd.conf index 87e7a84..9491e16 100644 --- a/nscd/nscd.conf +++ b/nscd/nscd.conf @@ -23,6 +23,7 @@ # check-files # persistent # shared +# max-db-szie # # Currently supported cache names (services): passwd, group, hosts # @@ -45,6 +46,7 @@ check-files passwd yes persistent passwd yes shared passwd yes + max-db-size passwd 33554432 enable-cache group yes positive-time-to-live group 3600 @@ -53,6 +55,7 @@ check-files group yes persistent group yes shared group yes + max-db-size group 33554432 enable-cache hosts yes positive-time-to-live hosts 3600 @@ -61,3 +64,4 @@ check-files hosts yes persistent hosts yes shared hosts yes + max-db-size hosts 33554432 diff --git a/nscd/nscd.h b/nscd/nscd.h index 25a4b38..3859d95 100644 --- a/nscd/nscd.h +++ b/nscd/nscd.h @@ -63,6 +63,7 @@ struct database_dyn int check_file; int persistent; int shared; + size_t max_db_size; const char *filename; const char *db_filename; time_t file_mtime; @@ -99,6 +100,12 @@ struct database_dyn #define BLOCK_ALIGN (1 << BLOCK_ALIGN_LOG) #define BLOCK_ALIGN_M1 (BLOCK_ALIGN - 1) +/* Default value for the maximum size of the database files. */ +#define DEFAULT_MAX_DB_SIZE (32 * 1024 * 1024) + +/* Number of bytes of data we initially reserve for each hash table bucket. */ +#define DEFAULT_DATASIZE_PER_BUCKET 1024 + /* Global variables. */ extern struct database_dyn dbs[lastdb]; @@ -241,4 +248,14 @@ extern void gc (struct database_dyn *db); /* nscd_setup_thread.c */ extern void setup_thread (struct database_dyn *db); + +/* Special version of TEMP_FAILURE_RETRY for functions returning error + values. */ +#define TEMP_FAILURE_RETRY_VAL(expression) \ + (__extension__ \ + ({ long int __result; \ + do __result = (long int) (expression); \ + while (__result == EINTR); \ + __result; })) + #endif /* nscd.h */ diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c index d21f2fc..c5c06ae 100644 --- a/nscd/nscd_conf.c +++ b/nscd/nscd_conf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1998, 2000, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1998, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk , 1998. @@ -171,6 +171,17 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb]) if (cnt == lastdb) dbg_log ("database %s is not supported\n", arg1); } + else if (strcmp (entry, "max-db-size") == 0) + { + for (cnt = 0; cnt < lastdb; ++cnt) + if (strcmp (arg1, dbnames[cnt]) == 0) + { + dbs[cnt].max_db_size = atol (arg2); + break; + } + if (cnt == lastdb) + dbg_log ("database %s is not supported\n", arg1); + } else if (strcmp (entry, "logfile") == 0) set_logfile (arg1); else if (strcmp (entry, "debug-level") == 0) @@ -290,6 +301,22 @@ cannot get current working directory: %s; disabling paranoia mode"), if (max_nthreads < nthreads) max_nthreads = nthreads; + for (cnt = 0; cnt < lastdb; ++cnt) + { + size_t datasize = (sizeof (struct database_pers_head) + + roundup (dbs[cnt].suggested_module + * sizeof (ref_t), ALIGN) + + (dbs[cnt].suggested_module + * DEFAULT_DATASIZE_PER_BUCKET)); + if (datasize > dbs[cnt].max_db_size) + { + dbg_log (_("maximum file size for %s database too small"), + dbnames[cnt]); + dbs[cnt].max_db_size = datasize; + } + + } + /* Free the buffer. */ free (line); /* Close configuration file. */ diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c index 43f6266..c1d0bff 100644 --- a/nscd/nscd_stat.c +++ b/nscd/nscd_stat.c @@ -133,7 +133,8 @@ send_stats (int fd, struct database_dyn dbs[lastdb]) if (selinux_enabled) nscd_avc_cache_stats (&data.cstats); - if (TEMP_FAILURE_RETRY (write (fd, &data, sizeof (data))) != sizeof (data)) + if (TEMP_FAILURE_RETRY (send (fd, &data, sizeof (data), MSG_NOSIGNAL)) + != sizeof (data)) { char buf[256]; dbg_log (_("cannot write statistics: %s"), @@ -180,7 +181,8 @@ receive_print_stats (void) req.version = NSCD_VERSION; req.type = GETSTAT; req.key_len = 0; - nbytes = TEMP_FAILURE_RETRY (write (fd, &req, sizeof (request_header))); + nbytes = TEMP_FAILURE_RETRY (send (fd, &req, sizeof (request_header), + MSG_NOSIGNAL)); if (nbytes != sizeof (request_header)) { int err = errno; diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c index 34265c3..6b25968 100644 --- a/nscd/pwdcache.c +++ b/nscd/pwdcache.c @@ -114,7 +114,8 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req, written = total = sizeof (notfound); if (fd != -1) - written = TEMP_FAILURE_RETRY (write (fd, ¬found, total)); + written = TEMP_FAILURE_RETRY (send (fd, ¬found, total, + MSG_NOSIGNAL)); dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len); /* If we cannot permanently store the result, so be it. */ -- cgit v1.1