> Later I will try compiling it to see if it works, but that will take
> awhile -- all I have is a P166. I will probably get a reply from the
> list before this thing can finish the job. :)
I made a patch which *seems* to work. But I'm absolutely clueless if I did the Right Thing (tm)...
So use it on your own risk. Please don't blame me if it eats your disk.
Flo
--- loop.c Thu Sep 27 16:39:10 2001
+++ loop.c Fri Sep 28 11:37:11 2001
@@ -36,6 +36,9 @@
* Al Viro too.
* Jens Axboe <axboe@xxxxxxx>, Nov 2000
*
+ * Fixed and made IV calculation customizable by lo_iv_mode
+ * Herbert Valerio Riedel <hvr@xxxxxxx>, Apr 2001
+ *
* Still To Fix:
* - Advisory locking is ignored here.
* - Should use an own CAP_* category instead of CAP_SYS_ADMIN
@@ -168,6 +171,43 @@
lo->lo_device);
}
+static inline int loop_get_bs(struct loop_device *lo)
+{
+ int bs = 0;
+
+ if (blksize_size[MAJOR(lo->lo_device)])
+ bs = blksize_size[MAJOR(lo->lo_device)][MINOR(lo->lo_device)];
+ if (!bs)
+ bs = BLOCK_SIZE;
+
+ return bs;
+}
+
+static inline unsigned long loop_get_iv(struct loop_device *lo,
+ unsigned long sector)
+{
+ unsigned long offset, IV;
+ int bs;
+
+ switch (lo->lo_iv_mode) {
+ case LO_IV_MODE_SECTOR:
+ IV = sector + (lo->lo_offset >> LO_IV_SECTOR_BITS);
+ break;
+
+ default:
+ printk (KERN_WARNING "loop: unexpected lo_iv_mode\n");
+ case LO_IV_MODE_DEFAULT:
+ bs = loop_get_bs(lo);
+ IV = sector / (bs >> 9) + lo->lo_offset / bs;
+ offset = ((sector % (bs >> 9)) << 9) + lo->lo_offset % bs;
+ if (offset >= bs)
+ IV++;
+ break;
+ }
+
+ return IV;
+}
+
static int lo_send(struct loop_device *lo, struct buffer_head *bh, int bsize,
loff_t pos)
{
@@ -185,7 +225,8 @@
len = bh->b_size;
data = bh->b_data;
while (len > 0) {
- int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize;
+ unsigned long IV = loop_get_iv(lo, (pos - lo->lo_offset) >> LO_IV_SECTOR_BITS);
+
size = PAGE_CACHE_SIZE - offset;
if (size > len)
size = len;
@@ -236,7 +277,10 @@
unsigned long count = desc->count;
struct lo_read_data *p = (struct lo_read_data*)desc->buf;
struct loop_device *lo = p->lo;
- int IV = page->index * (PAGE_CACHE_SIZE/p->bsize) + offset/p->bsize;
+ unsigned long IV = loop_get_iv(lo,
+ ((page->index << (PAGE_CACHE_SHIFT - LO_IV_SECTOR_BITS))
+ + (offset >> LO_IV_SECTOR_BITS)
+ - (lo->lo_offset >> LO_IV_SECTOR_BITS)));
if (size > count)
size = count;
@@ -276,32 +320,6 @@
return desc.error;
}
-static inline int loop_get_bs(struct loop_device *lo)
-{
- int bs = 0;
-
- if (blksize_size[MAJOR(lo->lo_device)])
- bs = blksize_size[MAJOR(lo->lo_device)][MINOR(lo->lo_device)];
- if (!bs)
- bs = BLOCK_SIZE;
-
- return bs;
-}
-
-static inline unsigned long loop_get_iv(struct loop_device *lo,
- unsigned long sector)
-{
- int bs = loop_get_bs(lo);
- unsigned long offset, IV;
-
- IV = sector / (bs >> 9) + lo->lo_offset / bs;
- offset = ((sector % (bs >> 9)) << 9) + lo->lo_offset % bs;
- if (offset >= bs)
- IV++;
-
- return IV;
-}
-
static int do_bh_filebacked(struct loop_device *lo, struct buffer_head *bh, int rw)
{
loff_t pos;
@@ -493,8 +511,11 @@
/*
* piggy old buffer on original, and submit for I/O
*/
- bh = loop_get_buffer(lo, rbh);
IV = loop_get_iv(lo, rbh->b_rsector);
+
+ bh = loop_get_buffer(lo, rbh);
+ bh->b_private = rbh;
+
if (rw == WRITE) {
set_bit(BH_Dirty, &bh->b_state);
if (lo_do_transfer(lo, WRITE, bh->b_data, rbh->b_data,
@@ -663,6 +684,7 @@
lo->lo_backing_file = file;
lo->transfer = NULL;
lo->ioctl = NULL;
+ lo->lo_iv_mode = LO_IV_MODE_DEFAULT;
figure_loop_size(lo);
lo->old_gfp_mask = inode->i_mapping->gfp_mask;
inode->i_mapping->gfp_mask = GFP_NOIO;
@@ -672,7 +694,7 @@
bs = blksize_size[MAJOR(lo_device)][MINOR(lo_device)];
if (!bs)
bs = BLOCK_SIZE;
-
+
set_blocksize(dev, bs);
lo->lo_bh = lo->lo_bhtail = NULL;