[ENBD] nbd 2.4.27: partition >4GB problem
Peter T. Breuer
enbd@lists.community.tummy.com
Tue, 12 Mar 2002 17:00:38 +0100 (MET)
"A month of sundays ago Tad Kollar wrote:"
> I just got into ENBD the other day... started with nbd 2.4.27 and kernel
> 2.4.18. It worked fine up until I tried to use a partition larger than 4GB.
> Above that point the client would always see the same erroneous size[1] (2TB)
> for the partition, though the server reported[2] sending the correct size
> (~26GB in this case).
Actually, I guess that's more a feature than a real big bug :-). But
yes, it needs to be fixed. It may have something to do with the support
for removable devices.
OK .. at the server side (nbd-server.c), we do this:
u64 size_host = 0;
...
size_host = htonll(self->size);
if (writenet(self, "size ", 5) < 0) {
PERR("Introduction failed: %m\n");
err = -5;
goto fail;
}
if (writenet(self, (char*)&size_host, sizeof(size_host)) < 0) {
PERR("Introduction failed: %m\n");
err = -5;
goto fail;
}
MSG("server (%d) sent size %Lu ok\n", self->i, self->size);
so we write "size " plus a 64bit network order datum (crazy, but true;
I am going to have to revise this for endianness someday).
On the client side (nbd-client.c), we get ...
u64 size64;
....
size:
memcpy(&size64, buf, sizeof(size64));
size64 = ntohll (size64);
// PTB set object parm
self->size = size64;
DEBUG ("client (%d) got size = %Lu\n", self->i, size64);
goto next;
so can you show me the client side log output about what it sees
vis-a-vis size data? You might want to change that DEBUG to a MSG.
Did I really make all that clientside information into DEBUG? Maybe
I should change it all to MSG.
The client appears to do the right thing initially with the size info:
err = setkernel(self,size64,0,self->blksize,
^^^^^^^
self->flags&NBD_CLIENT_READONLY,
self->pulse_intvl,
self->flags&NBD_CLIENT_SHOW_ERRS,
self->flags&NBD_CLIENT_MD5SUM,
self->flags&NBD_CLIENT_BUFFERWR,
self->pid);
...
static int
setkernel(struct nbd_client* self, u64 size64, int sigbuf[],
^^^^^^^^^^^
unsigned blksize, int ro, long pulse_intvl, int show_errs,
int md5sum, int buffer_writes, int svpd) {
...
if (size64 > 0) {
if (setdevicesize(self, size64) < 0) {
PERR ("Failed set size %Lu on fd %d: %m\n",size64,dev);
return -1;
}
DEBUG ("client (%d) set size %Lu\n", self->i, self->size);
}
...
static unsigned
setdevicesize(struct nbd_client * self, u64 size) {
^^^^^^^^^
...
Oh!!!!
...
unsigned sectors = size >> 9;
// PTB HACK HACK HACK .. why not allow more sectors :-)
if (size > (u64)(unsigned)(-1)) {
sectors = (unsigned)(-1);
}
DEBUG("client (%d) device not yet set to size\n", self->i);
err = self->ioctl(self, NBD_SET_SECTORS, (char*)sectors);
Uh. I don't know what to say. It sets the number of sectors to some
number <= 2^55, and then truncates that to 2^32 at most. So the biggest
device it can hope to deal with is 2^41 bytes (2TB). But worse, if
we pass a size that is >= 2^32, then for some reason known not
even to myself, it shifts the sector number up to the maximum possible,
before telling the kernel that we have a whopping big device.
I wonder why? Could I have been testing the behaviour with removable
devices and left that in?
Anyway, remove the 4 lines beginning HACK HACK HACK, and tell me how it
goes.
I wonder what that breaks?
Peter