summaryrefslogtreecommitdiffstats
path: root/fs/ext2
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-08-10 13:46:28 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-08-10 13:46:28 -0400
commit2f058256cb64e346f4fb4499ff4e0f1c2791a4b4 (patch)
tree91e06602f4d3abb6812ea8c9bc9ba4501e14c84e /fs/ext2
parent0274aa2506fd2fe89a58dd6cd64d3b3f7b976af8 (diff)
parent86b3786078d63242d3194ffc58ae8dae1d1bbef3 (diff)
downloadkernel-crypto-2f058256cb64e346f4fb4499ff4e0f1c2791a4b4.tar.gz
kernel-crypto-2f058256cb64e346f4fb4499ff4e0f1c2791a4b4.tar.xz
kernel-crypto-2f058256cb64e346f4fb4499ff4e0f1c2791a4b4.zip
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'fs/ext2')
-rw-r--r--fs/ext2/Makefile1
-rw-r--r--fs/ext2/acl.c12
-rw-r--r--fs/ext2/acl.h2
-rw-r--r--fs/ext2/ext2.h11
-rw-r--r--fs/ext2/file.c14
-rw-r--r--fs/ext2/ialloc.c1
-rw-r--r--fs/ext2/inode.c31
-rw-r--r--fs/ext2/namei.c12
-rw-r--r--fs/ext2/super.c51
-rw-r--r--fs/ext2/xattr.c2
-rw-r--r--fs/ext2/xip.c93
-rw-r--r--fs/ext2/xip.h25
12 files changed, 236 insertions, 19 deletions
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile
index ee240a14e70..c5d02da73bc 100644
--- a/fs/ext2/Makefile
+++ b/fs/ext2/Makefile
@@ -10,3 +10,4 @@ ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o
+ext2-$(CONFIG_EXT2_FS_XIP) += xip.o
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 25f4a64fd6b..213148c36eb 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -396,12 +396,12 @@ static size_t
ext2_xattr_list_acl_access(struct inode *inode, char *list, size_t list_size,
const char *name, size_t name_len)
{
- const size_t size = sizeof(XATTR_NAME_ACL_ACCESS);
+ const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
if (!test_opt(inode->i_sb, POSIX_ACL))
return 0;
if (list && size <= list_size)
- memcpy(list, XATTR_NAME_ACL_ACCESS, size);
+ memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
return size;
}
@@ -409,12 +409,12 @@ static size_t
ext2_xattr_list_acl_default(struct inode *inode, char *list, size_t list_size,
const char *name, size_t name_len)
{
- const size_t size = sizeof(XATTR_NAME_ACL_DEFAULT);
+ const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
if (!test_opt(inode->i_sb, POSIX_ACL))
return 0;
if (list && size <= list_size)
- memcpy(list, XATTR_NAME_ACL_DEFAULT, size);
+ memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
return size;
}
@@ -506,14 +506,14 @@ ext2_xattr_set_acl_default(struct inode *inode, const char *name,
}
struct xattr_handler ext2_xattr_acl_access_handler = {
- .prefix = XATTR_NAME_ACL_ACCESS,
+ .prefix = POSIX_ACL_XATTR_ACCESS,
.list = ext2_xattr_list_acl_access,
.get = ext2_xattr_get_acl_access,
.set = ext2_xattr_set_acl_access,
};
struct xattr_handler ext2_xattr_acl_default_handler = {
- .prefix = XATTR_NAME_ACL_DEFAULT,
+ .prefix = POSIX_ACL_XATTR_DEFAULT,
.list = ext2_xattr_list_acl_default,
.get = ext2_xattr_get_acl_default,
.set = ext2_xattr_set_acl_default,
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h
index fed96ae81a7..0bde85bafe3 100644
--- a/fs/ext2/acl.h
+++ b/fs/ext2/acl.h
@@ -4,7 +4,7 @@
(C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*/
-#include <linux/xattr_acl.h>
+#include <linux/posix_acl_xattr.h>
#define EXT2_ACL_VERSION 0x0001
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 8f0fd726c3f..e977f8566d1 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -2,6 +2,15 @@
#include <linux/ext2_fs.h>
/*
+ * ext2 mount options
+ */
+struct ext2_mount_options {
+ unsigned long s_mount_opt;
+ uid_t s_resuid;
+ gid_t s_resgid;
+};
+
+/*
* second extended file system inode data in memory
*/
struct ext2_inode_info {
@@ -147,9 +156,11 @@ extern struct file_operations ext2_dir_operations;
/* file.c */
extern struct inode_operations ext2_file_inode_operations;
extern struct file_operations ext2_file_operations;
+extern struct file_operations ext2_xip_file_operations;
/* inode.c */
extern struct address_space_operations ext2_aops;
+extern struct address_space_operations ext2_aops_xip;
extern struct address_space_operations ext2_nobh_aops;
/* namei.c */
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index f5e86141ec5..a484412fc78 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -55,6 +55,20 @@ struct file_operations ext2_file_operations = {
.sendfile = generic_file_sendfile,
};
+#ifdef CONFIG_EXT2_FS_XIP
+struct file_operations ext2_xip_file_operations = {
+ .llseek = generic_file_llseek,
+ .read = xip_file_read,
+ .write = xip_file_write,
+ .ioctl = ext2_ioctl,
+ .mmap = xip_file_mmap,
+ .open = generic_file_open,
+ .release = ext2_release_file,
+ .fsync = ext2_sync_file,
+ .sendfile = xip_file_sendfile,
+};
+#endif
+
struct inode_operations ext2_file_inode_operations = {
.truncate = ext2_truncate,
#ifdef CONFIG_EXT2_FS_XATTR
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 77e05914921..161f156d98c 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -612,6 +612,7 @@ got:
err = ext2_init_acl(inode, dir);
if (err) {
DQUOT_FREE_INODE(inode);
+ DQUOT_DROP(inode);
goto fail2;
}
mark_inode_dirty(inode);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index a50d9db4b6e..53dceb0c659 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -33,6 +33,7 @@
#include <linux/mpage.h>
#include "ext2.h"
#include "acl.h"
+#include "xip.h"
MODULE_AUTHOR("Remy Card and others");
MODULE_DESCRIPTION("Second Extended Filesystem");
@@ -594,6 +595,16 @@ out:
if (err)
goto cleanup;
+ if (ext2_use_xip(inode->i_sb)) {
+ /*
+ * we need to clear the block
+ */
+ err = ext2_clear_xip_target (inode,
+ le32_to_cpu(chain[depth-1].key));
+ if (err)
+ goto cleanup;
+ }
+
if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)
goto changed;
@@ -691,6 +702,11 @@ struct address_space_operations ext2_aops = {
.writepages = ext2_writepages,
};
+struct address_space_operations ext2_aops_xip = {
+ .bmap = ext2_bmap,
+ .get_xip_page = ext2_get_xip_page,
+};
+
struct address_space_operations ext2_nobh_aops = {
.readpage = ext2_readpage,
.readpages = ext2_readpages,
@@ -910,7 +926,9 @@ void ext2_truncate (struct inode * inode)
iblock = (inode->i_size + blocksize-1)
>> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
- if (test_opt(inode->i_sb, NOBH))
+ if (mapping_is_xip(inode->i_mapping))
+ xip_truncate_page(inode->i_mapping, inode->i_size);
+ else if (test_opt(inode->i_sb, NOBH))
nobh_truncate_page(inode->i_mapping, inode->i_size);
else
block_truncate_page(inode->i_mapping,
@@ -1110,11 +1128,16 @@ void ext2_read_inode (struct inode * inode)
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext2_file_inode_operations;
- inode->i_fop = &ext2_file_operations;
- if (test_opt(inode->i_sb, NOBH))
+ if (ext2_use_xip(inode->i_sb)) {
+ inode->i_mapping->a_ops = &ext2_aops_xip;
+ inode->i_fop = &ext2_xip_file_operations;
+ } else if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops;
- else
+ inode->i_fop = &ext2_file_operations;
+ } else {
inode->i_mapping->a_ops = &ext2_aops;
+ inode->i_fop = &ext2_file_operations;
+ }
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ext2_dir_inode_operations;
inode->i_fop = &ext2_dir_operations;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 3176b3d3ffa..c5513953c82 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -34,6 +34,7 @@
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
+#include "xip.h"
/*
* Couple of helper functions - make the code slightly cleaner.
@@ -127,11 +128,16 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, st
int err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
inode->i_op = &ext2_file_inode_operations;
- inode->i_fop = &ext2_file_operations;
- if (test_opt(inode->i_sb, NOBH))
+ if (ext2_use_xip(inode->i_sb)) {
+ inode->i_mapping->a_ops = &ext2_aops_xip;
+ inode->i_fop = &ext2_xip_file_operations;
+ } else if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops;
- else
+ inode->i_fop = &ext2_file_operations;
+ } else {
inode->i_mapping->a_ops = &ext2_aops;
+ inode->i_fop = &ext2_file_operations;
+ }
mark_inode_dirty(inode);
err = ext2_add_nondir(dentry, inode);
}
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 661c3d98d94..dcfe331dc4c 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -31,6 +31,7 @@
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
+#include "xip.h"
static void ext2_sync_super(struct super_block *sb,
struct ext2_super_block *es);
@@ -257,7 +258,7 @@ enum {
Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
- Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
+ Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip,
Opt_ignore, Opt_err,
};
@@ -286,6 +287,7 @@ static match_table_t tokens = {
{Opt_nouser_xattr, "nouser_xattr"},
{Opt_acl, "acl"},
{Opt_noacl, "noacl"},
+ {Opt_xip, "xip"},
{Opt_ignore, "grpquota"},
{Opt_ignore, "noquota"},
{Opt_ignore, "quota"},
@@ -397,6 +399,13 @@ static int parse_options (char * options,
printk("EXT2 (no)acl options not supported\n");
break;
#endif
+ case Opt_xip:
+#ifdef CONFIG_EXT2_FS_XIP
+ set_opt (sbi->s_mount_opt, XIP);
+#else
+ printk("EXT2 xip option not supported\n");
+#endif
+ break;
case Opt_ignore:
break;
default:
@@ -640,6 +649,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
MS_POSIXACL : 0);
+ ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset
+ EXT2_MOUNT_XIP if not */
+
if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
(EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
@@ -668,6 +680,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
+ if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) ||
+ (sb->s_blocksize != blocksize))) {
+ if (!silent)
+ printk("XIP: Unsupported blocksize\n");
+ goto failed_mount;
+ }
+
/* If the blocksize doesn't match, re-read the thing.. */
if (sb->s_blocksize != blocksize) {
brelse(bh);
@@ -916,17 +935,34 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
{
struct ext2_sb_info * sbi = EXT2_SB(sb);
struct ext2_super_block * es;
+ unsigned long old_mount_opt = sbi->s_mount_opt;
+ struct ext2_mount_options old_opts;
+ unsigned long old_sb_flags;
+ int err;
+
+ /* Store the old options */
+ old_sb_flags = sb->s_flags;
+ old_opts.s_mount_opt = sbi->s_mount_opt;
+ old_opts.s_resuid = sbi->s_resuid;
+ old_opts.s_resgid = sbi->s_resgid;
/*
* Allow the "check" option to be passed as a remount option.
*/
- if (!parse_options (data, sbi))
- return -EINVAL;
+ if (!parse_options (data, sbi)) {
+ err = -EINVAL;
+ goto restore_opts;
+ }
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
es = sbi->s_es;
+ if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) !=
+ (old_mount_opt & EXT2_MOUNT_XIP)) &&
+ invalidate_inodes(sb))
+ ext2_warning(sb, __FUNCTION__, "busy inodes while remounting "\
+ "xip remain in cache (no functional problem)");
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
return 0;
if (*flags & MS_RDONLY) {
@@ -946,7 +982,8 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
printk("EXT2-fs: %s: couldn't remount RDWR because of "
"unsupported optional features (%x).\n",
sb->s_id, le32_to_cpu(ret));
- return -EROFS;
+ err = -EROFS;
+ goto restore_opts;
}
/*
* Mounting a RDONLY partition read-write, so reread and
@@ -959,6 +996,12 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
}
ext2_sync_super(sb, es);
return 0;
+restore_opts:
+ sbi->s_mount_opt = old_opts.s_mount_opt;
+ sbi->s_resuid = old_opts.s_resuid;
+ sbi->s_resgid = old_opts.s_resgid;
+ sb->s_flags = old_sb_flags;
+ return err;
}
static int ext2_statfs (struct super_block * sb, struct kstatfs * buf)
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index 27982b500e8..0099462d427 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -823,7 +823,7 @@ cleanup:
void
ext2_xattr_put_super(struct super_block *sb)
{
- mb_cache_shrink(ext2_xattr_cache, sb->s_bdev);
+ mb_cache_shrink(sb->s_bdev);
}
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
new file mode 100644
index 00000000000..ca7f0031238
--- /dev/null
+++ b/fs/ext2/xip.c
@@ -0,0 +1,93 @@
+/*
+ * 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 sector,
+ unsigned long *data)
+{
+ BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
+ return inode->i_sb->s_bdev->bd_disk->fops
+ ->direct_access(inode->i_sb->s_bdev,sector,data);
+}
+
+static inline int
+__ext2_get_sector(struct inode *inode, sector_t offset, int create,
+ sector_t *result)
+{
+ struct buffer_head tmp;
+ int rc;
+
+ memset(&tmp, 0, sizeof(struct buffer_head));
+ rc = ext2_get_block(inode, offset/ (PAGE_SIZE/512), &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, int block)
+{
+ sector_t sector = block * (PAGE_SIZE/512);
+ unsigned long data;
+ int rc;
+
+ rc = __inode_direct_access(inode, sector, &data);
+ if (!rc)
+ clear_page((void*)data);
+ 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");
+ }
+}
+
+struct page *
+ext2_get_xip_page(struct address_space *mapping, sector_t offset,
+ int create)
+{
+ int rc;
+ unsigned long data;
+ sector_t sector;
+
+ /* first, retrieve the sector number */
+ rc = __ext2_get_sector(mapping->host, offset, create, &sector);
+ if (rc)
+ goto error;
+
+ /* retrieve address of the target data */
+ rc = __inode_direct_access
+ (mapping->host, sector * (PAGE_SIZE/512), &data);
+ if (!rc)
+ return virt_to_page(data);
+
+ error:
+ return ERR_PTR(rc);
+}
diff --git a/fs/ext2/xip.h b/fs/ext2/xip.h
new file mode 100644
index 00000000000..aa85331d6c5
--- /dev/null
+++ b/fs/ext2/xip.h
@@ -0,0 +1,25 @@
+/*
+ * linux/fs/ext2/xip.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Author: Carsten Otte (cotte@de.ibm.com)
+ */
+
+#ifdef CONFIG_EXT2_FS_XIP
+extern void ext2_xip_verify_sb (struct super_block *);
+extern int ext2_clear_xip_target (struct inode *, int);
+
+static inline int ext2_use_xip (struct super_block *sb)
+{
+ struct ext2_sb_info *sbi = EXT2_SB(sb);
+ return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
+}
+struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
+#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
+#else
+#define mapping_is_xip(map) 0
+#define ext2_xip_verify_sb(sb) do { } while (0)
+#define ext2_use_xip(sb) 0
+#define ext2_clear_xip_target(inode, chain) 0
+#define ext2_get_xip_page NULL
+#endif