2003-06-23 01:14:14

by Andries E. Brouwer

[permalink] [raw]
Subject: [PATCH] loop.c - part 1 of many

> If you, Andries, are really volunteering to split the patch up,
> you're my hero :)

Below a patch for loop.[ch]. It can be applied.

This does the following:
(i) remove trailing spaces
(ii) make loop.h independent by including bio.h, blk.h, spinlock.h
(iii) replace the lock/unlock functions by module_get/module_put;
in struct loop this is the change
- void (*lock)(struct loop_device *);
- void (*unlock)(struct loop_device *);
+ struct module *owner;
(iv) replace the integer lo_encrypt_type by the pointer lo_encryption;
there was a race with loop_unregister_transfer
(v) fixed an off-by-one in loop_register_transfer

This is Step 1 of a series of half a dozen or so.

Half of the above is from Jari. Anything that is wrong is mine.
It compiles and works with my own crypto algorithm.

An unusual part is that the crypto algorithm module can be removed
any moment, even when it is in use. I am not sure I like that, will
probably change this in a subsequent patch unless people convince me
that this was done for a good reason.

Andries

diff -u --recursive --new-file -X /linux/dontdiff a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c Sun Jun 15 01:40:53 2003
+++ b/drivers/block/loop.c Mon Jun 23 03:44:06 2003
@@ -2,7 +2,7 @@
* linux/drivers/block/loop.c
*
* Written by Theodore Ts'o, 3/29/93
- *
+ *
* Copyright 1993 by Theodore Ts'o. Redistribution of this file is
* permitted under the GNU General Public License.
*
@@ -21,12 +21,12 @@
* Loadable modules and other fixes by AK, 1998
*
* Make real block number available to downstream transfer functions, enables
- * CBC (and relatives) mode encryption requiring unique IVs per data block.
+ * CBC (and relatives) mode encryption requiring unique IVs per data block.
* Reed H. Petty, [email protected]
*
* Maximum number of loop devices now dynamic via max_loop module parameter.
* Russell Kroll <[email protected]> 19990701
- *
+ *
* Maximum number of loop devices when compiled-in now selectable by passing
* max_loop=<1-255> to the kernel on boot.
* Erik I. Bols?, <[email protected]>, Oct 31, 1999
@@ -40,19 +40,19 @@
* Heinz Mauelshagen <[email protected]>, Feb 2002
*
* Still To Fix:
- * - Advisory locking is ignored here.
- * - Should use an own CAP_* category instead of CAP_SYS_ADMIN
+ * - Advisory locking is ignored here.
+ * - Should use an own CAP_* category instead of CAP_SYS_ADMIN
*
* WARNING/FIXME:
* - The block number as IV passing to low level transfer functions is broken:
* 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.
+ * 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 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/config.h>
#include <linux/module.h>
@@ -60,12 +60,10 @@
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/file.h>
-#include <linux/bio.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/wait.h>
-#include <linux/blk.h>
#include <linux/blkpg.h>
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
@@ -127,24 +125,25 @@
return 0;
}

-struct loop_func_table none_funcs = {
+struct loop_func_table none_funcs = {
.number = LO_CRYPT_NONE,
.transfer = transfer_none,
};

-struct loop_func_table xor_funcs = {
+struct loop_func_table xor_funcs = {
.number = LO_CRYPT_XOR,
.transfer = transfer_xor,
.init = xor_status
};

-/* xfer_funcs[0] is special - its release function is never called */
+/* xfer_funcs[0] is special - its release function is never called */
struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = {
&none_funcs,
- &xor_funcs
+ &xor_funcs
};

-static int figure_loop_size(struct loop_device *lo)
+static int
+figure_loop_size(struct loop_device *lo)
{
loff_t size = lo->lo_backing_file->f_dentry->d_inode->i_mapping->host->i_size;
sector_t x;
@@ -154,15 +153,17 @@
*/
size = (size - lo->lo_offset) >> 9;
x = (sector_t)size;
+
if ((loff_t)x != size)
return -EFBIG;

- set_capacity(disks[lo->lo_number], size);
+ set_capacity(disks[lo->lo_number], x);
return 0;
}

-static inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
- char *lbuf, int size, sector_t rblock)
+static inline int
+lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
+ char *lbuf, int size, sector_t rblock)
{
if (!lo->transfer)
return 0;
@@ -614,9 +615,12 @@

daemonize("loop%d", lo->lo_number);

- current->flags |= PF_IOTHREAD; /* loop can be used in an encrypted device
- hence, it mustn't be stopped at all because it could
- be indirectly used during suspension */
+ /*
+ * loop can be used in an encrypted device,
+ * hence, it mustn't be stopped at all
+ * because it could be indirectly used during suspension
+ */
+ current->flags |= PF_IOTHREAD;

set_user_nice(current, -20);

@@ -771,36 +775,42 @@
return error;
}

-static int loop_release_xfer(struct loop_device *lo)
+static int
+loop_release_xfer(struct loop_device *lo)
{
- int err = 0;
- if (lo->lo_encrypt_type) {
- 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;
+ int err = 0;
+ struct loop_func_table *xfer = lo->lo_encryption;
+
+ if (xfer) {
+ if (xfer->release)
+ err = xfer->release(lo);
+ lo->transfer = NULL;
+ lo->lo_encryption = NULL;
+ module_put(xfer->owner);
}
return err;
}

static int
-loop_init_xfer(struct loop_device *lo, int type, const struct loop_info64 *i)
+loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer,
+ const struct loop_info64 *i)
{
- int err = 0;
- if (type) {
- struct loop_func_table *xfer = xfer_funcs[type];
+ int err = 0;
+
+ if (xfer) {
+ struct module *owner = xfer->owner;
+
+ if (!try_module_get(owner))
+ return -EINVAL;
if (xfer->init)
err = xfer->init(lo, i);
- if (!err) {
- lo->lo_encrypt_type = type;
- if (xfer->lock)
- xfer->lock(lo);
- }
+ if (err)
+ module_put(owner);
+ else
+ lo->lo_encryption = xfer;
}
return err;
-}
+}

static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
{
@@ -809,9 +819,11 @@

if (lo->lo_state != Lo_bound)
return -ENXIO;
+
if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */
return -EBUSY;
- if (filp==NULL)
+
+ if (filp == NULL)
return -EINVAL;

spin_lock_irq(&lo->lo_lock);
@@ -828,7 +840,7 @@
lo->transfer = NULL;
lo->ioctl = NULL;
lo->lo_device = NULL;
- lo->lo_encrypt_type = 0;
+ lo->lo_encryption = NULL;
lo->lo_offset = 0;
lo->lo_encrypt_key_size = 0;
lo->lo_flags = 0;
@@ -849,49 +861,55 @@
loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
{
int err;
- unsigned int type;
- loff_t offset;
+ struct loop_func_table *xfer;

- if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid &&
+ if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
if (lo->lo_state != Lo_bound)
return -ENXIO;
if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
return -EINVAL;
- type = info->lo_encrypt_type;
- if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL)
- return -EINVAL;
- if (type == LO_CRYPT_XOR && info->lo_encrypt_key_size == 0)
- return -EINVAL;

err = loop_release_xfer(lo);
- if (!err)
- err = loop_init_xfer(lo, type, info);
+ if (err)
+ return err;

- offset = lo->lo_offset;
- if (offset != info->lo_offset) {
- lo->lo_offset = info->lo_offset;
- if (figure_loop_size(lo)){
- err = -EFBIG;
- lo->lo_offset = offset;
- }
- }
+ if (info->lo_encrypt_type) {
+ unsigned int type = info->lo_encrypt_type;
+
+ if (type >= MAX_LO_CRYPT)
+ return -EINVAL;
+ xfer = xfer_funcs[type];
+ if (xfer == NULL)
+ return -EINVAL;
+ } else
+ xfer = NULL;

+ err = loop_init_xfer(lo, xfer, info);
if (err)
- return err;
+ return err;
+
+ if (lo->lo_offset != info->lo_offset) {
+ lo->lo_offset = info->lo_offset;
+ if (figure_loop_size(lo))
+ return -EFBIG;
+ }

strlcpy(lo->lo_name, info->lo_name, LO_NAME_SIZE);

- lo->transfer = xfer_funcs[type]->transfer;
- lo->ioctl = xfer_funcs[type]->ioctl;
+ if (!xfer)
+ xfer = &none_funcs;
+ lo->transfer = xfer->transfer;
+ lo->ioctl = xfer->ioctl;
+
lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
lo->lo_init[0] = info->lo_init[0];
lo->lo_init[1] = info->lo_init[1];
if (info->lo_encrypt_key_size) {
- memcpy(lo->lo_encrypt_key, info->lo_encrypt_key,
+ memcpy(lo->lo_encrypt_key, info->lo_encrypt_key,
info->lo_encrypt_key_size);
- lo->lo_key_owner = current->uid;
+ lo->lo_key_owner = current->uid;
}

return 0;
@@ -917,7 +935,8 @@
info->lo_offset = lo->lo_offset;
info->lo_flags = lo->lo_flags;
strlcpy(info->lo_name, lo->lo_name, LO_NAME_SIZE);
- info->lo_encrypt_type = lo->lo_encrypt_type;
+ info->lo_encrypt_type =
+ lo->lo_encryption ? lo->lo_encryption->number : 0;
if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) {
info->lo_encrypt_key_size = lo->lo_encrypt_key_size;
memcpy(info->lo_encrypt_key, lo->lo_encrypt_key,
@@ -1060,30 +1079,22 @@
static int lo_open(struct inode *inode, struct file *file)
{
struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
- int type;

down(&lo->lo_ctl_mutex);
-
- type = lo->lo_encrypt_type;
- if (type && xfer_funcs[type] && xfer_funcs[type]->lock)
- xfer_funcs[type]->lock(lo);
lo->lo_refcnt++;
up(&lo->lo_ctl_mutex);
+
return 0;
}

static int lo_release(struct inode *inode, struct file *file)
{
struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
- int type;

down(&lo->lo_ctl_mutex);
- type = lo->lo_encrypt_type;
--lo->lo_refcnt;
- if (xfer_funcs[type] && xfer_funcs[type]->unlock)
- xfer_funcs[type]->unlock(lo);
-
up(&lo->lo_ctl_mutex);
+
return 0;
}

@@ -1103,34 +1114,41 @@

int loop_register_transfer(struct loop_func_table *funcs)
{
- if ((unsigned)funcs->number > MAX_LO_CRYPT || xfer_funcs[funcs->number])
+ unsigned int n = funcs->number;
+
+ if (n >= MAX_LO_CRYPT || xfer_funcs[n])
return -EINVAL;
- xfer_funcs[funcs->number] = funcs;
- return 0;
+ xfer_funcs[n] = funcs;
+ return 0;
}

int loop_unregister_transfer(int number)
{
- struct loop_device *lo;
+ unsigned int n = number;
+ struct loop_device *lo;
+ struct loop_func_table *xfer;

- 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;
- }
+ if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL)
+ return -EINVAL;
+
+ xfer_funcs[n] = NULL;
+
+ for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) {
+ down(&lo->lo_ctl_mutex);
+
+ if (lo->lo_encryption == xfer)
+ loop_release_xfer(lo);
+
+ up(&lo->lo_ctl_mutex);
}
- xfer_funcs[number] = NULL;
- return 0;
+
+ return 0;
}

EXPORT_SYMBOL(loop_register_transfer);
EXPORT_SYMBOL(loop_unregister_transfer);

-int __init loop_init(void)
+int __init loop_init(void)
{
int i;

@@ -1190,9 +1208,10 @@
return -ENOMEM;
}

-void loop_exit(void)
+void loop_exit(void)
{
int i;
+
for (i = 0; i < max_loop; i++) {
del_gendisk(disks[i]);
put_disk(disks[i]);
diff -u --recursive --new-file -X /linux/dontdiff a/include/linux/loop.h b/include/linux/loop.h
--- a/include/linux/loop.h Sun Jun 15 01:41:06 2003
+++ b/include/linux/loop.h Mon Jun 23 03:42:22 2003
@@ -14,6 +14,9 @@
#define LO_KEY_SIZE 32

#ifdef __KERNEL__
+#include <linux/bio.h>
+#include <linux/blk.h>
+#include <linux/spinlock.h>

/* Possible states of device */
enum {
@@ -22,18 +25,20 @@
Lo_rundown,
};

+struct loop_func_table;
+
struct loop_device {
int lo_number;
int lo_refcnt;
int lo_offset;
- int lo_encrypt_type;
- int lo_encrypt_key_size;
int lo_flags;
int (*transfer)(struct loop_device *, int cmd,
char *raw_buf, char *loop_buf, int size,
sector_t real_block);
char lo_name[LO_NAME_SIZE];
char lo_encrypt_key[LO_KEY_SIZE];
+ int lo_encrypt_key_size;
+ struct loop_func_table *lo_encryption;
__u32 lo_init[2];
uid_t lo_key_owner; /* Who set the key */
int (*ioctl)(struct loop_device *, int cmd,
@@ -129,9 +134,7 @@
/* 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 *);
+ struct module *owner;
};

int loop_register_transfer(struct loop_func_table *funcs);


2003-06-23 01:33:31

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH] loop.c - part 1 of many

On Mon, Jun 23, 2003 at 03:27:51AM +0200, [email protected] wrote:

> -static int figure_loop_size(struct loop_device *lo)
> +static int
> +figure_loop_size(struct loop_device *lo)

Please, don't. See recent flamewar re conversion from K&R style -
splitting declaration before function name is a Bad Thing(tm).

2003-06-23 05:07:35

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH] loop.c - part 1 of many

On Mon, Jun 23, 2003 at 03:27:51AM +0200, [email protected] wrote:
> -static int figure_loop_size(struct loop_device *lo)
> +static int
> +figure_loop_size(struct loop_device *lo)

This moves away from Documentation/CondingStyle..

> int loop_register_transfer(struct loop_func_table *funcs)
> {
> - if ((unsigned)funcs->number > MAX_LO_CRYPT || xfer_funcs[funcs->number])
> + unsigned int n = funcs->number;
> +
> + if (n >= MAX_LO_CRYPT || xfer_funcs[n])
> return -EINVAL;
> - xfer_funcs[funcs->number] = funcs;
> - return 0;
> + xfer_funcs[n] = funcs;
> + return 0;
> }

Once you start touching loop_{,un}register_transfer please also get
rid of the array in favour of a linked list..

2003-06-23 08:26:38

by Andries E. Brouwer

[permalink] [raw]
Subject: Re: [PATCH] loop.c - part 1 of many

hch:

> Once you start touching loop_{,un}register_transfer please also get
> rid of the array in favour of a linked list..

Why do you think that might be a good idea? General elegance?
The array is legacy only - it will not grow.
It has length 20, and only three entries are frequently used:
18 for CryptoAPI, 16 for loopAES, 0 for no encryption.

Andries

2003-06-23 08:29:59

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH] loop.c - part 1 of many

On Mon, Jun 23, 2003 at 10:40:32AM +0200, [email protected] wrote:
> Why do you think that might be a good idea? General elegance?
> The array is legacy only - it will not grow.
> It has length 20, and only three entries are frequently used:
> 18 for CryptoAPI, 16 for loopAES, 0 for no encryption.

Having fixed arrays for extenions is generally a bad design, yes.
Also selection of those extensions by magic number is very very bad,
IMHO we should replace it with a by-name selection before any other
transformation is added to the kernel so we can just special-case the
existing two onesand stop worrying about magic numbers.

2003-06-23 08:33:32

by Andries E. Brouwer

[permalink] [raw]
Subject: Re: [PATCH] loop.c - part 1 of many

> IMHO we should replace it with a by-name selection

But it has already been replaced by by-name selection.
That is what CryptoAPI does.

2003-06-23 08:35:04

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH] loop.c - part 1 of many

On Mon, Jun 23, 2003 at 10:47:35AM +0200, [email protected] wrote:
> But it has already been replaced by by-name selection.
> That is what CryptoAPI does.

The last time I checked CryptoAPI did _not_ replace it but add another
level of indirection.

2003-06-23 08:45:32

by Andries E. Brouwer

[permalink] [raw]
Subject: Re: [PATCH] loop.c - part 1 of many

>>> IMHO we should replace it with a by-name selection

>> That is what CryptoAPI does

> CryptoAPI did _not_ replace it but add another level of indirection

Right. That is backwards compatibility for you.
algorithm 0: no encryption
algorithm 1: XOR
algorithm 2: DES
...
algorithm 16: AES
...
algorithm 18: CryptoAPI - select by name

Changing this, while at the same time remaining backwards compatible,
would only uglify the kernel, for no reason whatsoever.
And I am not breaking user space, if I can avoid it.

Andries

2003-06-23 14:03:35

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH] loop.c - part 1 of many

On Mon, Jun 23, 2003 at 10:59:35AM +0200, [email protected] wrote:
> >>> IMHO we should replace it with a by-name selection
>
> >> That is what CryptoAPI does
>
> > CryptoAPI did _not_ replace it but add another level of indirection
>
> Right. That is backwards compatibility for you.

The only backwards-compatiblity we care for in mainline is
XOR and special-casing that is trivial, we don't even need to support
anything else with the by magic number ioctl. In fact I wonder
whether we should care for X0R - I know of exactly one real-life use...

2003-06-23 16:01:22

by Paul Komkoff

[permalink] [raw]
Subject: [Q] loop.c

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Replying to [email protected]:
> Below a patch for loop.[ch]. It can be applied.

Please, can anybody review the possibility of making offset LARGEFILE-capable?
I was stuck in it couple of time, yes, not yet understood what actually
happening inside loop.c to just blindly add new ioctl and do loff_t
internally.

Maybe I'm too stupid for this and it have more elegant solution than coding
what I've said ...

- --
Paul P 'Stingray' Komkoff Jr // http://stingr.net/key <- my pgp key
This message represents the official view of the voices in my head
-----BEGIN PGP SIGNATURE-----

iD8DBQE+9ydlyMW8naS07KQRAiocAKCVSom0DtFtvEb3bbeWY1uda2iJkgCgu8E2
IoAERy2wzdhbc2Q5Z7zpFqs=
=DbIz
-----END PGP SIGNATURE-----

2003-06-23 23:17:22

by Andries Brouwer

[permalink] [raw]
Subject: Re: [Q] loop.c

On Mon, Jun 23, 2003 at 08:14:30PM +0400, Paul P Komkoff Jr wrote:

> Replying to [email protected]:
> > Below a patch for loop.[ch]. It can be applied.
>
> Please, can anybody review the possibility of making offset LARGEFILE-capable?

These patches make lo_offset a loff_t.

2003-06-24 05:12:34

by Paul Komkoff

[permalink] [raw]
Subject: Re: [Q] loop.c

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Replying to Andries Brouwer:
> These patches make lo_offset a loff_t.

ioctls are still passing 32bit value?

- --
Paul P 'Stingray' Komkoff Jr // http://stingr.net/key <- my pgp key
This message represents the official view of the voices in my head
-----BEGIN PGP SIGNATURE-----

iD8DBQE+9+EKyMW8naS07KQRAr6wAKDEzItu+8ZSaLODV7RO5WgZ4UAcYgCfZZsh
PGFhBGvkbRWd3oDHpbbVWc8=
=cWKH
-----END PGP SIGNATURE-----