aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorAndrea Arcangeli <andrea@novell.com>2004-11-18 22:52:39 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-11-18 22:52:39 -0800
commitfc2219b2156b88f75688a4512f19a7c3d7bb4da9 (patch)
tree089c8228166e2cd72aaaf38b88d78d85548a8332 /mm
parent9f2a3e2ed17bfca51474459f0895eb23f4e9e4c7 (diff)
downloadhistory-fc2219b2156b88f75688a4512f19a7c3d7bb4da9.tar.gz
[PATCH] fix for mpol mm corruption on tmpfs
With the inline symlink shmem_inode_info structure is overwritten with data until vfs_inode, and that caused the ->policy to be a corrupted pointer during unlink. It wasn't immediatly easy to see what was going on due the random mm corruption that generated a weird oops, it looked more like a race condition on freed memory at first. There's simply no need to set a policy for inodes, since the idx is always zero. All we have to do is to initialize the data structure (the semaphore may need to run during the page allocation for the non-inline symlink) but we don't need to allocate the rb nodes. This way we don't need to call mpol_free during the destroy_inode (not doable at all if the policy rbtree is corrupt by the inline symlink ;). An equivalent version of this patch based on a 2.6.5 tree with additional numa features on top of this (i.e. interleaved by default, and that's prompted me to add a comment in the LNK init path), works fine in a numa simulation on my laptop (untested on the bare hardware). Signed-off-by: Andrea Arcangeli <andrea@novell.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/shmem.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index 99ceb026e8d31e..e1ff7d74c249a4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1292,7 +1292,6 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
info = SHMEM_I(inode);
memset(info, 0, (char *)inode - (char *)info);
spin_lock_init(&info->lock);
- mpol_shared_policy_init(&info->policy);
INIT_LIST_HEAD(&info->swaplist);
switch (mode & S_IFMT) {
@@ -1303,6 +1302,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
case S_IFREG:
inode->i_op = &shmem_inode_operations;
inode->i_fop = &shmem_file_operations;
+ mpol_shared_policy_init(&info->policy);
break;
case S_IFDIR:
inode->i_nlink++;
@@ -1312,6 +1312,11 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
inode->i_fop = &simple_dir_operations;
break;
case S_IFLNK:
+ /*
+ * Must not load anything in the rbtree,
+ * mpol_free_shared_policy will not be called.
+ */
+ mpol_shared_policy_init(&info->policy);
break;
}
} else if (sbinfo) {
@@ -2030,7 +2035,10 @@ static struct inode *shmem_alloc_inode(struct super_block *sb)
static void shmem_destroy_inode(struct inode *inode)
{
- mpol_free_shared_policy(&SHMEM_I(inode)->policy);
+ if ((inode->i_mode & S_IFMT) == S_IFREG) {
+ /* only struct inode is valid if it's an inline symlink */
+ mpol_free_shared_policy(&SHMEM_I(inode)->policy);
+ }
kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
}