--- compressed_loop.c 2008-07-11 18:40:51.356951242 -0700 +++ /tmp/compressed_loop.c 2008-07-11 18:39:03.676141237 -0700 @@ -20,7 +20,7 @@ */ #define CLOOP_NAME "cloop" -#define CLOOP_VERSION "2.624" +#define CLOOP_VERSION "2.625" #define CLOOP_MAX 8 #ifndef KBUILD_MODNAME @@ -124,6 +124,7 @@ int current_bufnum; void *buffer[BUFFERED_BLOCKS]; void *compressed_buffer; + size_t preload_size; void *preload_cache; z_stream zstream; @@ -131,6 +132,7 @@ struct file *backing_file; /* associated file */ struct inode *backing_inode; /* for bmap */ + unsigned long largest_block; unsigned int underlying_blksize; int clo_number; int refcnt; @@ -156,6 +158,18 @@ #error "Invalid Kernel configuration. CONFIG_ZLIB_INFLATE support is needed for cloop." #endif +/* Use __get_free_pages instead of vmalloc, allows up to 32 pages, + * 2MB in one piece */ +static void *cloop_malloc(size_t size) +{ + return (void *)__get_free_pages(GFP_KERNEL, get_order(size)); +} + +static void cloop_free(void *mem, size_t size) +{ + free_pages((unsigned long)mem, get_order(size)); +} + static int uncompress(struct cloop_device *clo, unsigned char *dest, unsigned long *destLen, unsigned char *source, unsigned long sourceLen) @@ -178,32 +192,6 @@ return Z_OK; } -/* This is more complicated than it looks. */ -struct cloop_read_data -{ - struct cloop_device *clo; - char *data; /* We need to keep track of where we are in the buffer */ - int bsize; -}; - -/* We need this for do_generic_file_read() because the default function */ -/* wants to read into user-space for an unknown reason. :-/ See loop.c. */ -static int cloop_read_actor(read_descriptor_t * desc, struct page *page, - unsigned long offset, unsigned long size) -{ - unsigned long count = desc->count; - struct cloop_read_data *p = (struct cloop_read_data*)desc->arg.data; - char *kaddr_page; - if (size > count) size = count; - kaddr_page = kmap(page); - memcpy(p->data, kaddr_page + offset, size); - kunmap(page); - desc->count = count - size; - desc->written += size; - p->data += size; - return size; -} - static size_t cloop_read_from_file(struct cloop_device *clo, struct file *f, char *buf, loff_t pos, size_t buf_len) { @@ -211,35 +199,21 @@ while (buf_done < buf_len) { size_t size = buf_len - buf_done; - struct cloop_read_data cd={ /* do_generic_file_read() needs this. */ - clo, /* struct cloop_device *clo */ - (char *)(buf + buf_done), /* char *data */ - size}; /* Actual data size */ - read_descriptor_t desc; - desc.written = 0; - desc.count = size; - desc.arg.data = (char*)&cd; - desc.error = 0; -#ifdef REDHAT_KERNEL /* Greenshoe Linux */ - do_generic_file_read(f, &pos, &desc, cloop_read_actor, 0); -#else /* Normal Kernel */ - do_generic_file_read(f, &pos, &desc, cloop_read_actor); -#endif - if(desc.error||desc.written<=0) + size_t size_read = do_sync_read(f, buf + buf_done, size, &pos); + if(size_read <= 0) { - int left = size - desc.written; + size_t left = size - size_read; if(left<0) left = 0; /* better safe than sorry */ printk(KERN_ERR "%s: Read error at pos %Lu in file %s, " "%d bytes lost.\n", cloop_name, pos, file, left); memset(buf + buf_len - left, 0, left); break; } - buf_done += desc.written; + buf_done += size_read; } return buf_done; } - /* This looks more complicated than it is */ /* Returns number of block buffer to use for this request */ static int cloop_load_buffer(struct cloop_device *clo, int blocknum) @@ -300,7 +274,6 @@ { int buffered_blocknum = -1; int preloaded = 0; - struct bio *bio; loff_t offset = (loff_t) req->sector<<9; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) /* New kernel */ struct bio_vec *bvec; @@ -351,6 +324,7 @@ kunmap(bvec->bv_page); } /* end rq_for_each_segment*/ #else /* Old Kernel */ + struct bio *bio; rq_for_each_bio(bio, req) { struct bio_vec *bvec; @@ -425,22 +399,27 @@ list_for_each_safe(p, n, &clo->clo_list) { int uptodate; + unsigned long flags; struct request *req; + spin_lock_irqsave(&clo->queue_lock, flags); req = list_entry(p, struct request, queuelist); - spin_lock_irq(&clo->queue_lock); list_del_init(&req->queuelist); - spin_unlock_irq(&clo->queue_lock); -/* DEBUGP(KERN_ERR "cloop_handle_request(%p, %p), sector=%d, nr_sectors=%d, current_nr_sectors=%d ", clo, req, (int)req->sector, (int)req->nr_sectors, (int)req->current_nr_sectors); */ + spin_unlock_irqrestore(&clo->queue_lock, flags); uptodate = cloop_handle_request(clo, req); -/* DEBUGP(KERN_ERR "cloop_handle_request done, uptodate=%d\n", uptodate); */ - spin_lock_irq(&clo->queue_lock); + spin_lock_irqsave(&clo->queue_lock, flags); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) /* New kernel */ + __blk_end_request(req, uptodate ? 0 : -EIO, req->nr_sectors << 9); +#else if(!end_that_request_first(req, uptodate, req->nr_sectors)) end_that_request_last(req, uptodate); - spin_unlock_irq(&clo->queue_lock); +#endif + spin_unlock_irqrestore(&clo->queue_lock, flags); } +#if 0 spin_lock_irq(&clo->queue_lock); blk_start_queue(clo->clo_queue); spin_unlock_irq(&clo->queue_lock); +#endif } DEBUGP(KERN_ERR "cloop_thread exited.\n"); return 0; @@ -475,7 +454,9 @@ goto error_continue; } blkdev_dequeue_request(req); /* Dequeue request first. */ +#if 0 blk_stop_queue(q); /* Stop queue processing */ +#endif list_add(&req->queuelist, &clo->clo_list); /* Add to working list for thread */ count++; wake_up(&clo->clo_event); /* Wake up cloop_thread */ @@ -483,7 +464,11 @@ error_continue: DEBUGP(KERN_ERR "cloop_do_request: Discarding request %p.\n", req); req->errors++; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) /* New kernel */ + __blk_end_request(req, -EIO, req->nr_sectors << 9); +#else end_request(req, 0); /* Discard */ +#endif } } @@ -494,7 +479,6 @@ struct inode *inode; char *bbuf=NULL; unsigned int i, offsets_read, total_offsets; - unsigned long largest_block=0; int isblkdev; int error = 0; inode = file->f_dentry->d_inode; @@ -531,7 +515,7 @@ else clo->underlying_blksize = PAGE_SIZE; DEBUGP("Underlying blocksize is %u\n", clo->underlying_blksize); - bbuf = vmalloc(clo->underlying_blksize); + bbuf = cloop_malloc(clo->underlying_blksize); if(!bbuf) { printk(KERN_ERR "%s: out of kernel mem for block buffer (%lu bytes)\n", @@ -580,7 +564,7 @@ cloop_name, ntohl(clo->head.num_blocks)); error=-EBADF; goto error_release; } - clo->offsets = vmalloc(sizeof(loff_t) * total_offsets); + clo->offsets = cloop_malloc(sizeof(loff_t) * total_offsets); if (!clo->offsets) { printk(KERN_ERR "%s: out of kernel mem for offsets\n", cloop_name); @@ -598,18 +582,18 @@ for(i=0;ioffsets[i+1]) - be64_to_cpu(clo->offsets[i]); - largest_block=MAX(largest_block,d); + clo->largest_block=MAX(clo->largest_block,d); } printk(KERN_INFO "%s: %s: %u blocks, %u bytes/block, largest block is %lu bytes.\n", cloop_name, filename, ntohl(clo->head.num_blocks), - ntohl(clo->head.block_size), largest_block); + ntohl(clo->head.block_size), clo->largest_block); } /* Combo kmalloc used too large chunks (>130000). */ { int i; for(i=0;ibuffer[i] = vmalloc(ntohl(clo->head.block_size)); + clo->buffer[i] = cloop_malloc(ntohl(clo->head.block_size)); if(!clo->buffer[i]) { printk(KERN_ERR "%s: out of memory for buffer %lu\n", @@ -618,14 +602,14 @@ } } } - clo->compressed_buffer = vmalloc(largest_block); + clo->compressed_buffer = cloop_malloc(clo->largest_block); if(!clo->compressed_buffer) { printk(KERN_ERR "%s: out of memory for compressed buffer %lu\n", - cloop_name, largest_block); + cloop_name, clo->largest_block); error=-ENOMEM; goto error_release_free_buffer; } - clo->zstream.workspace = vmalloc(zlib_inflate_workspacesize()); + clo->zstream.workspace = cloop_malloc(zlib_inflate_workspacesize()); if(!clo->zstream.workspace) { printk(KERN_ERR "%s: out of mem for zlib working area %u\n", @@ -640,7 +624,7 @@ cloop_name, be64_to_cpu(clo->offsets[ntohl(clo->head.num_blocks)]), inode->i_size); - vfree(clo->zstream.workspace); clo->zstream.workspace=NULL; + cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace=NULL; goto error_release_free_all; } { @@ -659,9 +643,9 @@ } if(preload > 0) { - size_t preload_size = ((preload<=ntohl(clo->head.num_blocks))?preload:ntohl(clo->head.num_blocks)) + clo->preload_size = ((preload<=ntohl(clo->head.num_blocks))?preload:ntohl(clo->head.num_blocks)) * ntohl(clo->head.block_size); - if((clo->preload_cache = vmalloc(preload_size)) != NULL) + if((clo->preload_cache = cloop_malloc(clo->preload_size)) != NULL) { int i; for(i=0; ihead.num_blocks); i++) @@ -674,7 +658,7 @@ else { printk(KERN_WARNING "%s: can't read block %d into preload cache, ignored.\n", cloop_name, i); - vfree(clo->preload_cache); + cloop_free(clo->preload_cache, clo->preload_size); clo->preload_cache = NULL; break; } @@ -686,7 +670,7 @@ /* Uncheck */ return error; error_release_free_all: - vfree(clo->compressed_buffer); + cloop_free(clo->compressed_buffer, clo->largest_block); clo->compressed_buffer=NULL; error_release_free_buffer: { @@ -695,16 +679,16 @@ { if(clo->buffer[i]) { - vfree(clo->buffer[i]); + cloop_free(clo->buffer[i], ntohl(clo->head.block_size)); clo->buffer[i]=NULL; } } } error_release_free: - vfree(clo->offsets); + cloop_free(clo->offsets, sizeof(loff_t) * total_offsets); clo->offsets=NULL; error_release: - if(bbuf) vfree(bbuf); + if(bbuf) cloop_free(bbuf, clo->underlying_blksize); clo->backing_file=NULL; return error; } @@ -740,13 +724,13 @@ else { filp_close(initial_file,0); initial_file=NULL; } clo->backing_file = NULL; clo->backing_inode = NULL; - if(clo->offsets) { vfree(clo->offsets); clo->offsets = NULL; } - if(clo->preload_cache) { vfree(clo->preload_cache); clo->preload_cache = NULL; } + if(clo->offsets) { cloop_free(clo->offsets, clo->underlying_blksize); clo->offsets = NULL; } + if(clo->preload_cache) { cloop_free(clo->preload_cache, clo->preload_size); clo->preload_cache = NULL; } for(i=0; ibuffer[i]) { vfree(clo->buffer[i]); clo->buffer[i]=NULL; } - if(clo->compressed_buffer) { vfree(clo->compressed_buffer); clo->compressed_buffer = NULL; } + if(clo->buffer[i]) { cloop_free(clo->buffer[i], ntohl(clo->head.block_size)); clo->buffer[i]=NULL; } + if(clo->compressed_buffer) { cloop_free(clo->compressed_buffer, clo->largest_block); clo->compressed_buffer = NULL; } zlib_inflateEnd(&clo->zstream); - if(clo->zstream.workspace) { vfree(clo->zstream.workspace); clo->zstream.workspace = NULL; } + if(clo->zstream.workspace) { cloop_free(clo->zstream.workspace, zlib_inflate_workspacesize()); clo->zstream.workspace = NULL; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) if(bdev) invalidate_bdev(bdev, 0); #else