Skip to content

Commit ea13a86

Browse files
jankaraAl Viro
authored andcommitted
vfs: Block mmapped writes while the fs is frozen
We should not allow file modification via mmap while the filesystem is frozen. So block in block_page_mkwrite() while the filesystem is frozen. We cannot do the blocking wait in __block_page_mkwrite() since e.g. ext4 will want to call that function with transaction started in some cases and that would deadlock. But we can at least do the non-blocking reliable check in __block_page_mkwrite() which is the hardest part anyway. We have to check for frozen filesystem with the page marked dirty and under page lock with which we then return from ->page_mkwrite(). Only that way we cannot race with writeback done by freezing code - either we mark the page dirty after the writeback has started, see freezing in progress and block, or writeback will wait for our page lock which is released only when the fault is done and then writeback will writeout and writeprotect the page again. Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Jan Kara <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 24da4fa commit ea13a86

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

fs/buffer.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2331,6 +2331,9 @@ EXPORT_SYMBOL(block_commit_write);
23312331
* page lock we can determine safely if the page is beyond EOF. If it is not
23322332
* beyond EOF, then the page is guaranteed safe against truncation until we
23332333
* unlock the page.
2334+
*
2335+
* Direct callers of this function should call vfs_check_frozen() so that page
2336+
* fault does not busyloop until the fs is thawed.
23342337
*/
23352338
int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
23362339
get_block_t get_block)
@@ -2362,6 +2365,18 @@ int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
23622365

23632366
if (unlikely(ret < 0))
23642367
goto out_unlock;
2368+
/*
2369+
* Freezing in progress? We check after the page is marked dirty and
2370+
* with page lock held so if the test here fails, we are sure freezing
2371+
* code will wait during syncing until the page fault is done - at that
2372+
* point page will be dirty and unlocked so freezing code will write it
2373+
* and writeprotect it again.
2374+
*/
2375+
set_page_dirty(page);
2376+
if (inode->i_sb->s_frozen != SB_UNFROZEN) {
2377+
ret = -EAGAIN;
2378+
goto out_unlock;
2379+
}
23652380
return 0;
23662381
out_unlock:
23672382
unlock_page(page);
@@ -2372,8 +2387,15 @@ EXPORT_SYMBOL(__block_page_mkwrite);
23722387
int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
23732388
get_block_t get_block)
23742389
{
2375-
int ret = __block_page_mkwrite(vma, vmf, get_block);
2390+
int ret;
2391+
struct super_block *sb = vma->vm_file->f_path.dentry->d_inode->i_sb;
23762392

2393+
/*
2394+
* This check is racy but catches the common case. The check in
2395+
* __block_page_mkwrite() is reliable.
2396+
*/
2397+
vfs_check_frozen(sb, SB_FREEZE_WRITE);
2398+
ret = __block_page_mkwrite(vma, vmf, get_block);
23772399
return block_page_mkwrite_return(ret);
23782400
}
23792401
EXPORT_SYMBOL(block_page_mkwrite);

include/linux/buffer_head.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ static inline int block_page_mkwrite_return(int err)
230230
return VM_FAULT_NOPAGE;
231231
if (err == -ENOMEM)
232232
return VM_FAULT_OOM;
233+
if (err == -EAGAIN)
234+
return VM_FAULT_RETRY;
233235
/* -ENOSPC, -EDQUOT, -EIO ... */
234236
return VM_FAULT_SIGBUS;
235237
}

0 commit comments

Comments
 (0)