Commit eb63bae1 authored by Andries E. Brouwer's avatar Andries E. Brouwer Committed by Arnaldo Carvalho de Melo

[PATCH] loop.c cleanups

This does the following:
 - remove trailing spaces
 - make loop.h independent by including bio.h, blk.h, spinlock.h
 - 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;
 - replace the integer lo_encrypt_type by the pointer lo_encryption;
   there was a race with loop_unregister_transfer
 - 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.
parent b42db0f5
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* linux/drivers/block/loop.c * linux/drivers/block/loop.c
* *
* Written by Theodore Ts'o, 3/29/93 * Written by Theodore Ts'o, 3/29/93
* *
* Copyright 1993 by Theodore Ts'o. Redistribution of this file is * Copyright 1993 by Theodore Ts'o. Redistribution of this file is
* permitted under the GNU General Public License. * permitted under the GNU General Public License.
* *
...@@ -21,12 +21,12 @@ ...@@ -21,12 +21,12 @@
* Loadable modules and other fixes by AK, 1998 * Loadable modules and other fixes by AK, 1998
* *
* Make real block number available to downstream transfer functions, enables * 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, rhp@draper.net * Reed H. Petty, rhp@draper.net
* *
* Maximum number of loop devices now dynamic via max_loop module parameter. * Maximum number of loop devices now dynamic via max_loop module parameter.
* Russell Kroll <rkroll@exploits.org> 19990701 * Russell Kroll <rkroll@exploits.org> 19990701
* *
* Maximum number of loop devices when compiled-in now selectable by passing * Maximum number of loop devices when compiled-in now selectable by passing
* max_loop=<1-255> to the kernel on boot. * max_loop=<1-255> to the kernel on boot.
* Erik I. Bols, <eriki@himolde.no>, Oct 31, 1999 * Erik I. Bols, <eriki@himolde.no>, Oct 31, 1999
...@@ -40,19 +40,19 @@ ...@@ -40,19 +40,19 @@
* Heinz Mauelshagen <mge@sistina.com>, Feb 2002 * Heinz Mauelshagen <mge@sistina.com>, Feb 2002
* *
* Still To Fix: * Still To Fix:
* - Advisory locking is ignored here. * - Advisory locking is ignored here.
* - Should use an own CAP_* category instead of CAP_SYS_ADMIN * - Should use an own CAP_* category instead of CAP_SYS_ADMIN
* *
* WARNING/FIXME: * WARNING/FIXME:
* - The block number as IV passing to low level transfer functions is broken: * - The block number as IV passing to low level transfer functions is broken:
* it passes the underlying device's block number instead of the * it passes the underlying device's block number instead of the
* offset. This makes it change for a given block when the file is * offset. This makes it change for a given block when the file is
* moved/restored/copied and also doesn't work over NFS. * moved/restored/copied and also doesn't work over NFS.
* AV, Feb 12, 2000: we pass the logical block number now. It fixes the * 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 * problem above. Encryption modules that used to rely on the old scheme
* should just call ->i_mapping->bmap() to calculate the physical block * should just call ->i_mapping->bmap() to calculate the physical block
* number. * number.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -60,12 +60,10 @@ ...@@ -60,12 +60,10 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/bio.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/blk.h>
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
...@@ -127,24 +125,25 @@ static int xor_status(struct loop_device *lo, const struct loop_info64 *info) ...@@ -127,24 +125,25 @@ static int xor_status(struct loop_device *lo, const struct loop_info64 *info)
return 0; return 0;
} }
struct loop_func_table none_funcs = { struct loop_func_table none_funcs = {
.number = LO_CRYPT_NONE, .number = LO_CRYPT_NONE,
.transfer = transfer_none, .transfer = transfer_none,
}; };
struct loop_func_table xor_funcs = { struct loop_func_table xor_funcs = {
.number = LO_CRYPT_XOR, .number = LO_CRYPT_XOR,
.transfer = transfer_xor, .transfer = transfer_xor,
.init = xor_status .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] = { struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = {
&none_funcs, &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; loff_t size = lo->lo_backing_file->f_dentry->d_inode->i_mapping->host->i_size;
sector_t x; sector_t x;
...@@ -154,15 +153,17 @@ static int figure_loop_size(struct loop_device *lo) ...@@ -154,15 +153,17 @@ static int figure_loop_size(struct loop_device *lo)
*/ */
size = (size - lo->lo_offset) >> 9; size = (size - lo->lo_offset) >> 9;
x = (sector_t)size; x = (sector_t)size;
if ((loff_t)x != size) if ((loff_t)x != size)
return -EFBIG; return -EFBIG;
set_capacity(disks[lo->lo_number], size); set_capacity(disks[lo->lo_number], x);
return 0; return 0;
} }
static inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf, static inline int
char *lbuf, int size, sector_t rblock) lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
char *lbuf, int size, sector_t rblock)
{ {
if (!lo->transfer) if (!lo->transfer)
return 0; return 0;
...@@ -614,9 +615,12 @@ static int loop_thread(void *data) ...@@ -614,9 +615,12 @@ static int loop_thread(void *data)
daemonize("loop%d", lo->lo_number); 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 * loop can be used in an encrypted device,
be indirectly used during suspension */ * 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); set_user_nice(current, -20);
...@@ -771,36 +775,42 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, ...@@ -771,36 +775,42 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
return error; return error;
} }
static int loop_release_xfer(struct loop_device *lo) static int
loop_release_xfer(struct loop_device *lo)
{ {
int err = 0; int err = 0;
if (lo->lo_encrypt_type) { struct loop_func_table *xfer = lo->lo_encryption;
struct loop_func_table *xfer= xfer_funcs[lo->lo_encrypt_type];
if (xfer && xfer->release) if (xfer) {
err = xfer->release(lo); if (xfer->release)
if (xfer && xfer->unlock) err = xfer->release(lo);
xfer->unlock(lo); lo->transfer = NULL;
lo->lo_encrypt_type = 0; lo->lo_encryption = NULL;
module_put(xfer->owner);
} }
return err; return err;
} }
static int 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; int err = 0;
if (type) {
struct loop_func_table *xfer = xfer_funcs[type]; if (xfer) {
struct module *owner = xfer->owner;
if (!try_module_get(owner))
return -EINVAL;
if (xfer->init) if (xfer->init)
err = xfer->init(lo, i); err = xfer->init(lo, i);
if (!err) { if (err)
lo->lo_encrypt_type = type; module_put(owner);
if (xfer->lock) else
xfer->lock(lo); lo->lo_encryption = xfer;
}
} }
return err; return err;
} }
static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
{ {
...@@ -809,9 +819,11 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) ...@@ -809,9 +819,11 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
if (lo->lo_state != Lo_bound) if (lo->lo_state != Lo_bound)
return -ENXIO; return -ENXIO;
if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */ if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */
return -EBUSY; return -EBUSY;
if (filp==NULL)
if (filp == NULL)
return -EINVAL; return -EINVAL;
spin_lock_irq(&lo->lo_lock); spin_lock_irq(&lo->lo_lock);
...@@ -828,7 +840,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) ...@@ -828,7 +840,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
lo->transfer = NULL; lo->transfer = NULL;
lo->ioctl = NULL; lo->ioctl = NULL;
lo->lo_device = NULL; lo->lo_device = NULL;
lo->lo_encrypt_type = 0; lo->lo_encryption = NULL;
lo->lo_offset = 0; lo->lo_offset = 0;
lo->lo_encrypt_key_size = 0; lo->lo_encrypt_key_size = 0;
lo->lo_flags = 0; lo->lo_flags = 0;
...@@ -849,49 +861,55 @@ static int ...@@ -849,49 +861,55 @@ static int
loop_set_status(struct loop_device *lo, const struct loop_info64 *info) loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
{ {
int err; int err;
unsigned int type; struct loop_func_table *xfer;
loff_t offset;
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)) !capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (lo->lo_state != Lo_bound) if (lo->lo_state != Lo_bound)
return -ENXIO; return -ENXIO;
if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE) if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
return -EINVAL; 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); err = loop_release_xfer(lo);
if (!err) if (err)
err = loop_init_xfer(lo, type, info); return err;
offset = lo->lo_offset; if (info->lo_encrypt_type) {
if (offset != info->lo_offset) { unsigned int type = info->lo_encrypt_type;
lo->lo_offset = info->lo_offset;
if (figure_loop_size(lo)){
err = -EFBIG;
lo->lo_offset = offset;
}
}
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) 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); strlcpy(lo->lo_name, info->lo_name, LO_NAME_SIZE);
lo->transfer = xfer_funcs[type]->transfer; if (!xfer)
lo->ioctl = xfer_funcs[type]->ioctl; xfer = &none_funcs;
lo->transfer = xfer->transfer;
lo->ioctl = xfer->ioctl;
lo->lo_encrypt_key_size = info->lo_encrypt_key_size; lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
lo->lo_init[0] = info->lo_init[0]; lo->lo_init[0] = info->lo_init[0];
lo->lo_init[1] = info->lo_init[1]; lo->lo_init[1] = info->lo_init[1];
if (info->lo_encrypt_key_size) { 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); info->lo_encrypt_key_size);
lo->lo_key_owner = current->uid; lo->lo_key_owner = current->uid;
} }
return 0; return 0;
...@@ -917,7 +935,8 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info) ...@@ -917,7 +935,8 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info)
info->lo_offset = lo->lo_offset; info->lo_offset = lo->lo_offset;
info->lo_flags = lo->lo_flags; info->lo_flags = lo->lo_flags;
strlcpy(info->lo_name, lo->lo_name, LO_NAME_SIZE); 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)) { if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) {
info->lo_encrypt_key_size = lo->lo_encrypt_key_size; info->lo_encrypt_key_size = lo->lo_encrypt_key_size;
memcpy(info->lo_encrypt_key, lo->lo_encrypt_key, memcpy(info->lo_encrypt_key, lo->lo_encrypt_key,
...@@ -1060,30 +1079,22 @@ static int lo_ioctl(struct inode * inode, struct file * file, ...@@ -1060,30 +1079,22 @@ static int lo_ioctl(struct inode * inode, struct file * file,
static int lo_open(struct inode *inode, struct file *file) static int lo_open(struct inode *inode, struct file *file)
{ {
struct loop_device *lo = inode->i_bdev->bd_disk->private_data; struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
int type;
down(&lo->lo_ctl_mutex); 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++; lo->lo_refcnt++;
up(&lo->lo_ctl_mutex); up(&lo->lo_ctl_mutex);
return 0; return 0;
} }
static int lo_release(struct inode *inode, struct file *file) static int lo_release(struct inode *inode, struct file *file)
{ {
struct loop_device *lo = inode->i_bdev->bd_disk->private_data; struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
int type;
down(&lo->lo_ctl_mutex); down(&lo->lo_ctl_mutex);
type = lo->lo_encrypt_type;
--lo->lo_refcnt; --lo->lo_refcnt;
if (xfer_funcs[type] && xfer_funcs[type]->unlock)
xfer_funcs[type]->unlock(lo);
up(&lo->lo_ctl_mutex); up(&lo->lo_ctl_mutex);
return 0; return 0;
} }
...@@ -1103,34 +1114,41 @@ MODULE_LICENSE("GPL"); ...@@ -1103,34 +1114,41 @@ MODULE_LICENSE("GPL");
int loop_register_transfer(struct loop_func_table *funcs) 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; return -EINVAL;
xfer_funcs[funcs->number] = funcs; xfer_funcs[n] = funcs;
return 0; return 0;
} }
int loop_unregister_transfer(int number) int loop_unregister_transfer(int number)
{ {
struct loop_device *lo; unsigned int n = number;
struct loop_device *lo;
if ((unsigned)number >= MAX_LO_CRYPT) struct loop_func_table *xfer;
return -EINVAL;
for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) { if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL)
int type = lo->lo_encrypt_type; return -EINVAL;
if (type == number) {
xfer_funcs[type]->release(lo); xfer_funcs[n] = NULL;
lo->transfer = NULL;
lo->lo_encrypt_type = 0; 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_register_transfer);
EXPORT_SYMBOL(loop_unregister_transfer); EXPORT_SYMBOL(loop_unregister_transfer);
int __init loop_init(void) int __init loop_init(void)
{ {
int i; int i;
...@@ -1190,9 +1208,10 @@ int __init loop_init(void) ...@@ -1190,9 +1208,10 @@ int __init loop_init(void)
return -ENOMEM; return -ENOMEM;
} }
void loop_exit(void) void loop_exit(void)
{ {
int i; int i;
for (i = 0; i < max_loop; i++) { for (i = 0; i < max_loop; i++) {
del_gendisk(disks[i]); del_gendisk(disks[i]);
put_disk(disks[i]); put_disk(disks[i]);
......
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
#define LO_KEY_SIZE 32 #define LO_KEY_SIZE 32
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/bio.h>
#include <linux/blk.h>
#include <linux/spinlock.h>
/* Possible states of device */ /* Possible states of device */
enum { enum {
...@@ -22,18 +25,20 @@ enum { ...@@ -22,18 +25,20 @@ enum {
Lo_rundown, Lo_rundown,
}; };
struct loop_func_table;
struct loop_device { struct loop_device {
int lo_number; int lo_number;
int lo_refcnt; int lo_refcnt;
int lo_offset; int lo_offset;
int lo_encrypt_type;
int lo_encrypt_key_size;
int lo_flags; int lo_flags;
int (*transfer)(struct loop_device *, int cmd, int (*transfer)(struct loop_device *, int cmd,
char *raw_buf, char *loop_buf, int size, char *raw_buf, char *loop_buf, int size,
sector_t real_block); sector_t real_block);
char lo_name[LO_NAME_SIZE]; char lo_name[LO_NAME_SIZE];
char lo_encrypt_key[LO_KEY_SIZE]; char lo_encrypt_key[LO_KEY_SIZE];
int lo_encrypt_key_size;
struct loop_func_table *lo_encryption;
__u32 lo_init[2]; __u32 lo_init[2];
uid_t lo_key_owner; /* Who set the key */ uid_t lo_key_owner; /* Who set the key */
int (*ioctl)(struct loop_device *, int cmd, int (*ioctl)(struct loop_device *, int cmd,
...@@ -129,9 +134,7 @@ struct loop_func_table { ...@@ -129,9 +134,7 @@ struct loop_func_table {
/* release is called from loop_unregister_transfer or clr_fd */ /* release is called from loop_unregister_transfer or clr_fd */
int (*release)(struct loop_device *); int (*release)(struct loop_device *);
int (*ioctl)(struct loop_device *, int cmd, unsigned long arg); int (*ioctl)(struct loop_device *, int cmd, unsigned long arg);
/* lock and unlock manage the module use counts */ struct module *owner;
void (*lock)(struct loop_device *);
void (*unlock)(struct loop_device *);
}; };
int loop_register_transfer(struct loop_func_table *funcs); int loop_register_transfer(struct loop_func_table *funcs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment