Re: [CFT][PATCH] loopback fixes for 2.3

From: Alexander Viro (aviro@redhat.com)
Date: Sat Feb 12 2000 - 19:52:01 EST


On Sat, 12 Feb 2000, Alexander Viro wrote:

>
>
>
> On Sun, 13 Feb 2000, Andi Kleen wrote:
>
> > > The bottom line: encryption driver can trivially compensate for the change.
> > > So if it's a problem with on-disk format - fine, let's keep the transformation
> > > in the format-handling code.
> >
> > Unfortunately they can not. One design problem of loopback crypto is
> > that you cannot store any additional information. The only way to
> > check if the user entered the right password is to see if ext2 can mount
> > the file system. There is really no way to detect old and new format.
>
> HUH? You don't need the additional information. You need a different version
> of module that would work with 2.3/2.4 (and I hope that you didn't use
> loopback right before the change - it's severely fscked up as of 2.3.43).
> This version of module should take the page number/offset it got, take the
> lo->lo_dentry->d_inode->i_mapping, find mapping->bmap(mapping, block). That
> will be the on-disk block. What additional information are you talking about?
> Kernel version? lo->transfer() gets lo, it gets page->index, it gets offset
> within the page. What else do you need to calculate the physical block position
> (== old IV)?

Oh, crap... OK, so we need to pass actual _block_ number here. Fine, that will
be done. Will that satisfy you? Because the conversion from file- to disk-block
number is trivial.

Check the patch below (it also adds the sanity checks I missed in original
variant). With that _all_ you should do in the encryption module is

int new_transfer(lo,...,IV) {
        struct address_space mapping = lo->lo_dentry->d_inode->i_mapping;
        int block;
        if (mapping->bmap)
                block = mapping->bmap(mapping, IV);
        else
                block = IV;
        return old_tranfer(...., block);
}
(or just add the code to the beginning of your ->transfer(), indeed).
Oh, sorry - if your code doesn't handle larger-than-block sizes you'll need to
repeat that for IV+1, etc.

Patch to loop.c follows:

diff -urN linux-2.3.44/drivers/block/loop.c linux-bird.vm/drivers/block/loop.c
--- linux-2.3.44/drivers/block/loop.c Sat Feb 12 19:25:26 2000
+++ linux-bird.vm/drivers/block/loop.c Sat Feb 12 19:42:09 2000
@@ -40,10 +40,10 @@
  * it passes the underlying device's block number instead of the
  * offset. This makes it change for a given block when the file is
  * moved/restored/copied and also doesn't work over NFS.
- * AV, Feb 11, 2000: for files we pass the page index now. It should fix the
- * problem above. Since the granularity is PAGE_CACHE_SIZE now it seems to
- * be correct way. OTOH, taking the thing from x86 to Alpha may become
- * interesting, so we might want to rethink it.
+ * AV, Feb 12, 2000: we pass the logical block number now. It fixes the
+ * problem above. Encryption modules that used to rely on the old scheme
+ * should just call ->i_mapping->bmap() to calculate the physical block
+ * number.
  */
 
 #include <linux/module.h>
@@ -164,7 +164,8 @@
         loop_sizes[lo->lo_number] = size;
 }
 
-static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos)
+static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos,
+ int blksize)
 {
         struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
         struct address_space *mapping = lo->lo_dentry->d_inode->i_mapping;
@@ -177,6 +178,7 @@
         index = pos >> PAGE_CACHE_SHIFT;
         offset = pos & (PAGE_CACHE_SIZE - 1);
         while (len > 0) {
+ int IV = index * (PAGE_CACHE_SIZE/blksize) + offset/blksize;
                 size = PAGE_CACHE_SIZE - offset;
                 if (size > len)
                         size = len;
@@ -187,7 +189,7 @@
                 if (aops->prepare_write(page, offset, offset+size))
                         goto unlock;
                 kaddr = (char*)page_address(page);
- if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, index))
+ if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV))
                         goto write_fail;
                 if (aops->commit_write(file, page, offset, offset+size))
                         goto unlock;
@@ -217,6 +219,7 @@
 struct lo_read_data {
         struct loop_device *lo;
         char *data;
+ int blksize;
 };
 
 static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
@@ -225,12 +228,13 @@
         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->blksize) + offset/p->blksize;
 
         if (size > count)
                 size = count;
 
         kaddr = (char*)kmap(page);
- if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,page->index)) {
+ if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) {
                 size = 0;
                 printk(KERN_ERR "loop: transfer error block %ld\n",page->index);
                 desc->error = -EINVAL;
@@ -243,7 +247,8 @@
         return size;
 }
 
-static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos)
+static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos,
+ int blksize)
 {
         struct file *file = lo->lo_backing_file;
         struct lo_read_data cookie;
@@ -251,6 +256,7 @@
 
         cookie.lo = lo;
         cookie.data = data;
+ cookie.blksize = blksize;
         desc.written = 0;
         desc.count = len;
         desc.buf = (char*)&cookie;
@@ -287,8 +293,6 @@
 
         dest_addr = current_request->buffer;
         len = current_request->current_nr_sectors << 9;
- if (lo->lo_flags & LO_FLAGS_DO_BMAP)
- goto file_backed;
 
         blksize = BLOCK_SIZE;
         if (blksize_size[MAJOR(lo->lo_device)]) {
@@ -296,6 +300,10 @@
             if (!blksize)
               blksize = BLOCK_SIZE;
         }
+
+ if (lo->lo_flags & LO_FLAGS_DO_BMAP)
+ goto file_backed;
+
         if (blksize < 512) {
                 block = current_request->sector * (512/blksize);
                 offset = 0;
@@ -357,10 +365,10 @@
         pos = ((loff_t)current_request->sector << 9) + lo->lo_offset;
         spin_unlock_irq(&io_request_lock);
         if (current_request->cmd == WRITE) {
- if (lo_send(lo, dest_addr, len, pos))
+ if (lo_send(lo, dest_addr, len, pos, blksize))
                         goto error_out_lock;
         } else {
- if (lo_receive(lo, dest_addr, len, pos))
+ if (lo_receive(lo, dest_addr, len, pos, blksize))
                         goto error_out_lock;
         }
 done:
@@ -416,6 +424,7 @@
                    a file structure */
                 lo->lo_backing_file = NULL;
         } else if (S_ISREG(inode->i_mode)) {
+ struct address_space_operations *aops;
                 /* Backed by a regular file - we need to hold onto a file
                    structure for this file. Friggin' NFS can't live without
                    it on write and for reading we use do_generic_file_read(),
@@ -444,16 +453,23 @@
                                 lo->lo_backing_file = NULL;
                         }
                 }
+ aops = lo->lo_dentry->d_inode->i_mapping->a_ops;
+ /*
+ * If we can't read - sorry. If we only can't write - well,
+ * it's going to be read-only.
+ */
+ if (!aops->readpage)
+ error = -EINVAL;
+ else if (!aops->prepare_write || !aops->commit_write) {
+ lo->lo_flags |= LO_FLAGS_READ_ONLY;
         }
         if (error)
                 goto out_putf;
 
- if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) {
+ if (IS_RDONLY (inode) || is_read_only(lo->lo_device))
                 lo->lo_flags |= LO_FLAGS_READ_ONLY;
- set_device_ro(dev, 1);
- } else {
- set_device_ro(dev, 0);
- }
+
+ set_device_ro(dev, (lo->lo_flags & LO_FLAGS_READ_ONLY)!=0);
 
         lo->lo_dentry = dget(file->f_dentry);
         lo->transfer = NULL;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Feb 15 2000 - 21:00:23 EST