Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2aed8df authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull large btrfs update from Chris Mason:
 "This pull request is very large, and the two main features in here
  have been under testing/devel for quite a while.

  We have subvolume quotas from the strato developers.  This enables
  full tracking of how many blocks are allocated to each subvolume (and
  all snapshots) and you can set limits on a per-subvolume basis.  You
  can also create quota groups and toss multiple subvolumes into a big
  group.  It's everything you need to be a web hosting company and give
  each user their own subvolume.

  The userland side of the quotas is being refreshed, they'll send out
  details on where to grab it soon.

  Next is the kernel side of btrfs send/receive from Alexander Block.
  This leverages the same infrastructure as the quota code to figure out
  relationships between blocks and their owners.  It can then compute
  the difference between two snapshots and sends the diffs in a neutral
  format into userland.

  The basic model:

        create a snapshot
        send that snapshot as the initial backup
        make changes
        create a second snapshot
        send the incremental as a backup
        delete the first snapshot
        (use the second snapshot for the next incremental)

  The receive portion is all in userland, and in the 'next' branch of my
  btrfs-progs repo.

  There's still some work to do in terms of optimizing the send side
  from kernel to userland.  The really important part is figuring out
  how two snapshots are different, and this is where we are
  concentrating right now.  The initial send of a dataset is a little
  slower than tar, but the incremental sends are dramatically faster
  than what rsync can do.

  On top of all of that, we have a nice queue of fixes, cleanups and
  optimizations."

Fix up trivial modify/del conflict in fs/btrfs/ioctl.c

Also fix up semantic conflict in fs/btrfs/send.c: the interface to
dentry_open() changed in commit 765927b2 ("switch dentry_open() to
struct path, make it grab references itself"), and since it now grabs
whatever references it needs, we should no longer do the mntget() on the
mnt (and we need to dput() the dentry reference we took).

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (65 commits)
  Btrfs: uninit variable fixes in send/receive
  Btrfs: introduce BTRFS_IOC_SEND for btrfs send/receive
  Btrfs: add btrfs_compare_trees function
  Btrfs: introduce subvol uuids and times
  Btrfs: make iref_to_path non static
  Btrfs: add a barrier before a waitqueue_active check
  Btrfs: call the ordered free operation without any locks held
  Btrfs: Check INCOMPAT flags on remount and add helper function
  Btrfs: add helper for tree enumeration
  btrfs: allow cross-subvolume file clone
  Btrfs: improve multi-thread buffer read
  Btrfs: make btrfs's allocation smoothly with preallocation
  Btrfs: lock the transition from dirty to writeback for an eb
  Btrfs: fix potential race in extent buffer freeing
  Btrfs: don't return true in releasepage unless we actually freed the eb
  Btrfs: suppress printk() if all device I/O stats are zero
  Btrfs: remove unwanted printk() for btrfs device I/O stats
  Btrfs: rewrite BTRFS_SETGET_FUNCS
  Btrfs: zero unused bytes in inode item
  Btrfs: kill free_space pointer from inode structure
  ...

Conflicts:
	fs/btrfs/ioctl.c
parents 47652500 b24baf69
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -8,7 +8,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
	   extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
	   extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
	   export.o tree-log.o free-space-cache.o zlib.o lzo.o \
	   export.o tree-log.o free-space-cache.o zlib.o lzo.o \
	   compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
	   compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
	   reada.o backref.o ulist.o
	   reada.o backref.o ulist.o qgroup.o send.o


btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
+8 −1
Original line number Original line Diff line number Diff line
@@ -206,10 +206,17 @@ static noinline void run_ordered_completions(struct btrfs_workers *workers,


		work->ordered_func(work);
		work->ordered_func(work);


		/* now take the lock again and call the freeing code */
		/* now take the lock again and drop our item from the list */
		spin_lock(&workers->order_lock);
		spin_lock(&workers->order_lock);
		list_del(&work->order_list);
		list_del(&work->order_list);
		spin_unlock(&workers->order_lock);

		/*
		 * we don't want to call the ordered free functions
		 * with the lock held though
		 */
		work->ordered_free(work);
		work->ordered_free(work);
		spin_lock(&workers->order_lock);
	}
	}


	spin_unlock(&workers->order_lock);
	spin_unlock(&workers->order_lock);
+14 −26
Original line number Original line Diff line number Diff line
@@ -773,9 +773,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
 */
 */
static int find_parent_nodes(struct btrfs_trans_handle *trans,
static int find_parent_nodes(struct btrfs_trans_handle *trans,
			     struct btrfs_fs_info *fs_info, u64 bytenr,
			     struct btrfs_fs_info *fs_info, u64 bytenr,
			     u64 delayed_ref_seq, u64 time_seq,
			     u64 time_seq, struct ulist *refs,
			     struct ulist *refs, struct ulist *roots,
			     struct ulist *roots, const u64 *extent_item_pos)
			     const u64 *extent_item_pos)
{
{
	struct btrfs_key key;
	struct btrfs_key key;
	struct btrfs_path *path;
	struct btrfs_path *path;
@@ -837,7 +836,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
				btrfs_put_delayed_ref(&head->node);
				btrfs_put_delayed_ref(&head->node);
				goto again;
				goto again;
			}
			}
			ret = __add_delayed_refs(head, delayed_ref_seq,
			ret = __add_delayed_refs(head, time_seq,
						 &prefs_delayed);
						 &prefs_delayed);
			mutex_unlock(&head->mutex);
			mutex_unlock(&head->mutex);
			if (ret) {
			if (ret) {
@@ -981,8 +980,7 @@ static void free_leaf_list(struct ulist *blocks)
 */
 */
static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
				struct btrfs_fs_info *fs_info, u64 bytenr,
				struct btrfs_fs_info *fs_info, u64 bytenr,
				u64 delayed_ref_seq, u64 time_seq,
				u64 time_seq, struct ulist **leafs,
				struct ulist **leafs,
				const u64 *extent_item_pos)
				const u64 *extent_item_pos)
{
{
	struct ulist *tmp;
	struct ulist *tmp;
@@ -997,7 +995,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
		return -ENOMEM;
		return -ENOMEM;
	}
	}


	ret = find_parent_nodes(trans, fs_info, bytenr, delayed_ref_seq,
	ret = find_parent_nodes(trans, fs_info, bytenr,
				time_seq, *leafs, tmp, extent_item_pos);
				time_seq, *leafs, tmp, extent_item_pos);
	ulist_free(tmp);
	ulist_free(tmp);


@@ -1024,8 +1022,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
 */
 */
int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
				struct btrfs_fs_info *fs_info, u64 bytenr,
				struct btrfs_fs_info *fs_info, u64 bytenr,
				u64 delayed_ref_seq, u64 time_seq,
				u64 time_seq, struct ulist **roots)
				struct ulist **roots)
{
{
	struct ulist *tmp;
	struct ulist *tmp;
	struct ulist_node *node = NULL;
	struct ulist_node *node = NULL;
@@ -1043,7 +1040,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,


	ULIST_ITER_INIT(&uiter);
	ULIST_ITER_INIT(&uiter);
	while (1) {
	while (1) {
		ret = find_parent_nodes(trans, fs_info, bytenr, delayed_ref_seq,
		ret = find_parent_nodes(trans, fs_info, bytenr,
					time_seq, tmp, *roots, NULL);
					time_seq, tmp, *roots, NULL);
		if (ret < 0 && ret != -ENOENT) {
		if (ret < 0 && ret != -ENOENT) {
			ulist_free(tmp);
			ulist_free(tmp);
@@ -1125,7 +1122,7 @@ static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
 * required for the path to fit into the buffer. in that case, the returned
 * required for the path to fit into the buffer. in that case, the returned
 * value will be smaller than dest. callers must check this!
 * value will be smaller than dest. callers must check this!
 */
 */
static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
			 struct btrfs_inode_ref *iref,
			 struct btrfs_inode_ref *iref,
			 struct extent_buffer *eb_in, u64 parent,
			 struct extent_buffer *eb_in, u64 parent,
			 char *dest, u32 size)
			 char *dest, u32 size)
@@ -1376,11 +1373,9 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
	struct ulist *roots = NULL;
	struct ulist *roots = NULL;
	struct ulist_node *ref_node = NULL;
	struct ulist_node *ref_node = NULL;
	struct ulist_node *root_node = NULL;
	struct ulist_node *root_node = NULL;
	struct seq_list seq_elem = {};
	struct seq_list tree_mod_seq_elem = {};
	struct seq_list tree_mod_seq_elem = {};
	struct ulist_iterator ref_uiter;
	struct ulist_iterator ref_uiter;
	struct ulist_iterator root_uiter;
	struct ulist_iterator root_uiter;
	struct btrfs_delayed_ref_root *delayed_refs = NULL;


	pr_debug("resolving all inodes for extent %llu\n",
	pr_debug("resolving all inodes for extent %llu\n",
			extent_item_objectid);
			extent_item_objectid);
@@ -1391,16 +1386,11 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
		trans = btrfs_join_transaction(fs_info->extent_root);
		trans = btrfs_join_transaction(fs_info->extent_root);
		if (IS_ERR(trans))
		if (IS_ERR(trans))
			return PTR_ERR(trans);
			return PTR_ERR(trans);

		delayed_refs = &trans->transaction->delayed_refs;
		spin_lock(&delayed_refs->lock);
		btrfs_get_delayed_seq(delayed_refs, &seq_elem);
		spin_unlock(&delayed_refs->lock);
		btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem);
		btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem);
	}
	}


	ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
	ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
				   seq_elem.seq, tree_mod_seq_elem.seq, &refs,
				   tree_mod_seq_elem.seq, &refs,
				   &extent_item_pos);
				   &extent_item_pos);
	if (ret)
	if (ret)
		goto out;
		goto out;
@@ -1408,7 +1398,6 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
	ULIST_ITER_INIT(&ref_uiter);
	ULIST_ITER_INIT(&ref_uiter);
	while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
	while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
		ret = btrfs_find_all_roots(trans, fs_info, ref_node->val,
		ret = btrfs_find_all_roots(trans, fs_info, ref_node->val,
						seq_elem.seq,
					   tree_mod_seq_elem.seq, &roots);
					   tree_mod_seq_elem.seq, &roots);
		if (ret)
		if (ret)
			break;
			break;
@@ -1431,7 +1420,6 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
out:
out:
	if (!search_commit_root) {
	if (!search_commit_root) {
		btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
		btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
		btrfs_put_delayed_seq(delayed_refs, &seq_elem);
		btrfs_end_transaction(trans, fs_info->extent_root);
		btrfs_end_transaction(trans, fs_info->extent_root);
	}
	}


@@ -1543,7 +1531,7 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
					ipath->fspath->bytes_left - s_ptr : 0;
					ipath->fspath->bytes_left - s_ptr : 0;


	fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr;
	fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr;
	fspath = iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb,
	fspath = btrfs_iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb,
				inum, fspath_min, bytes_left);
				inum, fspath_min, bytes_left);
	if (IS_ERR(fspath))
	if (IS_ERR(fspath))
		return PTR_ERR(fspath);
		return PTR_ERR(fspath);
+5 −2
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@


#include "ioctl.h"
#include "ioctl.h"
#include "ulist.h"
#include "ulist.h"
#include "extent_io.h"


#define BTRFS_BACKREF_SEARCH_COMMIT_ROOT ((struct btrfs_trans_handle *)0)
#define BTRFS_BACKREF_SEARCH_COMMIT_ROOT ((struct btrfs_trans_handle *)0)


@@ -58,8 +59,10 @@ int paths_from_inode(u64 inum, struct inode_fs_paths *ipath);


int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
				struct btrfs_fs_info *fs_info, u64 bytenr,
				struct btrfs_fs_info *fs_info, u64 bytenr,
				u64 delayed_ref_seq, u64 time_seq,
				u64 time_seq, struct ulist **roots);
				struct ulist **roots);
char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
			 struct btrfs_inode_ref *iref, struct extent_buffer *eb,
			 u64 parent, char *dest, u32 size);


struct btrfs_data_container *init_data_container(u32 total_bytes);
struct btrfs_data_container *init_data_container(u32 total_bytes);
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
+7 −7
Original line number Original line Diff line number Diff line
@@ -87,9 +87,6 @@ struct btrfs_inode {
	/* node for the red-black tree that links inodes in subvolume root */
	/* node for the red-black tree that links inodes in subvolume root */
	struct rb_node rb_node;
	struct rb_node rb_node;


	/* the space_info for where this inode's data allocations are done */
	struct btrfs_space_info *space_info;

	unsigned long runtime_flags;
	unsigned long runtime_flags;


	/* full 64 bit generation number, struct vfs_inode doesn't have a big
	/* full 64 bit generation number, struct vfs_inode doesn't have a big
@@ -191,11 +188,14 @@ static inline void btrfs_i_size_write(struct inode *inode, u64 size)
	BTRFS_I(inode)->disk_i_size = size;
	BTRFS_I(inode)->disk_i_size = size;
}
}


static inline bool btrfs_is_free_space_inode(struct btrfs_root *root,
static inline bool btrfs_is_free_space_inode(struct inode *inode)
				       struct inode *inode)
{
{
	if (root == root->fs_info->tree_root ||
	struct btrfs_root *root = BTRFS_I(inode)->root;
	    BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)

	if (root == root->fs_info->tree_root &&
	    btrfs_ino(inode) != BTRFS_BTREE_INODE_OBJECTID)
		return true;
	if (BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)
		return true;
		return true;
	return false;
	return false;
}
}
Loading