On Wednesday 22 September 2010 21:09, Rob Landley wrote:
> On Tuesday 21 September 2010 19:19:17 Denys Vlasenko wrote:
> > Outer for(;;) loop looks wrong. For one, on the second iteration
> > nbd file descriptor will be closed. I have doubts ioctls can work
> > on closed fds. Repeatedly daemonizing also looks strange.
> >
> > I imagine the loop should just be removed, body should execute just once.
>
> The problem is the ioctl _can_ exit. I'm not sure the circumstances under
> which it does so, could be a certain number of dropped packets, or it could
> be
> the server rebooted. Not sure. (I haven't rewritten the server side yet, no
> immediate call for it here.)
My problem with this loop is here:
// Make sure the /dev/nbd exists.
nbd = xopen(device, O_RDWR);
// Repeat until spanked
for (;;) {
...
// Daemonize here.
daemon(0, 0); <==== why do we daemonize on each iteration??
// Process NBD requests until further notice.
if (ioctl(nbd, NBD_DO_IT)>=0 || errno==EBADR)
break;
close(sock);
close(nbd); <==== ?! so on 2nd iteration nbd is closed??
}
> In theory you could call a non-daemon version of NBD from an upstart variant
> that respawns it when it goes away, and thus bump this retry up to an
> external
> level. However, the retry doesn't re-login, it only retries with the same
> login credentials, and if it gets an EBADR return it goes "oh, login
> credentis
> are stale, exit" so it doesn't try to swap in a _different_ block device
> under
> an existing active mount (which would be bad).
>
> So without the retry, it's less reliable. With an externally imposed retry,
> it may increase the likelihood of data corruption. (I also dunno under what
> circumstances a mount on top of the network block device fails and unmounts
> itself.)
>
> If the loop isn't working right now, removing it is reasonable.
I am thinking along "it is obviously broken as it is coded right now. It can't
possibly work if it does more than one iteration" lines.
> > // Open the device to force reread of the partition table.
> > if (!fork()) {
> > char *s = strrchr(device, '/');
> > sprintf(data, "/sys/block/%.32s/pid", s ? s+1 :
> > device); // Is it up yet?
> > for (;;) {
> > temp = open(data, O_RDONLY);
> > if (temp == -1) sleep(1);
> > else {
> > close(temp);
> > break;
> > }
> > }
> > close(open(device, O_RDONLY));
> > exit(0);
> > }
> >
> > Why do you do it in a child? nbd-client's parent might actually
> > prefer to know that this step is complete before nbd-client
> > exits. As it stands, now reread happens "somewhere in the future,
> > maybe in 2050, who knows".
>
> A) They can't happen in the same process, ioctl(NBD_DO_IT) blocks and the
> open
> won't succeed until some process is in that ioctl() handling packets.
>
> B) The NBD daemon doesn't _use_ the partition information, and in its normal
> use case it daemonizes so you can't tell when it's done anyway. The
> information propogates through udev/mdev and you can trigger on new devices
> showing up that way, so it's already an external hotplug callback.
>
> Calling the ioctl(NBD_DO_IT) sits there and processes NBD requests, it
> doesn't
> return until you disconnect the NBD from the server. That IOCTL turns the
> process that calls it into a dedicated NBD request handler. The partition
> table doesn't get re-read until the first open() of the NBD _after_ the
> request
> handler gets set up (due to some race in the kernel that makes it hard to do
> in-kernel).
>
> So the process that calls ioctl(NBD_DO_IT) can't be the one that calls the
> open() to force the partition table re-read, because the open() won't succeed
> until there's already a request handler running, and the request handler
> doesn't return while the NBD is connected.
Understood.
We have a problem here. fork() is not available on NOMMU.
> > // Process NBD requests until further notice.
> >
> > if (ioctl(nbd, NBD_DO_IT)>=0 || errno==EBADR) break;
> >
> > Need more comments here.
> > Does this ioctl block for a long time, processing many requests?
>
> Yes. It's the in-kernel request handler, which requires a process context.
> It's where the daemon spends the rest of its runtime after doing the setup.
I committed the code to git after fixing it up so that it looks non-buggy
wrt closed fd problem and NOMMU problem.
Can you test current git?
--
vda
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox