#include <linux/list_sort.h>
#include <linux/raid/xor.h>
#include <linux/mm.h>
+#include <crypto/hash.h>
#include "messages.h"
#include "ctree.h"
#include "disk-io.h"
start_async_work(rbio, rmw_rbio_work);
}
+/*
+ * Return the memory holding a recovered sector: the bio's pages when we are
+ * rebuilding a read, the rbio's own stripe pages otherwise.
+ */
+static struct sector_ptr *recovered_sector(struct btrfs_raid_bio *rbio,
+ int stripe_nr, int sector_nr)
+{
+ if (rbio->operation == BTRFS_RBIO_READ_REBUILD)
+ return sector_in_rbio(rbio, stripe_nr, sector_nr, 0);
+ return rbio_stripe_sector(rbio, stripe_nr, sector_nr);
+}
+
+/*
+ * Verify one reconstructed tree block.
+ *
+ * Data sectors are verified individually against the csum tree, but a tree
+ * block carries its csum in its own header, covering the whole nodesize
+ * block. So metadata cannot be checked a sector at a time: the check has to
+ * wait until every sector of the block has been recovered, which is why this
+ * runs after the vertical recovery loop rather than inside it.
+ *
+ * A tree block never straddles a column. nodesize and BTRFS_STRIPE_LEN are
+ * both powers of two with nodesize <= BTRFS_STRIPE_LEN, and a full stripe is
+ * stripe-length aligned, so each column begins on a nodesize boundary and
+ * tree blocks tile it exactly.
+ *
+ * @sector_nr is the first sector of the block within the column.
+ */
+static int verify_one_eb(struct btrfs_raid_bio *rbio, int stripe_nr,
+ int sector_nr)
+{
+ struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
+ const u32 sectorsize = fs_info->sectorsize;
+ const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits;
+ const u64 logical = rbio->bioc->full_stripe_logical +
+ (u64)stripe_nr * BTRFS_STRIPE_LEN +
+ (u64)sector_nr * sectorsize;
+ SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
+ u8 on_disk_csum[BTRFS_CSUM_SIZE];
+ u8 calculated_csum[BTRFS_CSUM_SIZE];
+ struct sector_ptr *sector;
+ void *kaddr;
+ u64 found_bytenr;
+ bool bad_fsid;
+
+ /*
+ * The header lives at the start of the block. Read what we need from
+ * it before walking the rest: a block whose bytenr or fsid do not
+ * match was not reconstructed into what it claims to be, and there is
+ * no point csumming it.
+ */
+ sector = recovered_sector(rbio, stripe_nr, sector_nr);
+ kaddr = kmap_local_sector(sector);
+ memcpy(on_disk_csum, ((struct btrfs_header *)kaddr)->csum,
+ fs_info->csum_size);
+ found_bytenr = btrfs_stack_header_bytenr((struct btrfs_header *)kaddr);
+ bad_fsid = memcmp(((struct btrfs_header *)kaddr)->fsid,
+ fs_info->fs_devices->metadata_uuid,
+ BTRFS_FSID_SIZE) != 0;
+ kunmap_local(kaddr);
+
+ if (unlikely(found_bytenr != logical)) {
+ btrfs_warn_rl(fs_info,
+"raid56: reconstructed tree block %llu has bytenr %llu, cannot be trusted",
+ logical, found_bytenr);
+ return -EIO;
+ }
+ if (unlikely(bad_fsid)) {
+ btrfs_warn_rl(fs_info,
+"raid56: reconstructed tree block %llu has the wrong fsid, cannot be trusted",
+ logical);
+ return -EIO;
+ }
+
+ shash->tfm = fs_info->csum_shash;
+ crypto_shash_init(shash);
+ for (int i = 0; i < sectors_per_tree; i++) {
+ sector = recovered_sector(rbio, stripe_nr, sector_nr + i);
+ kaddr = kmap_local_sector(sector);
+ /* The csum field itself is not covered by the csum. */
+ if (i == 0)
+ crypto_shash_update(shash, kaddr + BTRFS_CSUM_SIZE,
+ sectorsize - BTRFS_CSUM_SIZE);
+ else
+ crypto_shash_update(shash, kaddr, sectorsize);
+ kunmap_local(kaddr);
+ }
+ crypto_shash_final(shash, calculated_csum);
+
+ if (unlikely(memcmp(calculated_csum, on_disk_csum, fs_info->csum_size))) {
+ btrfs_warn_rl(fs_info,
+"raid56: reconstructed tree block %llu fails its csum, cannot be trusted",
+ logical);
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * Verify every tree block this rbio was asked to read, once recovery has
+ * filled in the missing columns.
+ *
+ * Only blocks the caller actually requested are checked: those are known to
+ * be live tree blocks, whereas the rest of a stripe may be free space, which
+ * has no header to verify and would fail every test here.
+ *
+ * Without this, a metadata rbio reconstructs a column and marks it uptodate
+ * having checked nothing -- verify_one_sector() returns success immediately
+ * when there is no csum_bitmap, and metadata never has one (see
+ * fill_data_csums()). A wrong reconstruction would then be handed back to
+ * the caller, and cached, for validate_extent_buffer() to reject much later.
+ */
+static int verify_recovered_ebs(struct btrfs_raid_bio *rbio)
+{
+ struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
+ const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits;
+
+ /*
+ * Data has its own per-sector verification. A mixed block group has
+ * neither: its sectors get no csums (fill_data_csums() skips mixed
+ * groups) and its contents may be file data rather than tree blocks,
+ * so there is nothing here to check either.
+ */
+ if (rbio->bioc->map_type & BTRFS_BLOCK_GROUP_DATA)
+ return 0;
+
+ /*
+ * Only when rebuilding a read. recover_sectors() is also reached from
+ * the read-modify-write path, and there the bio list covers the blocks
+ * being written -- already-verified memory -- while the sectors that
+ * were actually reconstructed are the ones read off the other columns.
+ * Those cannot be checked: any of them may be free space rather than a
+ * live tree block, and free space has no header to verify. Knowing
+ * which ranges hold live metadata is exactly what this layer lacks,
+ * so a reconstruction feeding an RMW's parity stays unverified.
+ */
+ if (rbio->operation != BTRFS_RBIO_READ_REBUILD)
+ return 0;
+
+ for (int stripe_nr = 0; stripe_nr < rbio->nr_data; stripe_nr++) {
+ for (int sector_nr = 0;
+ sector_nr + sectors_per_tree <= rbio->stripe_nsectors;
+ sector_nr += sectors_per_tree) {
+ bool requested = true;
+ int ret;
+
+ for (int i = 0; i < sectors_per_tree; i++) {
+ const int index = rbio_stripe_sector_index(rbio,
+ stripe_nr, sector_nr + i);
+
+ if (!rbio->bio_sectors[index].has_paddr) {
+ requested = false;
+ break;
+ }
+ }
+ if (!requested)
+ continue;
+
+ ret = verify_one_eb(rbio, stripe_nr, sector_nr);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ return 0;
+}
+
static int verify_one_sector(struct btrfs_raid_bio *rbio,
int stripe_nr, int sector_nr)
{
break;
}
+ /* Metadata is verified per tree block, once every sector is back. */
+ if (ret == 0)
+ ret = verify_recovered_ebs(rbio);
+
out:
kfree(pointers);
kfree(unmap_array);