aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <axboe@fb.com>2015-01-13 23:58:45 -0500
committerJens Axboe <axboe@fb.com>2015-01-13 23:58:45 -0500
commitd4119ee0e1aa2b74e5e367cbc915e79db7b9e271 (patch)
treedae4e7bebdda0db62a00c5bb3d054a6018d68444
parent91117a20245b59f70b563523edbf998a62fc6383 (diff)
parentdd22f551ac0ad366f92f601835f6623b83adc331 (diff)
Merge branch 'for-3.20/core' into for-3.20/drivers
-rw-r--r--Documentation/filesystems/xip.txt15
-rw-r--r--arch/powerpc/sysdev/axonram.c17
-rw-r--r--drivers/block/brd.c14
-rw-r--r--drivers/s390/block/dcssblk.c21
-rw-r--r--fs/block_dev.c40
-rw-r--r--fs/ext2/xip.c31
-rw-r--r--include/linux/blkdev.h6
7 files changed, 86 insertions, 58 deletions
diff --git a/Documentation/filesystems/xip.txt b/Documentation/filesystems/xip.txt
index 0466ee569278..b77472949ede 100644
--- a/Documentation/filesystems/xip.txt
+++ b/Documentation/filesystems/xip.txt
@@ -28,12 +28,15 @@ Implementation
28Execute-in-place is implemented in three steps: block device operation, 28Execute-in-place is implemented in three steps: block device operation,
29address space operation, and file operations. 29address space operation, and file operations.
30 30
31A block device operation named direct_access is used to retrieve a 31A block device operation named direct_access is used to translate the
32reference (pointer) to a block on-disk. The reference is supposed to be 32block device sector number to a page frame number (pfn) that identifies
33cpu-addressable, physical address and remain valid until the release operation 33the physical page for the memory. It also returns a kernel virtual
34is performed. A struct block_device reference is used to address the device, 34address that can be used to access the memory.
35and a sector_t argument is used to identify the individual block. As an 35
36alternative, memory technology devices can be used for this. 36The direct_access method takes a 'size' parameter that indicates the
37number of bytes being requested. The function should return the number
38of bytes that can be contiguously accessed at that offset. It may also
39return a negative errno if an error occurs.
37 40
38The block device operation is optional, these block devices support it as of 41The block device operation is optional, these block devices support it as of
39today: 42today:
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index 367533bb3d48..ee90db17b097 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -139,26 +139,17 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
139 * axon_ram_direct_access - direct_access() method for block device 139 * axon_ram_direct_access - direct_access() method for block device
140 * @device, @sector, @data: see block_device_operations method 140 * @device, @sector, @data: see block_device_operations method
141 */ 141 */
142static int 142static long
143axon_ram_direct_access(struct block_device *device, sector_t sector, 143axon_ram_direct_access(struct block_device *device, sector_t sector,
144 void **kaddr, unsigned long *pfn) 144 void **kaddr, unsigned long *pfn, long size)
145{ 145{
146 struct axon_ram_bank *bank = device->bd_disk->private_data; 146 struct axon_ram_bank *bank = device->bd_disk->private_data;
147 loff_t offset; 147 loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT;
148
149 offset = sector;
150 if (device->bd_part != NULL)
151 offset += device->bd_part->start_sect;
152 offset <<= AXON_RAM_SECTOR_SHIFT;
153 if (offset >= bank->size) {
154 dev_err(&bank->device->dev, "Access outside of address space\n");
155 return -ERANGE;
156 }
157 148
158 *kaddr = (void *)(bank->ph_addr + offset); 149 *kaddr = (void *)(bank->ph_addr + offset);
159 *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; 150 *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT;
160 151
161 return 0; 152 return bank->size - offset;
162} 153}
163 154
164static const struct block_device_operations axon_ram_devops = { 155static const struct block_device_operations axon_ram_devops = {
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index 3598110d2cef..89e90ec52f28 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -370,25 +370,25 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector,
370} 370}
371 371
372#ifdef CONFIG_BLK_DEV_XIP 372#ifdef CONFIG_BLK_DEV_XIP
373static int brd_direct_access(struct block_device *bdev, sector_t sector, 373static long brd_direct_access(struct block_device *bdev, sector_t sector,
374 void **kaddr, unsigned long *pfn) 374 void **kaddr, unsigned long *pfn, long size)
375{ 375{
376 struct brd_device *brd = bdev->bd_disk->private_data; 376 struct brd_device *brd = bdev->bd_disk->private_data;
377 struct page *page; 377 struct page *page;
378 378
379 if (!brd) 379 if (!brd)
380 return -ENODEV; 380 return -ENODEV;
381 if (sector & (PAGE_SECTORS-1))
382 return -EINVAL;
383 if (sector + PAGE_SECTORS > get_capacity(bdev->bd_disk))
384 return -ERANGE;
385 page = brd_insert_page(brd, sector); 381 page = brd_insert_page(brd, sector);
386 if (!page) 382 if (!page)
387 return -ENOSPC; 383 return -ENOSPC;
388 *kaddr = page_address(page); 384 *kaddr = page_address(page);
389 *pfn = page_to_pfn(page); 385 *pfn = page_to_pfn(page);
390 386
391 return 0; 387 /*
388 * TODO: If size > PAGE_SIZE, we could look to see if the next page in
389 * the file happens to be mapped to the next page of physical RAM.
390 */
391 return PAGE_SIZE;
392} 392}
393#endif 393#endif
394 394
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index b550c8c8d010..31d6884f3351 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -28,8 +28,8 @@
28static int dcssblk_open(struct block_device *bdev, fmode_t mode); 28static int dcssblk_open(struct block_device *bdev, fmode_t mode);
29static void dcssblk_release(struct gendisk *disk, fmode_t mode); 29static void dcssblk_release(struct gendisk *disk, fmode_t mode);
30static void dcssblk_make_request(struct request_queue *q, struct bio *bio); 30static void dcssblk_make_request(struct request_queue *q, struct bio *bio);
31static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, 31static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
32 void **kaddr, unsigned long *pfn); 32 void **kaddr, unsigned long *pfn, long size);
33 33
34static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; 34static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
35 35
@@ -866,25 +866,22 @@ fail:
866 bio_io_error(bio); 866 bio_io_error(bio);
867} 867}
868 868
869static int 869static long
870dcssblk_direct_access (struct block_device *bdev, sector_t secnum, 870dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
871 void **kaddr, unsigned long *pfn) 871 void **kaddr, unsigned long *pfn, long size)
872{ 872{
873 struct dcssblk_dev_info *dev_info; 873 struct dcssblk_dev_info *dev_info;
874 unsigned long pgoff; 874 unsigned long offset, dev_sz;
875 875
876 dev_info = bdev->bd_disk->private_data; 876 dev_info = bdev->bd_disk->private_data;
877 if (!dev_info) 877 if (!dev_info)
878 return -ENODEV; 878 return -ENODEV;
879 if (secnum % (PAGE_SIZE/512)) 879 dev_sz = dev_info->end - dev_info->start;
880 return -EINVAL; 880 offset = secnum * 512;
881 pgoff = secnum / (PAGE_SIZE / 512); 881 *kaddr = (void *) (dev_info->start + offset);
882 if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
883 return -ERANGE;
884 *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE);
885 *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; 882 *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT;
886 883
887 return 0; 884 return dev_sz - offset;
888} 885}
889 886
890static void 887static void
diff --git a/fs/block_dev.c b/fs/block_dev.c
index b48c41bf0f86..f314c2c0567d 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -429,6 +429,46 @@ int bdev_write_page(struct block_device *bdev, sector_t sector,
429} 429}
430EXPORT_SYMBOL_GPL(bdev_write_page); 430EXPORT_SYMBOL_GPL(bdev_write_page);
431 431
432/**
433 * bdev_direct_access() - Get the address for directly-accessibly memory
434 * @bdev: The device containing the memory
435 * @sector: The offset within the device
436 * @addr: Where to put the address of the memory
437 * @pfn: The Page Frame Number for the memory
438 * @size: The number of bytes requested
439 *
440 * If a block device is made up of directly addressable memory, this function
441 * will tell the caller the PFN and the address of the memory. The address
442 * may be directly dereferenced within the kernel without the need to call
443 * ioremap(), kmap() or similar. The PFN is suitable for inserting into
444 * page tables.
445 *
446 * Return: negative errno if an error occurs, otherwise the number of bytes
447 * accessible at this address.
448 */
449long bdev_direct_access(struct block_device *bdev, sector_t sector,
450 void **addr, unsigned long *pfn, long size)
451{
452 long avail;
453 const struct block_device_operations *ops = bdev->bd_disk->fops;
454
455 if (size < 0)
456 return size;
457 if (!ops->direct_access)
458 return -EOPNOTSUPP;
459 if ((sector + DIV_ROUND_UP(size, 512)) >
460 part_nr_sects_read(bdev->bd_part))
461 return -ERANGE;
462 sector += get_start_sect(bdev);
463 if (sector % (PAGE_SIZE / 512))
464 return -EINVAL;
465 avail = ops->direct_access(bdev, sector, addr, pfn, size);
466 if (!avail)
467 return -ERANGE;
468 return min(avail, size);
469}
470EXPORT_SYMBOL_GPL(bdev_direct_access);
471
432/* 472/*
433 * pseudo-fs 473 * pseudo-fs
434 */ 474 */
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
index e98171a11cfe..bbc5fec6ff7f 100644
--- a/fs/ext2/xip.c
+++ b/fs/ext2/xip.c
@@ -13,18 +13,12 @@
13#include "ext2.h" 13#include "ext2.h"
14#include "xip.h" 14#include "xip.h"
15 15
16static inline int 16static inline long __inode_direct_access(struct inode *inode, sector_t block,
17__inode_direct_access(struct inode *inode, sector_t block, 17 void **kaddr, unsigned long *pfn, long size)
18 void **kaddr, unsigned long *pfn)
19{ 18{
20 struct block_device *bdev = inode->i_sb->s_bdev; 19 struct block_device *bdev = inode->i_sb->s_bdev;
21 const struct block_device_operations *ops = bdev->bd_disk->fops; 20 sector_t sector = block * (PAGE_SIZE / 512);
22 sector_t sector; 21 return bdev_direct_access(bdev, sector, kaddr, pfn, size);
23
24 sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */
25
26 BUG_ON(!ops->direct_access);
27 return ops->direct_access(bdev, sector, kaddr, pfn);
28} 22}
29 23
30static inline int 24static inline int
@@ -53,12 +47,13 @@ ext2_clear_xip_target(struct inode *inode, sector_t block)
53{ 47{
54 void *kaddr; 48 void *kaddr;
55 unsigned long pfn; 49 unsigned long pfn;
56 int rc; 50 long size;
57 51
58 rc = __inode_direct_access(inode, block, &kaddr, &pfn); 52 size = __inode_direct_access(inode, block, &kaddr, &pfn, PAGE_SIZE);
59 if (!rc) 53 if (size < 0)
60 clear_page(kaddr); 54 return size;
61 return rc; 55 clear_page(kaddr);
56 return 0;
62} 57}
63 58
64void ext2_xip_verify_sb(struct super_block *sb) 59void ext2_xip_verify_sb(struct super_block *sb)
@@ -77,7 +72,7 @@ void ext2_xip_verify_sb(struct super_block *sb)
77int ext2_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create, 72int ext2_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create,
78 void **kmem, unsigned long *pfn) 73 void **kmem, unsigned long *pfn)
79{ 74{
80 int rc; 75 long rc;
81 sector_t block; 76 sector_t block;
82 77
83 /* first, retrieve the sector number */ 78 /* first, retrieve the sector number */
@@ -86,6 +81,6 @@ int ext2_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create,
86 return rc; 81 return rc;
87 82
88 /* retrieve address of the target data */ 83 /* retrieve address of the target data */
89 rc = __inode_direct_access(mapping->host, block, kmem, pfn); 84 rc = __inode_direct_access(mapping->host, block, kmem, pfn, PAGE_SIZE);
90 return rc; 85 return (rc < 0) ? rc : 0;
91} 86}
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 92f4b4b288dd..e9086be6d9a0 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1601,8 +1601,8 @@ struct block_device_operations {
1601 int (*rw_page)(struct block_device *, sector_t, struct page *, int rw); 1601 int (*rw_page)(struct block_device *, sector_t, struct page *, int rw);
1602 int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); 1602 int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
1603 int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); 1603 int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
1604 int (*direct_access) (struct block_device *, sector_t, 1604 long (*direct_access)(struct block_device *, sector_t,
1605 void **, unsigned long *); 1605 void **, unsigned long *pfn, long size);
1606 unsigned int (*check_events) (struct gendisk *disk, 1606 unsigned int (*check_events) (struct gendisk *disk,
1607 unsigned int clearing); 1607 unsigned int clearing);
1608 /* ->media_changed() is DEPRECATED, use ->check_events() instead */ 1608 /* ->media_changed() is DEPRECATED, use ->check_events() instead */
@@ -1620,6 +1620,8 @@ extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int,
1620extern int bdev_read_page(struct block_device *, sector_t, struct page *); 1620extern int bdev_read_page(struct block_device *, sector_t, struct page *);
1621extern int bdev_write_page(struct block_device *, sector_t, struct page *, 1621extern int bdev_write_page(struct block_device *, sector_t, struct page *,
1622 struct writeback_control *); 1622 struct writeback_control *);
1623extern long bdev_direct_access(struct block_device *, sector_t, void **addr,
1624 unsigned long *pfn, long size);
1623#else /* CONFIG_BLOCK */ 1625#else /* CONFIG_BLOCK */
1624 1626
1625struct block_device; 1627struct block_device;