Commit b6c7f357 authored by Andries E. Brouwer's avatar Andries E. Brouwer Committed by Linus Torvalds

[PATCH] loop.c - part 2 of N

This does the following:

 - IV value is current 512-byte sector relative to start of loop
   container file.  This is what all cryptoloop people have done, if I
   am not mistaken.  Andi or others - if you can demonstrate the need
   for a more flexible setup an additional ioctl field may be needed.  I
   hope we can do without.

 - made some things static

 - made lo_offset a loff_t

 - added lo_sizelimit

   If one wanted a (crypto)loop somewhere inside a container file, the
   old code allowed a starting offset, but no size, so that the
   cryptoloop always extended to the end of the container file.  This
   field allows one to select an arbitrary interval.  Note that this
   changes struct loop_info64.

 - improve error handling of loop_init()

 - removed the unused typedef transfer_proc_t.

 - added a define for LO_CRYPT_CRYPTOAPI
parent 7602aa8d
...@@ -43,15 +43,6 @@ ...@@ -43,15 +43,6 @@
* - 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:
* - 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.
* 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/config.h>
...@@ -118,26 +109,26 @@ static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf, ...@@ -118,26 +109,26 @@ static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf,
return 0; return 0;
} }
static int xor_status(struct loop_device *lo, const struct loop_info64 *info) static int xor_init(struct loop_device *lo, const struct loop_info64 *info)
{ {
if (info->lo_encrypt_key_size <= 0) if (info->lo_encrypt_key_size <= 0)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
struct loop_func_table none_funcs = { static 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 = { static 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_init
}; };
/* 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] = { static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = {
&none_funcs, &none_funcs,
&xor_funcs &xor_funcs
}; };
...@@ -145,13 +136,21 @@ struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { ...@@ -145,13 +136,21 @@ struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = {
static int static int
figure_loop_size(struct loop_device *lo) 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, offset, loopsize;
sector_t x; sector_t x;
/* Compute loopsize in bytes */
size = lo->lo_backing_file->f_dentry->d_inode->i_mapping->host->i_size;
offset = lo->lo_offset;
loopsize = size - offset;
if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize)
loopsize = lo->lo_sizelimit;
/* /*
* Unfortunately, if we want to do I/O on the device, * Unfortunately, if we want to do I/O on the device,
* the number of 512-byte sectors has to fit into a sector_t. * the number of 512-byte sectors has to fit into a sector_t.
*/ */
size = (size - lo->lo_offset) >> 9; size = loopsize >> 9;
x = (sector_t)size; x = (sector_t)size;
if ((loff_t)x != size) if ((loff_t)x != size)
...@@ -190,9 +189,11 @@ do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos) ...@@ -190,9 +189,11 @@ do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos)
data = kmap(bvec->bv_page) + bvec->bv_offset; data = kmap(bvec->bv_page) + bvec->bv_offset;
len = bvec->bv_len; len = bvec->bv_len;
while (len > 0) { while (len > 0) {
sector_t IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize; sector_t IV;
int transfer_result; int transfer_result;
IV = ((sector_t)index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9);
size = PAGE_CACHE_SIZE - offset; size = PAGE_CACHE_SIZE - offset;
if (size > len) if (size > len)
size = len; size = len;
...@@ -203,7 +204,8 @@ do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos) ...@@ -203,7 +204,8 @@ do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos)
if (aops->prepare_write(file, page, offset, offset+size)) if (aops->prepare_write(file, page, offset, offset+size))
goto unlock; goto unlock;
kaddr = kmap(page); kaddr = kmap(page);
transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV); transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset,
data, size, IV);
if (transfer_result) { if (transfer_result) {
/* /*
* The transfer failed, but we still write the data to * The transfer failed, but we still write the data to
...@@ -272,7 +274,9 @@ lo_read_actor(read_descriptor_t *desc, struct page *page, ...@@ -272,7 +274,9 @@ lo_read_actor(read_descriptor_t *desc, struct page *page,
unsigned long count = desc->count; unsigned long count = desc->count;
struct lo_read_data *p = (struct lo_read_data*)desc->buf; struct lo_read_data *p = (struct lo_read_data*)desc->buf;
struct loop_device *lo = p->lo; struct loop_device *lo = p->lo;
int IV = page->index * (PAGE_CACHE_SIZE/p->bsize) + offset/p->bsize; sector_t IV;
IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9);
if (size > count) if (size > count)
size = count; size = count;
...@@ -327,20 +331,6 @@ lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos) ...@@ -327,20 +331,6 @@ lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
return ret; return ret;
} }
static inline unsigned long
loop_get_iv(struct loop_device *lo, unsigned long sector)
{
int bs = lo->lo_blocksize;
unsigned long offset, IV;
IV = sector / (bs >> 9) + lo->lo_offset / bs;
offset = ((sector % (bs >> 9)) << 9) + lo->lo_offset % bs;
if (offset >= bs)
IV++;
return IV;
}
static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
{ {
loff_t pos; loff_t pos;
...@@ -504,11 +494,13 @@ static struct bio *loop_get_buffer(struct loop_device *lo, struct bio *rbh) ...@@ -504,11 +494,13 @@ static struct bio *loop_get_buffer(struct loop_device *lo, struct bio *rbh)
static int loop_transfer_bio(struct loop_device *lo, static int loop_transfer_bio(struct loop_device *lo,
struct bio *to_bio, struct bio *from_bio) struct bio *to_bio, struct bio *from_bio)
{ {
unsigned long IV = loop_get_iv(lo, from_bio->bi_sector); sector_t IV;
struct bio_vec *from_bvec, *to_bvec; struct bio_vec *from_bvec, *to_bvec;
char *vto, *vfrom; char *vto, *vfrom;
int ret = 0, i; int ret = 0, i;
IV = from_bio->bi_sector + (lo->lo_offset >> 9);
__bio_for_each_segment(from_bvec, from_bio, i, 0) { __bio_for_each_segment(from_bvec, from_bio, i, 0) {
to_bvec = &to_bio->bi_io_vec[i]; to_bvec = &to_bio->bi_io_vec[i];
...@@ -728,6 +720,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, ...@@ -728,6 +720,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
lo->lo_backing_file = file; lo->lo_backing_file = file;
lo->transfer = NULL; lo->transfer = NULL;
lo->ioctl = NULL; lo->ioctl = NULL;
lo->lo_sizelimit = 0;
if (figure_loop_size(lo)) { if (figure_loop_size(lo)) {
error = -EFBIG; error = -EFBIG;
fput(file); fput(file);
...@@ -842,6 +835,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) ...@@ -842,6 +835,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
lo->lo_device = NULL; lo->lo_device = NULL;
lo->lo_encryption = NULL; lo->lo_encryption = NULL;
lo->lo_offset = 0; lo->lo_offset = 0;
lo->lo_sizelimit = 0;
lo->lo_encrypt_key_size = 0; lo->lo_encrypt_key_size = 0;
lo->lo_flags = 0; lo->lo_flags = 0;
lo->lo_queue.queuedata = NULL; lo->lo_queue.queuedata = NULL;
...@@ -890,8 +884,10 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) ...@@ -890,8 +884,10 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
if (err) if (err)
return err; return err;
if (lo->lo_offset != info->lo_offset) { if (lo->lo_offset != info->lo_offset ||
lo->lo_sizelimit != info->lo_sizelimit) {
lo->lo_offset = info->lo_offset; lo->lo_offset = info->lo_offset;
lo->lo_sizelimit = info->lo_sizelimit;
if (figure_loop_size(lo)) if (figure_loop_size(lo))
return -EFBIG; return -EFBIG;
} }
...@@ -933,6 +929,7 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info) ...@@ -933,6 +929,7 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info)
info->lo_inode = stat.ino; info->lo_inode = stat.ino;
info->lo_rdevice = lo->lo_device ? stat.rdev : stat.dev; info->lo_rdevice = lo->lo_device ? stat.rdev : stat.dev;
info->lo_offset = lo->lo_offset; info->lo_offset = lo->lo_offset;
info->lo_sizelimit = lo->lo_sizelimit;
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 = info->lo_encrypt_type =
...@@ -948,11 +945,13 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info) ...@@ -948,11 +945,13 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info)
static void static void
loop_info64_from_old(const struct loop_info *info, struct loop_info64 *info64) loop_info64_from_old(const struct loop_info *info, struct loop_info64 *info64)
{ {
memset(info64, 0, sizeof(*info64));
info64->lo_number = info->lo_number; info64->lo_number = info->lo_number;
info64->lo_device = info->lo_device; info64->lo_device = info->lo_device;
info64->lo_inode = info->lo_inode; info64->lo_inode = info->lo_inode;
info64->lo_rdevice = info->lo_rdevice; info64->lo_rdevice = info->lo_rdevice;
info64->lo_offset = info->lo_offset; info64->lo_offset = info->lo_offset;
info64->lo_sizelimit = 0;
info64->lo_encrypt_type = info->lo_encrypt_type; info64->lo_encrypt_type = info->lo_encrypt_type;
info64->lo_encrypt_key_size = info->lo_encrypt_key_size; info64->lo_encrypt_key_size = info->lo_encrypt_key_size;
info64->lo_flags = info->lo_flags; info64->lo_flags = info->lo_flags;
...@@ -965,6 +964,7 @@ loop_info64_from_old(const struct loop_info *info, struct loop_info64 *info64) ...@@ -965,6 +964,7 @@ loop_info64_from_old(const struct loop_info *info, struct loop_info64 *info64)
static int static int
loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info) loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info)
{ {
memset(info, 0, sizeof(*info));
info->lo_number = info64->lo_number; info->lo_number = info64->lo_number;
info->lo_device = info64->lo_device; info->lo_device = info64->lo_device;
info->lo_inode = info64->lo_inode; info->lo_inode = info64->lo_inode;
...@@ -1152,7 +1152,7 @@ int __init loop_init(void) ...@@ -1152,7 +1152,7 @@ int __init loop_init(void)
{ {
int i; int i;
if ((max_loop < 1) || (max_loop > 256)) { if (max_loop < 1 || max_loop > 256) {
printk(KERN_WARNING "loop: invalid max_loop (must be between" printk(KERN_WARNING "loop: invalid max_loop (must be between"
" 1 and 256), using default (8)\n"); " 1 and 256), using default (8)\n");
max_loop = 8; max_loop = 8;
...@@ -1161,22 +1161,22 @@ int __init loop_init(void) ...@@ -1161,22 +1161,22 @@ int __init loop_init(void)
if (register_blkdev(LOOP_MAJOR, "loop")) if (register_blkdev(LOOP_MAJOR, "loop"))
return -EIO; return -EIO;
devfs_mk_dir("loop");
loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL); loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
if (!loop_dev) if (!loop_dev)
return -ENOMEM; goto out_mem1;
disks = kmalloc(max_loop * sizeof(struct gendisk *), GFP_KERNEL); disks = kmalloc(max_loop * sizeof(struct gendisk *), GFP_KERNEL);
if (!disks) if (!disks)
goto out_mem; goto out_mem2;
for (i = 0; i < max_loop; i++) { for (i = 0; i < max_loop; i++) {
disks[i] = alloc_disk(1); disks[i] = alloc_disk(1);
if (!disks[i]) if (!disks[i])
goto out_mem2; goto out_mem3;
} }
devfs_mk_dir("loop");
for (i = 0; i < max_loop; i++) { for (i = 0; i < max_loop; i++) {
struct loop_device *lo = &loop_dev[i]; struct loop_device *lo = &loop_dev[i];
struct gendisk *disk = disks[i]; struct gendisk *disk = disks[i];
...@@ -1198,12 +1198,14 @@ int __init loop_init(void) ...@@ -1198,12 +1198,14 @@ int __init loop_init(void)
printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop); printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
return 0; return 0;
out_mem2: out_mem3:
while (i--) while (i--)
put_disk(disks[i]); put_disk(disks[i]);
kfree(disks); kfree(disks);
out_mem: out_mem2:
kfree(loop_dev); kfree(loop_dev);
out_mem1:
unregister_blkdev(LOOP_MAJOR, "loop");
printk(KERN_ERR "loop: ran out of memory\n"); printk(KERN_ERR "loop: ran out of memory\n");
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -30,7 +30,8 @@ struct loop_func_table; ...@@ -30,7 +30,8 @@ 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; loff_t lo_offset;
loff_t lo_sizelimit;
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,
...@@ -64,10 +65,6 @@ struct loop_device { ...@@ -64,10 +65,6 @@ struct loop_device {
request_queue_t lo_queue; request_queue_t lo_queue;
}; };
typedef int (* transfer_proc_t)(struct loop_device *, int cmd,
char *raw_buf, char *loop_buf, int size,
int real_block);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
/* /*
...@@ -96,13 +93,14 @@ struct loop_info { ...@@ -96,13 +93,14 @@ struct loop_info {
}; };
struct loop_info64 { struct loop_info64 {
__u64 lo_device; /* ioctl r/o */ __u64 lo_device; /* ioctl r/o */
__u64 lo_inode; /* ioctl r/o */ __u64 lo_inode; /* ioctl r/o */
__u64 lo_rdevice; /* ioctl r/o */ __u64 lo_rdevice; /* ioctl r/o */
__u64 lo_offset; __u64 lo_offset;
__u32 lo_number; /* ioctl r/o */ __u64 lo_sizelimit;/* bytes, 0 == max available */
__u32 lo_number; /* ioctl r/o */
__u32 lo_encrypt_type; __u32 lo_encrypt_type;
__u32 lo_encrypt_key_size; /* ioctl w/o */ __u32 lo_encrypt_key_size; /* ioctl w/o */
__u32 lo_flags; /* ioctl r/o */ __u32 lo_flags; /* ioctl r/o */
__u8 lo_name[LO_NAME_SIZE]; __u8 lo_name[LO_NAME_SIZE];
__u8 lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ __u8 lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
...@@ -113,21 +111,22 @@ struct loop_info64 { ...@@ -113,21 +111,22 @@ struct loop_info64 {
* Loop filter types * Loop filter types
*/ */
#define LO_CRYPT_NONE 0 #define LO_CRYPT_NONE 0
#define LO_CRYPT_XOR 1 #define LO_CRYPT_XOR 1
#define LO_CRYPT_DES 2 #define LO_CRYPT_DES 2
#define LO_CRYPT_FISH2 3 /* Brand new Twofish encryption */ #define LO_CRYPT_FISH2 3 /* Twofish encryption */
#define LO_CRYPT_BLOW 4 #define LO_CRYPT_BLOW 4
#define LO_CRYPT_CAST128 5 #define LO_CRYPT_CAST128 5
#define LO_CRYPT_IDEA 6 #define LO_CRYPT_IDEA 6
#define LO_CRYPT_DUMMY 9 #define LO_CRYPT_DUMMY 9
#define LO_CRYPT_SKIPJACK 10 #define LO_CRYPT_SKIPJACK 10
#define MAX_LO_CRYPT 20 #define LO_CRYPT_CRYPTOAPI 18
#define MAX_LO_CRYPT 20
#ifdef __KERNEL__ #ifdef __KERNEL__
/* Support for loadable transfer modules */ /* Support for loadable transfer modules */
struct loop_func_table { struct loop_func_table {
int number; /* filter type */ int number; /* filter type */
int (*transfer)(struct loop_device *lo, int cmd, char *raw_buf, int (*transfer)(struct loop_device *lo, int cmd, char *raw_buf,
char *loop_buf, int size, sector_t real_block); char *loop_buf, int size, sector_t real_block);
int (*init)(struct loop_device *, const struct loop_info64 *); int (*init)(struct loop_device *, const struct loop_info64 *);
......
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