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 updates from Chris Mason:
 "This pull is mostly cleanups and fixes:

   - The raid5/6 cleanups from Zhao Lei fixup some long standing warts
     in the code and add improvements on top of the scrubbing support
     from 3.19.

   - Josef has round one of our ENOSPC fixes coming from large btrfs
     clusters here at FB.

   - Dave Sterba continues a long series of cleanups (thanks Dave), and
     Filipe continues hammering on corner cases in fsync and others

  This all was held up a little trying to track down a use-after-free in
  btrfs raid5/6.  It's not clear yet if this is just made easier to
  trigger with this pull or if its a new bug from the raid5/6 cleanups.
  Dave Sterba is the only one to trigger it so far, but he has a
  consistent way to reproduce, so we'll get it nailed shortly"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (68 commits)
  Btrfs: don't remove extents and xattrs when logging new names
  Btrfs: fix fsync data loss after adding hard link to inode
  Btrfs: fix BUG_ON in btrfs_orphan_add() when delete unused block group
  Btrfs: account for large extents with enospc
  Btrfs: don't set and clear delalloc for O_DIRECT writes
  Btrfs: only adjust outstanding_extents when we do a short write
  btrfs: Fix out-of-space bug
  Btrfs: scrub, fix sleep in atomic context
  Btrfs: fix scheduler warning when syncing log
  Btrfs: Remove unnecessary placeholder in btrfs_err_code
  btrfs: cleanup init for list in free-space-cache
  btrfs: delete chunk allocation attemp when setting block group ro
  btrfs: clear bio reference after submit_one_bio()
  Btrfs: fix scrub race leading to use-after-free
  Btrfs: add missing cleanup on sysfs init failure
  Btrfs: fix race between transaction commit and empty block group removal
  btrfs: add more checks to btrfs_read_sys_array
  btrfs: cleanup, rename a few variables in btrfs_read_sys_array
  btrfs: add checks for sys_chunk_array sizes
  btrfs: more superblock checks, lower bounds on devices and sectorsize/nodesize
  ...
  • Loading branch information
Linus Torvalds committed Feb 19, 2015
2 parents 4533f6e + a742994 commit 2b9fb53
Show file tree
Hide file tree
Showing 34 changed files with 1,063 additions and 861 deletions.
28 changes: 6 additions & 22 deletions fs/btrfs/backref.c
Original file line number Diff line number Diff line change
Expand Up @@ -1246,25 +1246,6 @@ int btrfs_check_shared(struct btrfs_trans_handle *trans,
return ret;
}

/*
* this makes the path point to (inum INODE_ITEM ioff)
*/
int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
struct btrfs_path *path)
{
struct btrfs_key key;
return btrfs_find_item(fs_root, path, inum, ioff,
BTRFS_INODE_ITEM_KEY, &key);
}

static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
struct btrfs_path *path,
struct btrfs_key *found_key)
{
return btrfs_find_item(fs_root, path, inum, ioff,
BTRFS_INODE_REF_KEY, found_key);
}

int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
u64 start_off, struct btrfs_path *path,
struct btrfs_inode_extref **ret_extref,
Expand Down Expand Up @@ -1374,7 +1355,8 @@ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
btrfs_tree_read_unlock_blocking(eb);
free_extent_buffer(eb);
}
ret = inode_ref_info(parent, 0, fs_root, path, &found_key);
ret = btrfs_find_item(fs_root, path, parent, 0,
BTRFS_INODE_REF_KEY, &found_key);
if (ret > 0)
ret = -ENOENT;
if (ret)
Expand Down Expand Up @@ -1727,8 +1709,10 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
struct btrfs_key found_key;

while (!ret) {
ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,
&found_key);
ret = btrfs_find_item(fs_root, path, inum,
parent ? parent + 1 : 0, BTRFS_INODE_REF_KEY,
&found_key);

if (ret < 0)
break;
if (ret) {
Expand Down
3 changes: 0 additions & 3 deletions fs/btrfs/backref.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ struct inode_fs_paths {
typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root,
void *ctx);

int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
struct btrfs_path *path);

int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
struct btrfs_path *path, struct btrfs_key *found_key,
u64 *flags);
Expand Down
3 changes: 3 additions & 0 deletions fs/btrfs/btrfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ struct btrfs_inode {

struct btrfs_delayed_node *delayed_node;

/* File creation time. */
struct timespec i_otime;

struct inode vfs_inode;
};

Expand Down
55 changes: 27 additions & 28 deletions fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,19 @@ static struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
*/
static void add_root_to_dirty_list(struct btrfs_root *root)
{
if (test_bit(BTRFS_ROOT_DIRTY, &root->state) ||
!test_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state))
return;

spin_lock(&root->fs_info->trans_lock);
if (test_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state) &&
list_empty(&root->dirty_list)) {
list_add(&root->dirty_list,
&root->fs_info->dirty_cowonly_roots);
if (!test_and_set_bit(BTRFS_ROOT_DIRTY, &root->state)) {
/* Want the extent tree to be the last on the list */
if (root->objectid == BTRFS_EXTENT_TREE_OBJECTID)
list_move_tail(&root->dirty_list,
&root->fs_info->dirty_cowonly_roots);
else
list_move(&root->dirty_list,
&root->fs_info->dirty_cowonly_roots);
}
spin_unlock(&root->fs_info->trans_lock);
}
Expand Down Expand Up @@ -1363,8 +1371,7 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct btrfs_path *path,

if (tm->op == MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
BUG_ON(tm->slot != 0);
eb_rewin = alloc_dummy_extent_buffer(eb->start,
fs_info->tree_root->nodesize);
eb_rewin = alloc_dummy_extent_buffer(fs_info, eb->start);
if (!eb_rewin) {
btrfs_tree_read_unlock_blocking(eb);
free_extent_buffer(eb);
Expand Down Expand Up @@ -1444,7 +1451,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
} else if (old_root) {
btrfs_tree_read_unlock(eb_root);
free_extent_buffer(eb_root);
eb = alloc_dummy_extent_buffer(logical, root->nodesize);
eb = alloc_dummy_extent_buffer(root->fs_info, logical);
} else {
btrfs_set_lock_blocking_rw(eb_root, BTRFS_READ_LOCK);
eb = btrfs_clone_extent_buffer(eb_root);
Expand Down Expand Up @@ -2282,7 +2289,7 @@ static void reada_for_search(struct btrfs_root *root,
if ((search <= target && target - search <= 65536) ||
(search > target && search - target <= 65536)) {
gen = btrfs_node_ptr_generation(node, nr);
readahead_tree_block(root, search, blocksize);
readahead_tree_block(root, search);
nread += blocksize;
}
nscan++;
Expand All @@ -2301,15 +2308,13 @@ static noinline void reada_for_balance(struct btrfs_root *root,
u64 gen;
u64 block1 = 0;
u64 block2 = 0;
int blocksize;

parent = path->nodes[level + 1];
if (!parent)
return;

nritems = btrfs_header_nritems(parent);
slot = path->slots[level + 1];
blocksize = root->nodesize;

if (slot > 0) {
block1 = btrfs_node_blockptr(parent, slot - 1);
Expand All @@ -2334,9 +2339,9 @@ static noinline void reada_for_balance(struct btrfs_root *root,
}

if (block1)
readahead_tree_block(root, block1, blocksize);
readahead_tree_block(root, block1);
if (block2)
readahead_tree_block(root, block2, blocksize);
readahead_tree_block(root, block2);
}


Expand Down Expand Up @@ -2609,32 +2614,24 @@ static int key_search(struct extent_buffer *b, struct btrfs_key *key,
return 0;
}

int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *path,
u64 iobjectid, u64 ioff, u8 key_type,
struct btrfs_key *found_key)
{
int ret;
struct btrfs_key key;
struct extent_buffer *eb;
struct btrfs_path *path;

ASSERT(path);
ASSERT(found_key);

key.type = key_type;
key.objectid = iobjectid;
key.offset = ioff;

if (found_path == NULL) {
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
} else
path = found_path;

ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0);
if ((ret < 0) || (found_key == NULL)) {
if (path != found_path)
btrfs_free_path(path);
if (ret < 0)
return ret;
}

eb = path->nodes[0];
if (ret && path->slots[0] >= btrfs_header_nritems(eb)) {
Expand Down Expand Up @@ -3383,7 +3380,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
add_root_to_dirty_list(root);
extent_buffer_get(c);
path->nodes[level] = c;
path->locks[level] = BTRFS_WRITE_LOCK;
path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING;
path->slots[level] = 0;
return 0;
}
Expand Down Expand Up @@ -4356,13 +4353,15 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
path->search_for_split = 1;
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
path->search_for_split = 0;
if (ret > 0)
ret = -EAGAIN;
if (ret < 0)
goto err;

ret = -EAGAIN;
leaf = path->nodes[0];
/* if our item isn't there or got smaller, return now */
if (ret > 0 || item_size != btrfs_item_size_nr(leaf, path->slots[0]))
/* if our item isn't there, return now */
if (item_size != btrfs_item_size_nr(leaf, path->slots[0]))
goto err;

/* the leaf has changed, it now has room. return now */
Expand Down
39 changes: 10 additions & 29 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ static int btrfs_csum_sizes[] = { 4, 0 };

#define BTRFS_DIRTY_METADATA_THRESH (32 * 1024 * 1024)

#define BTRFS_MAX_EXTENT_SIZE (128 * 1024 * 1024)

/*
* The key defines the order in the tree, and so it also defines (optimal)
* block layout.
Expand Down Expand Up @@ -1020,6 +1022,9 @@ enum btrfs_raid_types {
BTRFS_BLOCK_GROUP_RAID6 | \
BTRFS_BLOCK_GROUP_DUP | \
BTRFS_BLOCK_GROUP_RAID10)
#define BTRFS_BLOCK_GROUP_RAID56_MASK (BTRFS_BLOCK_GROUP_RAID5 | \
BTRFS_BLOCK_GROUP_RAID6)

/*
* We need a bit for restriper to be able to tell when chunks of type
* SINGLE are available. This "extended" profile format is used in
Expand Down Expand Up @@ -1239,7 +1244,6 @@ enum btrfs_disk_cache_state {
BTRFS_DC_ERROR = 1,
BTRFS_DC_CLEAR = 2,
BTRFS_DC_SETUP = 3,
BTRFS_DC_NEED_WRITE = 4,
};

struct btrfs_caching_control {
Expand Down Expand Up @@ -1277,7 +1281,6 @@ struct btrfs_block_group_cache {
unsigned long full_stripe_len;

unsigned int ro:1;
unsigned int dirty:1;
unsigned int iref:1;
unsigned int has_caching_ctl:1;
unsigned int removed:1;
Expand Down Expand Up @@ -1315,6 +1318,9 @@ struct btrfs_block_group_cache {
struct list_head ro_list;

atomic_t trimming;

/* For dirty block groups */
struct list_head dirty_list;
};

/* delayed seq elem */
Expand Down Expand Up @@ -1741,6 +1747,7 @@ struct btrfs_fs_info {

spinlock_t unused_bgs_lock;
struct list_head unused_bgs;
struct mutex unused_bg_unpin_mutex;

/* For btrfs to record security options */
struct security_mnt_opts security_opts;
Expand Down Expand Up @@ -1776,6 +1783,7 @@ struct btrfs_subvolume_writers {
#define BTRFS_ROOT_DEFRAG_RUNNING 6
#define BTRFS_ROOT_FORCE_COW 7
#define BTRFS_ROOT_MULTI_LOG_TASKS 8
#define BTRFS_ROOT_DIRTY 9

/*
* in ram representation of the tree. extent_root is used for all allocations
Expand All @@ -1794,8 +1802,6 @@ struct btrfs_root {
struct btrfs_fs_info *fs_info;
struct extent_io_tree dirty_log_pages;

struct kobject root_kobj;
struct completion kobj_unregister;
struct mutex objectid_mutex;

spinlock_t accounting_lock;
Expand Down Expand Up @@ -2465,31 +2471,6 @@ BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32);
BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32);
BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64);
BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64);

static inline struct btrfs_timespec *
btrfs_inode_atime(struct btrfs_inode_item *inode_item)
{
unsigned long ptr = (unsigned long)inode_item;
ptr += offsetof(struct btrfs_inode_item, atime);
return (struct btrfs_timespec *)ptr;
}

static inline struct btrfs_timespec *
btrfs_inode_mtime(struct btrfs_inode_item *inode_item)
{
unsigned long ptr = (unsigned long)inode_item;
ptr += offsetof(struct btrfs_inode_item, mtime);
return (struct btrfs_timespec *)ptr;
}

static inline struct btrfs_timespec *
btrfs_inode_ctime(struct btrfs_inode_item *inode_item)
{
unsigned long ptr = (unsigned long)inode_item;
ptr += offsetof(struct btrfs_inode_item, ctime);
return (struct btrfs_timespec *)ptr;
}

BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);
BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);
BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64);
Expand Down
38 changes: 22 additions & 16 deletions fs/btrfs/delayed-inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1755,27 +1755,31 @@ static void fill_stack_inode_item(struct btrfs_trans_handle *trans,
btrfs_set_stack_inode_flags(inode_item, BTRFS_I(inode)->flags);
btrfs_set_stack_inode_block_group(inode_item, 0);

btrfs_set_stack_timespec_sec(btrfs_inode_atime(inode_item),
btrfs_set_stack_timespec_sec(&inode_item->atime,
inode->i_atime.tv_sec);
btrfs_set_stack_timespec_nsec(btrfs_inode_atime(inode_item),
btrfs_set_stack_timespec_nsec(&inode_item->atime,
inode->i_atime.tv_nsec);

btrfs_set_stack_timespec_sec(btrfs_inode_mtime(inode_item),
btrfs_set_stack_timespec_sec(&inode_item->mtime,
inode->i_mtime.tv_sec);
btrfs_set_stack_timespec_nsec(btrfs_inode_mtime(inode_item),
btrfs_set_stack_timespec_nsec(&inode_item->mtime,
inode->i_mtime.tv_nsec);

btrfs_set_stack_timespec_sec(btrfs_inode_ctime(inode_item),
btrfs_set_stack_timespec_sec(&inode_item->ctime,
inode->i_ctime.tv_sec);
btrfs_set_stack_timespec_nsec(btrfs_inode_ctime(inode_item),
btrfs_set_stack_timespec_nsec(&inode_item->ctime,
inode->i_ctime.tv_nsec);

btrfs_set_stack_timespec_sec(&inode_item->otime,
BTRFS_I(inode)->i_otime.tv_sec);
btrfs_set_stack_timespec_nsec(&inode_item->otime,
BTRFS_I(inode)->i_otime.tv_nsec);
}

int btrfs_fill_inode(struct inode *inode, u32 *rdev)
{
struct btrfs_delayed_node *delayed_node;
struct btrfs_inode_item *inode_item;
struct btrfs_timespec *tspec;

delayed_node = btrfs_get_delayed_node(inode);
if (!delayed_node)
Expand All @@ -1802,17 +1806,19 @@ int btrfs_fill_inode(struct inode *inode, u32 *rdev)
*rdev = btrfs_stack_inode_rdev(inode_item);
BTRFS_I(inode)->flags = btrfs_stack_inode_flags(inode_item);

tspec = btrfs_inode_atime(inode_item);
inode->i_atime.tv_sec = btrfs_stack_timespec_sec(tspec);
inode->i_atime.tv_nsec = btrfs_stack_timespec_nsec(tspec);
inode->i_atime.tv_sec = btrfs_stack_timespec_sec(&inode_item->atime);
inode->i_atime.tv_nsec = btrfs_stack_timespec_nsec(&inode_item->atime);

inode->i_mtime.tv_sec = btrfs_stack_timespec_sec(&inode_item->mtime);
inode->i_mtime.tv_nsec = btrfs_stack_timespec_nsec(&inode_item->mtime);

tspec = btrfs_inode_mtime(inode_item);
inode->i_mtime.tv_sec = btrfs_stack_timespec_sec(tspec);
inode->i_mtime.tv_nsec = btrfs_stack_timespec_nsec(tspec);
inode->i_ctime.tv_sec = btrfs_stack_timespec_sec(&inode_item->ctime);
inode->i_ctime.tv_nsec = btrfs_stack_timespec_nsec(&inode_item->ctime);

tspec = btrfs_inode_ctime(inode_item);
inode->i_ctime.tv_sec = btrfs_stack_timespec_sec(tspec);
inode->i_ctime.tv_nsec = btrfs_stack_timespec_nsec(tspec);
BTRFS_I(inode)->i_otime.tv_sec =
btrfs_stack_timespec_sec(&inode_item->otime);
BTRFS_I(inode)->i_otime.tv_nsec =
btrfs_stack_timespec_nsec(&inode_item->otime);

inode->i_generation = BTRFS_I(inode)->generation;
BTRFS_I(inode)->index_cnt = (u64)-1;
Expand Down
Loading

0 comments on commit 2b9fb53

Please sign in to comment.