Re: Patch for drivers/block/loop.c (for encryption to work).

Andi Kleen (ak@muc.de)
02 Oct 1998 18:23:29 +0200


rohloff@informatik.tu-muenchen.de writes:

[Sorry for the late answer]

> Hi,
>
> I'm very interested in encryption using the loop device.
> (In fact I just coded the brand new Twofish algorithm by
> Bruce Schneier and others as module for the linux kernel.
> It will be released tomorrow.)
>
> First thanks for making the changes to loop.c so that encryption algorithms
> can now be written as modules.

[Explanation about bugs in the new loop module interface deleted].

I did the loop module changes. I know that there are bugs in it, and I
already have fixes for them, but I didn't get around yet to send them
to Linus. If you want you could test these patches, they work fine for
me but some additional testing would be good.

The old reference counting was completely broken, because it didn't handle
the circular dependencies correctly (between module setup code and fd counting
in loop.c)

On request I have a skipjack kernel module and a improved losetup tool
with better key setup (the old key setup was horrible) too.

-Andi

--- ../linus/linux/include/linux/loop.h Sat Sep 19 12:03:05 1998
+++ linux/include/linux/loop.h Sat Sep 12 15:33:02 1998
@@ -99,8 +99,12 @@
int (*transfer)(struct loop_device *lo, int cmd,
char *raw_buf, char *loop_buf, int size);
int (*init)(struct loop_device *, struct loop_info *);
- int (*release)(struct loop_device *);
+ /* release is called from loop_unregister_transfer or clr_fd */
+ int (*release)(struct loop_device *);
int (*ioctl)(struct loop_device *, int cmd, unsigned long arg);
+ /* lock and unlock manage the module use counts */
+ void (*lock)(struct loop_device *);
+ void (*unlock)(struct loop_device *);
};

int loop_register_transfer(struct loop_func_table *funcs);
--- ../linus/linux/drivers/block/loop.c Sat Sep 19 12:03:03 1998
+++ linux/drivers/block/loop.c Sat Sep 19 18:52:40 1998
@@ -1,4 +1,3 @@
-
/*
* linux/drivers/block/loop.c
*
@@ -22,9 +21,13 @@
* Still To Fix:
* - Advisory locking is ignored here.
* - Should use an own CAP_* category instead of CAP_SYS_ADMIN
+ * - Should use the underlying filesystems/devices read function if possible
+ * to support read ahead (and for write)
*/

#include <linux/module.h>
+
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/file.h>
@@ -305,7 +308,7 @@
file->f_version = ++event;
}

- if ((file->f_mode & FMODE_WRITE) == 0 || file->f_op->write == NULL) {
+ if (file->f_op->write == NULL) {
printk(KERN_WARNING "loop: cannot create block - file not writeable\n");
return FALSE;
}
@@ -421,15 +424,32 @@
{
int err = 0;
if (lo->lo_encrypt_type) {
- if (xfer_funcs[lo->lo_encrypt_type] &&
- xfer_funcs[lo->lo_encrypt_type]->release) {
- err = xfer_funcs[lo->lo_encrypt_type]->release(lo);
- }
+ struct loop_func_table *xfer= xfer_funcs[lo->lo_encrypt_type];
+ if (xfer && xfer->release)
+ err = xfer->release(lo);
+ if (xfer && xfer->unlock)
+ xfer->unlock(lo);
lo->lo_encrypt_type = 0;
}
return err;
}

+static int loop_init_xfer(struct loop_device *lo, int type,struct loop_info *i)
+{
+ int err = 0;
+ if (type) {
+ struct loop_func_table *xfer = xfer_funcs[type];
+ if (xfer->init)
+ err = xfer->init(lo, i);
+ if (!err) {
+ lo->lo_encrypt_type = type;
+ if (xfer->lock)
+ xfer->lock(lo);
+ }
+ }
+ return err;
+}
+
static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
{
struct dentry *dentry = lo->lo_dentry;
@@ -450,6 +470,7 @@
dput(dentry);
}

+ loop_release_xfer(lo);
lo->transfer = NULL;
lo->ioctl = NULL;
lo->lo_device = 0;
@@ -482,17 +503,14 @@
type = info.lo_encrypt_type;
if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL)
return -EINVAL;
- err = loop_release_xfer(lo);
- if (err)
- return err;
- if (xfer_funcs[type]->init)
- err = xfer_funcs[type]->init(lo, &info);
+ err = loop_release_xfer(lo);
+ if (!err)
+ err = loop_init_xfer(lo, type, &info);
if (err)
- return err;
+ return err;

lo->lo_offset = info.lo_offset;
strncpy(lo->lo_name, info.lo_name, LO_NAME_SIZE);
- lo->lo_encrypt_type = type;

lo->transfer = xfer_funcs[type]->transfer;
lo->ioctl = xfer_funcs[type]->ioctl;
@@ -573,7 +591,8 @@
static int lo_open(struct inode *inode, struct file *file)
{
struct loop_device *lo;
- int dev;
+ int dev, type;
+

if (!inode)
return -EINVAL;
@@ -586,6 +605,10 @@
return -ENODEV;
}
lo = &loop_dev[dev];
+
+ type = lo->lo_encrypt_type;
+ if (type && xfer_funcs[type] && xfer_funcs[type]->lock)
+ xfer_funcs[type]->lock(lo);
lo->lo_refcnt++;
MOD_INC_USE_COUNT;
return 0;
@@ -594,7 +617,7 @@
static int lo_release(struct inode *inode, struct file *file)
{
struct loop_device *lo;
- int dev, err = 0;
+ int dev, err;

if (!inode)
return 0;
@@ -606,14 +629,14 @@
if (dev >= MAX_LOOP)
return 0;
err = fsync_dev(inode->i_rdev);
- if (err < 0)
- return err;
lo = &loop_dev[dev];
if (lo->lo_refcnt <= 0)
printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", lo->lo_refcnt);
else {
- if (--lo->lo_refcnt == 0)
- err = loop_release_xfer(lo);
+ int type = lo->lo_encrypt_type;
+ --lo->lo_refcnt;
+ if (xfer_funcs[type] && xfer_funcs[type]->unlock)
+ xfer_funcs[type]->unlock(lo);
MOD_DEC_USE_COUNT;
}
return err;
@@ -647,11 +670,20 @@
return 0;
}

-/* Usage checking must be done by the caller - usually with MOD_INC/DEC_* */
int loop_unregister_transfer(int number)
{
+ struct loop_device *lo;
+
if ((unsigned)number >= MAX_LO_CRYPT)
return -EINVAL;
+ for (lo = &loop_dev[0]; lo < &loop_dev[MAX_LOOP]; lo++) {
+ int type = lo->lo_encrypt_type;
+ if (type == number) {
+ xfer_funcs[type]->release(lo);
+ lo->transfer = NULL;
+ lo->lo_encrypt_type = 0;
+ }
+ }
xfer_funcs[number] = NULL;
return 0;
}

-
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/