summaryrefslogtreecommitdiff
path: root/fs/ext2/xip.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext2/xip.c')
-rw-r--r--fs/ext2/xip.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
new file mode 100644
index 00000000..1c331285
--- /dev/null
+++ b/fs/ext2/xip.c
@@ -0,0 +1,90 @@
+/*
+ * 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/blkdev.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;
+ const 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_msg(sb, KERN_WARNING,
+ "warning: 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;
+}