diff options
author | Kirill Korotaev <dev@openvz.org> | 2006-03-11 06:27:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-11 12:19:34 -0500 |
commit | 0adb25d2e71ab047423d6fc63d5d184590d0a66f (patch) | |
tree | 0fd00ea22c07c88c3f24085cbf89f0a272f56697 | |
parent | 8bd0ee93fef9733c72fef1817330b3ee2b71cf9d (diff) |
[PATCH] ext3: ext3_symlink should use GFP_NOFS allocations inside
This patch fixes illegal __GFP_FS allocation inside ext3 transaction in
ext3_symlink(). Such allocation may re-enter ext3 code from
try_to_free_pages. But JBD/ext3 code keeps a pointer to current journal
handle in task_struct and, hence, is not reentrable.
This bug led to "Assertion failure in journal_dirty_metadata()" messages.
http://bugzilla.openvz.org/show_bug.cgi?id=115
Signed-off-by: Andrey Savochkin <saw@saw.sw.com.sg>
Signed-off-by: Kirill Korotaev <dev@openvz.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/ext3/namei.c | 3 | ||||
-rw-r--r-- | fs/namei.c | 13 | ||||
-rw-r--r-- | include/linux/fs.h | 2 |
3 files changed, 15 insertions, 3 deletions
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 8bd8ac077704..b8f5cd1e540d 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
@@ -2141,7 +2141,8 @@ retry: | |||
2141 | * We have a transaction open. All is sweetness. It also sets | 2141 | * We have a transaction open. All is sweetness. It also sets |
2142 | * i_size in generic_commit_write(). | 2142 | * i_size in generic_commit_write(). |
2143 | */ | 2143 | */ |
2144 | err = page_symlink(inode, symname, l); | 2144 | err = __page_symlink(inode, symname, l, |
2145 | mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); | ||
2145 | if (err) { | 2146 | if (err) { |
2146 | ext3_dec_count(handle, inode); | 2147 | ext3_dec_count(handle, inode); |
2147 | ext3_mark_inode_dirty(handle, inode); | 2148 | ext3_mark_inode_dirty(handle, inode); |
diff --git a/fs/namei.c b/fs/namei.c index 557dcf395ca1..8dc2b038d5d9 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2613,13 +2613,15 @@ void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) | |||
2613 | } | 2613 | } |
2614 | } | 2614 | } |
2615 | 2615 | ||
2616 | int page_symlink(struct inode *inode, const char *symname, int len) | 2616 | int __page_symlink(struct inode *inode, const char *symname, int len, |
2617 | gfp_t gfp_mask) | ||
2617 | { | 2618 | { |
2618 | struct address_space *mapping = inode->i_mapping; | 2619 | struct address_space *mapping = inode->i_mapping; |
2619 | struct page *page = grab_cache_page(mapping, 0); | 2620 | struct page *page; |
2620 | int err = -ENOMEM; | 2621 | int err = -ENOMEM; |
2621 | char *kaddr; | 2622 | char *kaddr; |
2622 | 2623 | ||
2624 | page = find_or_create_page(mapping, 0, gfp_mask); | ||
2623 | if (!page) | 2625 | if (!page) |
2624 | goto fail; | 2626 | goto fail; |
2625 | err = mapping->a_ops->prepare_write(NULL, page, 0, len-1); | 2627 | err = mapping->a_ops->prepare_write(NULL, page, 0, len-1); |
@@ -2654,6 +2656,12 @@ fail: | |||
2654 | return err; | 2656 | return err; |
2655 | } | 2657 | } |
2656 | 2658 | ||
2659 | int page_symlink(struct inode *inode, const char *symname, int len) | ||
2660 | { | ||
2661 | return __page_symlink(inode, symname, len, | ||
2662 | mapping_gfp_mask(inode->i_mapping)); | ||
2663 | } | ||
2664 | |||
2657 | struct inode_operations page_symlink_inode_operations = { | 2665 | struct inode_operations page_symlink_inode_operations = { |
2658 | .readlink = generic_readlink, | 2666 | .readlink = generic_readlink, |
2659 | .follow_link = page_follow_link_light, | 2667 | .follow_link = page_follow_link_light, |
@@ -2672,6 +2680,7 @@ EXPORT_SYMBOL(lookup_one_len); | |||
2672 | EXPORT_SYMBOL(page_follow_link_light); | 2680 | EXPORT_SYMBOL(page_follow_link_light); |
2673 | EXPORT_SYMBOL(page_put_link); | 2681 | EXPORT_SYMBOL(page_put_link); |
2674 | EXPORT_SYMBOL(page_readlink); | 2682 | EXPORT_SYMBOL(page_readlink); |
2683 | EXPORT_SYMBOL(__page_symlink); | ||
2675 | EXPORT_SYMBOL(page_symlink); | 2684 | EXPORT_SYMBOL(page_symlink); |
2676 | EXPORT_SYMBOL(page_symlink_inode_operations); | 2685 | EXPORT_SYMBOL(page_symlink_inode_operations); |
2677 | EXPORT_SYMBOL(path_lookup); | 2686 | EXPORT_SYMBOL(path_lookup); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 51c0c93bdf93..128d0082522c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1664,6 +1664,8 @@ extern int vfs_follow_link(struct nameidata *, const char *); | |||
1664 | extern int page_readlink(struct dentry *, char __user *, int); | 1664 | extern int page_readlink(struct dentry *, char __user *, int); |
1665 | extern void *page_follow_link_light(struct dentry *, struct nameidata *); | 1665 | extern void *page_follow_link_light(struct dentry *, struct nameidata *); |
1666 | extern void page_put_link(struct dentry *, struct nameidata *, void *); | 1666 | extern void page_put_link(struct dentry *, struct nameidata *, void *); |
1667 | extern int __page_symlink(struct inode *inode, const char *symname, int len, | ||
1668 | gfp_t gfp_mask); | ||
1667 | extern int page_symlink(struct inode *inode, const char *symname, int len); | 1669 | extern int page_symlink(struct inode *inode, const char *symname, int len); |
1668 | extern struct inode_operations page_symlink_inode_operations; | 1670 | extern struct inode_operations page_symlink_inode_operations; |
1669 | extern int generic_readlink(struct dentry *, char __user *, int); | 1671 | extern int generic_readlink(struct dentry *, char __user *, int); |