Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 54566b2c authored by Nick Piggin's avatar Nick Piggin Committed by Linus Torvalds
Browse files

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: default avatarNick Piggin <npiggin@suse.de>
Reviewed-by: default avatarKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: <stable@kernel.org>		[2.6.28.x]
Signed-off-by: default avatarKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: default avatarAndrew 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: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e687d691
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -628,7 +628,7 @@ static int affs_write_begin_ofs(struct file *file, struct address_space *mapping
	}

	index = pos >> PAGE_CACHE_SHIFT;
	page = __grab_cache_page(mapping, index);
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page)
		return -ENOMEM;
	*pagep = page;
+1 −1
Original line number Diff line number Diff line
@@ -144,7 +144,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
	candidate->state = AFS_WBACK_PENDING;
	init_waitqueue_head(&candidate->waitq);

	page = __grab_cache_page(mapping, index);
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page) {
		kfree(candidate);
		return -ENOMEM;
+2 −2
Original line number Diff line number Diff line
@@ -1996,7 +1996,7 @@ int block_write_begin(struct file *file, struct address_space *mapping,
	page = *pagep;
	if (page == NULL) {
		ownpage = 1;
		page = __grab_cache_page(mapping, index);
		page = grab_cache_page_write_begin(mapping, index, flags);
		if (!page) {
			status = -ENOMEM;
			goto out;
@@ -2502,7 +2502,7 @@ int nobh_write_begin(struct file *file, struct address_space *mapping,
	from = pos & (PAGE_CACHE_SIZE - 1);
	to = from + len;

	page = __grab_cache_page(mapping, index);
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page)
		return -ENOMEM;
	*pagep = page;
+1 −1
Original line number Diff line number Diff line
@@ -2074,7 +2074,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping,

	cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));

	page = __grab_cache_page(mapping, index);
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page) {
		rc = -ENOMEM;
		goto out;
+1 −1
Original line number Diff line number Diff line
@@ -288,7 +288,7 @@ static int ecryptfs_write_begin(struct file *file,
	loff_t prev_page_end_size;
	int rc = 0;

	page = __grab_cache_page(mapping, index);
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page)
		return -ENOMEM;
	*pagep = page;
Loading