diff options
-rw-r--r-- | fs/buffer.c | 24 | ||||
-rw-r--r-- | include/linux/buffer_head.h | 2 |
2 files changed, 25 insertions, 1 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index f6ad8f9b8fa5..b0675bfe8207 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -2331,6 +2331,9 @@ EXPORT_SYMBOL(block_commit_write); | |||
2331 | * page lock we can determine safely if the page is beyond EOF. If it is not | 2331 | * page lock we can determine safely if the page is beyond EOF. If it is not |
2332 | * beyond EOF, then the page is guaranteed safe against truncation until we | 2332 | * beyond EOF, then the page is guaranteed safe against truncation until we |
2333 | * unlock the page. | 2333 | * 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. | ||
2334 | */ | 2337 | */ |
2335 | int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, | 2338 | int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, |
2336 | get_block_t get_block) | 2339 | get_block_t get_block) |
@@ -2362,6 +2365,18 @@ int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, | |||
2362 | 2365 | ||
2363 | if (unlikely(ret < 0)) | 2366 | if (unlikely(ret < 0)) |
2364 | goto out_unlock; | 2367 | 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 | } | ||
2365 | return 0; | 2380 | return 0; |
2366 | out_unlock: | 2381 | out_unlock: |
2367 | unlock_page(page); | 2382 | unlock_page(page); |
@@ -2372,8 +2387,15 @@ EXPORT_SYMBOL(__block_page_mkwrite); | |||
2372 | int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, | 2387 | int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, |
2373 | get_block_t get_block) | 2388 | get_block_t get_block) |
2374 | { | 2389 | { |
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; | ||
2376 | 2392 | ||
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); | ||
2377 | return block_page_mkwrite_return(ret); | 2399 | return block_page_mkwrite_return(ret); |
2378 | } | 2400 | } |
2379 | EXPORT_SYMBOL(block_page_mkwrite); | 2401 | EXPORT_SYMBOL(block_page_mkwrite); |
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 2bf6a9136a94..503c8a6b3079 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h | |||
@@ -230,6 +230,8 @@ static inline int block_page_mkwrite_return(int err) | |||
230 | return VM_FAULT_NOPAGE; | 230 | return VM_FAULT_NOPAGE; |
231 | if (err == -ENOMEM) | 231 | if (err == -ENOMEM) |
232 | return VM_FAULT_OOM; | 232 | return VM_FAULT_OOM; |
233 | if (err == -EAGAIN) | ||
234 | return VM_FAULT_RETRY; | ||
233 | /* -ENOSPC, -EDQUOT, -EIO ... */ | 235 | /* -ENOSPC, -EDQUOT, -EIO ... */ |
234 | return VM_FAULT_SIGBUS; | 236 | return VM_FAULT_SIGBUS; |
235 | } | 237 | } |