summaryrefslogtreecommitdiff
path: root/sys/src
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2018-05-16 21:41:42 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2018-05-16 21:41:42 +0200
commit6e284eaad57843950a54f44f02f920216dd3fc88 (patch)
tree6abd320805cff612a155b11692f73bc63cbf81db /sys/src
parent5c2b4dfc8173355629e70a6437ccfc378f0bf757 (diff)
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().
Diffstat (limited to 'sys/src')
-rw-r--r--sys/src/cmd/ndb/cs.c48
-rw-r--r--sys/src/libndb/dnsquery.c36
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);