Messages in this thread Patch in this message |  | | Date | Fri, 9 Aug 1996 3:9:07 | From | Tornaria Gonzalo <> | Subject | loop device: sparse files, and loop on loop bug (w/fix) |
| |
It seems the loop device can't deal with sparse files. I don't know if that could/should work, but in any case we should check and at least not allow it. I don't know how to do either (how can I determine whether a file has holes or not? I thought of comparing st_blocks<<9 and st_size, but don't like it too much). I think it would be very useful if it worked with sparse files (e.g dosemu hdimages are generally sparse, and I want them to stay sparse).
--------------- numenor:~# dd if=/dev/zero of=a bs=1k seek=360 count=0 0+0 records in 0+0 records out numenor:~# cat a > b numenor:~# du a b 0 a 363 b numenor:~# losetup /dev/loop0 a numenor:~# losetup /dev/loop1 b numenor:~# mkfs /dev/loop1 360 120 inodes 360 blocks Firstdatazone=8 (8) Zonesize=1024 Maxsize=268966912 numenor:~# mkfs /dev/loop0 360 120 inodes 360 blocks Firstdatazone=8 (8) Zonesize=1024 Maxsize=268966912 loop: block 0 not present end_request: I/O error, dev 07:00, sector 0 mkfs.minix: unable to clear boot sector loop: block 8 not present end_request: I/O error, dev 07:00, sector 16 --------------- Another one: you can do "losetup /dev/loop0 /dev/loop0", but then you can't "losetup -d /dev/loop0". And the same thing with more than one loop device ("losetup /dev/loop0 /dev/loop1;losetup /dev/loop1 /dev/loop0"). I tried to solve this by returning -ENXIO when opening a loop device not configured, but of course, I need to open it to configure (via ioctl) :-) Well, I can live with this (Linux: a thousand ways to shot yourself on a foot if you have permission ;-) A solution would be to not allow looping a loop that is not configured, but what if you have two loop modules? (that would be silly, but..) Now, last one: --------------- numenor:~# losetup /dev/loop0 b numenor:~# losetup /dev/loop1 /dev/loop0 numenor:~# mount /dev/loop1 /mnt --------------- The mount process hungs (i.e. no kill -9). I found this to be the same problem with reentrancy that I found in do_sbpcd_request (but this time in do_lo_request). So it was easy to solve it (exactly the same hack that I did for sbpcd :-) I know that you don't normally loop a loop, but special cases should work too (no matter how useless). This seems a general omision, I think, the fact that the do_*_request are generally not reentrant! Here's a patch: --- drivers/block/loop.c.old Thu Aug 8 03:01:14 1996 +++ drivers/block/loop.c Thu Aug 8 05:29:25 1996 @@ -12,6 +12,9 @@ * Modularized and updated for 1.1.16 kernel - Mitch Dsouza 28th May 1994 * * Adapted for 1.3.59 kernel - Andries Brouwer, 1 Feb 1996 + * + * Hacked out a bug when using loop on another loop device. + * Gonzalo Tornaria (GTL), 8/8/1996 */ #include <linux/module.h> @@ -175,18 +178,40 @@ loop_sizes[lo->lo_number] = size; } +/* + * Special end_request for loop to solve double loop bug. (GTL) + * + * This is similar to what I found in sbpcd. + * Here we don't sleep, but we request some blocks from the same device. + * When we reenter do_lo_request() we haven't yet finished the first + * request, so we start over with it, then we request some blocks from + * the same device ... ad infinitum. + * + * May be all this block device request stuff needs a global change? + * + * see also drivers/cdrom/sbpcd.c (it's the same fix) + */ +static inline void loop_end_request(struct request *req, int uptodate) { + req->next=CURRENT; + CURRENT=req; + end_request(uptodate); +} + static void do_lo_request(void) { int real_block, block, offset, len, blksize, size; char *dest_addr; struct loop_device *lo; struct buffer_head *bh; + struct request *req; repeat: INIT_REQUEST; - if (MINOR(CURRENT->rq_dev) >= MAX_LOOP) + req=CURRENT; /* take out our request so to avoid */ + CURRENT=req->next; /* reentrancy problems GTL */ + if (MINOR(req->rq_dev) >= MAX_LOOP) goto error_out; - lo = &loop_dev[MINOR(CURRENT->rq_dev)]; + lo = &loop_dev[MINOR(req->rq_dev)]; if (!lo->lo_inode || !lo->transfer) goto error_out; @@ -197,14 +222,14 @@ blksize = BLOCK_SIZE; } - dest_addr = CURRENT->buffer; + dest_addr = req->buffer; if (blksize < 512) { - block = CURRENT->sector * (512/blksize); + block = req->sector * (512/blksize); offset = 0; } else { - block = CURRENT->sector / (blksize >> 9); - offset = (CURRENT->sector % (blksize >> 9)) << 9; + block = req->sector / (blksize >> 9); + offset = (req->sector % (blksize >> 9)) << 9; } block += lo->lo_offset / blksize; offset += lo->lo_offset % blksize; @@ -212,13 +237,13 @@ block++; offset -= blksize; } - len = CURRENT->current_nr_sectors << 9; + len = req->current_nr_sectors << 9; - if (CURRENT->cmd == WRITE) { + if (req->cmd == WRITE) { if (lo->lo_flags & LO_FLAGS_READ_ONLY) goto error_out; - } else if (CURRENT->cmd != READ) { - printk("unknown loop device command (%d)?!?", CURRENT->cmd); + } else if (req->cmd != READ) { + printk("unknown loop device command (%d)?!?", req->cmd); goto error_out; } while (len > 0) { @@ -237,7 +262,7 @@ block, blksize); goto error_out; } - if (!buffer_uptodate(bh) && ((CURRENT->cmd == READ) || + if (!buffer_uptodate(bh) && ((req->cmd == READ) || (offset || (len < blksize)))) { ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); @@ -250,13 +275,13 @@ if (size > len) size = len; - if ((lo->transfer)(lo, CURRENT->cmd, bh->b_data + offset, + if ((lo->transfer)(lo, req->cmd, bh->b_data + offset, dest_addr, size)) { printk("loop: transfer error block %d\n", block); brelse(bh); goto error_out; } - if (CURRENT->cmd == WRITE) { + if (req->cmd == WRITE) { mark_buffer_uptodate(bh, 1); mark_buffer_dirty(bh, 1); } @@ -266,10 +291,10 @@ offset = 0; block++; } - end_request(1); + loop_end_request(req, 1); goto repeat; error_out: - end_request(0); + loop_end_request(req, 0); goto repeat; } ------------- Saludos, Gonzalo
PS: sorry, some 5 lines got wrapped. I can't do nothing from here. My normal conection (tornaria@cmat.edu.uy) is down and this is a stupid bbs software (flame the guy in X-Mailer:). If someone has problems with that I can resend the patch once my conection is up, or put it into my home page.
-- GM/CS/S d? a-- C++(+++) UL++(+++)>++++ P++>+++ L+++>++++ E--- W-(+) N+(++) w--- O M-(--) V-(--) PGP(--) b++(+++) G++ e>++++
|  |