* @start: Logical address of target checksum range.
* @end: End offset (inclusive) of the target checksum range.
* @list: List for adding each checksum that was found.
+ * Can be NULL in case the caller only wants to check if
+ * there any checksums for the range.
* @nowait: Indicate if the search must be non-blocking or not.
*
- * Return < 0 on error and 0 on success.
+ * Return < 0 on error, 0 if no checksums were found, or 1 if checksums were
+ * found.
*/
int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
struct list_head *list, bool nowait)
struct btrfs_ordered_sum *sums;
struct btrfs_csum_item *item;
int ret;
+ bool found_csums = false;
ASSERT(IS_ALIGNED(start, fs_info->sectorsize) &&
IS_ALIGNED(end + 1, fs_info->sectorsize));
continue;
}
+ found_csums = true;
+ if (!list)
+ goto out;
+
csum_end = min(csum_end, end + 1);
item = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_csum_item);
}
path->slots[0]++;
}
- ret = 0;
out:
+ btrfs_free_path(path);
if (ret < 0) {
- struct btrfs_ordered_sum *tmp_sums;
+ if (list) {
+ struct btrfs_ordered_sum *tmp_sums;
- list_for_each_entry_safe(sums, tmp_sums, list, list)
- kfree(sums);
+ list_for_each_entry_safe(sums, tmp_sums, list, list)
+ kfree(sums);
+ }
+
+ return ret;
}
- btrfs_free_path(path);
- return ret;
+ return found_csums ? 1 : 0;
}
/*
u64 bytenr, u64 num_bytes, bool nowait)
{
struct btrfs_root *csum_root = btrfs_csum_root(fs_info, bytenr);
- struct btrfs_ordered_sum *sums;
- int ret;
- LIST_HEAD(list);
-
- ret = btrfs_lookup_csums_list(csum_root, bytenr, bytenr + num_bytes - 1,
- &list, nowait);
- if (ret == 0 && list_empty(&list))
- return 0;
- while (!list_empty(&list)) {
- sums = list_entry(list.next, struct btrfs_ordered_sum, list);
- list_del(&sums->list);
- kfree(sums);
- }
- if (ret < 0)
- return ret;
- return 1;
+ return btrfs_lookup_csums_list(csum_root, bytenr, bytenr + num_bytes - 1,
+ NULL, nowait);
}
static int fallback_to_cow(struct btrfs_inode *inode, struct page *locked_page,
ret = btrfs_lookup_csums_list(csum_root, disk_bytenr,
disk_bytenr + ordered->num_bytes - 1,
&list, false);
- if (ret)
+ if (ret < 0)
return ret;
while (!list_empty(&list)) {
ret = btrfs_lookup_csums_list(root->log_root,
csum_start, csum_end - 1,
&ordered_sums, false);
- if (ret)
+ if (ret < 0)
goto out;
+ ret = 0;
/*
* Now delete all existing cums in the csum root that
* cover our range. We do this because we can have an
ret = btrfs_lookup_csums_list(csum_root, disk_bytenr,
disk_bytenr + extent_num_bytes - 1,
&ordered_sums, false);
- if (ret)
+ if (ret < 0)
goto out;
+ ret = 0;
list_for_each_entry_safe(sums, sums_next, &ordered_sums, list) {
if (!ret)
ret = btrfs_lookup_csums_list(csum_root, em->block_start + csum_offset,
em->block_start + csum_offset +
csum_len - 1, &ordered_sums, false);
- if (ret)
+ if (ret < 0)
return ret;
+ ret = 0;
while (!list_empty(&ordered_sums)) {
struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next,