--- loop.c-2.2.original	Mon Sep 16 21:50:11 2002
+++ patched-loop.c	Wed Nov 17 17:46:35 2004
@@ -65,10 +65,18 @@
 static struct loop_device loop_dev[MAX_LOOP];
 static int loop_sizes[MAX_LOOP];
 static int loop_blksizes[MAX_LOOP];
+static int loop_hardsizes[MAX_LOOP];
 
 #define FALSE 0
 #define TRUE (!FALSE)
 
+/* begin compatibility bogus code */
+int lo_prealloc[9];
+MODULE_PARM(lo_prealloc, "1-9i");
+int lo_nice;
+MODULE_PARM(lo_nice, "1i");
+/* end compatibility bogus code */
+
 /* Forward declaration of function to create missing blocks in the 
    backing file (can happen if the backing file is sparse) */
 static int create_missing_block(struct loop_device *lo, int block, int blksize);
@@ -83,6 +91,7 @@
 		memcpy(loop_buf, raw_buf, size);
 	else
 		memcpy(raw_buf, loop_buf, size);
+	if(current->need_resched) {current->state=TASK_RUNNING;schedule();}
 	return 0;
 }
 
@@ -103,6 +112,7 @@
 	keysize = lo->lo_encrypt_key_size;
 	for (i=0; i < size; i++)
 		*out++ = *in++ ^ key[(i & 511) % keysize];
+	if(current->need_resched) {current->state=TASK_RUNNING;schedule();}
 	return 0;
 }
 
@@ -143,12 +153,12 @@
 	int	size;
 
 	if (S_ISREG(lo->lo_dentry->d_inode->i_mode))
-		size = (lo->lo_dentry->d_inode->i_size - lo->lo_offset) / BLOCK_SIZE;
+		size = (lo->lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
 	else {
 		kdev_t lodev = lo->lo_device;
 		if (blk_size[MAJOR(lodev)])
 			size = blk_size[MAJOR(lodev)][MINOR(lodev)] -
-                                lo->lo_offset / BLOCK_SIZE;
+				 (lo->lo_offset >> BLOCK_SIZE_BITS);
 		else
 			size = MAX_DISK_SIZE;
 	}
@@ -193,7 +203,7 @@
 	}
 	block += lo->lo_offset / blksize;
 	offset += lo->lo_offset % blksize;
-	if (offset > blksize) {
+	if (offset >= blksize) {
 		block++;
 		offset -= blksize;
 	}
@@ -203,7 +213,7 @@
 		if (lo->lo_flags & LO_FLAGS_READ_ONLY)
 			goto error_out;
 	} else if (current_request->cmd != READ) {
-		printk(KERN_ERR "unknown loop device command (%d)?!?", current_request->cmd);
+		printk(KERN_ERR "unknown loop device command (%d)?!?\n", current_request->cmd);
 		goto error_out;
 	}
 	spin_unlock_irq(&io_request_lock);
@@ -240,7 +250,7 @@
 		if (block_present) {
 			bh = getblk(lo->lo_device, real_block, blksize);
 			if (!bh) {
-				printk(KERN_ERR "loop: device %s: getblk(-, %d, %d) returned NULL",
+				printk(KERN_ERR "loop: device %s: getblk(-, %d, %d) returned NULL\n",
 					kdevname(lo->lo_device),
 					block, blksize);
 				goto error_out_lock;
@@ -256,7 +266,7 @@
 			}
 
 			if ((lo->transfer)(lo, current_request->cmd, bh->b_data + offset,
-					dest_addr, size, real_block)) {
+					dest_addr, size, (int)((((unsigned int)blksize >> 9) * (unsigned int)block) + ((unsigned int)offset >> 9)))) {
 				printk(KERN_ERR "loop: transfer error block %d\n", block);
 				brelse(bh);
 				goto error_out_lock;
@@ -274,6 +284,8 @@
 		block++;
 	}
 	spin_lock_irq(&io_request_lock);
+	current_request->sector += current_request->current_nr_sectors;
+	current_request->nr_sectors -= current_request->current_nr_sectors;
 	current_request->next=CURRENT;
 	CURRENT=current_request;
 	end_request(1);
@@ -336,7 +348,7 @@
 	if (retval < 0) {
 		printk(KERN_WARNING
 		    "loop: cannot create block - FS write failed: code %d\n",
-		    (int)retval);
+		    (int)retval); /**/
 		return FALSE;
 	} else {
 		return TRUE;
@@ -347,7 +359,7 @@
 {
 	struct file	*file;
 	struct inode	*inode;
-	int error;
+	int error, hardsz = 512;
 
 	MOD_INC_USE_COUNT;
 
@@ -375,6 +387,8 @@
 		/* Backed by a block device - don't need to hold onto
 		   a file structure */
 		lo->lo_backing_file = NULL;
+
+		hardsz = get_hardblocksize(lo->lo_device);
 	} else if (S_ISREG(inode->i_mode)) {
 		if (!inode->i_op->bmap) { 
 			printk(KERN_ERR "loop: device has no block access/not implemented\n");
@@ -413,8 +427,10 @@
 	if (error)
 		goto out_putf;
 
-	if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) {
+	loop_hardsizes[MINOR(dev)] = hardsz;
+	if ((S_ISREG(inode->i_mode) && IS_RDONLY(inode)) || is_read_only(lo->lo_device) || !(file->f_mode & FMODE_WRITE)) {
 		lo->lo_flags |= LO_FLAGS_READ_ONLY;
+		lo->lo_flags |= 0x200000; /* export to user space */
 		set_device_ro(dev, 1);
 	} else {
 		invalidate_inode_pages (inode);
@@ -473,8 +489,10 @@
 	if (lo->lo_refcnt > 1)	/* we needed one fd for the ioctl */
 		return -EBUSY;
 
-	if (S_ISBLK(dentry->d_inode->i_mode))
+	if (S_ISBLK(dentry->d_inode->i_mode)) {
+		fsync_dev(dentry->d_inode->i_rdev);
 		blkdev_release (dentry->d_inode);
+	}
 	lo->lo_dentry = NULL;
 
 	if (lo->lo_backing_file != NULL) {
@@ -561,6 +579,8 @@
 		info.lo_encrypt_key_size = lo->lo_encrypt_key_size;
 		memcpy(info.lo_encrypt_key, lo->lo_encrypt_key,
 		       lo->lo_encrypt_key_size);
+		info.lo_init[0] = lo->lo_init[0];
+		info.lo_init[1] = lo->lo_init[1];
 	}
 	return copy_to_user(arg, &info, sizeof(info)) ? -EFAULT : 0;
 }
@@ -605,7 +625,7 @@
 static int lo_open(struct inode *inode, struct file *file)
 {
 	struct loop_device *lo;
-	int	dev, type;
+	int	dev;
 
 
 	if (!inode)
@@ -619,10 +639,6 @@
 		return -ENODEV;
 	}
 	lo = &loop_dev[dev];
-
-	type = lo->lo_encrypt_type; 
-	if (type && xfer_funcs[type] && xfer_funcs[type]->lock)
-		xfer_funcs[type]->lock(lo);
 	lo->lo_refcnt++;
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -647,10 +663,7 @@
 	if (lo->lo_refcnt <= 0)
 		printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", lo->lo_refcnt);
 	else  {
-		int type  = lo->lo_encrypt_type;
 		--lo->lo_refcnt;
-		if (xfer_funcs[type] && xfer_funcs[type]->unlock)
-			xfer_funcs[type]->unlock(lo);
 		MOD_DEC_USE_COUNT;
 	}
 	return err;
@@ -678,7 +691,7 @@
 
 int loop_register_transfer(struct loop_func_table *funcs)
 {
-	if ((unsigned)funcs->number > MAX_LO_CRYPT || xfer_funcs[funcs->number])
+	if ((unsigned)funcs->number >= MAX_LO_CRYPT || xfer_funcs[funcs->number])
 		return -EINVAL;
 	xfer_funcs[funcs->number] = funcs;
 	return 0; 
@@ -725,16 +738,35 @@
 	}
 	memset(&loop_sizes, 0, sizeof(loop_sizes));
 	memset(&loop_blksizes, 0, sizeof(loop_blksizes));
+	memset(&loop_hardsizes, 0, sizeof(loop_hardsizes));
 	blk_size[MAJOR_NR] = loop_sizes;
 	blksize_size[MAJOR_NR] = loop_blksizes;
+	hardsect_size[MAJOR_NR] = loop_hardsizes;
 
+	{ extern int init_module_aes(void); init_module_aes(); }
 	return 0;
 }
 
 #ifdef MODULE
 void cleanup_module(void) 
 {
+	{ extern void cleanup_module_aes(void); cleanup_module_aes(); }
 	if (unregister_blkdev(MAJOR_NR, "loop") != 0)
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
+
+	blk_size[MAJOR_NR] = 0;
+	blksize_size[MAJOR_NR] = 0;
+	hardsect_size[MAJOR_NR] = 0;
 }
 #endif
+
+extern void loop_compute_sector_iv(int, u_int32_t *);
+EXPORT_SYMBOL(loop_compute_sector_iv);
+extern void loop_compute_md5_iv_v3(int, u_int32_t *, u_int32_t *);
+EXPORT_SYMBOL(loop_compute_md5_iv_v3);
+extern void loop_compute_md5_iv(int, u_int32_t *, u_int32_t *);
+EXPORT_SYMBOL(loop_compute_md5_iv);
+extern void md5_transform_CPUbyteorder(u_int32_t *, u_int32_t const *);
+EXPORT_SYMBOL_NOVERS(md5_transform_CPUbyteorder);
+extern void md5_transform_CPUbyteorder_C(u_int32_t *, u_int32_t const *);
+EXPORT_SYMBOL(md5_transform_CPUbyteorder_C);
