From 6e284eaad57843950a54f44f02f920216dd3fc88 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Wed, 16 May 2018 21:41:42 +0200 Subject: [PATCH] ndb/cs: prevent deadlock with ndb/cs by mounting /srv/dns *AFTER* /net the dnsquery() library function should not start mouting /srv/dns on its own. this problem arrises only for ndb/cs as it is started before ndb/dns. the issue with mounting /srv/dns before /net is when ndb/cs attempts to read the list of interfaces, accessing /net/ipifc, which triggers a rpc to ndb/dns as it is ontop of the mount. this can yield a deadlock when ndb/dns blocks its 9p loop waiting for requests to complete on a refresh and the requests are stuck waiting for ndb/cs to translate a dial string for announce(). --- sys/src/cmd/ndb/cs.c | 48 +++++++++++++++++++++++++++++++++++---- sys/src/libndb/dnsquery.c | 36 +++++++---------------------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/sys/src/cmd/ndb/cs.c b/sys/src/cmd/ndb/cs.c index 71e2d9e0b..4451f223f 100644 --- a/sys/src/cmd/ndb/cs.c +++ b/sys/src/cmd/ndb/cs.c @@ -1081,12 +1081,8 @@ netinit(int background) Network *np; if(background){ - switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){ - case 0: - break; - default: + if(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT) != 0) return; - } qlock(&netlock); } @@ -1627,6 +1623,43 @@ slave(char *host) } +static int +mountdns(void) +{ + static QLock mountlock; + static int mounted; + char buf[128], *p; + int fd; + + if(mounted) + return 0; + + qlock(&mountlock); + snprint(buf, sizeof(buf), "%s/dns", mntpt); + if(access(buf, AEXIST) == 0) + goto done; + if(strcmp(mntpt, "/net") == 0) + snprint(buf, sizeof(buf), "/srv/dns"); + else { + snprint(buf, sizeof(buf), "/srv/dns%s", mntpt); + while((p = strchr(buf+8, '/')) != nil) + *p = '_'; + } + if((fd = open(buf, ORDWR)) < 0){ +err: + qunlock(&mountlock); + return -1; + } + if(mount(fd, -1, mntpt, MAFTER, "") < 0){ + close(fd); + goto err; + } +done: + mounted = 1; + qunlock(&mountlock); + return 0; +} + static Ndbtuple* dnsip6lookup(char *mntpt, char *buf, Ndbtuple *t) { @@ -1662,6 +1695,11 @@ dnsiplookup(char *host, Ndbs *s, int v6) return nil; } + if(mountdns() < 0){ + qlock(&dblock); + return nil; + } + if(strcmp(ipattr(host), "ip") == 0) t = dnsquery(mntpt, host, "ptr"); else { diff --git a/sys/src/libndb/dnsquery.c b/sys/src/libndb/dnsquery.c index 634756b76..1bf1ff8b3 100644 --- a/sys/src/libndb/dnsquery.c +++ b/sys/src/libndb/dnsquery.c @@ -12,13 +12,12 @@ static Ndbtuple *doquery(int, char *dn, char *type); * search for a tuple that has the given 'attr=val' and also 'rattr=x'. * copy 'x' into 'buf' and return the whole tuple. * - * return 0 if not found. + * return nil if not found. */ Ndbtuple* dnsquery(char *net, char *val, char *type) { - char rip[128]; - char *p; + char buf[128]; Ndbtuple *t; int fd; @@ -28,37 +27,18 @@ dnsquery(char *net, char *val, char *type) if(net == nil) net = "/net"; - snprint(rip, sizeof(rip), "%s/dns", net); - fd = open(rip, ORDWR); - if(fd < 0){ - if(strcmp(net, "/net") == 0) - snprint(rip, sizeof(rip), "/srv/dns"); - else { - snprint(rip, sizeof(rip), "/srv/dns%s", net); - p = strrchr(rip, '/'); - *p = '_'; - } - fd = open(rip, ORDWR); - if(fd < 0) - return nil; - if(mount(fd, -1, net, MBEFORE, "") < 0){ - close(fd); - return nil; - } - /* fd is now closed */ - snprint(rip, sizeof(rip), "%s/dns", net); - fd = open(rip, ORDWR); - if(fd < 0) - return nil; - } + + snprint(buf, sizeof(buf), "%s/dns", net); + if((fd = open(buf, ORDWR)) < 0) + return nil; /* zero out the error string */ werrstr(""); /* if this is a reverse lookup, first lookup the domain name */ if(strcmp(type, "ptr") == 0){ - mkptrname(val, rip, sizeof rip); - t = doquery(fd, rip, "ptr"); + mkptrname(val, buf, sizeof buf); + t = doquery(fd, buf, "ptr"); } else t = doquery(fd, val, type);