| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
#define CLOOP_NAME "cloop" |
|---|
| 24 |
#define CLOOP_VERSION "2.01" |
|---|
| 25 |
#define CLOOP_MAX 64 |
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
#include <linux/version.h> |
|---|
| 31 |
#include <linux/module.h> |
|---|
| 32 |
#include <linux/init.h> |
|---|
| 33 |
#include <linux/sched.h> |
|---|
| 34 |
#include <linux/fs.h> |
|---|
| 35 |
#include <linux/file.h> |
|---|
| 36 |
#include <linux/stat.h> |
|---|
| 37 |
#include <linux/errno.h> |
|---|
| 38 |
#include <linux/major.h> |
|---|
| 39 |
#include <linux/vmalloc.h> |
|---|
| 40 |
#include <linux/slab.h> |
|---|
| 41 |
#include <linux/devfs_fs_kernel.h> |
|---|
| 42 |
#include <asm/semaphore.h> |
|---|
| 43 |
#include <asm/div64.h> |
|---|
| 44 |
#include <asm/uaccess.h> |
|---|
| 45 |
|
|---|
| 46 |
#include <linux/zutil.h> |
|---|
| 47 |
#include <linux/loop.h> |
|---|
| 48 |
|
|---|
| 49 |
// #include <linux/buffer_head.h> |
|---|
| 50 |
// #endif |
|---|
| 51 |
#include "compressed_loop.h" |
|---|
| 52 |
|
|---|
| 53 |
|
|---|
| 54 |
|
|---|
| 55 |
|
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 |
|
|---|
| 59 |
#undef ntohl |
|---|
| 60 |
uint32_t ntohl(x) |
|---|
| 61 |
uint32_t x; |
|---|
| 62 |
{ |
|---|
| 63 |
#if BYTE_ORDER == LITTLE_ENDIAN |
|---|
| 64 |
u_char *s = (u_char *)&x; |
|---|
| 65 |
return (uint32_t)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); |
|---|
| 66 |
#else |
|---|
| 67 |
return x; |
|---|
| 68 |
#endif |
|---|
| 69 |
} |
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
#ifdef MODULE_LICENSE |
|---|
| 75 |
MODULE_LICENSE("GPL"); |
|---|
| 76 |
#endif |
|---|
| 77 |
#ifdef MODULE_AUTHOR |
|---|
| 78 |
MODULE_AUTHOR("Klaus Knopper (Kernel 2.4 and up, Knoppix version), Paul Russel (initial version)"); |
|---|
| 79 |
#endif |
|---|
| 80 |
#ifdef MODULE_DESCRIPTION |
|---|
| 81 |
MODULE_DESCRIPTION("Transparently decompressing loopback block device"); |
|---|
| 82 |
#endif |
|---|
| 83 |
|
|---|
| 84 |
#ifndef MIN |
|---|
| 85 |
#define MIN(x,y) ((x) < (y) ? (x) : (y)) |
|---|
| 86 |
#endif |
|---|
| 87 |
|
|---|
| 88 |
#ifndef MAX |
|---|
| 89 |
#define MAX(x,y) ((x) > (y) ? (x) : (y)) |
|---|
| 90 |
#endif |
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
#define MAJOR_NR 240 |
|---|
| 94 |
|
|---|
| 95 |
#define DEVICE_NAME CLOOP_NAME |
|---|
| 96 |
#define DEVICE_NR(device) (MINOR(device)) |
|---|
| 97 |
#define DEVICE_ON(device) |
|---|
| 98 |
#define DEVICE_OFF(device) |
|---|
| 99 |
#define DEVICE_NO_RANDOM |
|---|
| 100 |
#define TIMEOUT_VALUE (6 * HZ) |
|---|
| 101 |
|
|---|
| 102 |
#include <linux/blkdev.h> |
|---|
| 103 |
#include <linux/buffer_head.h> |
|---|
| 104 |
|
|---|
| 105 |
#if 0 |
|---|
| 106 |
#define DEBUGP printk |
|---|
| 107 |
#else |
|---|
| 108 |
#define DEBUGP(format, x...) |
|---|
| 109 |
#endif |
|---|
| 110 |
|
|---|
| 111 |
|
|---|
| 112 |
|
|---|
| 113 |
static char *file=NULL; |
|---|
| 114 |
MODULE_PARM(file, "s"); |
|---|
| 115 |
MODULE_PARM_DESC(file, "Initial cloop image file (full path) for /dev/cloop"); |
|---|
| 116 |
static struct file *initial_file=NULL; |
|---|
| 117 |
|
|---|
| 118 |
struct cloop_device |
|---|
| 119 |
{ |
|---|
| 120 |
|
|---|
| 121 |
struct cloop_head head; |
|---|
| 122 |
|
|---|
| 123 |
|
|---|
| 124 |
loff_t *offsets; |
|---|
| 125 |
|
|---|
| 126 |
|
|---|
| 127 |
int buffered_blocknum; |
|---|
| 128 |
void *buffer; |
|---|
| 129 |
void *compressed_buffer; |
|---|
| 130 |
|
|---|
| 131 |
z_stream zstream; |
|---|
| 132 |
|
|---|
| 133 |
struct file *backing_file; |
|---|
| 134 |
struct inode *backing_inode; |
|---|
| 135 |
|
|---|
| 136 |
unsigned int underlying_blksize; |
|---|
| 137 |
int refcnt; |
|---|
| 138 |
struct block_device *bdev; |
|---|
| 139 |
int isblkdev; |
|---|
| 140 |
struct semaphore clo_lock; |
|---|
| 141 |
struct gendisk *disk; |
|---|
| 142 |
request_queue_t *clo_queue; |
|---|
| 143 |
}; |
|---|
| 144 |
|
|---|
| 145 |
static struct cloop_device cloop_dev[CLOOP_MAX]; |
|---|
| 146 |
static char *cloop_name=CLOOP_NAME; |
|---|
| 147 |
static const int max_cloop = CLOOP_MAX; |
|---|
| 148 |
|
|---|
| 149 |
#if (!(defined(CONFIG_ZLIB_INFLATE) || defined(CONFIG_ZLIB_INFLATE_MODULE))) |
|---|
| 150 |
#error "Invalid Kernel configuration. CONFIG_ZLIB_INFLATE support is needed for cloop." |
|---|
| 151 |
#endif |
|---|
| 152 |
|
|---|
| 153 |
static int uncompress(struct cloop_device *clo, char *dest, unsigned long *destLen, |
|---|
| 154 |
char *source, unsigned long sourceLen) |
|---|
| 155 |
{ |
|---|
| 156 |
|
|---|
| 157 |
int err; |
|---|
| 158 |
clo->zstream.next_in = source; |
|---|
| 159 |
clo->zstream.avail_in = sourceLen; |
|---|
| 160 |
clo->zstream.next_out = dest; |
|---|
| 161 |
clo->zstream.avail_out = *destLen; |
|---|
| 162 |
err = zlib_inflateReset(&clo->zstream); |
|---|
| 163 |
if (err != Z_OK) |
|---|
| 164 |
{ |
|---|
| 165 |
printk(KERN_ERR "%s: zlib_inflateReset error %d\n", cloop_name, err); |
|---|
| 166 |
zlib_inflateEnd(&clo->zstream); zlib_inflateInit(&clo->zstream); |
|---|
| 167 |
} |
|---|
| 168 |
err = zlib_inflate(&clo->zstream, Z_FINISH); |
|---|
| 169 |
*destLen = clo->zstream.total_out; |
|---|
| 170 |
if (err != Z_STREAM_END) return err; |
|---|
| 171 |
return Z_OK; |
|---|
| 172 |
} |
|---|
| 173 |
|
|---|
| 174 |
|
|---|
| 175 |
struct clo_read_data |
|---|
| 176 |
{ |
|---|
| 177 |
struct cloop_device *clo; |
|---|
| 178 |
char *data; |
|---|
| 179 |
int bsize; |
|---|
| 180 |
}; |
|---|
| 181 |
|
|---|
| 182 |
|
|---|
| 183 |
|
|---|
| 184 |
static int clo_read_actor(read_descriptor_t * desc, struct page *page, |
|---|
| 185 |
unsigned long offset, unsigned long size) |
|---|
| 186 |
{ |
|---|
| 187 |
char *kaddr; |
|---|
| 188 |
struct clo_read_data *p = (struct clo_read_data*)desc->arg.buf; |
|---|
| 189 |
unsigned long count = desc->count; |
|---|
| 190 |
if (size > count) size = count; |
|---|
| 191 |
kaddr = kmap(page); |
|---|
| 192 |
memcpy(p->data, kaddr + offset, size); |
|---|
| 193 |
kunmap(page); |
|---|
| 194 |
desc->count = count - size; |
|---|
| 195 |
desc->written += size; |
|---|
| 196 |
p->data += size; |
|---|
| 197 |
return size; |
|---|
| 198 |
} |
|---|
| 199 |
|
|---|
| 200 |
static size_t clo_read_from_file(struct cloop_device *clo, struct file *f, char *buf, |
|---|
| 201 |
loff_t pos, size_t buf_len) |
|---|
| 202 |
{ |
|---|
| 203 |
size_t buf_done=0; |
|---|
| 204 |
while (buf_done < buf_len) |
|---|
| 205 |
{ |
|---|
| 206 |
size_t size = buf_len - buf_done; |
|---|
| 207 |
struct clo_read_data cd={ |
|---|
| 208 |
clo, |
|---|
| 209 |
(char *)(buf + buf_done), |
|---|
| 210 |
size}; |
|---|
| 211 |
read_descriptor_t desc; |
|---|
| 212 |
desc.written = 0; |
|---|
| 213 |
desc.count = size; |
|---|
| 214 |
desc.arg.buf = (char*)&cd; |
|---|
| 215 |
desc.error = 0; |
|---|
| 216 |
#ifdef REDHAT_KERNEL |
|---|
| 217 |
do_generic_file_read(f, &pos, &desc, clo_read_actor, 0); |
|---|
| 218 |
#else |
|---|
| 219 |
do_generic_file_read(f, &pos, &desc, clo_read_actor); |
|---|
| 220 |
#endif |
|---|
| 221 |
if(desc.error||desc.written<=0) |
|---|
| 222 |
{ |
|---|
| 223 |
int left = size - desc.written; |
|---|
| 224 |
if(left<0) left = 0; |
|---|
| 225 |
printk(KERN_ERR "%s: Read error at pos %Lu in file %s, %d bytes lost.\n", |
|---|
| 226 |
cloop_name, pos, file, left); |
|---|
| 227 |
memset(buf + buf_len - left, 0, left); |
|---|
| 228 |
break; |
|---|
| 229 |
} |
|---|
| 230 |
buf_done+=desc.written; |
|---|
| 231 |
} |
|---|
| 232 |
return buf_done; |
|---|
| 233 |
} |
|---|
| 234 |
|
|---|
| 235 |
|
|---|
| 236 |
static int load_buffer(struct cloop_device *clo, int blocknum) |
|---|
| 237 |
{ |
|---|
| 238 |
unsigned int buf_done = 0; |
|---|
| 239 |
unsigned long buflen; |
|---|
| 240 |
unsigned int buf_length; |
|---|
| 241 |
int ret; |
|---|
| 242 |
|
|---|
| 243 |
if(blocknum > ntohl(clo->head.num_blocks) || blocknum < 0) |
|---|
| 244 |
{ |
|---|
| 245 |
printk(KERN_WARNING "%s: Invalid block number %d requested.\n", |
|---|
| 246 |
cloop_name, blocknum); |
|---|
| 247 |
clo->buffered_blocknum = -1; |
|---|
| 248 |
return 0; |
|---|
| 249 |
} |
|---|
| 250 |
|
|---|
| 251 |
if (blocknum == clo->buffered_blocknum) return 1; |
|---|
| 252 |
|
|---|
| 253 |
|
|---|
| 254 |
buf_length = be64_to_cpu(clo->offsets[blocknum+1]) - be64_to_cpu(clo->offsets[blocknum]); |
|---|
| 255 |
|
|---|
| 256 |
|
|---|
| 257 |
clo_read_from_file(clo, clo->backing_file, (char *)clo->compressed_buffer, |
|---|
| 258 |
be64_to_cpu(clo->offsets[blocknum]), buf_length); |
|---|
| 259 |
|
|---|
| 260 |
|
|---|
| 261 |
buflen = ntohl(clo->head.block_size); |
|---|
| 262 |
|
|---|
| 263 |
|
|---|
| 264 |
ret = uncompress(clo, clo->buffer, &buflen, clo->compressed_buffer, |
|---|
| 265 |
buf_length); |
|---|
| 266 |
|
|---|
| 267 |
if (ret != 0) |
|---|
| 268 |
{ |
|---|
| 269 |
printk(KERN_ERR "%s: error %i uncompressing block %u %u/%lu/%u/%u " |
|---|
| 270 |
"%Lu-%Lu\n", cloop_name, ret, blocknum, |
|---|
| 271 |
ntohl(clo->head.block_size), buflen, buf_length, buf_done, |
|---|
| 272 |
be64_to_cpu(clo->offsets[blocknum]), be64_to_cpu(clo->offsets[blocknum+1])); |
|---|
| 273 |
clo->buffered_blocknum = -1; |
|---|
| 274 |
return 0; |
|---|
| 275 |
} |
|---|
| 276 |
clo->buffered_blocknum = blocknum; |
|---|
| 277 |
return 1; |
|---|
| 278 |
} |
|---|
| 279 |
|
|---|
| 280 |
static int make_clo_request(request_queue_t *q, struct bio *bio) |
|---|
| 281 |
{ |
|---|
| 282 |
struct cloop_device *cloop; |
|---|
| 283 |
int status = 0; |
|---|
| 284 |
unsigned int len; |
|---|
| 285 |
loff_t offset; |
|---|
| 286 |
char *dest; |
|---|
| 287 |
|
|---|
| 288 |
int rw = bio_rw(bio); |
|---|
| 289 |
unsigned int vecnr; |
|---|
| 290 |
cloop = q->queuedata; |
|---|
| 291 |
|
|---|
| 292 |
|
|---|
| 293 |
if (rw != READ && rw != READA) |
|---|
| 294 |
{ |
|---|
| 295 |
DEBUGP("do_clo_request: bad command\n"); |
|---|
| 296 |
goto out; |
|---|
| 297 |
} |
|---|
| 298 |
|
|---|
| 299 |
if (!cloop->backing_file) |
|---|
| 300 |
{ |
|---|
| 301 |
DEBUGP("do_clo_request: not connected to a file\n"); |
|---|
| 302 |
goto out; |
|---|
| 303 |
} |
|---|
| 304 |
|
|---|
| 305 |
down(&cloop->clo_lock); |
|---|
| 306 |
offset = (loff_t)bio->bi_sector << 9; |
|---|
| 307 |
for(vecnr=0; vecnr < bio->bi_vcnt; vecnr++) |
|---|
| 308 |
{ |
|---|
| 309 |
struct bio_vec *bvec=&bio->bi_io_vec[vecnr]; |
|---|
| 310 |
len = bvec->bv_len; |
|---|
| 311 |
dest= kmap(bvec->bv_page) + bvec->bv_offset; |
|---|
| 312 |
|
|---|
| 313 |
while(len > 0) |
|---|
| 314 |
{ |
|---|
| 315 |
u_int32_t length_in_buffer; |
|---|
| 316 |
loff_t block_offset=offset; |
|---|
| 317 |
|
|---|
| 318 |
|
|---|
| 319 |
|
|---|
| 320 |
|
|---|
| 321 |
|
|---|
| 322 |
u_int32_t offset_in_buffer; |
|---|
| 323 |
offset_in_buffer = do_div(block_offset, ntohl(cloop->head.block_size)); |
|---|
| 324 |
|
|---|
| 325 |
status=load_buffer(cloop,block_offset); |
|---|
| 326 |
if(!status) break; |
|---|
| 327 |
|
|---|
| 328 |
|
|---|
| 329 |
length_in_buffer = ntohl(cloop->head.block_size) - offset_in_buffer; |
|---|
| 330 |
|
|---|
| 331 |
if(length_in_buffer > len) |
|---|
| 332 |
{ |
|---|
| 333 |
|
|---|
| 334 |
|
|---|
| 335 |
length_in_buffer = len; |
|---|
| 336 |
} |
|---|
| 337 |
|
|---|
| 338 |
memcpy(dest, cloop->buffer + offset_in_buffer, length_in_buffer); |
|---|
| 339 |
|
|---|
| 340 |
dest += length_in_buffer; |
|---|
| 341 |
len -= length_in_buffer; |
|---|
| 342 |
offset += length_in_buffer; |
|---|
| 343 |
} |
|---|
| 344 |
|
|---|
| 345 |
kunmap(bvec->bv_page); |
|---|
| 346 |
} |
|---|
| 347 |
|
|---|
| 348 |
up(&cloop->clo_lock); |
|---|
| 349 |
|
|---|
| 350 |
out: |
|---|
| 351 |
bio_endio(bio, bio->bi_size,status==0); |
|---|
| 352 |
return 0; |
|---|
| 353 |
} |
|---|
| 354 |
|
|---|
| 355 |
|
|---|
| 356 |
static int clo_set_file(int cloop_num, struct file *file, char *filename) |
|---|
| 357 |
{ |
|---|
| 358 |
struct cloop_device *clo=&cloop_dev[cloop_num]; |
|---|
| 359 |
struct inode *inode; |
|---|
| 360 |
char *bbuf=NULL; |
|---|
| 361 |
unsigned int i, offsets_read, total_offsets; |
|---|
| 362 |
unsigned long largest_block=0; |
|---|
| 363 |
int isblkdev; |
|---|
| 364 |
|
|---|
| 365 |
int error = 0; |
|---|
| 366 |
|
|---|
| 367 |
inode = file->f_dentry->d_inode; |
|---|
| 368 |
isblkdev=S_ISBLK(inode->i_mode)?1:0; |
|---|
| 369 |
if(!isblkdev&&!S_ISREG(inode->i_mode)) |
|---|
| 370 |
{ |
|---|
| 371 |
printk(KERN_ERR "%s: %s not a regular file or block device\n", |
|---|
| 372 |
cloop_name, filename); |
|---|
| 373 |
error=-EBADF; goto error_release; |
|---|
| 374 |
} |
|---|
| 375 |
|
|---|
| 376 |
clo->backing_file = file; |
|---|
| 377 |
clo->backing_inode= inode ; |
|---|
| 378 |
|
|---|
| 379 |
if(!isblkdev&&inode->i_size<sizeof(struct cloop_head)) |
|---|
| 380 |
{ |
|---|
| 381 |
printk(KERN_ERR "%s: %lu bytes (must be >= %u bytes)\n", |
|---|
| 382 |
cloop_name, (unsigned long)inode->i_size, |
|---|
| 383 |
(unsigned)sizeof(struct cloop_head)); |
|---|
| 384 |
error=-EBADF; goto error_release; |
|---|
| 385 |
} |
|---|
| 386 |
|
|---|
| 387 |
|
|---|
| 388 |
|
|---|
| 389 |
|
|---|
| 390 |
|
|---|
| 391 |
|
|---|
| 392 |
|
|---|
| 393 |
|
|---|
| 394 |
|
|---|
| 395 |
|
|---|
| 396 |
|
|---|
| 397 |
|
|---|
| 398 |
|
|---|
| 399 |
clo->underlying_blksize = inode->i_blksize; |
|---|
| 400 |
|
|---|
| 401 |
DEBUGP("Underlying blocksize is %u\n", clo->underlying_blksize); |
|---|
| 402 |
|
|---|
| 403 |
bbuf = vmalloc(clo->underlying_blksize); |
|---|
| 404 |
if(!bbuf) |
|---|
| 405 |
{ |
|---|
| 406 |
printk(KERN_ERR "%s: out of kernel mem for block buffer (%lu bytes)\n", |
|---|
| 407 |
cloop_name, (unsigned long)clo->underlying_blksize); |
|---|
| 408 |
error=-ENOMEM; goto error_release; |
|---|
| 409 |
} |
|---|
| 410 |
total_offsets = 1; |
|---|
| 411 |
for (i = 0, offsets_read = 0; offsets_read < total_offsets; i++) |
|---|
| 412 |
{ |
|---|
| 413 |
unsigned int offset = 0, num_readable; |
|---|
| 414 |
|
|---|
| 415 |
|
|---|
| 416 |
size_t bytes_read = clo_read_from_file(clo, file, bbuf, |
|---|
| 417 |
i*clo->underlying_blksize, |
|---|
| 418 |
clo->underlying_blksize); |
|---|
| 419 |
if(bytes_read != clo->underlying_blksize) { error=-EBADF; goto error_release; } |
|---|
| 420 |
|
|---|
| 421 |
|
|---|
| 422 |
if(i==0) |
|---|
| 423 |
{ |
|---|
| 424 |
memcpy(&clo->head, bbuf, sizeof(struct cloop_head)); |
|---|
| 425 |
offset = sizeof(struct cloop_head); |
|---|
| 426 |
if (ntohl(clo->head.block_size) % 512 != 0) |
|---|
| 427 |
{ |
|---|
| 428 |
printk(KERN_ERR "%s: blocksize %u not multiple of 512\n", |
|---|
| 429 |
cloop_name, ntohl(clo->head.block_size)); |
|---|
| 430 |
error=-EBADF; goto error_release; |
|---|
| 431 |
} |
|---|
| 432 |
|
|---|
| 433 |
if (clo->head.preamble[0x0B]!='V'||clo->head.preamble[0x0C]<'1') |
|---|
| 434 |
{ |
|---|
| 435 |
printk(KERN_ERR "%s: Cannot read old 32-bit (version 0.68) images, " |
|---|
| 436 |
"please use an older version of %s for this file.\n", |
|---|
| 437 |
cloop_name, cloop_name); |
|---|
| 438 |
error=-EBADF; goto error_release; |
|---|
| 439 |
} |
|---|
| 440 |
|
|---|
| 441 |
if (clo->head.preamble[0x0C]<'2') |
|---|
| 442 |
{ |
|---|
| 443 |
printk(KERN_ERR "%s: Cannot read old architecture-dependent " |
|---|
| 444 |
"(format <= 1.0) images, please use an older " |
|---|
| 445 |
"version of %s for this file.\n", |
|---|
| 446 |
cloop_name, cloop_name); |
|---|
| 447 |
error=-EBADF; goto error_release; |
|---|
| 448 |
} |
|---|
| 449 |
|
|---|
| 450 |
total_offsets=ntohl(clo->head.num_blocks)+1; |
|---|
| 451 |
|
|---|
| 452 |
if (!isblkdev && (sizeof(struct cloop_head)+sizeof(loff_t)* |
|---|
| 453 |
total_offsets > inode->i_size)) |
|---|
| 454 |
{ |
|---|
| 455 |
printk(KERN_ERR "%s: file too small for %u blocks\n", |
|---|
| 456 |
cloop_name, ntohl(clo->head.num_blocks)); |
|---|
| 457 |
error=-EBADF; goto error_release; |
|---|
| 458 |
} |
|---|
| 459 |
|
|---|
| 460 |
clo->offsets = vmalloc(sizeof(loff_t) * total_offsets); |
|---|
| 461 |
if (!clo->offsets) |
|---|
| 462 |
{ |
|---|
| 463 |
printk(KERN_ERR "%s: out of kernel mem for offsets\n", cloop_name); |
|---|
| 464 |
error=-ENOMEM; goto error_release; |
|---|
| 465 |
} |
|---|
| 466 |
} |
|---|
| 467 |
|
|---|
| 468 |
num_readable = MIN(total_offsets - offsets_read, |
|---|
| 469 |
(clo->underlying_blksize - offset) |
|---|
| 470 |
/ sizeof(loff_t)); |
|---|
| 471 |
memcpy(&clo->offsets[offsets_read], bbuf+offset, num_readable * sizeof(loff_t)); |
|---|
| 472 |
offsets_read += num_readable; |
|---|
| 473 |
} |
|---|
| 474 |
|
|---|
| 475 |
{ |
|---|
| 476 |
int i; |
|---|
| 477 |
for(i=0;i<total_offsets-1;i++) |
|---|
| 478 |
{ |
|---|
| 479 |
loff_t d=be64_to_cpu(clo->offsets[i+1]) - be64_to_cpu(clo->offsets[i]); |
|---|
| 480 |
largest_block=MAX(largest_block,d); |
|---|
| 481 |
} |
|---|
| 482 |
printk("%s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", |
|---|
| 483 |
cloop_name, filename, ntohl(clo->head.num_blocks), |
|---|
| 484 |
ntohl(clo->head.block_size), largest_block); |
|---|
| 485 |
} |
|---|
| 486 |
|
|---|
| 487 |
|
|---|
| 488 |
clo->buffer = vmalloc(ntohl(clo->head.block_size)); |
|---|
| 489 |
if(!clo->buffer) |
|---|
| 490 |
{ |
|---|
| 491 |
printk(KERN_ERR "%s: out of memory for buffer %lu\n", |
|---|
| 492 |
cloop_name, (unsigned long) ntohl(clo->head.block_size)); |
|---|
| 493 |
error=-ENOMEM; goto error_release_free; |
|---|
| 494 |
} |
|---|
| 495 |
|
|---|
| 496 |
clo->compressed_buffer = vmalloc(largest_block); |
|---|
| 497 |
|
|---|
| 498 |
if(!clo->compressed_buffer) |
|---|
| 499 |
{ |
|---|
| 500 |
printk(KERN_ERR "%s: out of memory for compressed buffer %lu\n", |
|---|
| 501 |
cloop_name, largest_block); |
|---|
| 502 |
error=-ENOMEM; goto error_release_free_buffer; |
|---|
| 503 |
} |
|---|
| 504 |
clo->zstream.workspace = vmalloc(zlib_inflate_workspacesize()); |
|---|
| 505 |
if(!clo->zstream.workspace) |
|---|
| 506 |
{ |
|---|
| 507 |
printk(KERN_ERR "%s: out of mem for zlib working area %u\n", |
|---|
| 508 |
cloop_name, zlib_inflate_workspacesize()); |
|---|
| 509 |
error=-ENOMEM; goto error_release_free_all; |
|---|
| 510 |
} |
|---|
| 511 |
zlib_inflateInit(&clo->zstream); |
|---|
| 512 |
|
|---|
| 513 |
if(!isblkdev && |
|---|
| 514 |
be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]) != inode->i_size) |
|---|
| 515 |
{ |
|---|
| 516 |
printk(KERN_ERR "%s: final offset wrong (%Lu not %Lu)\n", |
|---|
| 517 |
cloop_name, |
|---|
| 518 |
be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]), |
|---|
| 519 |
inode->i_size); |
|---|
| 520 |
vfree(clo->zstream.workspace); clo->zstream.workspace=NULL; |
|---|
| 521 |
goto error_release_free_all; |
|---|
| 522 |
} |
|---|
| 523 |
|
|---|
| 524 |
clo->buffered_blocknum = -1; |
|---|
| 525 |
set_capacity(clo->disk, (sector_t)(ntohl(clo->head.num_blocks)*(ntohl(clo->head.block_size)>>9))); |
|---|
| 526 |
return error; |
|---|
| 527 |
|
|---|
| 528 |
error_release_free_all: |
|---|
| 529 |
vfree(clo->compressed_buffer); |
|---|
| 530 |
clo->compressed_buffer=NULL; |
|---|
| 531 |
error_release_free_buffer: |
|---|
| 532 |
vfree(clo->buffer); |
|---|
| 533 |
clo->buffer=NULL; |
|---|
| 534 |
error_release_free: |
|---|
| 535 |
vfree(clo->offsets); |
|---|
| 536 |
clo->offsets=NULL; |
|---|
| 537 |
error_release: |
|---|
| 538 |
if(bbuf) vfree(bbuf); |
|---|
| 539 |
clo->backing_file=NULL; |
|---|
| 540 |
return error; |
|---|
| 541 |
} |
|---|
| 542 |
|
|---|
| 543 |
|
|---|
| 544 |
|
|---|
| 545 |
static int clo_set_fd(int cloop_num, struct file *clo_file, |
|---|