[RFC/PATCH 4/5] loop: add execute in place support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[RFC/PATCH 4/5] loop: add execute in place support
The old loop driver in 2.6.11. used the readpage/writepage aops to
transfer data. Now loop can also use read/write and direct_IO on the
file if readpage/writepage are not available. Unlike the old 2.6.11.
version, today's loop driver does work with files that do not have
readpage/writepage. Threrefore, this patch is optional.
This patch adds one more transport method to loop that uses the new
address space operation get_xip_page if available.

Signed-off-by: Carsten Otte <[email protected]>
---
diff -ruN linux-2.6-git/drivers/block/loop.c linux-2.6-git-xip/drivers/block/loop.c
--- linux-2.6-git/drivers/block/loop.c	2005-05-10 14:55:05.000000000 +0200
+++ linux-2.6-git-xip/drivers/block/loop.c	2005-05-10 16:21:49.803071544 +0200
@@ -275,6 +275,83 @@
 	goto out;
 }

+
+static int
+do_lo_send_xip(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos,
+		struct page* ignored)
+{
+	struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
+	struct address_space *mapping = file->f_mapping;
+	struct address_space_operations *aops = mapping->a_ops;
+	struct page *page;
+	pgoff_t index;
+	unsigned size, offset, bv_offs;
+	int len;
+	int ret = 0;
+
+	down(&mapping->host->i_sem);
+	index = pos >> PAGE_CACHE_SHIFT;
+	offset = pos & ((pgoff_t)PAGE_CACHE_SIZE - 1);
+	bv_offs = bvec->bv_offset;
+	len = bvec->bv_len;
+	while (len > 0) {
+		sector_t IV;
+		int transfer_result;
+
+		IV = ((sector_t)index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9);
+
+		size = PAGE_CACHE_SIZE - offset;
+		if (size > len)
+			size = len;
+
+		page = aops->get_xip_page(mapping,
+			index*(PAGE_SIZE/512), 0);
+		if (!page)
+			goto fail;
+		if (unlikely(IS_ERR(page))) {
+			if (PTR_ERR(page) == -ENODATA) {
+				/* sparse */
+				page = virt_to_page(empty_zero_page);
+			} else
+				goto fail;
+		} else
+			BUG_ON(!PageUptodate(page));
+
+		transfer_result = lo_do_transfer(lo, WRITE, page, offset,
+						 bvec->bv_page, bv_offs,
+						 size, IV);
+		if (transfer_result) {
+			char *kaddr;
+
+			/*
+			 * The transfer failed, but we still write the data to
+			 * keep prepare/commit calls balanced.
+			 */
+			printk(KERN_ERR "loop: transfer error block %llu\n",
+			       (unsigned long long)index);
+			kaddr = kmap_atomic(page, KM_USER0);
+			memset(kaddr + offset, 0, size);
+			kunmap_atomic(kaddr, KM_USER0);
+		}
+		flush_dcache_page(page);
+		if (transfer_result)
+			goto fail;
+		bv_offs += size;
+		len -= size;
+		offset = 0;
+		index++;
+		pos += size;
+	}
+	up(&mapping->host->i_sem);
+out:
+	return ret;
+
+fail:
+	up(&mapping->host->i_sem);
+	ret = -1;
+	goto out;
+}
+
 /**
  * __do_lo_send_write - helper for writing data to a loop device
  *
@@ -356,8 +433,11 @@
 	struct page *page = NULL;
 	int i, ret = 0;

-	do_lo_send = do_lo_send_aops;
-	if (!(lo->lo_flags & LO_FLAGS_USE_AOPS)) {
+	if (lo->lo_flags & LO_FLAGS_USE_AOPS)
+		do_lo_send = do_lo_send_aops;
+	else if (lo->lo_flags & LO_FLAGS_USE_XIP)
+		do_lo_send = do_lo_send_xip;
+	else {
 		do_lo_send = do_lo_send_direct_write;
 		if (lo->transfer != transfer_none) {
 			page = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
@@ -787,11 +867,13 @@
 		 */
 		if (!file->f_op->sendfile)
 			goto out_putf;
-		if (aops->prepare_write && aops->commit_write)
+		if (aops->get_xip_page)
+			lo_flags |= LO_FLAGS_USE_XIP;
+		else if (aops->prepare_write && aops->commit_write)
 			lo_flags |= LO_FLAGS_USE_AOPS;
-		if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
+		if (!(lo_flags & (LO_FLAGS_USE_AOPS | LO_FLAGS_USE_XIP))
+		    && !file->f_op->write)
 			lo_flags |= LO_FLAGS_READ_ONLY;
-
 		lo_blocksize = inode->i_blksize;
 		error = 0;
 	} else {
diff -ruN linux-2.6-git/include/linux/loop.h linux-2.6-git-xip/include/linux/loop.h
--- linux-2.6-git/include/linux/loop.h	2005-05-10 14:55:23.000000000 +0200
+++ linux-2.6-git-xip/include/linux/loop.h	2005-05-10 16:21:31.816805872 +0200
@@ -74,6 +74,7 @@
 enum {
 	LO_FLAGS_READ_ONLY	= 1,
 	LO_FLAGS_USE_AOPS	= 2,
+	LO_FLAGS_USE_XIP        = 4,
 };

 #include <asm/posix_types.h>	/* for __kernel_old_dev_t */


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux