summaryrefslogtreecommitdiff
path: root/drivers/block
diff options
context:
space:
mode:
authorAndries E. Brouwer <andries.brouwer@cwi.nl>2003-06-22 04:37:32 -0700
committerArnaldo Carvalho de Melo <acme@conectiva.com.br>2003-06-22 04:37:32 -0700
commiteb63bae150b444d67e7bbd4d61611112286388e5 (patch)
treef88dad8ea99bafd8e29c7e7aec629b57824a1bdb /drivers/block
parentb42db0f5e2c6cff85595b23972595bcfaa470b27 (diff)
[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.
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/loop.c207
1 files changed, 113 insertions, 94 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index b0fefe1460cc..5e08a760f1d9 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -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, rhp@draper.net
*
* Maximum number of loop devices now dynamic via max_loop module parameter.
* Russell Kroll <rkroll@exploits.org> 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ų, <eriki@himolde.no>, Oct 31, 1999
@@ -40,19 +40,19 @@
* Heinz Mauelshagen <mge@sistina.com>, 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 @@ static int xor_status(struct loop_device *lo, const struct loop_info64 *info)
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 @@ static int figure_loop_size(struct loop_device *lo)
*/
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 @@ static int loop_thread(void *data)
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 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
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 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
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 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
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 @@ static int
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 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info)
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_ioctl(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;
- 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 @@ MODULE_LICENSE("GPL");
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;
-
- 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;
- }
+ unsigned int n = number;
+ struct loop_device *lo;
+ struct loop_func_table *xfer;
+
+ 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 @@ out_mem:
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]);