diff -Nur linux-2.4.16/drivers/block/loop.c linux-int-2.4.16/drivers/block/loop.c --- linux-2.4.16/drivers/block/loop.c Mon Nov 19 23:48:02 2001 +++ linux-int-2.4.16/drivers/block/loop.c Tue Dec 4 16:52:20 2001 @@ -49,6 +49,15 @@ * problem above. Encryption modules that used to rely on the old scheme * should just call ->i_mapping->bmap() to calculate the physical block * number. + * + * IV is now passed as (512 byte) sector number. + * Jari Ruusu , May 18 2001 + * + * External encryption module locking bug fixed. + * Ingo Rohloff , June 21 2001 + * + * Make device backed loop work with swap (pre-allocated buffers + queue rewrite). + * Jari Ruusu , September 2 2001 */ #include @@ -93,7 +102,7 @@ else memcpy(raw_buf, loop_buf, size); } - + if(current->need_resched) schedule(); return 0; } @@ -115,12 +124,12 @@ keysize = lo->lo_encrypt_key_size; for (i = 0; i < size; i++) *out++ = *in++ ^ key[(i & 511) % keysize]; + if(current->need_resched) schedule(); return 0; } static int none_status(struct loop_device *lo, struct loop_info *info) { - lo->lo_flags |= LO_FLAGS_BH_REMAP; return 0; } @@ -149,6 +158,224 @@ &xor_funcs }; +/* + * First number of 'lo_prealloc' is the default number of RAM pages + * to pre-allocate for each device backed loop. Every (configured) + * device backed loop pre-allocates this amount of RAM pages unless + * later 'lo_prealloc' numbers provide an override. 'lo_prealloc' + * overrides are defined in pairs: loop_index,number_of_pages + */ +static int lo_prealloc[9] = { 125, 999, 0, 999, 0, 999, 0, 999, 0 }; +#define LO_PREALLOC_MIN 4 /* minimum user defined pre-allocated RAM pages */ +#define LO_PREALLOC_MAX 512 /* maximum user defined pre-allocated RAM pages */ + +#ifdef MODULE +MODULE_PARM(lo_prealloc, "1-9i"); +MODULE_PARM_DESC(lo_prealloc, "Number of pre-allocated pages [,index,pages]..."); +#else +static int __init lo_prealloc_setup(char *str) +{ + int x, y, z; + + for(x = 0; x < (sizeof(lo_prealloc) / sizeof(int)); x++) { + z = get_option(&str, &y); + if(z > 0) lo_prealloc[x] = y; + if(z < 2) break; + } + return 1; +} +__setup("lo_prealloc=", lo_prealloc_setup); +#endif + +typedef struct { + struct buffer_head **q0; + struct buffer_head **q1; + struct buffer_head **q2; + int x0; + int x1; + int x2; +} QueLookUpTable; + +static void loop_prealloc_cleanup(struct loop_device *lo) +{ + struct buffer_head *bh; + + while((bh = lo->lo_bhFree)) { + __free_page(bh->b_page); + lo->lo_bhFree = bh->b_reqnext; + bh->b_reqnext = NULL; + kmem_cache_free(bh_cachep, bh); + } +} + +static int loop_prealloc_init(struct loop_device *lo, int pgCnt) +{ + struct buffer_head *bh; + int x; + + for(x = 0; x < pgCnt; x++) { + bh = kmem_cache_alloc(bh_cachep, SLAB_KERNEL); + if(!bh) { + loop_prealloc_cleanup(lo); + return(1); + } + bh->b_page = alloc_page(GFP_KERNEL); + if(!bh->b_page) { + bh->b_reqnext = NULL; + kmem_cache_free(bh_cachep, bh); + loop_prealloc_cleanup(lo); + return(1); + } + bh->b_reqnext = lo->lo_bhFree; + lo->lo_bhFree = bh; + } + return(0); +} + +static void loop_add_queue_last(struct loop_device *lo, struct buffer_head *bh, struct buffer_head **q) +{ + unsigned long flags; + + spin_lock_irqsave(&lo->lo_lock, flags); + if(*q) { + bh->b_reqnext = (*q)->b_reqnext; + (*q)->b_reqnext = bh; + } else { + bh->b_reqnext = bh; + } + *q = bh; + spin_unlock_irqrestore(&lo->lo_lock, flags); + + if(waitqueue_active(&lo->lo_bhWait)) { + wake_up_interruptible(&lo->lo_bhWait); + } +} + +static void loop_add_queue_first(struct loop_device *lo, struct buffer_head *bh, struct buffer_head **q) +{ + spin_lock_irq(&lo->lo_lock); + if(*q) { + bh->b_reqnext = (*q)->b_reqnext; + (*q)->b_reqnext = bh; + } else { + bh->b_reqnext = bh; + *q = bh; + } + spin_unlock_irq(&lo->lo_lock); +} + +static struct buffer_head *loop_get_bh(struct loop_device *lo, int *listNr, QueLookUpTable *qt) +{ + struct buffer_head *bh = NULL, *last; + + spin_lock_irq(&lo->lo_lock); + if((last = *qt->q0)) { + bh = last->b_reqnext; + if(bh == last) { + *qt->q0 = NULL; + } else { + last->b_reqnext = bh->b_reqnext; + } + bh->b_reqnext = NULL; + *listNr = qt->x0; + } else if((last = *qt->q1)) { + bh = last->b_reqnext; + if(bh == last) { + *qt->q1 = NULL; + } else { + last->b_reqnext = bh->b_reqnext; + } + bh->b_reqnext = NULL; + *listNr = qt->x1; + } else if((last = *qt->q2)) { + bh = last->b_reqnext; + if(bh == last) { + *qt->q2 = NULL; + } else { + last->b_reqnext = bh->b_reqnext; + } + bh->b_reqnext = NULL; + *listNr = qt->x2; + } + spin_unlock_irq(&lo->lo_lock); + return bh; +} + +static void loop_put_buffer(struct loop_device *lo, struct buffer_head *b) +{ + unsigned long flags; + int wk; + + spin_lock_irqsave(&lo->lo_lock, flags); + b->b_reqnext = lo->lo_bhFree; + lo->lo_bhFree = b; + wk = lo->lo_bhNeed; + spin_unlock_irqrestore(&lo->lo_lock, flags); + + if(wk && waitqueue_active(&lo->lo_bhWait)) { + wake_up_interruptible(&lo->lo_bhWait); + } +} + +static void loop_end_io_transfer_wr(struct buffer_head *bh, int uptodate) +{ + struct loop_device *lo = &loop_dev[MINOR(bh->b_dev)]; + struct buffer_head *rbh = bh->b_private; + + rbh->b_reqnext = NULL; + rbh->b_end_io(rbh, uptodate); + loop_put_buffer(lo, bh); + if(atomic_dec_and_test(&lo->lo_pending)) { + wake_up_interruptible(&lo->lo_bhWait); + } +} + +static void loop_end_io_transfer_rd(struct buffer_head *bh, int uptodate) +{ + struct loop_device *lo = &loop_dev[MINOR(bh->b_dev)]; + + if(!uptodate) { + loop_end_io_transfer_wr(bh, uptodate); + } else { + loop_add_queue_last(lo, bh, &lo->lo_bhQue0); + } +} + +static struct buffer_head *loop_get_buffer(struct loop_device *lo, + struct buffer_head *rbh, int fromThread, int rw) +{ + struct buffer_head *bh; + struct page *p; + unsigned long flags; + + spin_lock_irqsave(&lo->lo_lock, flags); + bh = lo->lo_bhFree; + if(bh) { + lo->lo_bhFree = bh->b_reqnext; + if(fromThread) lo->lo_bhNeed = 0; + } else { + if(fromThread) lo->lo_bhNeed = 1; + } + spin_unlock_irqrestore(&lo->lo_lock, flags); + if(!bh) return((struct buffer_head *)0); + + p = bh->b_page; + memset(bh, 0, sizeof(struct buffer_head)); + bh->b_page = p; + + bh->b_private = rbh; + bh->b_size = rbh->b_size; + bh->b_dev = rbh->b_rdev; + bh->b_rdev = lo->lo_device; + bh->b_state = (1 << BH_Req) | (1 << BH_Mapped) | (1 << BH_Lock); + bh->b_data = page_address(bh->b_page); + bh->b_end_io = (rw == WRITE) ? loop_end_io_transfer_wr : loop_end_io_transfer_rd; + bh->b_rsector = rbh->b_rsector + (lo->lo_offset >> 9); + init_waitqueue_head(&bh->b_wait); + + return bh; +} + #define MAX_DISK_SIZE 1024*1024*1024 static unsigned long compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev) @@ -168,8 +395,7 @@ lo->lo_device); } -static int lo_send(struct loop_device *lo, struct buffer_head *bh, int bsize, - loff_t pos) +static int lo_send(struct loop_device *lo, struct buffer_head *bh, loff_t pos) { struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */ struct address_space *mapping = file->f_dentry->d_inode->i_mapping; @@ -186,16 +412,22 @@ len = bh->b_size; data = bh->b_data; while (len > 0) { - int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize; + int IV = index * (PAGE_CACHE_SIZE >> 9) + (offset >> 9); int transfer_result; size = PAGE_CACHE_SIZE - offset; if (size > len) size = len; + try_again: page = grab_cache_page(mapping, index); - if (!page) - goto fail; + if (!page || IS_ERR(page)) { + up(&mapping->host->i_sem); + run_task_queue(&tq_disk); + schedule_timeout(HZ / 2); + down(&mapping->host->i_sem); + goto try_again; + } if (aops->prepare_write(file, page, offset, offset+size)) goto unlock; kaddr = page_address(page); @@ -217,7 +449,6 @@ len -= size; offset = 0; index++; - pos += size; UnlockPage(page); page_cache_release(page); } @@ -227,7 +458,6 @@ unlock: UnlockPage(page); page_cache_release(page); -fail: up(&mapping->host->i_sem); return -1; } @@ -235,7 +465,6 @@ struct lo_read_data { struct loop_device *lo; char *data; - int bsize; }; static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) @@ -244,7 +473,7 @@ unsigned long count = desc->count; struct lo_read_data *p = (struct lo_read_data*)desc->buf; struct loop_device *lo = p->lo; - int IV = page->index * (PAGE_CACHE_SIZE/p->bsize) + offset/p->bsize; + int IV = page->index * (PAGE_CACHE_SIZE >> 9) + (offset >> 9); if (size > count) size = count; @@ -263,8 +492,7 @@ return size; } -static int lo_receive(struct loop_device *lo, struct buffer_head *bh, int bsize, - loff_t pos) +static int lo_receive(struct loop_device *lo, struct buffer_head *bh, loff_t pos) { struct lo_read_data cookie; read_descriptor_t desc; @@ -272,7 +500,6 @@ cookie.lo = lo; cookie.data = bh->b_data; - cookie.bsize = bsize; desc.written = 0; desc.count = bh->b_size; desc.buf = (char*)&cookie; @@ -284,32 +511,6 @@ return desc.error; } -static inline int loop_get_bs(struct loop_device *lo) -{ - int bs = 0; - - if (blksize_size[MAJOR(lo->lo_device)]) - bs = blksize_size[MAJOR(lo->lo_device)][MINOR(lo->lo_device)]; - if (!bs) - bs = BLOCK_SIZE; - - return bs; -} - -static inline unsigned long loop_get_iv(struct loop_device *lo, - unsigned long sector) -{ - int bs = loop_get_bs(lo); - 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_bh_filebacked(struct loop_device *lo, struct buffer_head *bh, int rw) { loff_t pos; @@ -318,144 +519,17 @@ pos = ((loff_t) bh->b_rsector << 9) + lo->lo_offset; if (rw == WRITE) - ret = lo_send(lo, bh, loop_get_bs(lo), pos); + ret = lo_send(lo, bh, pos); else - ret = lo_receive(lo, bh, loop_get_bs(lo), pos); + ret = lo_receive(lo, bh, pos); return ret; } -static void loop_end_io_transfer(struct buffer_head *bh, int uptodate); -static void loop_put_buffer(struct buffer_head *bh) -{ - /* - * check b_end_io, may just be a remapped bh and not an allocated one - */ - if (bh && bh->b_end_io == loop_end_io_transfer) { - __free_page(bh->b_page); - kmem_cache_free(bh_cachep, bh); - } -} - -/* - * Add buffer_head to back of pending list - */ -static void loop_add_bh(struct loop_device *lo, struct buffer_head *bh) -{ - unsigned long flags; - - spin_lock_irqsave(&lo->lo_lock, flags); - if (lo->lo_bhtail) { - lo->lo_bhtail->b_reqnext = bh; - lo->lo_bhtail = bh; - } else - lo->lo_bh = lo->lo_bhtail = bh; - spin_unlock_irqrestore(&lo->lo_lock, flags); - - up(&lo->lo_bh_mutex); -} - -/* - * Grab first pending buffer - */ -static struct buffer_head *loop_get_bh(struct loop_device *lo) -{ - struct buffer_head *bh; - - spin_lock_irq(&lo->lo_lock); - if ((bh = lo->lo_bh)) { - if (bh == lo->lo_bhtail) - lo->lo_bhtail = NULL; - lo->lo_bh = bh->b_reqnext; - bh->b_reqnext = NULL; - } - spin_unlock_irq(&lo->lo_lock); - - return bh; -} - -/* - * when buffer i/o has completed. if BH_Dirty is set, this was a WRITE - * and lo->transfer stuff has already been done. if not, it was a READ - * so queue it for the loop thread and let it do the transfer out of - * b_end_io context (we don't want to do decrypt of a page with irqs - * disabled) - */ -static void loop_end_io_transfer(struct buffer_head *bh, int uptodate) -{ - struct loop_device *lo = &loop_dev[MINOR(bh->b_dev)]; - - if (!uptodate || test_bit(BH_Dirty, &bh->b_state)) { - struct buffer_head *rbh = bh->b_private; - - rbh->b_end_io(rbh, uptodate); - if (atomic_dec_and_test(&lo->lo_pending)) - up(&lo->lo_bh_mutex); - loop_put_buffer(bh); - } else - loop_add_bh(lo, bh); -} - -static struct buffer_head *loop_get_buffer(struct loop_device *lo, - struct buffer_head *rbh) -{ - struct buffer_head *bh; - - /* - * for xfer_funcs that can operate on the same bh, do that - */ - if (lo->lo_flags & LO_FLAGS_BH_REMAP) { - bh = rbh; - goto out_bh; - } - - do { - bh = kmem_cache_alloc(bh_cachep, SLAB_NOIO); - if (bh) - break; - - run_task_queue(&tq_disk); - schedule_timeout(HZ); - } while (1); - memset(bh, 0, sizeof(*bh)); - - bh->b_size = rbh->b_size; - bh->b_dev = rbh->b_rdev; - bh->b_state = (1 << BH_Req) | (1 << BH_Mapped) | (1 << BH_Lock); - - /* - * easy way out, although it does waste some memory for < PAGE_SIZE - * blocks... if highmem bounce buffering can get away with it, - * so can we :-) - */ - do { - bh->b_page = alloc_page(GFP_NOIO); - if (bh->b_page) - break; - - run_task_queue(&tq_disk); - schedule_timeout(HZ); - } while (1); - - bh->b_data = page_address(bh->b_page); - bh->b_end_io = loop_end_io_transfer; - bh->b_private = rbh; - init_waitqueue_head(&bh->b_wait); - -out_bh: - bh->b_rsector = rbh->b_rsector + (lo->lo_offset >> 9); - spin_lock_irq(&lo->lo_lock); - bh->b_rdev = lo->lo_device; - spin_unlock_irq(&lo->lo_lock); - - return bh; -} - static int loop_make_request(request_queue_t *q, int rw, struct buffer_head *rbh) { - struct buffer_head *bh = NULL; + struct buffer_head *bh; struct loop_device *lo; - unsigned long IV; if (!buffer_locked(rbh)) BUG(); @@ -488,35 +562,30 @@ * file backed, queue for loop_thread to handle */ if (lo->lo_flags & LO_FLAGS_DO_BMAP) { - /* - * rbh locked at this point, noone else should clear - * the dirty flag - */ - if (rw == WRITE) - set_bit(BH_Dirty, &rbh->b_state); - loop_add_bh(lo, rbh); + loop_add_queue_last(lo, rbh, (rw == WRITE) ? &lo->lo_bhQue1 : &lo->lo_bhQue0); return 0; } /* - * piggy old buffer on original, and submit for I/O + * device backed, start reads now, queue writes for thread to handle */ - bh = loop_get_buffer(lo, rbh); - IV = loop_get_iv(lo, rbh->b_rsector); - if (rw == WRITE) { - set_bit(BH_Dirty, &bh->b_state); - if (lo_do_transfer(lo, WRITE, bh->b_data, rbh->b_data, - bh->b_size, IV)) - goto err; + if(rw == READ) { + bh = loop_get_buffer(lo, rbh, 0, rw); + } else { + bh = NULL; + } + if(!bh) { + /* just queue request and let thread handle alloc later */ + loop_add_queue_last(lo, rbh, (rw == WRITE) ? &lo->lo_bhQue1 : &lo->lo_bhQue2); + return 0; } - generic_make_request(rw, bh); return 0; err: - if (atomic_dec_and_test(&lo->lo_pending)) - up(&lo->lo_bh_mutex); - loop_put_buffer(bh); + if(atomic_dec_and_test(&lo->lo_pending)) { + wake_up_interruptible(&lo->lo_bhWait); + } out: buffer_IO_error(rbh); return 0; @@ -525,41 +594,23 @@ goto out; } -static inline void loop_handle_bh(struct loop_device *lo,struct buffer_head *bh) -{ - int ret; - - /* - * For block backed loop, we know this is a READ - */ - if (lo->lo_flags & LO_FLAGS_DO_BMAP) { - int rw = !!test_and_clear_bit(BH_Dirty, &bh->b_state); - - ret = do_bh_filebacked(lo, bh, rw); - bh->b_end_io(bh, !ret); - } else { - struct buffer_head *rbh = bh->b_private; - unsigned long IV = loop_get_iv(lo, rbh->b_rsector); - - ret = lo_do_transfer(lo, READ, bh->b_data, rbh->b_data, - bh->b_size, IV); - - rbh->b_end_io(rbh, !ret); - loop_put_buffer(bh); - } -} - /* - * worker thread that handles reads/writes to file backed loop devices, - * to avoid blocking in our make_request_fn. it also does loop decrypting - * on reads for block backed loop, as that is too heavy to do from - * b_end_io context where irqs may be disabled. + * worker thread that handles all encryption and decryption. */ static int loop_thread(void *data) { struct loop_device *lo = data; - struct buffer_head *bh; + struct buffer_head *bh, *xbh; + int x, rw, qi = 0, flushcnt = 0; + wait_queue_t waitq; + QueLookUpTable qt[4] = { + { &lo->lo_bhQue0, &lo->lo_bhQue1, &lo->lo_bhQue2, 0, 1, 2 }, + { &lo->lo_bhQue2, &lo->lo_bhQue0, &lo->lo_bhQue1, 2, 0, 1 }, + { &lo->lo_bhQue0, &lo->lo_bhQue2, &lo->lo_bhQue1, 0, 2, 1 }, + { &lo->lo_bhQue1, &lo->lo_bhQue0, &lo->lo_bhQue2, 1, 0, 2 } + }; + init_waitqueue_entry(&waitq, current); daemonize(); exit_files(current); @@ -584,27 +635,101 @@ up(&lo->lo_sem); for (;;) { - down_interruptible(&lo->lo_bh_mutex); + add_wait_queue(&lo->lo_bhWait, &waitq); + for(;;) { + set_current_state(TASK_INTERRUPTIBLE); + if(!atomic_read(&lo->lo_pending)) break; + + x = 0; + spin_lock_irq(&lo->lo_lock); + if(lo->lo_bhQue0) { + x = 1; + } else if(lo->lo_bhQue1 || lo->lo_bhQue2) { + /* file backed works too because lo->lo_bhNeed == 0 */ + if(lo->lo_bhFree || !lo->lo_bhNeed) x = 1; + } + spin_unlock_irq(&lo->lo_lock); + if(x) break; + + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&lo->lo_bhWait, &waitq); + /* - * could be upped because of tear-down, not because of + * could be woken because of tear-down, not because of * pending work */ - if (!atomic_read(&lo->lo_pending)) - break; + if(!atomic_read(&lo->lo_pending)) break; + + /* + * read queues using alternating order to prevent starvation + */ + bh = loop_get_bh(lo, &x, &qt[++qi & 3]); + if(!bh) continue; + + /* + * x list tag usage(buffer-allocated) + * --- ------------- ----------------------- + * 0 lo->lo_bhQue0 dev-read(y) / file-read + * 1 lo->lo_bhQue1 dev-write(n) / file-write + * 2 lo->lo_bhQue2 dev-read(n) + */ + rw = (x == 1) ? WRITE : READ; + if((x >= 1) && !(lo->lo_flags & LO_FLAGS_DO_BMAP)) { + /* loop_make_request didn't allocate a buffer, do that now */ + xbh = loop_get_buffer(lo, bh, 1, rw); + if(!xbh) { + run_task_queue(&tq_disk); + flushcnt = 0; + loop_add_queue_first(lo, bh, (rw == WRITE) ? &lo->lo_bhQue1 : &lo->lo_bhQue2); + /* lo->lo_bhNeed should be 1 now, go back to sleep */ + continue; + } + if(rw == WRITE) { + if(lo_do_transfer(lo, WRITE, xbh->b_data, bh->b_data, xbh->b_size, xbh->b_rsector)) { + loop_put_buffer(lo, xbh); + buffer_IO_error(bh); + atomic_dec(&lo->lo_pending); + continue; + } + } + generic_make_request(rw, xbh); + + /* start I/O if there are no more requests lacking buffers */ + x = 0; + spin_lock_irq(&lo->lo_lock); + if(!lo->lo_bhQue1 && !lo->lo_bhQue2) x = 1; + spin_unlock_irq(&lo->lo_lock); + if(x || (++flushcnt >= lo->lo_bhFlsh)) { + run_task_queue(&tq_disk); + flushcnt = 0; + } - bh = loop_get_bh(lo); - if (!bh) { - printk("loop: missing bh\n"); + /* request not completely processed yet */ continue; } - loop_handle_bh(lo, bh); + if(lo->lo_flags & LO_FLAGS_DO_BMAP) { + /* request is for file backed device */ + x = do_bh_filebacked(lo, bh, rw); + bh->b_reqnext = NULL; + bh->b_end_io(bh, !x); + } else { + /* device backed read has completed, do decrypt now */ + xbh = bh->b_private; + /* must not use bh->b_rsector as IV, as it may be modified by LVM at this point */ + /* instead, recompute IV from original request */ + x = lo_do_transfer(lo, READ, bh->b_data, xbh->b_data, bh->b_size, xbh->b_rsector + (lo->lo_offset >> 9)); + xbh->b_reqnext = NULL; + xbh->b_end_io(xbh, !x); + loop_put_buffer(lo, bh); + } /* - * upped both for pending work and tear-down, lo_pending + * woken both for pending work and tear-down, lo_pending * will hit zero then */ - if (atomic_dec_and_test(&lo->lo_pending)) - break; + if(atomic_dec_and_test(&lo->lo_pending)) break; } up(&lo->lo_sem); @@ -638,7 +763,22 @@ if (!(file->f_mode & FMODE_WRITE)) lo_flags |= LO_FLAGS_READ_ONLY; + lo->lo_bhFree = lo->lo_bhQue2 = lo->lo_bhQue1 = lo->lo_bhQue0 = NULL; + lo->lo_bhNeed = lo->lo_bhFlsh = 0; + init_waitqueue_head(&lo->lo_bhWait); if (S_ISBLK(inode->i_mode)) { + int i, x = lo_prealloc[0]; + for(i = 1; i < (sizeof(lo_prealloc) / sizeof(int)); i += 2) { + if(lo_prealloc[i+1] && (lo->lo_number == lo_prealloc[i])) { + x = lo_prealloc[i+1]; + break; + } + } + lo->lo_bhFlsh = (x * 3) / 4; + if(loop_prealloc_init(lo, x)) { + error = -ENOMEM; + goto out_putf; + } lo_device = inode->i_rdev; } else if (S_ISREG(inode->i_mode)) { struct address_space_operations *aops = inode->i_mapping->a_ops; @@ -660,7 +800,7 @@ get_file(file); - if (IS_RDONLY (inode) || is_read_only(lo_device) + if ((S_ISREG(inode->i_mode) && IS_RDONLY(inode)) || is_read_only(lo_device) || !(lo_file->f_mode & FMODE_WRITE)) lo_flags |= LO_FLAGS_READ_ONLY; @@ -681,9 +821,14 @@ if (!bs) bs = BLOCK_SIZE; + if(S_ISREG(inode->i_mode)) { + int x = loop_sizes[lo->lo_number]; + if((bs == 8192) && (x & 7)) bs = 4096; + if((bs == 4096) && (x & 3)) bs = 2048; + if((bs == 2048) && (x & 1)) bs = 1024; + } set_blocksize(dev, bs); - lo->lo_bh = lo->lo_bhtail = NULL; kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); down(&lo->lo_sem); @@ -741,12 +886,14 @@ spin_lock_irq(&lo->lo_lock); lo->lo_state = Lo_rundown; - if (atomic_dec_and_test(&lo->lo_pending)) - up(&lo->lo_bh_mutex); + if(atomic_dec_and_test(&lo->lo_pending)) { + wake_up_interruptible(&lo->lo_bhWait); + } spin_unlock_irq(&lo->lo_lock); down(&lo->lo_sem); + loop_prealloc_cleanup(lo); lo->lo_backing_file = NULL; loop_release_xfer(lo); @@ -896,7 +1043,7 @@ static int lo_open(struct inode *inode, struct file *file) { struct loop_device *lo; - int dev, type; + int dev; if (!inode) return -EINVAL; @@ -911,10 +1058,6 @@ lo = &loop_dev[dev]; MOD_INC_USE_COUNT; 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; @@ -923,7 +1066,7 @@ static int lo_release(struct inode *inode, struct file *file) { struct loop_device *lo; - int dev, type; + int dev; if (!inode) return 0; @@ -938,11 +1081,7 @@ lo = &loop_dev[dev]; 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); MOD_DEC_USE_COUNT; return 0; @@ -1032,7 +1171,6 @@ memset(lo, 0, sizeof(struct loop_device)); init_MUTEX(&lo->lo_ctl_mutex); init_MUTEX_LOCKED(&lo->lo_sem); - init_MUTEX_LOCKED(&lo->lo_bh_mutex); lo->lo_number = i; spin_lock_init(&lo->lo_lock); } @@ -1044,13 +1182,18 @@ for (i = 0; i < max_loop; i++) register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0); + for(i = 0; i < (sizeof(lo_prealloc) / sizeof(int)); i += 2) { + if(!lo_prealloc[i]) continue; + if(lo_prealloc[i] < LO_PREALLOC_MIN) lo_prealloc[i] = LO_PREALLOC_MIN; + if(lo_prealloc[i] > LO_PREALLOC_MAX) lo_prealloc[i] = LO_PREALLOC_MAX; + } printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop); return 0; -out_sizes: - kfree(loop_dev); out_blksizes: kfree(loop_sizes); +out_sizes: + kfree(loop_dev); printk(KERN_ERR "loop: ran out of memory\n"); return -ENOMEM; } diff -Nur linux-2.4.16/include/linux/loop.h linux-int-2.4.16/include/linux/loop.h --- linux-2.4.16/include/linux/loop.h Mon Sep 17 22:16:30 2001 +++ linux-int-2.4.16/include/linux/loop.h Tue Dec 4 16:53:44 2001 @@ -17,6 +17,12 @@ #ifdef __KERNEL__ +/* definitions for IV metric */ +#define LOOP_IV_SECTOR_BITS 9 +#define LOOP_IV_SECTOR_SIZE (1 << LOOP_IV_SECTOR_BITS) + +typedef int loop_iv_t; + /* Possible states of device */ enum { Lo_unbound, @@ -49,13 +55,17 @@ int old_gfp_mask; spinlock_t lo_lock; - struct buffer_head *lo_bh; - struct buffer_head *lo_bhtail; + struct buffer_head *lo_bhQue0; + struct buffer_head *lo_bhQue1; int lo_state; struct semaphore lo_sem; struct semaphore lo_ctl_mutex; - struct semaphore lo_bh_mutex; atomic_t lo_pending; + struct buffer_head *lo_bhQue2; + struct buffer_head *lo_bhFree; + int lo_bhFlsh; + int lo_bhNeed; + wait_queue_head_t lo_bhWait; }; typedef int (* transfer_proc_t)(struct loop_device *, int cmd, @@ -77,7 +87,6 @@ */ #define LO_FLAGS_DO_BMAP 1 #define LO_FLAGS_READ_ONLY 2 -#define LO_FLAGS_BH_REMAP 4 /* * Note that this structure gets the wrong offsets when directly used @@ -122,6 +131,8 @@ #define LO_CRYPT_IDEA 6 #define LO_CRYPT_DUMMY 9 #define LO_CRYPT_SKIPJACK 10 +#define LO_CRYPT_AES 16 +#define LO_CRYPT_CRYPTOAPI 18 #define MAX_LO_CRYPT 20 #ifdef __KERNEL__