From a8b3a89074f8677533cdb3843da121d697c1938c Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 May 2020 15:26:07 +0200 Subject: btrfs: scrub: remove kmap/kunmap of pages All pages that scrub uses in the scrub_block::pagev array are allocated with GFP_KERNEL and never part of any mapping, so kmap is not necessary, we only need to know the page address. In scrub_write_page_to_dev_replace we don't even need to call flush_dcache_page because of the same reason as above. Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 016a025e36c7..368791b17bac 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1616,13 +1616,9 @@ static int scrub_write_page_to_dev_replace(struct scrub_block *sblock, struct scrub_page *spage = sblock->pagev[page_num]; BUG_ON(spage->page == NULL); - if (spage->io_error) { - void *mapped_buffer = kmap_atomic(spage->page); + if (spage->io_error) + clear_page(page_address(spage->page)); - clear_page(mapped_buffer); - flush_dcache_page(spage->page); - kunmap_atomic(mapped_buffer); - } return scrub_add_page_to_wr_bio(sblock->sctx, spage); } @@ -1805,7 +1801,7 @@ static int scrub_checksum_data(struct scrub_block *sblock) on_disk_csum = sblock->pagev[0]->csum; page = sblock->pagev[0]->page; - buffer = kmap_atomic(page); + buffer = page_address(page); len = sctx->fs_info->sectorsize; index = 0; @@ -1813,7 +1809,6 @@ static int scrub_checksum_data(struct scrub_block *sblock) u64 l = min_t(u64, len, PAGE_SIZE); crypto_shash_update(shash, buffer, l); - kunmap_atomic(buffer); len -= l; if (len == 0) break; @@ -1821,7 +1816,7 @@ static int scrub_checksum_data(struct scrub_block *sblock) BUG_ON(index >= sblock->page_count); BUG_ON(!sblock->pagev[index]->page); page = sblock->pagev[index]->page; - buffer = kmap_atomic(page); + buffer = page_address(page); } crypto_shash_final(shash, csum); @@ -1851,7 +1846,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) BUG_ON(sblock->page_count < 1); page = sblock->pagev[0]->page; - mapped_buffer = kmap_atomic(page); + mapped_buffer = page_address(page); h = (struct btrfs_header *)mapped_buffer; memcpy(on_disk_csum, h->csum, sctx->csum_size); @@ -1883,7 +1878,6 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) u64 l = min_t(u64, len, mapped_size); crypto_shash_update(shash, p, l); - kunmap_atomic(mapped_buffer); len -= l; if (len == 0) break; @@ -1891,7 +1885,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) BUG_ON(index >= sblock->page_count); BUG_ON(!sblock->pagev[index]->page); page = sblock->pagev[index]->page; - mapped_buffer = kmap_atomic(page); + mapped_buffer = page_address(page); mapped_size = PAGE_SIZE; p = mapped_buffer; } @@ -1925,7 +1919,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) BUG_ON(sblock->page_count < 1); page = sblock->pagev[0]->page; - mapped_buffer = kmap_atomic(page); + mapped_buffer = page_address(page); s = (struct btrfs_super_block *)mapped_buffer; memcpy(on_disk_csum, s->csum, sctx->csum_size); @@ -1946,7 +1940,6 @@ static int scrub_checksum_super(struct scrub_block *sblock) u64 l = min_t(u64, len, mapped_size); crypto_shash_update(shash, p, l); - kunmap_atomic(mapped_buffer); len -= l; if (len == 0) break; @@ -1954,7 +1947,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) BUG_ON(index >= sblock->page_count); BUG_ON(!sblock->pagev[index]->page); page = sblock->pagev[index]->page; - mapped_buffer = kmap_atomic(page); + mapped_buffer = page_address(page); mapped_size = PAGE_SIZE; p = mapped_buffer; } -- cgit From b04852520ec260dd4080864cd2b309d163f76b5e Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 May 2020 15:32:51 +0200 Subject: btrfs: scrub: unify naming of page address variables As the page mapping has been removed, rename the variables to 'kaddr' that we use everywhere else. The type is changed to 'char *' so pointer arithmetic works without casts. Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 368791b17bac..7dc4a090db57 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1788,7 +1788,7 @@ static int scrub_checksum_data(struct scrub_block *sblock) u8 csum[BTRFS_CSUM_SIZE]; u8 *on_disk_csum; struct page *page; - void *buffer; + char *kaddr; u64 len; int index; @@ -1801,14 +1801,14 @@ static int scrub_checksum_data(struct scrub_block *sblock) on_disk_csum = sblock->pagev[0]->csum; page = sblock->pagev[0]->page; - buffer = page_address(page); + kaddr = page_address(page); len = sctx->fs_info->sectorsize; index = 0; for (;;) { u64 l = min_t(u64, len, PAGE_SIZE); - crypto_shash_update(shash, buffer, l); + crypto_shash_update(shash, kaddr, l); len -= l; if (len == 0) break; @@ -1816,7 +1816,7 @@ static int scrub_checksum_data(struct scrub_block *sblock) BUG_ON(index >= sblock->page_count); BUG_ON(!sblock->pagev[index]->page); page = sblock->pagev[index]->page; - buffer = page_address(page); + kaddr = page_address(page); } crypto_shash_final(shash, csum); @@ -1835,7 +1835,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) u8 calculated_csum[BTRFS_CSUM_SIZE]; u8 on_disk_csum[BTRFS_CSUM_SIZE]; struct page *page; - void *mapped_buffer; + char *kaddr; u64 mapped_size; void *p; u64 len; @@ -1846,8 +1846,8 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) BUG_ON(sblock->page_count < 1); page = sblock->pagev[0]->page; - mapped_buffer = page_address(page); - h = (struct btrfs_header *)mapped_buffer; + kaddr = page_address(page); + h = (struct btrfs_header *)kaddr; memcpy(on_disk_csum, h->csum, sctx->csum_size); /* @@ -1872,7 +1872,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) len = sctx->fs_info->nodesize - BTRFS_CSUM_SIZE; mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE; - p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE; + p = kaddr + BTRFS_CSUM_SIZE; index = 0; for (;;) { u64 l = min_t(u64, len, mapped_size); @@ -1885,9 +1885,9 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) BUG_ON(index >= sblock->page_count); BUG_ON(!sblock->pagev[index]->page); page = sblock->pagev[index]->page; - mapped_buffer = page_address(page); + kaddr = page_address(page); mapped_size = PAGE_SIZE; - p = mapped_buffer; + p = kaddr; } crypto_shash_final(shash, calculated_csum); @@ -1906,7 +1906,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) u8 calculated_csum[BTRFS_CSUM_SIZE]; u8 on_disk_csum[BTRFS_CSUM_SIZE]; struct page *page; - void *mapped_buffer; + char *kaddr; u64 mapped_size; void *p; int fail_gen = 0; @@ -1919,8 +1919,8 @@ static int scrub_checksum_super(struct scrub_block *sblock) BUG_ON(sblock->page_count < 1); page = sblock->pagev[0]->page; - mapped_buffer = page_address(page); - s = (struct btrfs_super_block *)mapped_buffer; + kaddr = page_address(page); + s = (struct btrfs_super_block *)kaddr; memcpy(on_disk_csum, s->csum, sctx->csum_size); if (sblock->pagev[0]->logical != btrfs_super_bytenr(s)) @@ -1934,7 +1934,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) len = BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE; mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE; - p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE; + p = kaddr + BTRFS_CSUM_SIZE; index = 0; for (;;) { u64 l = min_t(u64, len, mapped_size); @@ -1947,9 +1947,9 @@ static int scrub_checksum_super(struct scrub_block *sblock) BUG_ON(index >= sblock->page_count); BUG_ON(!sblock->pagev[index]->page); page = sblock->pagev[index]->page; - mapped_buffer = page_address(page); + kaddr = page_address(page); mapped_size = PAGE_SIZE; - p = mapped_buffer; + p = kaddr; } crypto_shash_final(shash, calculated_csum); -- cgit From 83cf6d5eae54eb40727210e825f8d656a33e7d30 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 May 2020 15:40:36 +0200 Subject: btrfs: scrub: simplify superblock checksum calculation BTRFS_SUPER_INFO_SIZE is 4096, and fits to a page on all supported architectures, so we can calculate the checksum in one go. Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 7dc4a090db57..13ee43f29751 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1907,15 +1907,8 @@ static int scrub_checksum_super(struct scrub_block *sblock) u8 on_disk_csum[BTRFS_CSUM_SIZE]; struct page *page; char *kaddr; - u64 mapped_size; - void *p; int fail_gen = 0; int fail_cor = 0; - u64 len; - int index; - - shash->tfm = fs_info->csum_shash; - crypto_shash_init(shash); BUG_ON(sblock->page_count < 1); page = sblock->pagev[0]->page; @@ -1932,27 +1925,11 @@ static int scrub_checksum_super(struct scrub_block *sblock) if (!scrub_check_fsid(s->fsid, sblock->pagev[0])) ++fail_cor; - len = BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE; - mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE; - p = kaddr + BTRFS_CSUM_SIZE; - index = 0; - for (;;) { - u64 l = min_t(u64, len, mapped_size); - - crypto_shash_update(shash, p, l); - len -= l; - if (len == 0) - break; - index++; - BUG_ON(index >= sblock->page_count); - BUG_ON(!sblock->pagev[index]->page); - page = sblock->pagev[index]->page; - kaddr = page_address(page); - mapped_size = PAGE_SIZE; - p = kaddr; - } + shash->tfm = fs_info->csum_shash; + crypto_shash_init(shash); + crypto_shash_digest(shash, kaddr + BTRFS_CSUM_SIZE, + BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE, calculated_csum); - crypto_shash_final(shash, calculated_csum); if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) ++fail_cor; -- cgit From 74710cf1fbdc74b1593be953e85b3f392c9f43a4 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 May 2020 15:43:14 +0200 Subject: btrfs: scrub: remove temporary csum array in scrub_checksum_super The page contents with the checksum is available during the entire function so we don't need to make a copy. Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 13ee43f29751..abb39c5255d2 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1904,7 +1904,6 @@ static int scrub_checksum_super(struct scrub_block *sblock) struct btrfs_fs_info *fs_info = sctx->fs_info; SHASH_DESC_ON_STACK(shash, fs_info->csum_shash); u8 calculated_csum[BTRFS_CSUM_SIZE]; - u8 on_disk_csum[BTRFS_CSUM_SIZE]; struct page *page; char *kaddr; int fail_gen = 0; @@ -1914,7 +1913,6 @@ static int scrub_checksum_super(struct scrub_block *sblock) page = sblock->pagev[0]->page; kaddr = page_address(page); s = (struct btrfs_super_block *)kaddr; - memcpy(on_disk_csum, s->csum, sctx->csum_size); if (sblock->pagev[0]->logical != btrfs_super_bytenr(s)) ++fail_cor; @@ -1930,7 +1928,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) crypto_shash_digest(shash, kaddr + BTRFS_CSUM_SIZE, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE, calculated_csum); - if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) + if (memcmp(calculated_csum, s->csum, sctx->csum_size)) ++fail_cor; if (fail_cor + fail_gen) { -- cgit From c7460541093494f108adb6388351636d353715fb Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 May 2020 15:47:05 +0200 Subject: btrfs: scrub: clean up temporary page variables in scrub_checksum_super Add proper variable for the scrub page and use it instead of repeatedly dereferencing the other structures. Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index abb39c5255d2..aecaf5c7f655 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1904,23 +1904,23 @@ static int scrub_checksum_super(struct scrub_block *sblock) struct btrfs_fs_info *fs_info = sctx->fs_info; SHASH_DESC_ON_STACK(shash, fs_info->csum_shash); u8 calculated_csum[BTRFS_CSUM_SIZE]; - struct page *page; + struct scrub_page *spage; char *kaddr; int fail_gen = 0; int fail_cor = 0; BUG_ON(sblock->page_count < 1); - page = sblock->pagev[0]->page; - kaddr = page_address(page); + spage = sblock->pagev[0]; + kaddr = page_address(spage->page); s = (struct btrfs_super_block *)kaddr; - if (sblock->pagev[0]->logical != btrfs_super_bytenr(s)) + if (spage->logical != btrfs_super_bytenr(s)) ++fail_cor; - if (sblock->pagev[0]->generation != btrfs_super_generation(s)) + if (spage->generation != btrfs_super_generation(s)) ++fail_gen; - if (!scrub_check_fsid(s->fsid, sblock->pagev[0])) + if (!scrub_check_fsid(s->fsid, spage)) ++fail_cor; shash->tfm = fs_info->csum_shash; @@ -1941,10 +1941,10 @@ static int scrub_checksum_super(struct scrub_block *sblock) ++sctx->stat.super_errors; spin_unlock(&sctx->stat_lock); if (fail_cor) - btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev, + btrfs_dev_stat_inc_and_print(spage->dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); else - btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev, + btrfs_dev_stat_inc_and_print(spage->dev, BTRFS_DEV_STAT_GENERATION_ERRS); } -- cgit From 771aba0d12dd945132e2c3bbb512f96edc0efbaa Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 May 2020 15:54:41 +0200 Subject: btrfs: scrub: simplify data block checksum calculation We have sectorsize same as PAGE_SIZE, the checksum can be calculated in one go. Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index aecaf5c7f655..16c83130d884 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1789,37 +1789,19 @@ static int scrub_checksum_data(struct scrub_block *sblock) u8 *on_disk_csum; struct page *page; char *kaddr; - u64 len; - int index; BUG_ON(sblock->page_count < 1); if (!sblock->pagev[0]->have_csum) return 0; - shash->tfm = fs_info->csum_shash; - crypto_shash_init(shash); - on_disk_csum = sblock->pagev[0]->csum; page = sblock->pagev[0]->page; kaddr = page_address(page); - len = sctx->fs_info->sectorsize; - index = 0; - for (;;) { - u64 l = min_t(u64, len, PAGE_SIZE); - - crypto_shash_update(shash, kaddr, l); - len -= l; - if (len == 0) - break; - index++; - BUG_ON(index >= sblock->page_count); - BUG_ON(!sblock->pagev[index]->page); - page = sblock->pagev[index]->page; - kaddr = page_address(page); - } + shash->tfm = fs_info->csum_shash; + crypto_shash_init(shash); + crypto_shash_digest(shash, kaddr, PAGE_SIZE, csum); - crypto_shash_final(shash, csum); if (memcmp(csum, on_disk_csum, sctx->csum_size)) sblock->checksum_error = 1; -- cgit From d41ebef2005f3b1669da334183088668c168c74a Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 May 2020 16:20:35 +0200 Subject: btrfs: scrub: clean up temporary page variables in scrub_checksum_data Add proper variable for the scrub page and use it instead of repeatedly dereferencing the other structures. Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 16c83130d884..19a64c72f38e 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1786,23 +1786,21 @@ static int scrub_checksum_data(struct scrub_block *sblock) struct btrfs_fs_info *fs_info = sctx->fs_info; SHASH_DESC_ON_STACK(shash, fs_info->csum_shash); u8 csum[BTRFS_CSUM_SIZE]; - u8 *on_disk_csum; - struct page *page; + struct scrub_page *spage; char *kaddr; BUG_ON(sblock->page_count < 1); - if (!sblock->pagev[0]->have_csum) + spage = sblock->pagev[0]; + if (!spage->have_csum) return 0; - on_disk_csum = sblock->pagev[0]->csum; - page = sblock->pagev[0]->page; - kaddr = page_address(page); + kaddr = page_address(spage->page); shash->tfm = fs_info->csum_shash; crypto_shash_init(shash); crypto_shash_digest(shash, kaddr, PAGE_SIZE, csum); - if (memcmp(csum, on_disk_csum, sctx->csum_size)) + if (memcmp(csum, spage->csum, sctx->csum_size)) sblock->checksum_error = 1; return sblock->checksum_error; -- cgit From 521e1022274000af1981411673e4019d44bdea7f Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 May 2020 15:54:41 +0200 Subject: btrfs: scrub: simplify tree block checksum calculation Use a simpler iteration over tree block pages, same what csum_tree_block does: first page always exists, loop over the rest. Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 19a64c72f38e..663bb2c22c50 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1814,15 +1814,10 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) SHASH_DESC_ON_STACK(shash, fs_info->csum_shash); u8 calculated_csum[BTRFS_CSUM_SIZE]; u8 on_disk_csum[BTRFS_CSUM_SIZE]; + const int num_pages = sctx->fs_info->nodesize >> PAGE_SHIFT; + int i; struct page *page; char *kaddr; - u64 mapped_size; - void *p; - u64 len; - int index; - - shash->tfm = fs_info->csum_shash; - crypto_shash_init(shash); BUG_ON(sblock->page_count < 1); page = sblock->pagev[0]->page; @@ -1850,24 +1845,14 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) BTRFS_UUID_SIZE)) sblock->header_error = 1; - len = sctx->fs_info->nodesize - BTRFS_CSUM_SIZE; - mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE; - p = kaddr + BTRFS_CSUM_SIZE; - index = 0; - for (;;) { - u64 l = min_t(u64, len, mapped_size); + shash->tfm = fs_info->csum_shash; + crypto_shash_init(shash); + crypto_shash_update(shash, kaddr + BTRFS_CSUM_SIZE, + PAGE_SIZE - BTRFS_CSUM_SIZE); - crypto_shash_update(shash, p, l); - len -= l; - if (len == 0) - break; - index++; - BUG_ON(index >= sblock->page_count); - BUG_ON(!sblock->pagev[index]->page); - page = sblock->pagev[index]->page; - kaddr = page_address(page); - mapped_size = PAGE_SIZE; - p = kaddr; + for (i = 1; i < num_pages; i++) { + kaddr = page_address(sblock->pagev[i]->page); + crypto_shash_update(shash, kaddr, PAGE_SIZE); } crypto_shash_final(shash, calculated_csum); -- cgit From 100aa5d9f9f9d1163218bbbaad21bffbd8ee3e8d Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 May 2020 16:20:35 +0200 Subject: btrfs: scrub: clean up temporary page variables in scrub_checksum_tree_block Add proper variable for the scrub page and use it instead of repeatedly dereferencing the other structures. Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 663bb2c22c50..d935ac06323f 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1816,12 +1816,12 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) u8 on_disk_csum[BTRFS_CSUM_SIZE]; const int num_pages = sctx->fs_info->nodesize >> PAGE_SHIFT; int i; - struct page *page; + struct scrub_page *spage; char *kaddr; BUG_ON(sblock->page_count < 1); - page = sblock->pagev[0]->page; - kaddr = page_address(page); + spage = sblock->pagev[0]; + kaddr = page_address(spage->page); h = (struct btrfs_header *)kaddr; memcpy(on_disk_csum, h->csum, sctx->csum_size); @@ -1830,15 +1830,15 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) * a) don't have an extent buffer and * b) the page is already kmapped */ - if (sblock->pagev[0]->logical != btrfs_stack_header_bytenr(h)) + if (spage->logical != btrfs_stack_header_bytenr(h)) sblock->header_error = 1; - if (sblock->pagev[0]->generation != btrfs_stack_header_generation(h)) { + if (spage->generation != btrfs_stack_header_generation(h)) { sblock->header_error = 1; sblock->generation_error = 1; } - if (!scrub_check_fsid(h->fsid, sblock->pagev[0])) + if (!scrub_check_fsid(h->fsid, spage)) sblock->header_error = 1; if (memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid, -- cgit From fbabd4a36faaf74c83142d0b3d950c11ec14fda1 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 21 Jul 2020 10:38:37 -0400 Subject: btrfs: return EROFS for BTRFS_FS_STATE_ERROR cases Eric reported seeing this message while running generic/475 BTRFS: error (device dm-3) in btrfs_sync_log:3084: errno=-117 Filesystem corrupted Full stack trace: BTRFS: error (device dm-0) in btrfs_commit_transaction:2323: errno=-5 IO failure (Error while writing out transaction) BTRFS info (device dm-0): forced readonly BTRFS warning (device dm-0): Skipping commit of aborted transaction. ------------[ cut here ]------------ BTRFS: error (device dm-0) in cleanup_transaction:1894: errno=-5 IO failure BTRFS: Transaction aborted (error -117) BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c6480 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c6488 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c6490 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c6498 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64a0 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64a8 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64b0 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64b8 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64c0 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3572 rw 0,0 sector 0x1b85e8 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3572 rw 0,0 sector 0x1b85f0 len 4096 err no 10 WARNING: CPU: 3 PID: 23985 at fs/btrfs/tree-log.c:3084 btrfs_sync_log+0xbc8/0xd60 [btrfs] BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d4288 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d4290 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d4298 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42a0 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42a8 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42b0 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42b8 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42c0 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42c8 len 4096 err no 10 BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42d0 len 4096 err no 10 CPU: 3 PID: 23985 Comm: fsstress Tainted: G W L 5.8.0-rc4-default+ #1181 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014 RIP: 0010:btrfs_sync_log+0xbc8/0xd60 [btrfs] RSP: 0018:ffff909a44d17bd0 EFLAGS: 00010286 RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000001 RDX: ffff8f3be41cb940 RSI: ffffffffb0108d2b RDI: ffffffffb0108ff7 RBP: ffff909a44d17e70 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000037988 R12: ffff8f3bd20e4000 R13: ffff8f3bd20e4428 R14: 00000000ffffff8b R15: ffff909a44d17c70 FS: 00007f6a6ed3fb80(0000) GS:ffff8f3c3dc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f6a6ed3e000 CR3: 00000000525c0003 CR4: 0000000000160ee0 Call Trace: ? finish_wait+0x90/0x90 ? __mutex_unlock_slowpath+0x45/0x2a0 ? lock_acquire+0xa3/0x440 ? lockref_put_or_lock+0x9/0x30 ? dput+0x20/0x4a0 ? dput+0x20/0x4a0 ? do_raw_spin_unlock+0x4b/0xc0 ? _raw_spin_unlock+0x1f/0x30 btrfs_sync_file+0x335/0x490 [btrfs] do_fsync+0x38/0x70 __x64_sys_fsync+0x10/0x20 do_syscall_64+0x50/0xe0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x7f6a6ef1b6e3 Code: Bad RIP value. RSP: 002b:00007ffd01e20038 EFLAGS: 00000246 ORIG_RAX: 000000000000004a RAX: ffffffffffffffda RBX: 000000000007a120 RCX: 00007f6a6ef1b6e3 RDX: 00007ffd01e1ffa0 RSI: 00007ffd01e1ffa0 RDI: 0000000000000003 RBP: 0000000000000003 R08: 0000000000000001 R09: 00007ffd01e2004c R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000009f R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 irq event stamp: 0 hardirqs last enabled at (0): [<0000000000000000>] 0x0 hardirqs last disabled at (0): [] copy_process+0x67b/0x1b00 softirqs last enabled at (0): [] copy_process+0x67b/0x1b00 softirqs last disabled at (0): [<0000000000000000>] 0x0 ---[ end trace af146e0e38433456 ]--- BTRFS: error (device dm-0) in btrfs_sync_log:3084: errno=-117 Filesystem corrupted This ret came from btrfs_write_marked_extents(). If we get an aborted transaction via EIO before, we'll see it in btree_write_cache_pages() and return EUCLEAN, which gets printed as "Filesystem corrupted". Except we shouldn't be returning EUCLEAN here, we need to be returning EROFS because EUCLEAN is reserved for actual corruption, not IO errors. We are inconsistent about our handling of BTRFS_FS_STATE_ERROR elsewhere, but we want to use EROFS for this particular case. The original transaction abort has the real error code for why we ended up with an aborted transaction, all subsequent actions just need to return EROFS because they may not have a trans handle and have no idea about the original cause of the abort. After patch "btrfs: don't WARN if we abort a transaction with EROFS" the stacktrace will not be dumped either. Reported-by: Eric Sandeen CC: stable@vger.kernel.org # 5.4+ Signed-off-by: Josef Bacik Reviewed-by: David Sterba [ add full test stacktrace ] Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/btrfs/scrub.c') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index d935ac06323f..5a6cb9db512e 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3691,7 +3691,7 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx, struct btrfs_fs_info *fs_info = sctx->fs_info; if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) - return -EIO; + return -EROFS; /* Seed devices of a new filesystem has their own generation. */ if (scrub_dev->fs_devices != fs_info->fs_devices) -- cgit