diff options
| -rw-r--r-- | fs/btrfs/ctree.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 4eada52f3969..aeab453b8e24 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -5718,6 +5718,24 @@ again: | |||
| 5718 | ret = 0; | 5718 | ret = 0; |
| 5719 | goto done; | 5719 | goto done; |
| 5720 | } | 5720 | } |
| 5721 | /* | ||
| 5722 | * So the above check misses one case: | ||
| 5723 | * - after releasing the path above, someone has removed the item that | ||
| 5724 | * used to be at the very end of the block, and balance between leafs | ||
| 5725 | * gets another one with bigger key.offset to replace it. | ||
| 5726 | * | ||
| 5727 | * This one should be returned as well, or we can get leaf corruption | ||
| 5728 | * later(esp. in __btrfs_drop_extents()). | ||
| 5729 | * | ||
| 5730 | * And a bit more explanation about this check, | ||
| 5731 | * with ret > 0, the key isn't found, the path points to the slot | ||
| 5732 | * where it should be inserted, so the path->slots[0] item must be the | ||
| 5733 | * bigger one. | ||
| 5734 | */ | ||
| 5735 | if (nritems > 0 && ret > 0 && path->slots[0] == nritems - 1) { | ||
| 5736 | ret = 0; | ||
| 5737 | goto done; | ||
| 5738 | } | ||
| 5721 | 5739 | ||
| 5722 | while (level < BTRFS_MAX_LEVEL) { | 5740 | while (level < BTRFS_MAX_LEVEL) { |
| 5723 | if (!path->nodes[level]) { | 5741 | if (!path->nodes[level]) { |
