Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 7 Oct 2015 23:55:58 +0200
From:      Jilles Tjoelker <jilles@stack.nl>
To:        Eric van Gyzen <vangyzen@FreeBSD.org>
Cc:        freebsd-arch@freebsd.org
Subject:   Re: RFC: Automatically Reloading /etc/resolv.conf
Message-ID:  <20151007215558.GA41787@stack.nl>
In-Reply-To: <5615886F.3060601@FreeBSD.org>
References:  <5615886F.3060601@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, Oct 07, 2015 at 04:02:39PM -0500, Eric van Gyzen wrote:
> I would like to change the libc resolver to automatically reload
> /etc/resolv.conf when the latter changes.  I would like to hear opinions
> about the implementation.  Broadly, I see two approaches.

> == "stat" ==

> When loading the file, record the mod time.  Before each query, stat()
> the file to see if it has changed.

> Advantage:  It uses no extra persistently allocated objects.

> Disadvantage:  It incurs a stat() on every query.  I don't see this as a
> major disadvantage, since the resolver already does a lot of work on
> every query.  (For example, it creates and destroys a kqueue and a socket.)

> OpenBSD uses this approach.  It also uses clock_gettime(CLOCK_MONOTONIC)
> to rate-limit the stat() calls to one per several seconds.

This looks reasonable.

Nitpick: the resolver has used poll instead of kqueue for a while, but
that does not fundamentally change your argument.

Some glibc people think the extra stat may be too slow, though:
https://sourceware.org/bugzilla/show_bug.cgi?id=984

> == "kqueue" ==

> When loading the file, open a kqueue and register for the appropriate
> events.  Before each query, check for kevents.

> Advantage:  The per-query overhead is fairly small.

> Disadvantage:  This would persistently allocate an open file and a
> kqueue for every thread that ever uses the resolver, for the life of the
> thread.  This seems fairly expensive.

This sounds a bit scary in conjunction with code that bluntly closes
file descriptors it does not know about.

Also, kqueues do not inherit across fork, so the resolver needs some
sort of atfork handler.

> NetBSD uses this approach.  It mitigates most of the space-cost by using
> a shared pool of res_state objects, instead of one per thread [that uses
> the resolver].  On each query, a thread allocates/borrows a res_state
> from the pool, uses it, and returns it.  So, the number of objects is
> only the high water mark of the number of threads _concurrently_ issuing
> resolver queries.

Is there code that depends on implicit per-thread res_state objects? If
so, this will break it.

> There are probably several variations on each theme, of course.  I would
> appreciate your thoughts on these approaches and others I missed, as
> well as variations and details.

> FYI, I'm leaning toward the "stat" approach.

This seems safe, and being able to rely on automatic /etc/resolv.conf
reloading can simplify application code considerably.

The NextBSD people have a more efficient alternative notify(3). Using
that, resolvconf(8) can cause a counter in shared memory to be
incremented, which can be detected efficiently by the resolver in each
process. The stat() approach need not wait for this, though.

-- 
Jilles Tjoelker



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20151007215558.GA41787>