Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/mason/linux-btrfs

Pull btrfs update from Chris Mason:
 "From a feature point of view, most of the code here comes from Miao
  Xie and others at Fujitsu to implement scrubbing and replacing devices
  on raid56.  This has been in development for a while, and it's a big
  improvement.

  Filipe and Josef have a great assortment of fixes, many of which solve
  problems corruptions either after a crash or in error conditions.  I
  still have a round two from Filipe for next week that solves
  corruptions with discard and block group removal"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (62 commits)
  Btrfs: make get_caching_control unconditionally return the ctl
  Btrfs: fix unprotected deletion from pending_chunks list
  Btrfs: fix fs mapping extent map leak
  Btrfs: fix memory leak after block remove + trimming
  Btrfs: make btrfs_abort_transaction consider existence of new block groups
  Btrfs: fix race between writing free space cache and trimming
  Btrfs: fix race between fs trimming and block group remove/allocation
  Btrfs, replace: enable dev-replace for raid56
  Btrfs: fix freeing used extents after removing empty block group
  Btrfs: fix crash caused by block group removal
  Btrfs: fix invalid block group rbtree access after bg is removed
  Btrfs, raid56: fix use-after-free problem in the final device replace procedure on raid56
  Btrfs, replace: write raid56 parity into the replace target device
  Btrfs, replace: write dirty pages into the replace target device
  Btrfs, raid56: support parity scrub on raid56
  Btrfs, raid56: use a variant to record the operation type
  Btrfs, scrub: repair the common data on RAID5/6 if it is corrupted
  Btrfs, raid56: don't change bbio and raid_map
  Btrfs: remove unnecessary code of stripe_index assignment in __btrfs_map_block
  Btrfs: remove noused bbio_ret in __btrfs_map_block in condition
  ...
  • Loading branch information
Linus Torvalds committed Dec 12, 2014
2 parents 0349678 + 9627aee commit bdeb03c
Show file tree
Hide file tree
Showing 32 changed files with 2,740 additions and 641 deletions.
163 changes: 65 additions & 98 deletions fs/btrfs/check-integrity.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
#include <linux/mutex.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/vmalloc.h>
#include "ctree.h"
#include "disk-io.h"
#include "hash.h"
Expand Down Expand Up @@ -326,9 +327,6 @@ static int btrfsic_handle_extent_data(struct btrfsic_state *state,
static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
struct btrfsic_block_data_ctx *block_ctx_out,
int mirror_num);
static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr,
u32 len, struct block_device *bdev,
struct btrfsic_block_data_ctx *block_ctx_out);
static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx);
static int btrfsic_read_block(struct btrfsic_state *state,
struct btrfsic_block_data_ctx *block_ctx);
Expand Down Expand Up @@ -1326,24 +1324,25 @@ static int btrfsic_create_link_to_next_block(
l = NULL;
next_block->generation = BTRFSIC_GENERATION_UNKNOWN;
} else {
if (next_block->logical_bytenr != next_bytenr &&
!(!next_block->is_metadata &&
0 == next_block->logical_bytenr)) {
printk(KERN_INFO
"Referenced block @%llu (%s/%llu/%d)"
" found in hash table, %c,"
" bytenr mismatch (!= stored %llu).\n",
next_bytenr, next_block_ctx->dev->name,
next_block_ctx->dev_bytenr, *mirror_nump,
btrfsic_get_block_type(state, next_block),
next_block->logical_bytenr);
} else if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
printk(KERN_INFO
"Referenced block @%llu (%s/%llu/%d)"
" found in hash table, %c.\n",
next_bytenr, next_block_ctx->dev->name,
next_block_ctx->dev_bytenr, *mirror_nump,
btrfsic_get_block_type(state, next_block));
if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) {
if (next_block->logical_bytenr != next_bytenr &&
!(!next_block->is_metadata &&
0 == next_block->logical_bytenr))
printk(KERN_INFO
"Referenced block @%llu (%s/%llu/%d) found in hash table, %c, bytenr mismatch (!= stored %llu).\n",
next_bytenr, next_block_ctx->dev->name,
next_block_ctx->dev_bytenr, *mirror_nump,
btrfsic_get_block_type(state,
next_block),
next_block->logical_bytenr);
else
printk(KERN_INFO
"Referenced block @%llu (%s/%llu/%d) found in hash table, %c.\n",
next_bytenr, next_block_ctx->dev->name,
next_block_ctx->dev_bytenr, *mirror_nump,
btrfsic_get_block_type(state,
next_block));
}
next_block->logical_bytenr = next_bytenr;

next_block->mirror_num = *mirror_nump;
Expand Down Expand Up @@ -1529,7 +1528,9 @@ static int btrfsic_handle_extent_data(
return -1;
}
if (!block_was_created) {
if (next_block->logical_bytenr != next_bytenr &&
if ((state->print_mask &
BTRFSIC_PRINT_MASK_VERBOSE) &&
next_block->logical_bytenr != next_bytenr &&
!(!next_block->is_metadata &&
0 == next_block->logical_bytenr)) {
printk(KERN_INFO
Expand Down Expand Up @@ -1607,25 +1608,6 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
return ret;
}

static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr,
u32 len, struct block_device *bdev,
struct btrfsic_block_data_ctx *block_ctx_out)
{
block_ctx_out->dev = btrfsic_dev_state_lookup(bdev);
block_ctx_out->dev_bytenr = bytenr;
block_ctx_out->start = bytenr;
block_ctx_out->len = len;
block_ctx_out->datav = NULL;
block_ctx_out->pagev = NULL;
block_ctx_out->mem_to_free = NULL;
if (NULL != block_ctx_out->dev) {
return 0;
} else {
printk(KERN_INFO "btrfsic: error, cannot lookup dev (#2)!\n");
return -ENXIO;
}
}

static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx)
{
if (block_ctx->mem_to_free) {
Expand Down Expand Up @@ -1901,25 +1883,26 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
dev_state,
dev_bytenr);
}
if (block->logical_bytenr != bytenr &&
!(!block->is_metadata &&
block->logical_bytenr == 0))
printk(KERN_INFO
"Written block @%llu (%s/%llu/%d)"
" found in hash table, %c,"
" bytenr mismatch"
" (!= stored %llu).\n",
bytenr, dev_state->name, dev_bytenr,
block->mirror_num,
btrfsic_get_block_type(state, block),
block->logical_bytenr);
else if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
printk(KERN_INFO
"Written block @%llu (%s/%llu/%d)"
" found in hash table, %c.\n",
bytenr, dev_state->name, dev_bytenr,
block->mirror_num,
btrfsic_get_block_type(state, block));
if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) {
if (block->logical_bytenr != bytenr &&
!(!block->is_metadata &&
block->logical_bytenr == 0))
printk(KERN_INFO
"Written block @%llu (%s/%llu/%d) found in hash table, %c, bytenr mismatch (!= stored %llu).\n",
bytenr, dev_state->name,
dev_bytenr,
block->mirror_num,
btrfsic_get_block_type(state,
block),
block->logical_bytenr);
else
printk(KERN_INFO
"Written block @%llu (%s/%llu/%d) found in hash table, %c.\n",
bytenr, dev_state->name,
dev_bytenr, block->mirror_num,
btrfsic_get_block_type(state,
block));
}
block->logical_bytenr = bytenr;
} else {
if (num_pages * PAGE_CACHE_SIZE <
Expand Down Expand Up @@ -2002,24 +1985,13 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
}
}

if (block->is_superblock)
ret = btrfsic_map_superblock(state, bytenr,
processed_len,
bdev, &block_ctx);
else
ret = btrfsic_map_block(state, bytenr, processed_len,
&block_ctx, 0);
if (ret) {
printk(KERN_INFO
"btrfsic: btrfsic_map_block(root @%llu)"
" failed!\n", bytenr);
goto continue_loop;
}
block_ctx.datav = mapped_datav;
/* the following is required in case of writes to mirrors,
* use the same that was used for the lookup */
block_ctx.dev = dev_state;
block_ctx.dev_bytenr = dev_bytenr;
block_ctx.start = bytenr;
block_ctx.len = processed_len;
block_ctx.pagev = NULL;
block_ctx.mem_to_free = NULL;
block_ctx.datav = mapped_datav;

if (is_metadata || state->include_extent_data) {
block->never_written = 0;
Expand Down Expand Up @@ -2133,10 +2105,6 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
/* this is getting ugly for the
* include_extent_data case... */
bytenr = 0; /* unknown */
block_ctx.start = bytenr;
block_ctx.len = processed_len;
block_ctx.mem_to_free = NULL;
block_ctx.pagev = NULL;
} else {
processed_len = state->metablock_size;
bytenr = btrfs_stack_header_bytenr(
Expand All @@ -2149,22 +2117,15 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
"Written block @%llu (%s/%llu/?)"
" !found in hash table, M.\n",
bytenr, dev_state->name, dev_bytenr);

ret = btrfsic_map_block(state, bytenr, processed_len,
&block_ctx, 0);
if (ret) {
printk(KERN_INFO
"btrfsic: btrfsic_map_block(root @%llu)"
" failed!\n",
dev_bytenr);
goto continue_loop;
}
}
block_ctx.datav = mapped_datav;
/* the following is required in case of writes to mirrors,
* use the same that was used for the lookup */

block_ctx.dev = dev_state;
block_ctx.dev_bytenr = dev_bytenr;
block_ctx.start = bytenr;
block_ctx.len = processed_len;
block_ctx.pagev = NULL;
block_ctx.mem_to_free = NULL;
block_ctx.datav = mapped_datav;

block = btrfsic_block_alloc();
if (NULL == block) {
Expand Down Expand Up @@ -3130,10 +3091,13 @@ int btrfsic_mount(struct btrfs_root *root,
root->sectorsize, PAGE_CACHE_SIZE);
return -1;
}
state = kzalloc(sizeof(*state), GFP_NOFS);
if (NULL == state) {
printk(KERN_INFO "btrfs check-integrity: kmalloc() failed!\n");
return -1;
state = kzalloc(sizeof(*state), GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
if (!state) {
state = vzalloc(sizeof(*state));
if (!state) {
printk(KERN_INFO "btrfs check-integrity: vzalloc() failed!\n");
return -1;
}
}

if (!btrfsic_is_initialized) {
Expand Down Expand Up @@ -3277,5 +3241,8 @@ void btrfsic_unmount(struct btrfs_root *root,

mutex_unlock(&btrfsic_mutex);

kfree(state);
if (is_vmalloc_addr(state))
vfree(state);
else
kfree(state);
}
18 changes: 12 additions & 6 deletions fs/btrfs/compression.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,16 +224,19 @@ static void end_compressed_bio_read(struct bio *bio, int err)
* Clear the writeback bits on all of the file
* pages for a compressed write
*/
static noinline void end_compressed_writeback(struct inode *inode, u64 start,
unsigned long ram_size)
static noinline void end_compressed_writeback(struct inode *inode,
const struct compressed_bio *cb)
{
unsigned long index = start >> PAGE_CACHE_SHIFT;
unsigned long end_index = (start + ram_size - 1) >> PAGE_CACHE_SHIFT;
unsigned long index = cb->start >> PAGE_CACHE_SHIFT;
unsigned long end_index = (cb->start + cb->len - 1) >> PAGE_CACHE_SHIFT;
struct page *pages[16];
unsigned long nr_pages = end_index - index + 1;
int i;
int ret;

if (cb->errors)
mapping_set_error(inode->i_mapping, -EIO);

while (nr_pages > 0) {
ret = find_get_pages_contig(inode->i_mapping, index,
min_t(unsigned long,
Expand All @@ -244,6 +247,8 @@ static noinline void end_compressed_writeback(struct inode *inode, u64 start,
continue;
}
for (i = 0; i < ret; i++) {
if (cb->errors)
SetPageError(pages[i]);
end_page_writeback(pages[i]);
page_cache_release(pages[i]);
}
Expand Down Expand Up @@ -287,10 +292,11 @@ static void end_compressed_bio_write(struct bio *bio, int err)
tree->ops->writepage_end_io_hook(cb->compressed_pages[0],
cb->start,
cb->start + cb->len - 1,
NULL, 1);
NULL,
err ? 0 : 1);
cb->compressed_pages[0]->mapping = NULL;

end_compressed_writeback(inode, cb->start, cb->len);
end_compressed_writeback(inode, cb);
/* note, our inode could be gone now */

/*
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -2929,7 +2929,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
*/
if (!p->leave_spinning)
btrfs_set_path_blocking(p);
if (ret < 0)
if (ret < 0 && !p->skip_release_on_error)
btrfs_release_path(p);
return ret;
}
Expand Down
Loading

0 comments on commit bdeb03c

Please sign in to comment.