diff options
author | Nick Piggin <npiggin@suse.de> | 2009-01-04 15:00:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-04 16:33:20 -0500 |
commit | 54566b2c1594c2326a645a3551f9d989f7ba3c5e (patch) | |
tree | b373f3283fe5e197d0df29cd6b645c35adf1076c | |
parent | e687d691cb3790d25e31c74f5941fd7c565e9df5 (diff) |
fs: symlink write_begin allocation context fix
With the write_begin/write_end aops, page_symlink was broken because it
could no longer pass a GFP_NOFS type mask into the point where the
allocations happened. They are done in write_begin, which would always
assume that the filesystem can be entered from reclaim. This bug could
cause filesystem deadlocks.
The funny thing with having a gfp_t mask there is that it doesn't really
allow the caller to arbitrarily tinker with the context in which it can be
called. It couldn't ever be GFP_ATOMIC, for example, because it needs to
take the page lock. The only thing any callers care about is __GFP_FS
anyway, so turn that into a single flag.
Add a new flag for write_begin, AOP_FLAG_NOFS. Filesystems can now act on
this flag in their write_begin function. Change __grab_cache_page to
accept a nofs argument as well, to honour that flag (while we're there,
change the name to grab_cache_page_write_begin which is more instructive
and does away with random leading underscores).
This is really a more flexible way to go in the end anyway -- if a
filesystem happens to want any extra allocations aside from the pagecache
ones in ints write_begin function, it may now use GFP_KERNEL (rather than
GFP_NOFS) for common case allocations (eg. ocfs2_alloc_write_ctxt, for a
random example).
[kosaki.motohiro@jp.fujitsu.com: fix ubifs]
[kosaki.motohiro@jp.fujitsu.com: fix fuse]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: <stable@kernel.org> [2.6.28.x]
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
[ Cleaned up the calling convention: just pass in the AOP flags
untouched to the grab_cache_page_write_begin() function. That
just simplifies everybody, and may even allow future expansion of the
logic. - Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/affs/file.c | 2 | ||||
-rw-r--r-- | fs/afs/write.c | 2 | ||||
-rw-r--r-- | fs/buffer.c | 4 | ||||
-rw-r--r-- | fs/cifs/file.c | 2 | ||||
-rw-r--r-- | fs/ecryptfs/mmap.c | 2 | ||||
-rw-r--r-- | fs/ext3/inode.c | 2 | ||||
-rw-r--r-- | fs/ext3/namei.c | 3 | ||||
-rw-r--r-- | fs/ext4/inode.c | 4 | ||||
-rw-r--r-- | fs/ext4/namei.c | 3 | ||||
-rw-r--r-- | fs/fuse/file.c | 4 | ||||
-rw-r--r-- | fs/gfs2/ops_address.c | 2 | ||||
-rw-r--r-- | fs/hostfs/hostfs_kern.c | 2 | ||||
-rw-r--r-- | fs/jffs2/file.c | 2 | ||||
-rw-r--r-- | fs/libfs.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 13 | ||||
-rw-r--r-- | fs/nfs/file.c | 2 | ||||
-rw-r--r-- | fs/reiserfs/inode.c | 2 | ||||
-rw-r--r-- | fs/smbfs/file.c | 2 | ||||
-rw-r--r-- | fs/ubifs/file.c | 9 | ||||
-rw-r--r-- | include/linux/fs.h | 5 | ||||
-rw-r--r-- | include/linux/pagemap.h | 3 | ||||
-rw-r--r-- | mm/filemap.c | 13 |
22 files changed, 49 insertions, 36 deletions
diff --git a/fs/affs/file.c b/fs/affs/file.c index 1377b1240b6e..9246cb4aa018 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c | |||
@@ -628,7 +628,7 @@ static int affs_write_begin_ofs(struct file *file, struct address_space *mapping | |||
628 | } | 628 | } |
629 | 629 | ||
630 | index = pos >> PAGE_CACHE_SHIFT; | 630 | index = pos >> PAGE_CACHE_SHIFT; |
631 | page = __grab_cache_page(mapping, index); | 631 | page = grab_cache_page_write_begin(mapping, index, flags); |
632 | if (!page) | 632 | if (!page) |
633 | return -ENOMEM; | 633 | return -ENOMEM; |
634 | *pagep = page; | 634 | *pagep = page; |
diff --git a/fs/afs/write.c b/fs/afs/write.c index d6b85dab35fc..3fb36d433621 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c | |||
@@ -144,7 +144,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping, | |||
144 | candidate->state = AFS_WBACK_PENDING; | 144 | candidate->state = AFS_WBACK_PENDING; |
145 | init_waitqueue_head(&candidate->waitq); | 145 | init_waitqueue_head(&candidate->waitq); |
146 | 146 | ||
147 | page = __grab_cache_page(mapping, index); | 147 | page = grab_cache_page_write_begin(mapping, index, flags); |
148 | if (!page) { | 148 | if (!page) { |
149 | kfree(candidate); | 149 | kfree(candidate); |
150 | return -ENOMEM; | 150 | return -ENOMEM; |
diff --git a/fs/buffer.c b/fs/buffer.c index 776ae091d3b0..a13f09b696f7 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -1996,7 +1996,7 @@ int block_write_begin(struct file *file, struct address_space *mapping, | |||
1996 | page = *pagep; | 1996 | page = *pagep; |
1997 | if (page == NULL) { | 1997 | if (page == NULL) { |
1998 | ownpage = 1; | 1998 | ownpage = 1; |
1999 | page = __grab_cache_page(mapping, index); | 1999 | page = grab_cache_page_write_begin(mapping, index, flags); |
2000 | if (!page) { | 2000 | if (!page) { |
2001 | status = -ENOMEM; | 2001 | status = -ENOMEM; |
2002 | goto out; | 2002 | goto out; |
@@ -2502,7 +2502,7 @@ int nobh_write_begin(struct file *file, struct address_space *mapping, | |||
2502 | from = pos & (PAGE_CACHE_SIZE - 1); | 2502 | from = pos & (PAGE_CACHE_SIZE - 1); |
2503 | to = from + len; | 2503 | to = from + len; |
2504 | 2504 | ||
2505 | page = __grab_cache_page(mapping, index); | 2505 | page = grab_cache_page_write_begin(mapping, index, flags); |
2506 | if (!page) | 2506 | if (!page) |
2507 | return -ENOMEM; | 2507 | return -ENOMEM; |
2508 | *pagep = page; | 2508 | *pagep = page; |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b1e1fc6a6e6a..12bb656fbe75 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -2074,7 +2074,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, | |||
2074 | 2074 | ||
2075 | cFYI(1, ("write_begin from %lld len %d", (long long)pos, len)); | 2075 | cFYI(1, ("write_begin from %lld len %d", (long long)pos, len)); |
2076 | 2076 | ||
2077 | page = __grab_cache_page(mapping, index); | 2077 | page = grab_cache_page_write_begin(mapping, index, flags); |
2078 | if (!page) { | 2078 | if (!page) { |
2079 | rc = -ENOMEM; | 2079 | rc = -ENOMEM; |
2080 | goto out; | 2080 | goto out; |
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 04d7b3fa1ac6..46cec2b69796 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c | |||
@@ -288,7 +288,7 @@ static int ecryptfs_write_begin(struct file *file, | |||
288 | loff_t prev_page_end_size; | 288 | loff_t prev_page_end_size; |
289 | int rc = 0; | 289 | int rc = 0; |
290 | 290 | ||
291 | page = __grab_cache_page(mapping, index); | 291 | page = grab_cache_page_write_begin(mapping, index, flags); |
292 | if (!page) | 292 | if (!page) |
293 | return -ENOMEM; | 293 | return -ENOMEM; |
294 | *pagep = page; | 294 | *pagep = page; |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index c4bdccf976b5..5fa453b49a64 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -1161,7 +1161,7 @@ static int ext3_write_begin(struct file *file, struct address_space *mapping, | |||
1161 | to = from + len; | 1161 | to = from + len; |
1162 | 1162 | ||
1163 | retry: | 1163 | retry: |
1164 | page = __grab_cache_page(mapping, index); | 1164 | page = grab_cache_page_write_begin(mapping, index, flags); |
1165 | if (!page) | 1165 | if (!page) |
1166 | return -ENOMEM; | 1166 | return -ENOMEM; |
1167 | *pagep = page; | 1167 | *pagep = page; |
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 297ea8dfac7c..1dd2abe6313e 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
@@ -2175,8 +2175,7 @@ retry: | |||
2175 | * We have a transaction open. All is sweetness. It also sets | 2175 | * We have a transaction open. All is sweetness. It also sets |
2176 | * i_size in generic_commit_write(). | 2176 | * i_size in generic_commit_write(). |
2177 | */ | 2177 | */ |
2178 | err = __page_symlink(inode, symname, l, | 2178 | err = __page_symlink(inode, symname, l, 1); |
2179 | mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); | ||
2180 | if (err) { | 2179 | if (err) { |
2181 | drop_nlink(inode); | 2180 | drop_nlink(inode); |
2182 | unlock_new_inode(inode); | 2181 | unlock_new_inode(inode); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7c3325e0b005..6702a49992a6 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1346,7 +1346,7 @@ retry: | |||
1346 | goto out; | 1346 | goto out; |
1347 | } | 1347 | } |
1348 | 1348 | ||
1349 | page = __grab_cache_page(mapping, index); | 1349 | page = grab_cache_page_write_begin(mapping, index, flags); |
1350 | if (!page) { | 1350 | if (!page) { |
1351 | ext4_journal_stop(handle); | 1351 | ext4_journal_stop(handle); |
1352 | ret = -ENOMEM; | 1352 | ret = -ENOMEM; |
@@ -2550,7 +2550,7 @@ retry: | |||
2550 | goto out; | 2550 | goto out; |
2551 | } | 2551 | } |
2552 | 2552 | ||
2553 | page = __grab_cache_page(mapping, index); | 2553 | page = grab_cache_page_write_begin(mapping, index, flags); |
2554 | if (!page) { | 2554 | if (!page) { |
2555 | ext4_journal_stop(handle); | 2555 | ext4_journal_stop(handle); |
2556 | ret = -ENOMEM; | 2556 | ret = -ENOMEM; |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index da98a9012fa5..9fd2a5e1be4d 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -2212,8 +2212,7 @@ retry: | |||
2212 | * We have a transaction open. All is sweetness. It also sets | 2212 | * We have a transaction open. All is sweetness. It also sets |
2213 | * i_size in generic_commit_write(). | 2213 | * i_size in generic_commit_write(). |
2214 | */ | 2214 | */ |
2215 | err = __page_symlink(inode, symname, l, | 2215 | err = __page_symlink(inode, symname, l, 1); |
2216 | mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); | ||
2217 | if (err) { | 2216 | if (err) { |
2218 | clear_nlink(inode); | 2217 | clear_nlink(inode); |
2219 | unlock_new_inode(inode); | 2218 | unlock_new_inode(inode); |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 34930a964b82..4c9ee7011265 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -646,7 +646,7 @@ static int fuse_write_begin(struct file *file, struct address_space *mapping, | |||
646 | { | 646 | { |
647 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | 647 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
648 | 648 | ||
649 | *pagep = __grab_cache_page(mapping, index); | 649 | *pagep = grab_cache_page_write_begin(mapping, index, flags); |
650 | if (!*pagep) | 650 | if (!*pagep) |
651 | return -ENOMEM; | 651 | return -ENOMEM; |
652 | return 0; | 652 | return 0; |
@@ -779,7 +779,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, | |||
779 | break; | 779 | break; |
780 | 780 | ||
781 | err = -ENOMEM; | 781 | err = -ENOMEM; |
782 | page = __grab_cache_page(mapping, index); | 782 | page = grab_cache_page_write_begin(mapping, index, 0); |
783 | if (!page) | 783 | if (!page) |
784 | break; | 784 | break; |
785 | 785 | ||
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 27563816e1c5..15f710f2d4da 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -675,7 +675,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, | |||
675 | goto out_trans_fail; | 675 | goto out_trans_fail; |
676 | 676 | ||
677 | error = -ENOMEM; | 677 | error = -ENOMEM; |
678 | page = __grab_cache_page(mapping, index); | 678 | page = grab_cache_page_write_begin(mapping, index, flags); |
679 | *pagep = page; | 679 | *pagep = page; |
680 | if (unlikely(!page)) | 680 | if (unlikely(!page)) |
681 | goto out_endtrans; | 681 | goto out_endtrans; |
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 3a31451ac170..5c538e0ec14b 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
@@ -501,7 +501,7 @@ int hostfs_write_begin(struct file *file, struct address_space *mapping, | |||
501 | { | 501 | { |
502 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | 502 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
503 | 503 | ||
504 | *pagep = __grab_cache_page(mapping, index); | 504 | *pagep = grab_cache_page_write_begin(mapping, index, flags); |
505 | if (!*pagep) | 505 | if (!*pagep) |
506 | return -ENOMEM; | 506 | return -ENOMEM; |
507 | return 0; | 507 | return 0; |
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 5a98aa87c853..5edc2bf20581 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
@@ -132,7 +132,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
132 | uint32_t pageofs = index << PAGE_CACHE_SHIFT; | 132 | uint32_t pageofs = index << PAGE_CACHE_SHIFT; |
133 | int ret = 0; | 133 | int ret = 0; |
134 | 134 | ||
135 | pg = __grab_cache_page(mapping, index); | 135 | pg = grab_cache_page_write_begin(mapping, index, flags); |
136 | if (!pg) | 136 | if (!pg) |
137 | return -ENOMEM; | 137 | return -ENOMEM; |
138 | *pagep = pg; | 138 | *pagep = pg; |
diff --git a/fs/libfs.c b/fs/libfs.c index e960a8321902..bdaec17fa388 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -360,7 +360,7 @@ int simple_write_begin(struct file *file, struct address_space *mapping, | |||
360 | index = pos >> PAGE_CACHE_SHIFT; | 360 | index = pos >> PAGE_CACHE_SHIFT; |
361 | from = pos & (PAGE_CACHE_SIZE - 1); | 361 | from = pos & (PAGE_CACHE_SIZE - 1); |
362 | 362 | ||
363 | page = __grab_cache_page(mapping, index); | 363 | page = grab_cache_page_write_begin(mapping, index, flags); |
364 | if (!page) | 364 | if (!page) |
365 | return -ENOMEM; | 365 | return -ENOMEM; |
366 | 366 | ||
diff --git a/fs/namei.c b/fs/namei.c index dd5c9f0bf829..df2d3df4f049 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2817,18 +2817,23 @@ void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) | |||
2817 | } | 2817 | } |
2818 | } | 2818 | } |
2819 | 2819 | ||
2820 | int __page_symlink(struct inode *inode, const char *symname, int len, | 2820 | /* |
2821 | gfp_t gfp_mask) | 2821 | * The nofs argument instructs pagecache_write_begin to pass AOP_FLAG_NOFS |
2822 | */ | ||
2823 | int __page_symlink(struct inode *inode, const char *symname, int len, int nofs) | ||
2822 | { | 2824 | { |
2823 | struct address_space *mapping = inode->i_mapping; | 2825 | struct address_space *mapping = inode->i_mapping; |
2824 | struct page *page; | 2826 | struct page *page; |
2825 | void *fsdata; | 2827 | void *fsdata; |
2826 | int err; | 2828 | int err; |
2827 | char *kaddr; | 2829 | char *kaddr; |
2830 | unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE; | ||
2831 | if (nofs) | ||
2832 | flags |= AOP_FLAG_NOFS; | ||
2828 | 2833 | ||
2829 | retry: | 2834 | retry: |
2830 | err = pagecache_write_begin(NULL, mapping, 0, len-1, | 2835 | err = pagecache_write_begin(NULL, mapping, 0, len-1, |
2831 | AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); | 2836 | flags, &page, &fsdata); |
2832 | if (err) | 2837 | if (err) |
2833 | goto fail; | 2838 | goto fail; |
2834 | 2839 | ||
@@ -2852,7 +2857,7 @@ fail: | |||
2852 | int page_symlink(struct inode *inode, const char *symname, int len) | 2857 | int page_symlink(struct inode *inode, const char *symname, int len) |
2853 | { | 2858 | { |
2854 | return __page_symlink(inode, symname, len, | 2859 | return __page_symlink(inode, symname, len, |
2855 | mapping_gfp_mask(inode->i_mapping)); | 2860 | !(mapping_gfp_mask(inode->i_mapping) & __GFP_FS)); |
2856 | } | 2861 | } |
2857 | 2862 | ||
2858 | const struct inode_operations page_symlink_inode_operations = { | 2863 | const struct inode_operations page_symlink_inode_operations = { |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d319b49f8f06..90f292b520d2 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -354,7 +354,7 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, | |||
354 | file->f_path.dentry->d_name.name, | 354 | file->f_path.dentry->d_name.name, |
355 | mapping->host->i_ino, len, (long long) pos); | 355 | mapping->host->i_ino, len, (long long) pos); |
356 | 356 | ||
357 | page = __grab_cache_page(mapping, index); | 357 | page = grab_cache_page_write_begin(mapping, index, flags); |
358 | if (!page) | 358 | if (!page) |
359 | return -ENOMEM; | 359 | return -ENOMEM; |
360 | *pagep = page; | 360 | *pagep = page; |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 145c2d3e5e01..ed04f47007f8 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -2561,7 +2561,7 @@ static int reiserfs_write_begin(struct file *file, | |||
2561 | } | 2561 | } |
2562 | 2562 | ||
2563 | index = pos >> PAGE_CACHE_SHIFT; | 2563 | index = pos >> PAGE_CACHE_SHIFT; |
2564 | page = __grab_cache_page(mapping, index); | 2564 | page = grab_cache_page_write_begin(mapping, index, flags); |
2565 | if (!page) | 2565 | if (!page) |
2566 | return -ENOMEM; | 2566 | return -ENOMEM; |
2567 | *pagep = page; | 2567 | *pagep = page; |
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index e4f8d51a5553..92d5e8ffb639 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c | |||
@@ -297,7 +297,7 @@ static int smb_write_begin(struct file *file, struct address_space *mapping, | |||
297 | struct page **pagep, void **fsdata) | 297 | struct page **pagep, void **fsdata) |
298 | { | 298 | { |
299 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | 299 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
300 | *pagep = __grab_cache_page(mapping, index); | 300 | *pagep = grab_cache_page_write_begin(mapping, index, flags); |
301 | if (!*pagep) | 301 | if (!*pagep) |
302 | return -ENOMEM; | 302 | return -ENOMEM; |
303 | return 0; | 303 | return 0; |
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index fe82d2464d46..bf37374567fa 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c | |||
@@ -219,7 +219,8 @@ static void release_existing_page_budget(struct ubifs_info *c) | |||
219 | } | 219 | } |
220 | 220 | ||
221 | static int write_begin_slow(struct address_space *mapping, | 221 | static int write_begin_slow(struct address_space *mapping, |
222 | loff_t pos, unsigned len, struct page **pagep) | 222 | loff_t pos, unsigned len, struct page **pagep, |
223 | unsigned flags) | ||
223 | { | 224 | { |
224 | struct inode *inode = mapping->host; | 225 | struct inode *inode = mapping->host; |
225 | struct ubifs_info *c = inode->i_sb->s_fs_info; | 226 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
@@ -247,7 +248,7 @@ static int write_begin_slow(struct address_space *mapping, | |||
247 | if (unlikely(err)) | 248 | if (unlikely(err)) |
248 | return err; | 249 | return err; |
249 | 250 | ||
250 | page = __grab_cache_page(mapping, index); | 251 | page = grab_cache_page_write_begin(mapping, index, flags); |
251 | if (unlikely(!page)) { | 252 | if (unlikely(!page)) { |
252 | ubifs_release_budget(c, &req); | 253 | ubifs_release_budget(c, &req); |
253 | return -ENOMEM; | 254 | return -ENOMEM; |
@@ -438,7 +439,7 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping, | |||
438 | return -EROFS; | 439 | return -EROFS; |
439 | 440 | ||
440 | /* Try out the fast-path part first */ | 441 | /* Try out the fast-path part first */ |
441 | page = __grab_cache_page(mapping, index); | 442 | page = grab_cache_page_write_begin(mapping, index, flags); |
442 | if (unlikely(!page)) | 443 | if (unlikely(!page)) |
443 | return -ENOMEM; | 444 | return -ENOMEM; |
444 | 445 | ||
@@ -483,7 +484,7 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping, | |||
483 | unlock_page(page); | 484 | unlock_page(page); |
484 | page_cache_release(page); | 485 | page_cache_release(page); |
485 | 486 | ||
486 | return write_begin_slow(mapping, pos, len, pagep); | 487 | return write_begin_slow(mapping, pos, len, pagep, flags); |
487 | } | 488 | } |
488 | 489 | ||
489 | /* | 490 | /* |
diff --git a/include/linux/fs.h b/include/linux/fs.h index e2170ee21e18..f2a3010140e3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -423,6 +423,9 @@ enum positive_aop_returns { | |||
423 | 423 | ||
424 | #define AOP_FLAG_UNINTERRUPTIBLE 0x0001 /* will not do a short write */ | 424 | #define AOP_FLAG_UNINTERRUPTIBLE 0x0001 /* will not do a short write */ |
425 | #define AOP_FLAG_CONT_EXPAND 0x0002 /* called from cont_expand */ | 425 | #define AOP_FLAG_CONT_EXPAND 0x0002 /* called from cont_expand */ |
426 | #define AOP_FLAG_NOFS 0x0004 /* used by filesystem to direct | ||
427 | * helper code (eg buffer layer) | ||
428 | * to clear GFP_FS from alloc */ | ||
426 | 429 | ||
427 | /* | 430 | /* |
428 | * oh the beauties of C type declarations. | 431 | * oh the beauties of C type declarations. |
@@ -2035,7 +2038,7 @@ extern int page_readlink(struct dentry *, char __user *, int); | |||
2035 | extern void *page_follow_link_light(struct dentry *, struct nameidata *); | 2038 | extern void *page_follow_link_light(struct dentry *, struct nameidata *); |
2036 | extern void page_put_link(struct dentry *, struct nameidata *, void *); | 2039 | extern void page_put_link(struct dentry *, struct nameidata *, void *); |
2037 | extern int __page_symlink(struct inode *inode, const char *symname, int len, | 2040 | extern int __page_symlink(struct inode *inode, const char *symname, int len, |
2038 | gfp_t gfp_mask); | 2041 | int nofs); |
2039 | extern int page_symlink(struct inode *inode, const char *symname, int len); | 2042 | extern int page_symlink(struct inode *inode, const char *symname, int len); |
2040 | extern const struct inode_operations page_symlink_inode_operations; | 2043 | extern const struct inode_operations page_symlink_inode_operations; |
2041 | extern int generic_readlink(struct dentry *, char __user *, int); | 2044 | extern int generic_readlink(struct dentry *, char __user *, int); |
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 709742be02f0..01ca0856caff 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h | |||
@@ -241,7 +241,8 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t start, | |||
241 | unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, | 241 | unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, |
242 | int tag, unsigned int nr_pages, struct page **pages); | 242 | int tag, unsigned int nr_pages, struct page **pages); |
243 | 243 | ||
244 | struct page *__grab_cache_page(struct address_space *mapping, pgoff_t index); | 244 | struct page *grab_cache_page_write_begin(struct address_space *mapping, |
245 | pgoff_t index, unsigned flags); | ||
245 | 246 | ||
246 | /* | 247 | /* |
247 | * Returns locked page at given index in given cache, creating it if needed. | 248 | * Returns locked page at given index in given cache, creating it if needed. |
diff --git a/mm/filemap.c b/mm/filemap.c index f3e5f8944d17..f8c69273c37f 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2140,19 +2140,24 @@ EXPORT_SYMBOL(generic_file_direct_write); | |||
2140 | * Find or create a page at the given pagecache position. Return the locked | 2140 | * Find or create a page at the given pagecache position. Return the locked |
2141 | * page. This function is specifically for buffered writes. | 2141 | * page. This function is specifically for buffered writes. |
2142 | */ | 2142 | */ |
2143 | struct page *__grab_cache_page(struct address_space *mapping, pgoff_t index) | 2143 | struct page *grab_cache_page_write_begin(struct address_space *mapping, |
2144 | pgoff_t index, unsigned flags) | ||
2144 | { | 2145 | { |
2145 | int status; | 2146 | int status; |
2146 | struct page *page; | 2147 | struct page *page; |
2148 | gfp_t gfp_notmask = 0; | ||
2149 | if (flags & AOP_FLAG_NOFS) | ||
2150 | gfp_notmask = __GFP_FS; | ||
2147 | repeat: | 2151 | repeat: |
2148 | page = find_lock_page(mapping, index); | 2152 | page = find_lock_page(mapping, index); |
2149 | if (likely(page)) | 2153 | if (likely(page)) |
2150 | return page; | 2154 | return page; |
2151 | 2155 | ||
2152 | page = page_cache_alloc(mapping); | 2156 | page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~gfp_notmask); |
2153 | if (!page) | 2157 | if (!page) |
2154 | return NULL; | 2158 | return NULL; |
2155 | status = add_to_page_cache_lru(page, mapping, index, GFP_KERNEL); | 2159 | status = add_to_page_cache_lru(page, mapping, index, |
2160 | GFP_KERNEL & ~gfp_notmask); | ||
2156 | if (unlikely(status)) { | 2161 | if (unlikely(status)) { |
2157 | page_cache_release(page); | 2162 | page_cache_release(page); |
2158 | if (status == -EEXIST) | 2163 | if (status == -EEXIST) |
@@ -2161,7 +2166,7 @@ repeat: | |||
2161 | } | 2166 | } |
2162 | return page; | 2167 | return page; |
2163 | } | 2168 | } |
2164 | EXPORT_SYMBOL(__grab_cache_page); | 2169 | EXPORT_SYMBOL(grab_cache_page_write_begin); |
2165 | 2170 | ||
2166 | static ssize_t generic_perform_write(struct file *file, | 2171 | static ssize_t generic_perform_write(struct file *file, |
2167 | struct iov_iter *i, loff_t pos) | 2172 | struct iov_iter *i, loff_t pos) |