Btrfs: fix regression in btrfs_page_mkwrite() from vm_fault_t conversion
PATCH 1/1 Btrfs: fix regression in btrfs_page_mkwrite() from vm_fault_t conversion
The vm_fault_t conversion commit introduced a ret2 variable for tracking the integer return values from internal btrfs functions. It was sometimes returning VM_FAULT_LOCKED for pages that were actually invalid and had been removed from the radix. Something like this:
ret2 = btrfs_delalloc_reserve_space() // returns zero on success lock_page(page) if (page->mapping != inode->i_mapping) goto out_unlock;
...
out_unlock:
if (!ret2) {
...
return VM_FAULT_LOCKED;
}This ends up triggering this WARNING in btrfs_destroy_inode()
WARN_ON(BTRFS_I(inode)->block_rsv.size);
The fix used here is to use ret instead of ret2 in our check for success.
--- fs/btrfs/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/btrfs/inode.c +2 -1
@@ -9013,6 +9013,7 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) goto out_unlock; } ret2 =0 ; + ret =0 ;/* page is wholly or partially inside EOF */ if (page_start +PAGE_SIZE > size)
@@ -9037,7 +9038,7 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)unlock_extent_cached (io_tree, page_start, page_end, &cached_state); out_unlock: -if (!ret2) { +if (!ret) {btrfs_delalloc_release_extents (BTRFS_I (inode),PAGE_SIZE , true);sb_end_pagefault (inode->i_sb);extent_changeset_free (data_reserved);
Signature · 1 line
2.9.5
Quoted 35 lines · Chris Mason
The
vm_fault_tconversion commit introduced a ret2 variable for tracking the integer return values from internal btrfs functions. It was sometimes returningVM_FAULT_LOCKEDfor pages that were actually invalid and had been removed from the radix. Something like this:ret2 = btrfs_delalloc_reserve_space() // returns zero on success lock_page(page) if (page->mapping != inode->i_mapping) goto out_unlock;...
out_unlock:if (!ret2) { ... return VM_FAULT_LOCKED; }This ends up triggering this WARNING in
btrfs_destroy_inode()WARN_ON(BTRFS_I(inode)->block_rsv.size);The fix used here is to use ret instead of ret2 in our check for success.
Fixes a528a2415087 (btrfs: change return type of btrfs_page_mkwrite to vm_fault_t)Signed-off-by Chris Mason <[email protected]>--- fs/btrfs/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)fs/btrfs/inode.c +0
-0
fs/btrfs/inode.c vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) · line 9016
Quoted 4 lines
fs/btrfs/inode.c +1
-0@@ -9013,6 +9013,7 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) goto out_unlock; } ret2 =0 ; + ret =0 ;
That's something I'd rather avoid, now there are two error values that need to be tracked. Shouldn't the 'ret2 = 0' be removed completely?
fs/btrfs/inode.c vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) · line 9041
Quoted 9 lines
fs/btrfs/inode.c +1
-1/* page is wholly or partially inside EOF */ if (page_start +PAGE_SIZE > size)@@ -9037,7 +9038,7 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)unlock_extent_cached (io_tree, page_start, page_end, &cached_state); out_unlock: -if (!ret2) { +if (!ret) {
I'm not sure is safe, the new ret is one of the VM_FAULT_ values and it's not 0 by default and in fact I don't see anything that would set it to 0 directly or indirectly. Which means that the code in the out: label also needs to be revisited:
9016 out:
9017 btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, (ret != 0));
9018 btrfs_delalloc_release_space(inode, data_reserved, page_start,
9019 reserved_space, (ret != 0));
Quoted 3 lines
fs/btrfs/inode.c +0
-0btrfs_delalloc_release_extents (BTRFS_I (inode),PAGE_SIZE , true);sb_end_pagefault (inode->i_sb);extent_changeset_free (data_reserved);
Quoted 14 lines · David Sterba
fs/btrfs/inode.c vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) · line 9016
Quoted 9 lines · Chris Mason
fs/btrfs/inode.c +1
-0@@ -9013,6 +9013,7 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) goto out_unlock; } ret2 =0 ; + ret =0 ;That's something I'd rather avoid, now there are two error values that need to be tracked. Shouldn't the 'ret2 = 0' be removed completely?
Yeah, the whole thing hurts my eyes. Fixing.
Quoted 7 lines
Quoted 7 lines
fs/btrfs/inode.c +0
-0/* page is wholly or partially inside EOF */ if (page_start +PAGE_SIZE > size)@@ -9037,7 +9038,7 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)unlock_extent_cached (io_tree, page_start, page_end, &cached_state);
Quoted 8 lines
fs/btrfs/inode.c vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) · line 9041
Quoted 3 lines
fs/btrfs/inode.c +1
-1out_unlock: -if (!ret2) { +if (!ret) {I'm not sure is safe, the new ret is one of the
VM_FAULT_values and it's not 0 by default and in fact I don't see anything that would set it to 0 directly or indirectly. Which means that the code in the out: label also needs to be revisited:
Good point, ok.
-chris