From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29655 invoked by alias); 4 Aug 2004 21:19:37 -0000 Mailing-List: contact libc-hacker-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sources.redhat.com Received: (qmail 29635 invoked from network); 4 Aug 2004 21:19:36 -0000 Received: from unknown (HELO sunsite.ms.mff.cuni.cz) (195.113.15.26) by sourceware.org with SMTP; 4 Aug 2004 21:19:36 -0000 Received: from sunsite.ms.mff.cuni.cz (sunsite.mff.cuni.cz [127.0.0.1]) by sunsite.ms.mff.cuni.cz (8.12.8/8.12.8) with ESMTP id i74J2v3j032539; Wed, 4 Aug 2004 21:02:57 +0200 Received: (from jakub@localhost) by sunsite.ms.mff.cuni.cz (8.12.8/8.12.8/Submit) id i74J2vE2032537; Wed, 4 Aug 2004 21:02:57 +0200 Date: Wed, 04 Aug 2004 21:19:00 -0000 From: Jakub Jelinek To: Andreas Schwab Cc: Ulrich Drepper , Glibc hackers , jvdias@redhat.com Subject: Re: [PATCH] Change res_init to take (lazilly) effect in all threads Message-ID: <20040804190257.GH30497@sunsite.ms.mff.cuni.cz> Reply-To: Jakub Jelinek References: <20040804162551.GF30497@sunsite.ms.mff.cuni.cz> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.4.1i X-SW-Source: 2004-08/txt/msg00009.txt.bz2 On Wed, Aug 04, 2004 at 10:48:09PM +0200, Andreas Schwab wrote: > > --- libc/resolv/resolv.h.jj 2004-08-04 14:42:23.000000000 +0200 > > +++ libc/resolv/resolv.h 2004-08-04 14:54:25.568907618 +0200 > > @@ -134,6 +134,12 @@ struct __res_state { > > u_int16_t nscount6; > > u_int16_t nsinit; > > struct sockaddr_in6 *nsaddrs[MAXNS]; > > +#ifdef _LIBC > > + unsigned long long int initstamp > > + __attribute__((aligned (sizeof (long)))); > > +#else > > + unsigned int _initstamp[2]; > > +#endif > > You can't decrease alignment with the aligned attribute unless you also > add packed. Well, combining packed and aligned attribute doesn't work either (this is one of the infamous ABI incompatibilities between various GCC versions). But __attribute__((packed)) alone seems to DTRT, GCC knows the whole structure is sizeof (void *) aligned (it contains pointers) and the immediately preceeding member is a pointer too, so reading _u._ext.initstamp causes unaligned load on neither 32-bit nor 64-bit arches. I have checked this resolv.h layout on x86-64, i386, ppc32, ppc64 and ia64 and it looks good. So here is the updated patch: 2004-08-04 Jakub Jelinek * hesiod/hesiod.c (__hesiod_res_get): Use calloc instead of malloc + memset. (__hesiod_res_set): Free nsaddrs. * include/resolv.h (__res_maybe_init): Add prototype. * resolv/resolv.h (struct __res_state): Add _u._ext.initstamp field. * resolv/Versions (libc): Add __res_maybe_init@@GLIBC_PRIVATE. * resolv/res_libc.c (__res_initstamp, lock): New variables. (res_init): Increase __res_initstamp. (__res_maybe_init): New function. * resolv/res_init.c (__res_vinit): Initialize _u._ext.initstamp. * hesiod/hesiod.c (__hesiod_res_get): Use __res_maybe_init instead of RES_INIT check and {res_ninit,__res_ninit,res_init} call. * sysdeps/posix/getaddrinfo.c (gaih_inet): Likewise. * resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname2_r, _nss_dns_gethostbyaddr_r): Likewise. * resolv/nss_dns/dns-network.c (_nss_dns_getnetbyname_r, _nss_dns_getnetbyaddr_r): Likewise. * resolv/gethnamaddr.c (gethostbyname, gethostbyname2, gethostbyaddr): Likewise. * resolv/res_data.c (fp_nquery, res_mkquery, res_mkupdate, res_isourserver, res_sendsigned, res_update, res_search, res_querydomain): Likewise. * nss/getXXbyYY_r.c (INTERNAL (REENTRANT_NAME)): Likewise. * nss/digits_dots.c (__nss_hostname_digits_dots): Likewise. * nss/getnssent_r.c (__nss_setent, __nss_endent, __nss_getent_r): Likewise. --- libc/hesiod/hesiod.c.jj 2004-08-04 14:42:20.000000000 +0200 +++ libc/hesiod/hesiod.c 2004-08-04 14:54:25.000000000 +0200 @@ -448,10 +448,9 @@ __hesiod_res_get(void *context) { if (!ctx->res) { struct __res_state *res; - res = (struct __res_state *)malloc(sizeof *res); + res = (struct __res_state *)calloc(1, sizeof *res); if (res == NULL) return (NULL); - memset(res, 0, sizeof *res); __hesiod_res_set(ctx, res, free); } @@ -465,6 +464,12 @@ __hesiod_res_set(void *context, struct _ if (ctx->res && ctx->free_res) { res_nclose(ctx->res); + if ((ctx->res->options & RES_INIT) && ctx->res->nscount > 0) { + for (int ns = 0; ns < MAXNS; ns++) { + free (ctx->res->_u._ext.nsaddrs[ns]); + ctx->res->_u._ext.nsaddrs[ns] = NULL; + } + } (*ctx->free_res)(ctx->res); } @@ -478,8 +483,7 @@ init(struct hesiod_p *ctx) { if (!ctx->res && !__hesiod_res_get(ctx)) return (-1); - if (((ctx->res->options & RES_INIT) == 0) && - (res_ninit(ctx->res) == -1)) + if (__res_maybe_init (ctx->res, 0) == -1) return (-1); return (0); --- libc/sysdeps/posix/getaddrinfo.c.jj 2004-08-04 14:42:26.000000000 +0200 +++ libc/sysdeps/posix/getaddrinfo.c 2004-08-04 14:54:25.563908498 +0200 @@ -661,7 +661,7 @@ gaih_inet (const char *name, const struc no_more = __nss_database_lookup ("hosts", NULL, "dns [!UNAVAIL=return] files", &nip); - if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) + if (__res_maybe_init (&_res, 0) == -1) no_more = 1; old_res_options = _res.options; _res.options &= ~RES_USE_INET6; --- libc/include/resolv.h.jj 2004-08-04 14:42:20.000000000 +0200 +++ libc/include/resolv.h 2004-08-04 14:54:25.564908322 +0200 @@ -31,6 +31,7 @@ extern struct __res_state _res; /* Now define the internal interfaces. */ extern int __res_vinit (res_state, int); +extern int __res_maybe_init (res_state, int); extern void _sethtent (int); extern void _endhtent (void); extern struct hostent *_gethtent (void); @@ -46,6 +47,7 @@ extern void res_send_setrhook (res_send_ extern int res_ourserver_p (const res_state __statp, const struct sockaddr_in6 *__inp); libc_hidden_proto (__res_ninit) +libc_hidden_proto (__res_maybe_init) libc_hidden_proto (__res_nclose) libc_hidden_proto (__res_randomid) libc_hidden_proto (__res_state) --- libc/resolv/nss_dns/dns-host.c.jj 2004-08-04 14:42:23.000000000 +0200 +++ libc/resolv/nss_dns/dns-host.c 2004-08-04 14:54:25.000000000 +0200 @@ -145,7 +145,7 @@ _nss_dns_gethostbyname2_r (const char *n int olderr = errno; enum nss_status status; - if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1) + if (__res_maybe_init (&_res, 0) == -1) return NSS_STATUS_UNAVAIL; switch (af) { @@ -263,7 +263,7 @@ _nss_dns_gethostbyaddr_r (const void *ad int n, status; int olderr = errno; - if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1) + if (__res_maybe_init (&_res, 0) == -1) return NSS_STATUS_UNAVAIL; if (af == AF_INET6 && len == IN6ADDRSZ --- libc/resolv/nss_dns/dns-network.c.jj 2004-08-04 14:42:23.000000000 +0200 +++ libc/resolv/nss_dns/dns-network.c 2004-08-04 14:54:25.000000000 +0200 @@ -1,4 +1,5 @@ -/* Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004 + Free Software Foundation, Inc. This file is part of the GNU C Library. Extended from original form by Ulrich Drepper , 1996. @@ -120,7 +121,7 @@ _nss_dns_getnetbyname_r (const char *nam char *qbuf; enum nss_status status; - if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1) + if (__res_maybe_init (&_res, 0) == -1) return NSS_STATUS_UNAVAIL; qbuf = strdupa (name); @@ -171,7 +172,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, i if (type != AF_INET) return NSS_STATUS_UNAVAIL; - if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1) + if (__res_maybe_init (&_res, 0) == -1) return NSS_STATUS_UNAVAIL; net2 = (u_int32_t) net; --- libc/resolv/gethnamaddr.c.jj 2004-08-04 14:42:23.000000000 +0200 +++ libc/resolv/gethnamaddr.c 2004-08-04 14:54:25.000000000 +0200 @@ -493,10 +493,10 @@ gethostbyname(name) { struct hostent *hp; - if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) { + if (__res_maybe_init (&_res, 0) == -1) { __set_h_errno (NETDB_INTERNAL); return (NULL); - } + } if (_res.options & RES_USE_INET6) { hp = gethostbyname2(name, AF_INET6); if (hp) @@ -522,7 +522,7 @@ gethostbyname2(name, af) struct hostent *ret; extern struct hostent *_gethtbyname2(); - if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) { + if (__res_maybe_init (&_res, 0) == -1) { __set_h_errno (NETDB_INTERNAL); return (NULL); } @@ -665,7 +665,7 @@ gethostbyaddr(addr, len, af) #endif /*SUNSECURITY*/ extern struct hostent *_gethtbyaddr(); - if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) { + if (__res_maybe_init (&_res, 0) == -1) { __set_h_errno (NETDB_INTERNAL); return (NULL); } --- libc/resolv/res_data.c.jj 2004-08-04 14:42:23.000000000 +0200 +++ libc/resolv/res_data.c 2004-08-04 14:54:25.000000000 +0200 @@ -141,7 +141,7 @@ fp_query(const u_char *msg, FILE *file) void fp_nquery(const u_char *msg, int len, FILE *file) { - if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) + if (__res_maybe_init (&_res, 0) == -1) return; res_pquery(&_res, msg, len, file); @@ -157,7 +157,7 @@ res_mkquery(int op, /* opcode of query u_char *buf, /* buffer to put query */ int buflen) /* size of buffer */ { - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + if (__res_maybe_init (&_res, 1) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -169,7 +169,7 @@ res_mkquery(int op, /* opcode of query #ifdef BIND_UPDATE int res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + if (__res_maybe_init (&_res, 1) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -184,7 +184,7 @@ res_query(const char *name, /* domain na u_char *answer, /* buffer to put answer */ int anslen) /* size of answer buffer */ { - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + if (__res_maybe_init (&_res, 1) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -208,7 +208,7 @@ res_isourserver(const struct sockaddr_in int res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + if (__res_maybe_init (&_res, 1) == -1) { /* errno should have been set by res_init() in this case. */ return (-1); } @@ -221,7 +221,7 @@ int res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key, u_char *ans, int anssiz) { - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + if (__res_maybe_init (&_res, 1) == -1) { /* errno should have been set by res_init() in this case. */ return (-1); } @@ -249,7 +249,7 @@ res_close(void) { #ifdef BIND_UPDATE int res_update(ns_updrec *rrecp_in) { - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + if (__res_maybe_init (&_res, 1) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -264,7 +264,7 @@ res_search(const char *name, /* domain n u_char *answer, /* buffer to put answer */ int anslen) /* size of answer */ { - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + if (__res_maybe_init (&_res, 1) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -279,7 +279,7 @@ res_querydomain(const char *name, u_char *answer, /* buffer to put answer */ int anslen) /* size of answer */ { - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + if (__res_maybe_init (&_res, 1) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } --- libc/resolv/resolv.h.jj 2004-08-04 14:42:23.000000000 +0200 +++ libc/resolv/resolv.h 2004-08-04 14:54:25.568907618 +0200 @@ -134,6 +134,12 @@ struct __res_state { u_int16_t nscount6; u_int16_t nsinit; struct sockaddr_in6 *nsaddrs[MAXNS]; +#ifdef _LIBC + unsigned long long int initstamp + __attribute__((packed)); +#else + unsigned int _initstamp[2]; +#endif } _ext; } _u; }; --- libc/resolv/res_init.c.jj 2004-08-04 14:42:23.000000000 +0200 +++ libc/resolv/res_init.c 2004-08-04 14:54:25.567907794 +0200 @@ -161,6 +161,10 @@ __res_vinit(res_state statp, int preinit #ifndef RFC1535 int dots; #endif +#ifdef _LIBC + extern unsigned long long int __res_initstamp attribute_hidden; + statp->_u._ext.initstamp = __res_initstamp; +#endif if (!preinit) { statp->retrans = RES_TIMEOUT; --- libc/resolv/Versions.jj 2004-08-04 14:42:22.000000000 +0200 +++ libc/resolv/Versions 2004-08-04 14:54:25.570907266 +0200 @@ -38,6 +38,8 @@ libc { # This version is for the TLS symbol, GLIBC_2.0 is the old object symbol. h_errno; __resp; %endif + + __res_maybe_init; } } --- libc/resolv/res_libc.c.jj 2004-08-04 14:42:23.000000000 +0200 +++ libc/resolv/res_libc.c 2004-08-04 15:36:12.104626490 +0200 @@ -19,12 +19,16 @@ #include #include #include +#include /* The following bit is copied from res_data.c (where it is #ifdef'ed out) since res_init() should go into libc.so but the rest of that file should not. */ +unsigned long long int __res_initstamp attribute_hidden; +__libc_lock_define_initialized (static, lock); + int res_init(void) { extern int __res_vinit(res_state, int); @@ -70,8 +74,45 @@ res_init(void) { if (!_res.id) _res.id = res_randomid(); + __libc_lock_lock (lock); + /* Request all threads to re-initialize their resolver states, + resolv.conf might have changed. */ + __res_initstamp++; + __libc_lock_unlock (lock); + return (__res_vinit(&_res, 1)); } + +/* Initialize resp if RES_INIT is not yet set or if res_init in some other + thread requested re-initializing. */ +int +__res_maybe_init (res_state resp, int preinit) +{ + if (resp->options & RES_INIT) { + if (__res_initstamp != resp->_u._ext.initstamp) { + if (resp->nscount > 0) { + __res_nclose (resp); + for (int ns = 0; ns < MAXNS; ns++) { + free (resp->_u._ext.nsaddrs[ns]); + resp->_u._ext.nsaddrs[ns] = NULL; + } + return __res_vinit (resp, 1); + } + } + return 0; + } else if (preinit) { + if (!resp->retrans) + resp->retrans = RES_TIMEOUT; + if (!resp->retry) + resp->retry = 4; + resp->options = RES_DEFAULT; + if (!resp->id) + resp->id = res_randomid (); + return __res_vinit (resp, 1); + } else + return __res_ninit (resp); +} +libc_hidden_def (__res_maybe_init) /* This needs to be after the use of _res in res_init, above. */ #undef _res --- libc/nss/getXXbyYY_r.c.jj 2004-08-04 14:42:22.000000000 +0200 +++ libc/nss/getXXbyYY_r.c 2004-08-04 14:54:25.573906738 +0200 @@ -182,7 +182,7 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L #ifdef NEED__RES /* The resolver code will really be used so we have to initialize it. */ - if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1) + if (__res_maybe_init (&_res, 0) == -1) { *h_errnop = NETDB_INTERNAL; *result = NULL; --- libc/nss/digits_dots.c.jj 2004-08-04 14:42:22.000000000 +0200 +++ libc/nss/digits_dots.c 2004-08-04 14:54:25.571907090 +0200 @@ -43,7 +43,7 @@ __nss_hostname_digits_dots (const char * /* We have to test for the use of IPv6 which can only be done by examining `_res'. */ - if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1) + if (__res_maybe_init (&_res, 0) == -1) { if (h_errnop) *h_errnop = NETDB_INTERNAL; --- libc/nss/getnssent_r.c.jj 2004-08-04 14:42:22.000000000 +0200 +++ libc/nss/getnssent_r.c 2004-08-04 14:54:25.572906914 +0200 @@ -1,4 +1,4 @@ -/* Copyright (C) 2000,02 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2002, 2004 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 @@ -60,8 +60,7 @@ __nss_setent (const char *func_name, db_ } fct; int no_more; - if (res && (_res.options & RES_INIT) == 0 - && __res_ninit (&_res) == -1) + if (res && __res_maybe_init (&_res, 0) == -1) { __set_h_errno (NETDB_INTERNAL); return; @@ -104,8 +103,7 @@ __nss_endent (const char *func_name, db_ } fct; int no_more; - if (res && (_res.options & RES_INIT) == 0 - && __res_ninit (&_res) == -1) + if (res && __res_maybe_init (&_res, 0) == -1) { __set_h_errno (NETDB_INTERNAL); return; @@ -145,8 +143,7 @@ __nss_getent_r (const char *getent_func_ int no_more; enum nss_status status; - if (res && (_res.options & RES_INIT) == 0 - && __res_ninit (&_res) == -1) + if (res && __res_maybe_init (&_res, 0) == -1) { *h_errnop = NETDB_INTERNAL; *result = NULL; Jakub