Btrfs: Allow subvolumes and snapshots anywhere in the directory tree

Before, all snapshots and subvolumes lived in a single flat directory.  This
was awkward and confusing because the single flat directory was only writable
with the ioctls.

This commit changes the ioctls to create subvols and snapshots at any
point in the directory tree.  This requires making separate ioctls for
snapshot and subvol creation instead of a combining them into one.

The subvol ioctl does:

btrfsctl -S subvol_name parent_dir

After the ioctl is done subvol_name lives inside parent_dir.

The snapshot ioctl does:

btrfsctl -s path_for_snapshot root_to_snapshot

path_for_snapshot can be an absolute or relative path.  btrfsctl breaks it up
into directory and basename components.

root_to_snapshot can be any file or directory in the FS.  The snapshot
is taken of the entire root where that file lives.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 202c1b6..eec8b24 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -779,7 +779,6 @@
 	struct extent_buffer *tmp;
 	struct extent_buffer *old;
 	int ret;
-	int namelen;
 	u64 objectid;
 
 	new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
@@ -816,28 +815,48 @@
 	if (ret)
 		goto fail;
 
+	key.offset = (u64)-1;
+	memcpy(&pending->root_key, &key, sizeof(key));
+fail:
+	kfree(new_root_item);
+	return ret;
+}
+
+static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info,
+				   struct btrfs_pending_snapshot *pending)
+{
+	int ret;
+	int namelen;
+	u64 index = 0;
+	struct btrfs_trans_handle *trans;
+	struct inode *parent_inode;
+	struct inode *inode;
+
+	trans = btrfs_start_transaction(fs_info->fs_root, 1);
+
 	/*
 	 * insert the directory item
 	 */
-	key.offset = (u64)-1;
 	namelen = strlen(pending->name);
-	ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
-				    pending->name, namelen,
-				    root->fs_info->sb->s_root->d_inode->i_ino,
-				    &key, BTRFS_FT_DIR, 0);
+	parent_inode = pending->dentry->d_parent->d_inode;
+	ret = btrfs_set_inode_index(parent_inode, &index);
+	ret = btrfs_insert_dir_item(trans,
+			    BTRFS_I(parent_inode)->root,
+			    pending->name, namelen,
+			    parent_inode->i_ino,
+			    &pending->root_key, BTRFS_FT_DIR, index);
 
 	if (ret)
 		goto fail;
-
+#if 0
 	ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root,
 			     pending->name, strlen(pending->name), objectid,
 			     root->fs_info->sb->s_root->d_inode->i_ino, 0);
-
-	/* Invalidate existing dcache entry for new snapshot. */
-	btrfs_invalidate_dcache_root(root, pending->name, namelen);
-
+#endif
+	inode = btrfs_lookup_dentry(parent_inode, pending->dentry);
+	d_instantiate(pending->dentry, inode);
 fail:
-	kfree(new_root_item);
+	btrfs_end_transaction(trans, fs_info->fs_root);
 	return ret;
 }
 
@@ -849,12 +868,28 @@
 {
 	struct btrfs_pending_snapshot *pending;
 	struct list_head *head = &trans->transaction->pending_snapshots;
+	struct list_head *cur;
+	int ret;
+
+	list_for_each(cur, head) {
+		pending = list_entry(cur, struct btrfs_pending_snapshot, list);
+		ret = create_pending_snapshot(trans, fs_info, pending);
+		BUG_ON(ret);
+	}
+	return 0;
+}
+
+static noinline int finish_pending_snapshots(struct btrfs_trans_handle *trans,
+					     struct btrfs_fs_info *fs_info)
+{
+	struct btrfs_pending_snapshot *pending;
+	struct list_head *head = &trans->transaction->pending_snapshots;
 	int ret;
 
 	while(!list_empty(head)) {
 		pending = list_entry(head->next,
 				     struct btrfs_pending_snapshot, list);
-		ret = create_pending_snapshot(trans, fs_info, pending);
+		ret = finish_pending_snapshot(fs_info, pending);
 		BUG_ON(ret);
 		list_del(&pending->list);
 		kfree(pending->name);
@@ -1033,11 +1068,15 @@
 	btrfs_drop_dead_reloc_roots(root);
 	mutex_unlock(&root->fs_info->tree_reloc_mutex);
 
+	/* do the directory inserts of any pending snapshot creations */
+	finish_pending_snapshots(trans, root->fs_info);
+
 	mutex_lock(&root->fs_info->trans_mutex);
 
 	cur_trans->commit_done = 1;
 	root->fs_info->last_trans_committed = cur_trans->transid;
 	wake_up(&cur_trans->commit_wait);
+
 	put_transaction(cur_trans);
 	put_transaction(cur_trans);
 
@@ -1046,6 +1085,7 @@
 		list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots);
 
 	mutex_unlock(&root->fs_info->trans_mutex);
+
 	kmem_cache_free(btrfs_trans_handle_cachep, trans);
 
 	if (root->fs_info->closing) {