patch-2.4.10 linux/drivers/block/loop.c

Next file: linux/drivers/block/nbd.c
Previous file: linux/drivers/block/ll_rw_blk.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.9/linux/drivers/block/loop.c linux/drivers/block/loop.c
@@ -62,6 +62,7 @@
 #include <linux/major.h>
 #include <linux/wait.h>
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
@@ -86,10 +87,12 @@
 static int transfer_none(struct loop_device *lo, int cmd, char *raw_buf,
 			 char *loop_buf, int size, int real_block)
 {
-	if (cmd == READ)
-		memcpy(loop_buf, raw_buf, size);
-	else
-		memcpy(raw_buf, loop_buf, size);
+	if (raw_buf != loop_buf) {
+		if (cmd == READ)
+			memcpy(loop_buf, raw_buf, size);
+		else
+			memcpy(raw_buf, loop_buf, size);
+	}
 
 	return 0;
 }
@@ -117,6 +120,7 @@
 
 static int none_status(struct loop_device *lo, struct loop_info *info)
 {
+	lo->lo_flags |= LO_FLAGS_BH_REMAP;
 	return 0;
 }
 
@@ -313,9 +317,13 @@
 	return ret;
 }
 
+static void loop_end_io_transfer(struct buffer_head *bh, int uptodate);
 static void loop_put_buffer(struct buffer_head *bh)
 {
-	if (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);
 	}
@@ -385,6 +393,14 @@
 {
 	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)
@@ -397,9 +413,6 @@
 
 	bh->b_size = rbh->b_size;
 	bh->b_dev = rbh->b_rdev;
-	spin_lock_irq(&lo->lo_lock);
-	bh->b_rdev = lo->lo_device;
-	spin_unlock_irq(&lo->lo_lock);
 	bh->b_state = (1 << BH_Req) | (1 << BH_Mapped) | (1 << BH_Lock);
 
 	/*
@@ -418,9 +431,15 @@
 
 	bh->b_data = page_address(bh->b_page);
 	bh->b_end_io = loop_end_io_transfer;
-	bh->b_rsector = rbh->b_rsector + (lo->lo_offset >> 9);
+	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;
 }
 
@@ -475,8 +494,7 @@
 	 * piggy old buffer on original, and submit for I/O
 	 */
 	bh = loop_get_buffer(lo, rbh);
-	bh->b_private = rbh;
-	IV = loop_get_iv(lo, bh->b_rsector);
+	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,
@@ -600,7 +618,7 @@
 	error = -EBUSY;
 	if (lo->lo_state != Lo_unbound)
 		goto out;
-	 
+
 	error = -EBADF;
 	file = fget(arg);
 	if (!file)
@@ -620,7 +638,6 @@
 		 * If we can't read - sorry. If we only can't write - well,
 		 * it's going to be read-only.
 		 */
-		error = -EINVAL;
 		if (!aops->readpage)
 			goto out_putf;
 
@@ -848,11 +865,18 @@
 			err = -ENXIO;
 			break;
 		}
-		if (!arg) {
-			err = -EINVAL;
+		err = put_user(loop_sizes[lo->lo_number] << 1, (long *) arg);
+		break;
+	case BLKGETSIZE64:
+		if (lo->lo_state != Lo_bound) {
+			err = -ENXIO;
 			break;
 		}
-		err = put_user(loop_sizes[lo->lo_number] << 1, (long *) arg);
+		err = put_user((u64)loop_sizes[lo->lo_number] << 10, (u64*)arg);
+		break;
+	case BLKBSZGET:
+	case BLKBSZSET:
+		err = blk_ioctl(inode->i_rdev, cmd, arg);
 		break;
 	default:
 		err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)