Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

return pfn from direct_access, for XIP

Alter the block device ->direct_access() API to work with the new
get_xip_mem() API (that requires both kaddr and pfn are returned).

Some architectures will not do the right thing in their virt_to_page() for use
by XIP (to translate from the kernel virtual address returned by
direct_access(), to a user mappable pfn in XIP's page fault handler.

However, we can't switch it to just return the pfn and not the kaddr, because
we have no good way to get a kva from a pfn, and XIP requires the kva for its
read(2) and write(2) handlers. So we have to return both.

Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Carsten Otte <cotte@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: linux-mm@kvack.org
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Jared Hulbert and committed by
Linus Torvalds
30afcb4b 423bad60

+27 -18
+3 -2
arch/powerpc/sysdev/axonram.c
··· 143 143 */ 144 144 static int 145 145 axon_ram_direct_access(struct block_device *device, sector_t sector, 146 - unsigned long *data) 146 + void **kaddr, unsigned long *pfn) 147 147 { 148 148 struct axon_ram_bank *bank = device->bd_disk->private_data; 149 149 loff_t offset; ··· 154 154 return -ERANGE; 155 155 } 156 156 157 - *data = bank->ph_addr + offset; 157 + *kaddr = (void *)(bank->ph_addr + offset); 158 + *pfn = virt_to_phys(kaddr) >> PAGE_SHIFT; 158 159 159 160 return 0; 160 161 }
+3 -2
drivers/block/brd.c
··· 319 319 320 320 #ifdef CONFIG_BLK_DEV_XIP 321 321 static int brd_direct_access (struct block_device *bdev, sector_t sector, 322 - unsigned long *data) 322 + void **kaddr, unsigned long *pfn) 323 323 { 324 324 struct brd_device *brd = bdev->bd_disk->private_data; 325 325 struct page *page; ··· 333 333 page = brd_insert_page(brd, sector); 334 334 if (!page) 335 335 return -ENOMEM; 336 - *data = (unsigned long)page_address(page); 336 + *kaddr = page_address(page); 337 + *pfn = page_to_pfn(page); 337 338 338 339 return 0; 339 340 }
+5 -3
drivers/s390/block/dcssblk.c
··· 36 36 static int dcssblk_release(struct inode *inode, struct file *filp); 37 37 static int dcssblk_make_request(struct request_queue *q, struct bio *bio); 38 38 static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, 39 - unsigned long *data); 39 + void **kaddr, unsigned long *pfn); 40 40 41 41 static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; 42 42 ··· 636 636 637 637 static int 638 638 dcssblk_direct_access (struct block_device *bdev, sector_t secnum, 639 - unsigned long *data) 639 + void **kaddr, unsigned long *pfn) 640 640 { 641 641 struct dcssblk_dev_info *dev_info; 642 642 unsigned long pgoff; ··· 649 649 pgoff = secnum / (PAGE_SIZE / 512); 650 650 if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) 651 651 return -ERANGE; 652 - *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE); 652 + *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE); 653 + *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; 654 + 653 655 return 0; 654 656 } 655 657
+14 -10
fs/ext2/xip.c
··· 16 16 17 17 static inline int 18 18 __inode_direct_access(struct inode *inode, sector_t sector, 19 - unsigned long *data) 19 + void **kaddr, unsigned long *pfn) 20 20 { 21 - BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access); 22 - return inode->i_sb->s_bdev->bd_disk->fops 23 - ->direct_access(inode->i_sb->s_bdev,sector,data); 21 + struct block_device *bdev = inode->i_sb->s_bdev; 22 + struct block_device_operations *ops = bdev->bd_disk->fops; 23 + 24 + BUG_ON(!ops->direct_access); 25 + return ops->direct_access(bdev, sector, kaddr, pfn); 24 26 } 25 27 26 28 static inline int ··· 50 48 ext2_clear_xip_target(struct inode *inode, int block) 51 49 { 52 50 sector_t sector = block * (PAGE_SIZE/512); 53 - unsigned long data; 51 + void *kaddr; 52 + unsigned long pfn; 54 53 int rc; 55 54 56 - rc = __inode_direct_access(inode, sector, &data); 55 + rc = __inode_direct_access(inode, sector, &kaddr, &pfn); 57 56 if (!rc) 58 - clear_page((void*)data); 57 + clear_page(kaddr); 59 58 return rc; 60 59 } 61 60 ··· 77 74 int create) 78 75 { 79 76 int rc; 80 - unsigned long data; 77 + void *kaddr; 78 + unsigned long pfn; 81 79 sector_t sector; 82 80 83 81 /* first, retrieve the sector number */ ··· 88 84 89 85 /* retrieve address of the target data */ 90 86 rc = __inode_direct_access 91 - (mapping->host, sector * (PAGE_SIZE/512), &data); 87 + (mapping->host, sector * (PAGE_SIZE/512), &kaddr, &pfn); 92 88 if (!rc) 93 - return virt_to_page(data); 89 + return pfn_to_page(pfn); 94 90 95 91 error: 96 92 return ERR_PTR(rc);
+2 -1
include/linux/fs.h
··· 1178 1178 int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); 1179 1179 long (*unlocked_ioctl) (struct file *, unsigned, unsigned long); 1180 1180 long (*compat_ioctl) (struct file *, unsigned, unsigned long); 1181 - int (*direct_access) (struct block_device *, sector_t, unsigned long *); 1181 + int (*direct_access) (struct block_device *, sector_t, 1182 + void **, unsigned long *); 1182 1183 int (*media_changed) (struct gendisk *); 1183 1184 int (*revalidate_disk) (struct gendisk *); 1184 1185 int (*getgeo)(struct block_device *, struct hd_geometry *);