aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2009-01-04 15:00:53 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-04 16:33:20 -0500
commit54566b2c1594c2326a645a3551f9d989f7ba3c5e (patch)
treeb373f3283fe5e197d0df29cd6b645c35adf1076c /fs
parente687d691cb3790d25e31c74f5941fd7c565e9df5 (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>
Diffstat (limited to 'fs')
-rw-r--r--fs/affs/file.c2
-rw-r--r--fs/afs/write.c2
-rw-r--r--fs/buffer.c4
-rw-r--r--fs/cifs/file.c2
-rw-r--r--fs/ecryptfs/mmap.c2
-rw-r--r--fs/ext3/inode.c2
-rw-r--r--fs/ext3/namei.c3
-rw-r--r--fs/ext4/inode.c4
-rw-r--r--fs/ext4/namei.c3
-rw-r--r--fs/fuse/file.c4
-rw-r--r--fs/gfs2/ops_address.c2
-rw-r--r--fs/hostfs/hostfs_kern.c2
-rw-r--r--fs/jffs2/file.c2
-rw-r--r--fs/libfs.c2
-rw-r--r--fs/namei.c13
-rw-r--r--fs/nfs/file.c2
-rw-r--r--fs/reiserfs/inode.c2
-rw-r--r--fs/smbfs/file.c2
-rw-r--r--fs/ubifs/file.c9
19 files changed, 34 insertions, 30 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
1163retry: 1163retry:
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
2820int __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 */
2823int __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
2829retry: 2834retry:
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:
2852int page_symlink(struct inode *inode, const char *symname, int len) 2857int 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
2858const struct inode_operations page_symlink_inode_operations = { 2863const 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
221static int write_begin_slow(struct address_space *mapping, 221static 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 /*