diff options
author | Jared Hulbert <jaredeh@gmail.com> | 2008-04-28 05:13:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-28 11:58:23 -0400 |
commit | 30afcb4bd2762fa4b87b17ada9500aa46dc10b1b (patch) | |
tree | 0920f491a37683a8784c146270b98f82a7e0aa2c | |
parent | 423bad600443c590f34ed7ce357591f76f48f137 (diff) |
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>
-rw-r--r-- | arch/powerpc/sysdev/axonram.c | 5 | ||||
-rw-r--r-- | drivers/block/brd.c | 5 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 8 | ||||
-rw-r--r-- | fs/ext2/xip.c | 24 | ||||
-rw-r--r-- | include/linux/fs.h | 3 |
5 files changed, 27 insertions, 18 deletions
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index d359d6e92975..7f59188cd9a1 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c | |||
@@ -143,7 +143,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) | |||
143 | */ | 143 | */ |
144 | static int | 144 | static int |
145 | axon_ram_direct_access(struct block_device *device, sector_t sector, | 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 | struct axon_ram_bank *bank = device->bd_disk->private_data; | 148 | struct axon_ram_bank *bank = device->bd_disk->private_data; |
149 | loff_t offset; | 149 | loff_t offset; |
@@ -154,7 +154,8 @@ axon_ram_direct_access(struct block_device *device, sector_t sector, | |||
154 | return -ERANGE; | 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 | return 0; | 160 | return 0; |
160 | } | 161 | } |
diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 7bd76639544c..e8e38faeafd8 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c | |||
@@ -319,7 +319,7 @@ out: | |||
319 | 319 | ||
320 | #ifdef CONFIG_BLK_DEV_XIP | 320 | #ifdef CONFIG_BLK_DEV_XIP |
321 | static int brd_direct_access (struct block_device *bdev, sector_t sector, | 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 | struct brd_device *brd = bdev->bd_disk->private_data; | 324 | struct brd_device *brd = bdev->bd_disk->private_data; |
325 | struct page *page; | 325 | struct page *page; |
@@ -333,7 +333,8 @@ static int brd_direct_access (struct block_device *bdev, sector_t sector, | |||
333 | page = brd_insert_page(brd, sector); | 333 | page = brd_insert_page(brd, sector); |
334 | if (!page) | 334 | if (!page) |
335 | return -ENOMEM; | 335 | return -ENOMEM; |
336 | *data = (unsigned long)page_address(page); | 336 | *kaddr = page_address(page); |
337 | *pfn = page_to_pfn(page); | ||
337 | 338 | ||
338 | return 0; | 339 | return 0; |
339 | } | 340 | } |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 04787eab1016..bb52d2fbac18 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -36,7 +36,7 @@ static int dcssblk_open(struct inode *inode, struct file *filp); | |||
36 | static int dcssblk_release(struct inode *inode, struct file *filp); | 36 | static int dcssblk_release(struct inode *inode, struct file *filp); |
37 | static int dcssblk_make_request(struct request_queue *q, struct bio *bio); | 37 | static int dcssblk_make_request(struct request_queue *q, struct bio *bio); |
38 | static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, | 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 | static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; | 41 | static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; |
42 | 42 | ||
@@ -636,7 +636,7 @@ fail: | |||
636 | 636 | ||
637 | static int | 637 | static int |
638 | dcssblk_direct_access (struct block_device *bdev, sector_t secnum, | 638 | dcssblk_direct_access (struct block_device *bdev, sector_t secnum, |
639 | unsigned long *data) | 639 | void **kaddr, unsigned long *pfn) |
640 | { | 640 | { |
641 | struct dcssblk_dev_info *dev_info; | 641 | struct dcssblk_dev_info *dev_info; |
642 | unsigned long pgoff; | 642 | unsigned long pgoff; |
@@ -649,7 +649,9 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum, | |||
649 | pgoff = secnum / (PAGE_SIZE / 512); | 649 | pgoff = secnum / (PAGE_SIZE / 512); |
650 | if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) | 650 | if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) |
651 | return -ERANGE; | 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 | return 0; | 655 | return 0; |
654 | } | 656 | } |
655 | 657 | ||
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c index ca7f00312388..430b4c8ee971 100644 --- a/fs/ext2/xip.c +++ b/fs/ext2/xip.c | |||
@@ -16,11 +16,13 @@ | |||
16 | 16 | ||
17 | static inline int | 17 | static inline int |
18 | __inode_direct_access(struct inode *inode, sector_t sector, | 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); | 21 | struct block_device *bdev = inode->i_sb->s_bdev; |
22 | return inode->i_sb->s_bdev->bd_disk->fops | 22 | struct block_device_operations *ops = bdev->bd_disk->fops; |
23 | ->direct_access(inode->i_sb->s_bdev,sector,data); | 23 | |
24 | BUG_ON(!ops->direct_access); | ||
25 | return ops->direct_access(bdev, sector, kaddr, pfn); | ||
24 | } | 26 | } |
25 | 27 | ||
26 | static inline int | 28 | static inline int |
@@ -48,12 +50,13 @@ int | |||
48 | ext2_clear_xip_target(struct inode *inode, int block) | 50 | ext2_clear_xip_target(struct inode *inode, int block) |
49 | { | 51 | { |
50 | sector_t sector = block * (PAGE_SIZE/512); | 52 | sector_t sector = block * (PAGE_SIZE/512); |
51 | unsigned long data; | 53 | void *kaddr; |
54 | unsigned long pfn; | ||
52 | int rc; | 55 | int rc; |
53 | 56 | ||
54 | rc = __inode_direct_access(inode, sector, &data); | 57 | rc = __inode_direct_access(inode, sector, &kaddr, &pfn); |
55 | if (!rc) | 58 | if (!rc) |
56 | clear_page((void*)data); | 59 | clear_page(kaddr); |
57 | return rc; | 60 | return rc; |
58 | } | 61 | } |
59 | 62 | ||
@@ -74,7 +77,8 @@ ext2_get_xip_page(struct address_space *mapping, sector_t offset, | |||
74 | int create) | 77 | int create) |
75 | { | 78 | { |
76 | int rc; | 79 | int rc; |
77 | unsigned long data; | 80 | void *kaddr; |
81 | unsigned long pfn; | ||
78 | sector_t sector; | 82 | sector_t sector; |
79 | 83 | ||
80 | /* first, retrieve the sector number */ | 84 | /* first, retrieve the sector number */ |
@@ -84,9 +88,9 @@ ext2_get_xip_page(struct address_space *mapping, sector_t offset, | |||
84 | 88 | ||
85 | /* retrieve address of the target data */ | 89 | /* retrieve address of the target data */ |
86 | rc = __inode_direct_access | 90 | rc = __inode_direct_access |
87 | (mapping->host, sector * (PAGE_SIZE/512), &data); | 91 | (mapping->host, sector * (PAGE_SIZE/512), &kaddr, &pfn); |
88 | if (!rc) | 92 | if (!rc) |
89 | return virt_to_page(data); | 93 | return pfn_to_page(pfn); |
90 | 94 | ||
91 | error: | 95 | error: |
92 | return ERR_PTR(rc); | 96 | return ERR_PTR(rc); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index d6d7c52055c6..bd05f5678045 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1178,7 +1178,8 @@ struct block_device_operations { | |||
1178 | int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); | 1178 | int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); |
1179 | long (*unlocked_ioctl) (struct file *, unsigned, unsigned long); | 1179 | long (*unlocked_ioctl) (struct file *, unsigned, unsigned long); |
1180 | long (*compat_ioctl) (struct file *, unsigned, unsigned long); | 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 | int (*media_changed) (struct gendisk *); | 1183 | int (*media_changed) (struct gendisk *); |
1183 | int (*revalidate_disk) (struct gendisk *); | 1184 | int (*revalidate_disk) (struct gendisk *); |
1184 | int (*getgeo)(struct block_device *, struct hd_geometry *); | 1185 | int (*getgeo)(struct block_device *, struct hd_geometry *); |