diff mbox

[1/5] Btrfs: test_check_exists: Fix infinite loop when searching for free space entries

Message ID 201605270750.u4R7n7I1033516@mx0a-001b2d01.pphosted.com (mailing list archive)
State Superseded
Headers show

Commit Message

Feifei Xu May 27, 2016, 7 a.m. UTC
On a ppc64 machine using 64K as the block size, assume that the RB
tree at btrfs_free_space_ctl->free_space_offset contains following
two entries:

1. A bitmap entry having an offset value of 0 and having the bits
   corresponding to the address range [128M+512K, 128M+768K] set.
2. An extent entry corresponding to the address range
   [128M-256K, 128M-128K]

In such a scenario, test_check_exists() invoked for checking the
existence of address range [128M+768K, 256M] can lead to an
infinite loop as explained below:

- Checking for the extent entry fails.
- Checking for a bitmap entry results in the free space info in
  range [128M+512K, 128M+768K] beng returned.
- rb_prev(info) returns NULL because the bitmap entry starting from
  offset 0 comes first in the RB tree.
- current_node = bitmap node.
- while (current_node)
    tmp = rb_next(bitmap_node);/*tmp is extent based free space entry*/
    Since extent based free space entry's last address is smaller
    than the address being searched for (i.e. 128M+768K) we
    incorrectly again obtain the extent node as the "next right node"
    of the RB tree and thus end up looping infinitely.

This patch fixes the issue by updating "info" variable to point to
the most recently searched free space node.

Reviewed-by: Chandan Rajendra <chandan@linux.vnet.ibm.com>
Signed-off-by: Feifei Xu <xufeifei@linux.vnet.ibm.com>
---
 fs/btrfs/free-space-cache.c | 2 ++
 1 file changed, 2 insertions(+)
diff mbox

Patch

diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 5e6062c..05c9ef8 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -3662,6 +3662,7 @@  have_info:
 			if (tmp->offset + tmp->bytes < offset)
 				break;
 			if (offset + bytes < tmp->offset) {
+				info = tmp;
 				n = rb_prev(&info->offset_index);
 				continue;
 			}
@@ -3676,6 +3677,7 @@  have_info:
 			if (offset + bytes < tmp->offset)
 				break;
 			if (tmp->offset + tmp->bytes < offset) {
+				info = tmp;
 				n = rb_next(&info->offset_index);
 				continue;
 			}