loop: add execute in place support
Subsystems (2)
PATCH 4/5 loop: add execute in place support
[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]>
---
drivers/block/loop.c +87 -5
@@ -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 {
include/linux/loop.h +1 -0
@@ -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 */