70688e4dd1
Convert XIP to support non-struct page backed memory, using VM_MIXEDMAP for the user mappings. This requires the get_xip_page API to be changed to an address based one. Improve the API layering a little bit too, while we're here. This is required in order to support XIP filesystems on memory that isn't backed with struct page (but memory with struct page is still supported too). Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: Carsten Otte <cotte@de.ibm.com> Cc: Jared Hulbert <jaredeh@gmail.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
91 lines
2.0 KiB
C
91 lines
2.0 KiB
C
/*
|
|
* linux/fs/ext2/xip.c
|
|
*
|
|
* Copyright (C) 2005 IBM Corporation
|
|
* Author: Carsten Otte (cotte@de.ibm.com)
|
|
*/
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/genhd.h>
|
|
#include <linux/buffer_head.h>
|
|
#include <linux/ext2_fs_sb.h>
|
|
#include <linux/ext2_fs.h>
|
|
#include "ext2.h"
|
|
#include "xip.h"
|
|
|
|
static inline int
|
|
__inode_direct_access(struct inode *inode, sector_t block,
|
|
void **kaddr, unsigned long *pfn)
|
|
{
|
|
struct block_device *bdev = inode->i_sb->s_bdev;
|
|
struct block_device_operations *ops = bdev->bd_disk->fops;
|
|
sector_t sector;
|
|
|
|
sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */
|
|
|
|
BUG_ON(!ops->direct_access);
|
|
return ops->direct_access(bdev, sector, kaddr, pfn);
|
|
}
|
|
|
|
static inline int
|
|
__ext2_get_block(struct inode *inode, pgoff_t pgoff, int create,
|
|
sector_t *result)
|
|
{
|
|
struct buffer_head tmp;
|
|
int rc;
|
|
|
|
memset(&tmp, 0, sizeof(struct buffer_head));
|
|
rc = ext2_get_block(inode, pgoff, &tmp, create);
|
|
*result = tmp.b_blocknr;
|
|
|
|
/* did we get a sparse block (hole in the file)? */
|
|
if (!tmp.b_blocknr && !rc) {
|
|
BUG_ON(create);
|
|
rc = -ENODATA;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ext2_clear_xip_target(struct inode *inode, sector_t block)
|
|
{
|
|
void *kaddr;
|
|
unsigned long pfn;
|
|
int rc;
|
|
|
|
rc = __inode_direct_access(inode, block, &kaddr, &pfn);
|
|
if (!rc)
|
|
clear_page(kaddr);
|
|
return rc;
|
|
}
|
|
|
|
void ext2_xip_verify_sb(struct super_block *sb)
|
|
{
|
|
struct ext2_sb_info *sbi = EXT2_SB(sb);
|
|
|
|
if ((sbi->s_mount_opt & EXT2_MOUNT_XIP) &&
|
|
!sb->s_bdev->bd_disk->fops->direct_access) {
|
|
sbi->s_mount_opt &= (~EXT2_MOUNT_XIP);
|
|
ext2_warning(sb, __FUNCTION__,
|
|
"ignoring xip option - not supported by bdev");
|
|
}
|
|
}
|
|
|
|
int ext2_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create,
|
|
void **kmem, unsigned long *pfn)
|
|
{
|
|
int rc;
|
|
sector_t block;
|
|
|
|
/* first, retrieve the sector number */
|
|
rc = __ext2_get_block(mapping->host, pgoff, create, &block);
|
|
if (rc)
|
|
return rc;
|
|
|
|
/* retrieve address of the target data */
|
|
rc = __inode_direct_access(mapping->host, block, kmem, pfn);
|
|
return rc;
|
|
}
|