aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.cz>2013-03-06 09:57:46 -0500
committerChris Mason <chris.mason@fusionio.com>2013-05-07 10:50:27 -0400
commit1104a8855109a4051d74977f819a13b4516aa11e (patch)
treec81894968089f010c293bbba501a18e6331204e1 /fs/btrfs
parentb6919a58f09db5daaa29b0326d53513ee418b84b (diff)
btrfs: enhance superblock checks
The superblock checksum is not verified upon mount. <awkward silence> Add that check and also reorder existing checks to a more logical order. Current mkfs.btrfs does not calculate the correct checksum of super_block and thus a freshly created filesytem will fail to mount when this patch is applied. First transaction commit calculates correct superblock checksum and saves it to disk. Reproducer: $ mfks.btrfs /dev/sda $ mount /dev/sda /mnt $ btrfs scrub start /mnt $ sleep 5 $ btrfs scrub status /mnt ... super:2 ... Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h6
-rw-r--r--fs/btrfs/disk-io.c82
2 files changed, 71 insertions, 17 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 78b9d457d723..63c328a9ce95 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -2793,8 +2793,10 @@ BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block,
2793 2793
2794static inline int btrfs_super_csum_size(struct btrfs_super_block *s) 2794static inline int btrfs_super_csum_size(struct btrfs_super_block *s)
2795{ 2795{
2796 int t = btrfs_super_csum_type(s); 2796 u16 t = btrfs_super_csum_type(s);
2797 BUG_ON(t >= ARRAY_SIZE(btrfs_csum_sizes)); 2797 /*
2798 * csum type is validated at mount time
2799 */
2798 return btrfs_csum_sizes[t]; 2800 return btrfs_csum_sizes[t];
2799} 2801}
2800 2802
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 2bc1ecf5e840..bc423f7eddce 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -357,6 +357,44 @@ out:
357} 357}
358 358
359/* 359/*
360 * Return 0 if the superblock checksum type matches the checksum value of that
361 * algorithm. Pass the raw disk superblock data.
362 */
363static int btrfs_check_super_csum(char *raw_disk_sb)
364{
365 struct btrfs_super_block *disk_sb =
366 (struct btrfs_super_block *)raw_disk_sb;
367 u16 csum_type = btrfs_super_csum_type(disk_sb);
368 int ret = 0;
369
370 if (csum_type == BTRFS_CSUM_TYPE_CRC32) {
371 u32 crc = ~(u32)0;
372 const int csum_size = sizeof(crc);
373 char result[csum_size];
374
375 /*
376 * The super_block structure does not span the whole
377 * BTRFS_SUPER_INFO_SIZE range, we expect that the unused space
378 * is filled with zeros and is included in the checkum.
379 */
380 crc = btrfs_csum_data(raw_disk_sb + BTRFS_CSUM_SIZE,
381 crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
382 btrfs_csum_final(crc, result);
383
384 if (memcmp(raw_disk_sb, result, csum_size))
385 ret = 1;
386 }
387
388 if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) {
389 printk(KERN_ERR "btrfs: unsupported checksum algorithm %u\n",
390 csum_type);
391 ret = 1;
392 }
393
394 return ret;
395}
396
397/*
360 * helper to read a given tree block, doing retries as required when 398 * helper to read a given tree block, doing retries as required when
361 * the checksums don't match and we have alternate mirrors to try. 399 * the checksums don't match and we have alternate mirrors to try.
362 */ 400 */
@@ -2249,12 +2287,31 @@ int open_ctree(struct super_block *sb,
2249 fs_info, BTRFS_ROOT_TREE_OBJECTID); 2287 fs_info, BTRFS_ROOT_TREE_OBJECTID);
2250 2288
2251 invalidate_bdev(fs_devices->latest_bdev); 2289 invalidate_bdev(fs_devices->latest_bdev);
2290
2291 /*
2292 * Read super block and check the signature bytes only
2293 */
2252 bh = btrfs_read_dev_super(fs_devices->latest_bdev); 2294 bh = btrfs_read_dev_super(fs_devices->latest_bdev);
2253 if (!bh) { 2295 if (!bh) {
2254 err = -EINVAL; 2296 err = -EINVAL;
2255 goto fail_alloc; 2297 goto fail_alloc;
2256 } 2298 }
2257 2299
2300 /*
2301 * We want to check superblock checksum, the type is stored inside.
2302 * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k).
2303 */
2304 if (btrfs_check_super_csum(bh->b_data)) {
2305 printk(KERN_ERR "btrfs: superblock checksum mismatch\n");
2306 err = -EINVAL;
2307 goto fail_alloc;
2308 }
2309
2310 /*
2311 * super_copy is zeroed at allocation time and we never touch the
2312 * following bytes up to INFO_SIZE, the checksum is calculated from
2313 * the whole block of INFO_SIZE
2314 */
2258 memcpy(fs_info->super_copy, bh->b_data, sizeof(*fs_info->super_copy)); 2315 memcpy(fs_info->super_copy, bh->b_data, sizeof(*fs_info->super_copy));
2259 memcpy(fs_info->super_for_commit, fs_info->super_copy, 2316 memcpy(fs_info->super_for_commit, fs_info->super_copy,
2260 sizeof(*fs_info->super_for_commit)); 2317 sizeof(*fs_info->super_for_commit));
@@ -2262,6 +2319,13 @@ int open_ctree(struct super_block *sb,
2262 2319
2263 memcpy(fs_info->fsid, fs_info->super_copy->fsid, BTRFS_FSID_SIZE); 2320 memcpy(fs_info->fsid, fs_info->super_copy->fsid, BTRFS_FSID_SIZE);
2264 2321
2322 ret = btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
2323 if (ret) {
2324 printk(KERN_ERR "btrfs: superblock contains fatal errors\n");
2325 err = -EINVAL;
2326 goto fail_alloc;
2327 }
2328
2265 disk_super = fs_info->super_copy; 2329 disk_super = fs_info->super_copy;
2266 if (!btrfs_super_root(disk_super)) 2330 if (!btrfs_super_root(disk_super))
2267 goto fail_alloc; 2331 goto fail_alloc;
@@ -2270,13 +2334,6 @@ int open_ctree(struct super_block *sb,
2270 if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR) 2334 if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR)
2271 set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state); 2335 set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
2272 2336
2273 ret = btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
2274 if (ret) {
2275 printk(KERN_ERR "btrfs: superblock contains fatal errors\n");
2276 err = ret;
2277 goto fail_alloc;
2278 }
2279
2280 /* 2337 /*
2281 * run through our array of backup supers and setup 2338 * run through our array of backup supers and setup
2282 * our ring pointer to the oldest one 2339 * our ring pointer to the oldest one
@@ -3561,14 +3618,9 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
3561static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, 3618static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
3562 int read_only) 3619 int read_only)
3563{ 3620{
3564 if (btrfs_super_csum_type(fs_info->super_copy) >= ARRAY_SIZE(btrfs_csum_sizes)) { 3621 /*
3565 printk(KERN_ERR "btrfs: unsupported checksum algorithm\n"); 3622 * Placeholder for checks
3566 return -EINVAL; 3623 */
3567 }
3568
3569 if (read_only)
3570 return 0;
3571
3572 return 0; 3624 return 0;
3573} 3625}
3574 3626