]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/glibc/glibc-rh859965.patch
dhcpcd: fix delay after dhcp down.
[ipfire-2.x.git] / src / patches / glibc / glibc-rh859965.patch
1 #
2 # Based on the following patch:
3 #
4 # Upstream bug: https://sourceware.org/bugzilla/show_bug.cgi?id=14906
5 # URL: https://sourceware.org/ml/libc-alpha/2015-02/msg00504.html
6 #
7 # 2015-02-17 Carlos O'Donell <carlos@redhat.com>
8 #
9 # [BZ #14906]
10 # * nscd/cache.c (prune_cache): Use TRACED_FILE. Compare and update
11 # traced file mtime. Use consistent log message.
12 # * nscd/connections.c [HAVE_INOTIFY] (install_watches): New function.
13 # (register_traced_file): Call install_watches. Always set mtime.
14 # (invalidate_cache): Iterate over all trace files. Call install_watches.
15 # (inotify_check_files): Don't inline. Handle watching parent
16 # directories and configuration file movement in and out.
17 # (handle_inotify_events): New function.
18 # (main_loop_poll): Call handle_inotify_events.
19 # (main_loop_epoll): Likewise.
20 # * nscd/nscd.h: Define TRACED_FILE, TRACED_DIR, and PATH_MAX.
21 # (struct traced_file): Use array of inotify fds. Add parent directory,
22 # and basename.
23 # (struct database_dyn): Remove unused file_mtime.
24 # (init_traced_file): New inline function.
25 # (define_traced_file): New macro.
26 # * nss/nss_db/db-init.c: Use define_traced_file.
27 # (_nss_db_init): Use init_traced_file.
28 # * nss/nss_files/files-init.c: Use define_traced_file.
29 # (_nss_files_init): Use init_traced_file.
30 #
31 diff -urN glibc-2.12-2-gc4ccff1.orig/misc/sys/cdefs.h glibc-2.12-2-gc4ccff1.mod1/misc/sys/cdefs.h
32 --- glibc-2.12-2-gc4ccff1.orig/misc/sys/cdefs.h 2015-02-18 04:42:12.115187116 -0500
33 +++ glibc-2.12-2-gc4ccff1.mod1/misc/sys/cdefs.h 2015-02-18 04:02:03.635159090 -0500
34 @@ -362,6 +362,14 @@
35 # endif
36 #endif
37
38 +#if __GNUC__ >= 3
39 +# define __glibc_unlikely(cond) __builtin_expect ((cond), 0)
40 +# define __glibc_likely(cond) __builtin_expect ((cond), 1)
41 +#else
42 +# define __glibc_unlikely(cond) (cond)
43 +# define __glibc_likely(cond) (cond)
44 +#endif
45 +
46 #include <bits/wordsize.h>
47
48 #if defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH
49 diff -urN glibc-2.12-2-gc4ccff1.orig/nscd/cache.c glibc-2.12-2-gc4ccff1.mod1/nscd/cache.c
50 --- glibc-2.12-2-gc4ccff1.orig/nscd/cache.c 2015-02-18 04:42:12.329180362 -0500
51 +++ glibc-2.12-2-gc4ccff1.mod1/nscd/cache.c 2015-02-18 04:02:03.635159090 -0500
52 @@ -266,29 +266,52 @@
53
54 /* If we check for the modification of the underlying file we invalidate
55 the entries also in this case. */
56 - if (table->inotify_descr < 0 && table->check_file && now != LONG_MAX)
57 + if (table->check_file && now != LONG_MAX)
58 {
59 - struct stat64 st;
60 + struct traced_file *runp = table->traced_files;
61
62 - if (stat64 (table->filename, &st) < 0)
63 + while (runp != NULL)
64 {
65 - char buf[128];
66 - /* We cannot stat() the file, disable file checking if the
67 - file does not exist. */
68 - dbg_log (_("cannot stat() file `%s': %s"),
69 - table->filename, strerror_r (errno, buf, sizeof (buf)));
70 - if (errno == ENOENT)
71 - table->check_file = 0;
72 - }
73 - else
74 - {
75 - if (st.st_mtime != table->file_mtime)
76 +#ifdef HAVE_INOTIFY
77 + if (runp->inotify_descr[TRACED_FILE] == -1)
78 +#endif
79 {
80 - /* The file changed. Invalidate all entries. */
81 - now = LONG_MAX;
82 - table->file_mtime = st.st_mtime;
83 + struct stat64 st;
84 +
85 + if (stat64 (runp->fname, &st) < 0)
86 + {
87 + /* Print a diagnostic that the traced file was missing.
88 + We must not disable tracing since the file might return
89 + shortly and we want to reload it at the next pruning.
90 + Disabling tracing here would go against the configuration
91 + as specified by the user via check-files. */
92 + char buf[128];
93 + dbg_log (_("checking for monitored file `%s': %s"),
94 + runp->fname, strerror_r (errno, buf, sizeof (buf)));
95 + }
96 + else
97 + {
98 + /* This must be `!=` to catch cases where users turn the
99 + clocks back and we still want to detect any time difference
100 + in mtime. */
101 + if (st.st_mtime != runp->mtime)
102 + {
103 + dbg_log (_("monitored file `%s` changed (mtime)"),
104 + runp->fname);
105 + /* The file changed. Invalidate all entries. */
106 + now = LONG_MAX;
107 + runp->mtime = st.st_mtime;
108 +#ifdef HAVE_INOTIFY
109 + /* Attempt to install a watch on the file. */
110 + install_watches (runp);
111 +#endif
112 + }
113 + }
114 }
115 +
116 + runp = runp->next;
117 }
118 +
119 }
120
121 /* We run through the table and find values which are not valid anymore.
122 diff -urN glibc-2.12-2-gc4ccff1.orig/nscd/connections.c glibc-2.12-2-gc4ccff1.mod1/nscd/connections.c
123 --- glibc-2.12-2-gc4ccff1.orig/nscd/connections.c 2015-02-18 04:42:12.333180236 -0500
124 +++ glibc-2.12-2-gc4ccff1.mod1/nscd/connections.c 2015-02-18 04:40:51.674726008 -0500
125 @@ -74,6 +74,25 @@
126 static void begin_drop_privileges (void);
127 static void finish_drop_privileges (void);
128
129 +/* Define the traced files. */
130 +#define PWD_FILENAME "/etc/passwd"
131 +define_traced_file (pwd, PWD_FILENAME);
132 +
133 +#define GRP_FILENAME "/etc/group"
134 +define_traced_file (grp, GRP_FILENAME);
135 +
136 +#define HST_FILENAME "/etc/hosts"
137 +define_traced_file (hst, HST_FILENAME);
138 +
139 +#define RESOLV_FILENAME "/etc/resolv.conf"
140 +define_traced_file (resolv, RESOLV_FILENAME);
141 +
142 +#define SERV_FILENAME "/etc/services"
143 +define_traced_file (serv, SERV_FILENAME);
144 +
145 +#define NETGR_FILENAME "/etc/netgroup"
146 +define_traced_file (netgr, NETGR_FILENAME);
147 +
148 /* Map request type to a string. */
149 const char *const serv2str[LASTREQ] =
150 {
151 @@ -115,8 +134,6 @@
152 .shared = 0,
153 .max_db_size = DEFAULT_MAX_DB_SIZE,
154 .suggested_module = DEFAULT_SUGGESTED_MODULE,
155 - .reset_res = 0,
156 - .filename = "/etc/passwd",
157 .db_filename = _PATH_NSCD_PASSWD_DB,
158 .disabled_iov = &pwd_iov_disabled,
159 .postimeout = 3600,
160 @@ -136,8 +153,6 @@
161 .shared = 0,
162 .max_db_size = DEFAULT_MAX_DB_SIZE,
163 .suggested_module = DEFAULT_SUGGESTED_MODULE,
164 - .reset_res = 0,
165 - .filename = "/etc/group",
166 .db_filename = _PATH_NSCD_GROUP_DB,
167 .disabled_iov = &grp_iov_disabled,
168 .postimeout = 3600,
169 @@ -157,8 +172,6 @@
170 .shared = 0,
171 .max_db_size = DEFAULT_MAX_DB_SIZE,
172 .suggested_module = DEFAULT_SUGGESTED_MODULE,
173 - .reset_res = 1,
174 - .filename = "/etc/hosts",
175 .db_filename = _PATH_NSCD_HOSTS_DB,
176 .disabled_iov = &hst_iov_disabled,
177 .postimeout = 3600,
178 @@ -178,8 +191,6 @@
179 .shared = 0,
180 .max_db_size = DEFAULT_MAX_DB_SIZE,
181 .suggested_module = DEFAULT_SUGGESTED_MODULE,
182 - .reset_res = 0,
183 - .filename = "/etc/services",
184 .db_filename = _PATH_NSCD_SERVICES_DB,
185 .disabled_iov = &serv_iov_disabled,
186 .postimeout = 28800,
187 @@ -199,8 +210,6 @@
188 .shared = 0,
189 .max_db_size = DEFAULT_MAX_DB_SIZE,
190 .suggested_module = DEFAULT_SUGGESTED_MODULE,
191 - .reset_res = 0,
192 - .filename = "/etc/netgroup",
193 .db_filename = _PATH_NSCD_NETGROUP_DB,
194 .disabled_iov = &netgroup_iov_disabled,
195 .postimeout = 28800,
196 @@ -863,41 +872,26 @@
197 dbs[cnt].shared = 0;
198 assert (dbs[cnt].ro_fd == -1);
199 }
200 + }
201
202 - dbs[cnt].inotify_descr = -1;
203 - if (dbs[cnt].check_file)
204 - {
205 -#ifdef HAVE_INOTIFY
206 - if (inotify_fd < 0
207 - || (dbs[cnt].inotify_descr
208 - = inotify_add_watch (inotify_fd, dbs[cnt].filename,
209 - IN_DELETE_SELF | IN_MODIFY)) < 0)
210 - /* We cannot notice changes in the main thread. */
211 -#endif
212 - {
213 - /* We need the modification date of the file. */
214 - struct stat64 st;
215 + /* Initialize and register the traced files. */
216 + init_traced_file (&pwd_traced_file.file, PWD_FILENAME, 0);
217 + register_traced_file (pwddb, &pwd_traced_file.file);
218
219 - if (stat64 (dbs[cnt].filename, &st) < 0)
220 - {
221 - /* We cannot stat() the file, disable file checking. */
222 - dbg_log (_("cannot stat() file `%s': %s"),
223 - dbs[cnt].filename, strerror (errno));
224 - dbs[cnt].check_file = 0;
225 - }
226 - else
227 - dbs[cnt].file_mtime = st.st_mtime;
228 - }
229 - }
230 + init_traced_file (&grp_traced_file.file, GRP_FILENAME, 0);
231 + register_traced_file (grpdb, &grp_traced_file.file);
232
233 -#ifdef HAVE_INOTIFY
234 - if (cnt == hstdb && inotify_fd >= -1)
235 - /* We also monitor the resolver configuration file. */
236 - resolv_conf_descr = inotify_add_watch (inotify_fd,
237 - _PATH_RESCONF,
238 - IN_DELETE_SELF | IN_MODIFY);
239 -#endif
240 - }
241 + init_traced_file (&hst_traced_file.file, HST_FILENAME, 0);
242 + register_traced_file (hstdb, &hst_traced_file.file);
243 +
244 + init_traced_file (&resolv_traced_file.file, RESOLV_FILENAME, 1);
245 + register_traced_file (hstdb, &resolv_traced_file.file);
246 +
247 + init_traced_file (&serv_traced_file.file, SERV_FILENAME, 0);
248 + register_traced_file (servdb, &serv_traced_file.file);
249 +
250 + init_traced_file (&netgr_traced_file.file, NETGR_FILENAME, 0);
251 + register_traced_file (netgrdb, &netgr_traced_file.file);
252
253 /* Create the socket. */
254 #ifndef __ASSUME_SOCK_CLOEXEC
255 @@ -968,6 +962,92 @@
256 finish_drop_privileges ();
257 }
258
259 +#ifdef HAVE_INOTIFY
260 +#define TRACED_FILE_MASK (IN_DELETE_SELF | IN_CLOSE_WRITE | IN_MOVE_SELF)
261 +#define TRACED_DIR_MASK (IN_DELETE_SELF | IN_CREATE | IN_MOVED_TO | IN_MOVE_SELF)
262 +void
263 +install_watches (struct traced_file *finfo)
264 +{
265 + /* If we have inotify support use it exclusively with no fallback
266 + to stat. This is a design decision to make the implementation
267 + sipmler. Either we use fstat for the file name or we use inotify
268 + for both the file and parent directory. */
269 + if (finfo->inotify_descr[TRACED_FILE] < 0)
270 + finfo->inotify_descr[TRACED_FILE] = inotify_add_watch (inotify_fd,
271 + finfo->fname,
272 + TRACED_FILE_MASK);
273 + if (finfo->inotify_descr[TRACED_FILE] < 0)
274 + {
275 + dbg_log (_("disabled inotify-based monitoring for file `%s': %s"),
276 + finfo->fname, strerror (errno));
277 + return;
278 + }
279 + dbg_log (_("monitoring file `%s` (%d)"),
280 + finfo->fname, finfo->inotify_descr[TRACED_FILE]);
281 + /* Additionally listen for IN_CREATE events in the files parent
282 + directory. We do this because the file to be watched might be
283 + deleted and then added back again. When it is added back again
284 + we must re-add the watch. We must also cover IN_MOVED_TO to
285 + detect a file being moved into the directory. */
286 + if (finfo->inotify_descr[TRACED_DIR] < 0)
287 + finfo->inotify_descr[TRACED_DIR] = inotify_add_watch (inotify_fd,
288 + finfo->dname,
289 + TRACED_DIR_MASK);
290 + if (finfo->inotify_descr[TRACED_DIR] < 0)
291 + {
292 + dbg_log (_("disabled inotify-based monitoring for directory `%s': %s"),
293 + finfo->fname, strerror (errno));
294 + return;
295 + }
296 + dbg_log (_("monitoring directory `%s` (%d)"),
297 + finfo->dname, finfo->inotify_descr[TRACED_DIR]);
298 +}
299 +#endif
300 +
301 +/* Register the file in FINFO as a traced file for the database DBS[DBIX].
302 +
303 + We support registering multiple files per database. Each call to
304 + register_traced_file adds to the list of registered files.
305 +
306 + When we prune the database, either through timeout or a request to
307 + invalidate, we will check to see if any of the registered files has changed.
308 + When we accept new connections to handle a cache request we will also
309 + check to see if any of the registered files has changed.
310 +
311 + If we have inotify support then we install an inotify fd to notify us of
312 + file deletion or modification, both of which will require we invalidate
313 + the cache for the database. Without inotify support we stat the file and
314 + store st_mtime to determine if the file has been modified. */
315 +void
316 +register_traced_file (size_t dbidx, struct traced_file *finfo)
317 +{
318 + /* If the database is disabled or file checking is disabled
319 + then ignore the registration. */
320 + if (! dbs[dbidx].enabled || ! dbs[dbidx].check_file)
321 + return;
322 +
323 + if (__glibc_unlikely (debug_level > 0))
324 + dbg_log (_("monitoring file %s for database %s"),
325 + finfo->fname, dbnames[dbidx]);
326 +
327 +#ifdef HAVE_INOTIFY
328 + install_watches (finfo);
329 +#endif
330 + struct stat64 st;
331 + if (stat64 (finfo->fname, &st) < 0)
332 + {
333 + /* We cannot stat() the file, disable file checking. */
334 + dbg_log (_("disabled monitoring for file `%s': %s"),
335 + finfo->fname, strerror (errno));
336 + finfo->mtime = 0;
337 + }
338 + else
339 + finfo->mtime = st.st_mtime;
340 +
341 + /* Queue up the file name. */
342 + finfo->next = dbs[dbidx].traced_files;
343 + dbs[dbidx].traced_files = finfo;
344 +}
345
346 /* Close the connections. */
347 void
348 @@ -986,9 +1066,25 @@
349 for (number = pwddb; number < lastdb; ++number)
350 if (strcmp (key, dbnames[number]) == 0)
351 {
352 - if (dbs[number].reset_res)
353 - res_init ();
354 -
355 + struct traced_file *runp = dbs[number].traced_files;
356 + while (runp != NULL)
357 + {
358 + /* Make sure we reload from file when checking mtime. */
359 + runp->mtime = 0;
360 +#ifdef HAVE_INOTIFY
361 + /* During an invalidation we try to reload the traced
362 + file watches. This allows the user to re-sync if
363 + inotify events were lost. Similar to what we do during
364 + pruning. */
365 + install_watches (runp);
366 +#endif
367 + if (runp->call_res_init)
368 + {
369 + res_init ();
370 + break;
371 + }
372 + runp = runp->next;
373 + }
374 break;
375 }
376
377 @@ -1817,6 +1913,231 @@
378 /* Array for times a connection was accepted. */
379 static time_t *starttime;
380
381 +#ifdef HAVE_INOTIFY
382 +/* Inotify event for changed file. */
383 +union __inev
384 +{
385 + struct inotify_event i;
386 +# ifndef PATH_MAX
387 +# define PATH_MAX 1024
388 +# endif
389 + char buf[sizeof (struct inotify_event) + PATH_MAX];
390 +};
391 +
392 +/* Returns 0 if the file is there and matches the last mtime
393 + on record, otherwise -1. */
394 +int
395 +check_file (struct traced_file *finfo)
396 +{
397 + struct stat64 st;
398 + if (stat64 (finfo->fname, &st) < 0)
399 + return -1;
400 + return 0;
401 +}
402 +
403 +/* Process the inotify event in INEV. If the event matches any of the files
404 + registered with a database then mark that database as requiring its cache
405 + to be cleared. We indicate the cache needs clearing by setting
406 + TO_CLEAR[DBCNT] to true for the matching database. */
407 +static void
408 +inotify_check_files (bool *to_clear, union __inev *inev)
409 +{
410 + /* Check which of the files changed. */
411 + for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
412 + {
413 + struct traced_file *finfo = dbs[dbcnt].traced_files;
414 +
415 + while (finfo != NULL)
416 + {
417 + /* The configuration file was moved or deleted.
418 + We stop watching it at that point, and reinitialize. */
419 + if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
420 + && ((inev->i.mask & IN_MOVE_SELF)
421 + || (inev->i.mask & IN_DELETE_SELF)
422 + || (inev->i.mask & IN_IGNORED)))
423 + {
424 + int ret;
425 + bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
426 +
427 + if (check_file (finfo) == 0)
428 + {
429 + dbg_log (_("ignored out of order inotify event for `%s`"),
430 + finfo->fname);
431 + return;
432 + }
433 +
434 + dbg_log (_("monitored file `%s` was %s, removing watch"),
435 + finfo->fname, moved ? "moved" : "deleted");
436 + /* File was moved out, remove the watch. Watches are
437 + automatically removed when the file is deleted. */
438 + if (moved)
439 + {
440 + ret = inotify_rm_watch (inotify_fd, inev->i.wd);
441 + if (ret < 0)
442 + dbg_log (_("failed to remove file watch `%s`: %s"),
443 + finfo->fname, strerror (errno));
444 + }
445 + finfo->inotify_descr[TRACED_FILE] = -1;
446 + to_clear[dbcnt] = true;
447 + if (finfo->call_res_init)
448 + res_init ();
449 + return;
450 + }
451 + /* The configuration file was open for writing and has just closed.
452 + We reset the cache and reinitialize. */
453 + if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
454 + && inev->i.mask & IN_CLOSE_WRITE)
455 + {
456 + /* Mark cache as needing to be cleared and reinitialize. */
457 + dbg_log (_("monitored file `%s` was written to"), finfo->fname);
458 + to_clear[dbcnt] = true;
459 + if (finfo->call_res_init)
460 + res_init ();
461 + return;
462 + }
463 + /* The parent directory was moved or deleted. There is no coming
464 + back from this. We do not track the parent of the parent, and
465 + once this happens we trigger one last invalidation. You must
466 + restart nscd to track subsequent changes. We track this to
467 + do one last robust re-initialization and then we're done. */
468 + if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
469 + && ((inev->i.mask & IN_DELETE_SELF)
470 + || (inev->i.mask & IN_MOVE_SELF)
471 + || (inev->i.mask & IN_IGNORED)))
472 + {
473 + bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
474 + /* The directory watch may have already been removed
475 + but we don't know so we just remove it again and
476 + ignore the error. Then we remove the file watch.
477 + Note: watches are automatically removed for deleted
478 + files. */
479 + if (moved)
480 + inotify_rm_watch (inotify_fd, inev->i.wd);
481 + if (finfo->inotify_descr[TRACED_FILE] != -1)
482 + {
483 + dbg_log (_("monitored parent directory `%s` was %s, removing watch on `%s`"),
484 + finfo->dname, moved ? "moved" : "deleted", finfo->fname);
485 + if (inotify_rm_watch (inotify_fd, finfo->inotify_descr[TRACED_FILE]) < 0)
486 + dbg_log (_("failed to remove file watch `%s`: %s"),
487 + finfo->dname, strerror (errno));
488 + }
489 + finfo->inotify_descr[TRACED_FILE] = -1;
490 + finfo->inotify_descr[TRACED_DIR] = -1;
491 + to_clear[dbcnt] = true;
492 + if (finfo->call_res_init)
493 + res_init ();
494 + /* Continue to the next entry since this might be the
495 + parent directory for multiple registered files and
496 + we want to remove watches for all registered files. */
497 + continue;
498 + }
499 + /* The parent directory had a create or moved to event. */
500 + if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
501 + && ((inev->i.mask & IN_MOVED_TO)
502 + || (inev->i.mask & IN_CREATE))
503 + && strcmp (inev->i.name, finfo->sfname) == 0)
504 + {
505 + /* We detected a directory change. We look for the creation
506 + of the file we are tracking or the move of the same file
507 + into the directory. */
508 + int ret;
509 + dbg_log (_("monitored file `%s` was %s, adding watch"),
510 + finfo->fname,
511 + inev->i.mask & IN_CREATE ? "created" : "moved into place");
512 + /* File was moved in or created. Regenerate the watch. */
513 + if (finfo->inotify_descr[TRACED_FILE] != -1)
514 + inotify_rm_watch (inotify_fd,
515 + finfo->inotify_descr[TRACED_FILE]);
516 +
517 + ret = inotify_add_watch (inotify_fd,
518 + finfo->fname,
519 + TRACED_FILE_MASK);
520 + if (ret < 0)
521 + dbg_log (_("failed to add file watch `%s`: %s"),
522 + finfo->fname, strerror (errno));
523 +
524 + finfo->inotify_descr[TRACED_FILE] = ret;
525 +
526 + /* The file is new or moved so mark cache as needing to
527 + be cleared and reinitialize. */
528 + to_clear[dbcnt] = true;
529 + if (finfo->call_res_init)
530 + res_init ();
531 +
532 + /* Done re-adding the watch. Don't return, we may still
533 + have other files in this same directory, same watch
534 + descriptor, and need to process them. */
535 + }
536 + /* Other events are ignored, and we move on to the next file. */
537 + finfo = finfo->next;
538 + }
539 + }
540 +}
541 +
542 +/* If an entry in the array of booleans TO_CLEAR is TRUE then clear the cache
543 + for the associated database, otherwise do nothing. The TO_CLEAR array must
544 + have LASTDB entries. */
545 +static inline void
546 +clear_db_cache (bool *to_clear)
547 +{
548 + for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
549 + if (to_clear[dbcnt])
550 + {
551 + pthread_mutex_lock (&dbs[dbcnt].prune_lock);
552 + dbs[dbcnt].clear_cache = 1;
553 + pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
554 + pthread_cond_signal (&dbs[dbcnt].prune_cond);
555 + }
556 +}
557 +
558 +int
559 +handle_inotify_events (void)
560 +{
561 + bool to_clear[lastdb] = { false, };
562 + union __inev inev;
563 +
564 + /* Read all inotify events for files registered via
565 + register_traced_file(). */
566 + while (1)
567 + {
568 + /* Potentially read multiple events into buf. */
569 + ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd,
570 + &inev.buf,
571 + sizeof (inev)));
572 + if (nb < (ssize_t) sizeof (struct inotify_event))
573 + {
574 + /* Not even 1 event. */
575 + if (__glibc_unlikely (nb == -1 && errno != EAGAIN))
576 + return -1;
577 + /* Done reading events that are ready. */
578 + break;
579 + }
580 + /* Process all events. The normal inotify interface delivers
581 + complete events on a read and never a partial event. */
582 + char *eptr = &inev.buf[0];
583 + ssize_t count;
584 + while (1)
585 + {
586 + /* Check which of the files changed. */
587 + inotify_check_files (to_clear, &inev);
588 + count = sizeof (struct inotify_event) + inev.i.len;
589 + eptr += count;
590 + nb -= count;
591 + if (nb >= (ssize_t) sizeof (struct inotify_event))
592 + memcpy (&inev, eptr, nb);
593 + else
594 + break;
595 + }
596 + continue;
597 + }
598 + /* Actually perform the cache clearing. */
599 + clear_db_cache (to_clear);
600 + return 0;
601 +}
602 +
603 +
604 +#endif
605 +
606
607 static void
608 __attribute__ ((__noreturn__))
609 @@ -1910,66 +2231,21 @@
610 {
611 if (conns[1].revents != 0)
612 {
613 - bool to_clear[lastdb] = { false, };
614 - union
615 - {
616 -# ifndef PATH_MAX
617 -# define PATH_MAX 1024
618 -# endif
619 - struct inotify_event i;
620 - char buf[sizeof (struct inotify_event) + PATH_MAX];
621 - } inev;
622 + int ret;
623 + ret = handle_inotify_events ();
624
625 - while (1)
626 + if (ret == -1)
627 {
628 - ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
629 - sizeof (inev)));
630 - if (nb < (ssize_t) sizeof (struct inotify_event))
631 - {
632 - if (__builtin_expect (nb == -1 && errno != EAGAIN,
633 - 0))
634 - {
635 - /* Something went wrong when reading the inotify
636 - data. Better disable inotify. */
637 - dbg_log (_("\
638 -disabled inotify after read error %d"),
639 - errno);
640 - conns[1].fd = -1;
641 - firstfree = 1;
642 - if (nused == 2)
643 - nused = 1;
644 - close (inotify_fd);
645 - inotify_fd = -1;
646 - }
647 - break;
648 - }
649 -
650 - /* Check which of the files changed. */
651 - for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
652 - if (inev.i.wd == dbs[dbcnt].inotify_descr)
653 - {
654 - to_clear[dbcnt] = true;
655 - goto next;
656 - }
657 -
658 - if (inev.i.wd == resolv_conf_descr)
659 - {
660 - res_init ();
661 - to_clear[hstdb] = true;
662 - }
663 - next:;
664 + /* Something went wrong when reading the inotify
665 + data. Better disable inotify. */
666 + dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
667 + conns[1].fd = -1;
668 + firstfree = 1;
669 + if (nused == 2)
670 + nused = 1;
671 + close (inotify_fd);
672 + inotify_fd = -1;
673 }
674 -
675 - /* Actually perform the cache clearing. */
676 - for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
677 - if (to_clear[dbcnt])
678 - {
679 - pthread_mutex_lock (&dbs[dbcnt].prune_lock);
680 - dbs[dbcnt].clear_cache = 1;
681 - pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
682 - pthread_cond_signal (&dbs[dbcnt].prune_cond);
683 - }
684 -
685 --n;
686 }
687
688 @@ -2112,58 +2388,18 @@
689 # ifdef HAVE_INOTIFY
690 else if (revs[cnt].data.fd == inotify_fd)
691 {
692 - bool to_clear[lastdb] = { false, };
693 - union
694 - {
695 - struct inotify_event i;
696 - char buf[sizeof (struct inotify_event) + PATH_MAX];
697 - } inev;
698 -
699 - while (1)
700 + int ret;
701 + ret = handle_inotify_events ();
702 + if (ret == -1)
703 {
704 - ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
705 - sizeof (inev)));
706 - if (nb < (ssize_t) sizeof (struct inotify_event))
707 - {
708 - if (__builtin_expect (nb == -1 && errno != EAGAIN, 0))
709 - {
710 - /* Something went wrong when reading the inotify
711 - data. Better disable inotify. */
712 - dbg_log (_("disabled inotify after read error %d"),
713 - errno);
714 - (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd,
715 - NULL);
716 - close (inotify_fd);
717 - inotify_fd = -1;
718 - }
719 - break;
720 - }
721 -
722 - /* Check which of the files changed. */
723 - for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
724 - if (inev.i.wd == dbs[dbcnt].inotify_descr)
725 - {
726 - to_clear[dbcnt] = true;
727 - goto next;
728 - }
729 -
730 - if (inev.i.wd == resolv_conf_descr)
731 - {
732 - res_init ();
733 - to_clear[hstdb] = true;
734 - }
735 - next:;
736 + /* Something went wrong when reading the inotify
737 + data. Better disable inotify. */
738 + dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
739 + (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd, NULL);
740 + close (inotify_fd);
741 + inotify_fd = -1;
742 + break;
743 }
744 -
745 - /* Actually perform the cache clearing. */
746 - for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
747 - if (to_clear[dbcnt])
748 - {
749 - pthread_mutex_lock (&dbs[dbcnt].prune_lock);
750 - dbs[dbcnt].clear_cache = 1;
751 - pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
752 - pthread_cond_signal (&dbs[dbcnt].prune_cond);
753 - }
754 }
755 # endif
756 else
757 diff -urN glibc-2.12-2-gc4ccff1.orig/nscd/nscd.h glibc-2.12-2-gc4ccff1.mod1/nscd/nscd.h
758 --- glibc-2.12-2-gc4ccff1.orig/nscd/nscd.h 2015-02-18 04:42:12.329180362 -0500
759 +++ glibc-2.12-2-gc4ccff1.mod1/nscd/nscd.h 2015-02-18 04:02:03.636159059 -0500
760 @@ -62,6 +62,67 @@
761 80% of the thread stack size. */
762 #define MAX_STACK_USE ((8 * NSCD_THREAD_STACKSIZE) / 10)
763
764 +/* Records the file registered per database that when changed
765 + or modified requires invalidating the database. */
766 +struct traced_file
767 +{
768 + /* Tracks the last modified time of the traced file. */
769 + time_t mtime;
770 + /* Support multiple registered files per database. */
771 + struct traced_file *next;
772 + int call_res_init;
773 + /* Requires Inotify support to do anything useful. */
774 +#define TRACED_FILE 0
775 +#define TRACED_DIR 1
776 + int inotify_descr[2];
777 +# ifndef PATH_MAX
778 +# define PATH_MAX 1024
779 +# endif
780 + /* The parent directory is used to scan for creation/deletion. */
781 + char dname[PATH_MAX];
782 + /* Just the name of the file with no directory component. */
783 + char *sfname;
784 + /* The full-path name of the registered file. */
785 + char fname[];
786 +};
787 +
788 +/* Initialize a `struct traced_file`. As input we need the name
789 + of the file, and if invalidation requires calling res_init.
790 + If CRINIT is 1 then res_init will be called after invalidation
791 + or if the traced file is changed in any way, otherwise it will
792 + not. */
793 +static inline void
794 +init_traced_file(struct traced_file *file, const char *fname, int crinit)
795 +{
796 + char *dname;
797 + file->mtime = 0;
798 + file->inotify_descr[TRACED_FILE] = -1;
799 + file->inotify_descr[TRACED_DIR] = -1;
800 + strcpy (file->fname, fname);
801 + /* Compute the parent directory name and store a copy. The copy makes
802 + it much faster to add/remove watches while nscd is running instead
803 + of computing this over and over again in a temp buffer. */
804 + file->dname[0] = '\0';
805 + dname = strrchr (fname, '/');
806 + if (dname != NULL)
807 + {
808 + size_t len = (size_t)(dname - fname);
809 + if (len > sizeof (file->dname))
810 + abort ();
811 + strncpy (file->dname, file->fname, len);
812 + file->dname[len] = '\0';
813 + }
814 + /* The basename is the name just after the last forward slash. */
815 + file->sfname = &dname[1];
816 + file->call_res_init = crinit;
817 +}
818 +
819 +#define define_traced_file(id, filename) \
820 +static union \
821 +{ \
822 + struct traced_file file; \
823 + char buf[sizeof (struct traced_file) + sizeof (filename)]; \
824 +} id##_traced_file;
825
826 /* Structure describing dynamic part of one database. */
827 struct database_dyn
828 @@ -74,15 +135,12 @@
829
830 int enabled;
831 int check_file;
832 - int inotify_descr;
833 int clear_cache;
834 int persistent;
835 int shared;
836 int propagate;
837 - int reset_res;
838 - const char filename[16];
839 + struct traced_file *traced_files;
840 const char *db_filename;
841 - time_t file_mtime;
842 size_t suggested_module;
843 size_t max_db_size;
844
845 @@ -199,6 +257,10 @@
846
847 /* connections.c */
848 extern void nscd_init (void);
849 +extern void register_traced_file (size_t dbidx, struct traced_file *finfo);
850 +#ifdef HAVE_INOTIFY
851 +extern void install_watches (struct traced_file *finfo);
852 +#endif
853 extern void close_sockets (void);
854 extern void start_threads (void) __attribute__ ((__noreturn__));