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

Commit e06afa83 authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse
Browse files

Btrfs: rename

parent f9f3c6b6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
* Add generation number to key pointer in nodes
* Add generation number to inode
* Add ability to switch a block group from data to metadata or vice versa
* forbid cross subvolume renames and hardlinks
* Release
* Do real tree locking
* Add extent mirroring (backup copies of blocks)
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ extern struct kmem_cache *btrfs_path_cachep;
#define BTRFS_CSUM_SIZE 32
/* four bytes for CRC32 */
#define BTRFS_CRC32_SIZE 4
#define BTRFS_EMPTY_DIR_SIZE 6

/*
 * the key defines the order in the tree, and so it also defines (optimal)
+21 −6
Original line number Diff line number Diff line
@@ -9,7 +9,9 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
						   struct btrfs_root *root,
						   struct btrfs_path *path,
						   struct btrfs_key *cpu_key,
						   u32 data_size)
						   u32 data_size,
						   const char *name,
						   int name_len)
{
	int ret;
	char *ptr;
@@ -18,6 +20,10 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle

	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
	if (ret == -EEXIST) {
		struct btrfs_dir_item *di;
		di = btrfs_match_dir_item_name(root, path, name, name_len);
		if (di)
			return ERR_PTR(-EEXIST);
		ret = btrfs_extend_item(trans, root, path, data_size);
		WARN_ON(ret > 0);
		if (ret)
@@ -37,6 +43,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
			  struct btrfs_key *location, u8 type)
{
	int ret = 0;
	int ret2 = 0;
	struct btrfs_path *path;
	struct btrfs_dir_item *dir_item;
	char *name_ptr;
@@ -51,9 +58,12 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
	path = btrfs_alloc_path();
	btrfs_init_path(path);
	data_size = sizeof(*dir_item) + name_len;
	dir_item = insert_with_overflow(trans, root, path, &key, data_size);
	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
					name, name_len);
	if (IS_ERR(dir_item)) {
		ret = PTR_ERR(dir_item);
		if (ret == -EEXIST)
			goto second_insert;
		goto out;
	}

@@ -66,19 +76,20 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);

second_insert:
	/* FIXME, use some real flag for selecting the extra index */
	if (root == root->fs_info->tree_root) {
		ret = 0;
		goto out;
	}

	btrfs_release_path(root, path);

	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
	key.offset = location->objectid;
	dir_item = insert_with_overflow(trans, root, path, &key, data_size);
	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
					name, name_len);
	if (IS_ERR(dir_item)) {
		ret = PTR_ERR(dir_item);
		ret2 = PTR_ERR(dir_item);
		goto out;
	}
	btrfs_cpu_key_to_disk(&dir_item->location, location);
@@ -90,7 +101,11 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
	btrfs_mark_buffer_dirty(path->nodes[0]);
out:
	btrfs_free_path(path);
	if (ret)
		return ret;
	if (ret2)
		return ret2;
	return 0;
}

struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
+120 −12
Original line number Diff line number Diff line
@@ -375,6 +375,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
	struct btrfs_path *path;
	struct btrfs_key key;
	struct btrfs_disk_key *found_key;
	u32 found_type;
	struct btrfs_leaf *leaf;
	struct btrfs_file_extent_item *fi = NULL;
	u64 extent_start = 0;
@@ -386,12 +387,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
	/* FIXME, add redo link to tree so we don't leak on crash */
	key.objectid = inode->i_ino;
	key.offset = (u64)-1;
	key.flags = 0;
	/*
	 * use BTRFS_CSUM_ITEM_KEY because it is larger than inline keys
	 * or extent data
	 */
	btrfs_set_key_type(&key, BTRFS_CSUM_ITEM_KEY);
	key.flags = (u32)-1;
	while(1) {
		btrfs_init_path(path);
		ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
@@ -405,10 +401,13 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
		reada_truncate(root, path, inode->i_ino);
		leaf = btrfs_buffer_leaf(path->nodes[0]);
		found_key = &leaf->items[path->slots[0]].key;
		found_type = btrfs_disk_key_type(found_key);
		if (btrfs_disk_key_objectid(found_key) != inode->i_ino)
			break;
		if (btrfs_disk_key_type(found_key) != BTRFS_CSUM_ITEM_KEY &&
		    btrfs_disk_key_type(found_key) != BTRFS_EXTENT_DATA_KEY)
		if (found_type != BTRFS_CSUM_ITEM_KEY &&
		    found_type != BTRFS_DIR_ITEM_KEY &&
		    found_type != BTRFS_DIR_INDEX_KEY &&
		    found_type != BTRFS_EXTENT_DATA_KEY)
			break;
		if (btrfs_disk_key_offset(found_key) < inode->i_size)
			break;
@@ -460,10 +459,8 @@ static void btrfs_delete_inode(struct inode *inode)
	mutex_lock(&root->fs_info->fs_mutex);
	trans = btrfs_start_transaction(root, 1);
	btrfs_set_trans_block_group(trans, inode);
	if (S_ISREG(inode->i_mode)) {
	ret = btrfs_truncate_in_trans(trans, root, inode);
	BUG_ON(ret);
	}
	btrfs_free_inode(trans, root, inode);
	btrfs_end_transaction(trans, root);
	mutex_unlock(&root->fs_info->fs_mutex);
@@ -2504,6 +2501,116 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
	return 0;
}

static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry,
			   struct inode * new_dir,struct dentry *new_dentry)
{
	struct btrfs_trans_handle *trans;
	struct btrfs_root *root = BTRFS_I(old_dir)->root;
	struct inode *new_inode = new_dentry->d_inode;
	struct inode *old_inode = old_dentry->d_inode;
	struct timespec ctime = CURRENT_TIME;
	struct btrfs_path *path;
	struct btrfs_dir_item *di;
	int ret;

	if (S_ISDIR(old_inode->i_mode) && new_inode &&
	    new_inode->i_size > BTRFS_EMPTY_DIR_SIZE) {
		return -ENOTEMPTY;
	}
	mutex_lock(&root->fs_info->fs_mutex);
	trans = btrfs_start_transaction(root, 1);
	btrfs_set_trans_block_group(trans, new_dir);
	path = btrfs_alloc_path();
	if (!path) {
		ret = -ENOMEM;
		goto out_fail;
	}

	old_dentry->d_inode->i_nlink++;
	old_dir->i_ctime = old_dir->i_mtime = ctime;
	new_dir->i_ctime = new_dir->i_mtime = ctime;
	old_inode->i_ctime = ctime;
	if (S_ISDIR(old_inode->i_mode) && old_dir != new_dir) {
		struct btrfs_key *location = &BTRFS_I(new_dir)->location;
		u64 old_parent_oid;
		di = btrfs_lookup_dir_item(trans, root, path, old_inode->i_ino,
					   "..", 2, -1);
		if (IS_ERR(di)) {
			ret = PTR_ERR(di);
			goto out_fail;
		}
		if (!di) {
			ret = -ENOENT;
			goto out_fail;
		}
		old_parent_oid = btrfs_disk_key_objectid(&di->location);
		ret = btrfs_del_item(trans, root, path);
		if (ret) {
			ret = -EIO;
			goto out_fail;
		}
		btrfs_release_path(root, path);

		di = btrfs_lookup_dir_index_item(trans, root, path,
						 old_inode->i_ino,
						 old_parent_oid,
						 "..", 2, -1);
		if (IS_ERR(di)) {
			ret = PTR_ERR(di);
			goto out_fail;
		}
		if (!di) {
			ret = -ENOENT;
			goto out_fail;
		}
		ret = btrfs_del_item(trans, root, path);
		if (ret) {
			ret = -EIO;
			goto out_fail;
		}
		btrfs_release_path(root, path);

		ret = btrfs_insert_dir_item(trans, root, "..", 2,
					    old_inode->i_ino, location, 0);
		if (ret)
			goto out_fail;
	}


	ret = btrfs_add_link(trans, new_dentry, old_inode);
	if (ret == -EEXIST && new_inode)
		ret = 0;
	else if (ret)
		goto out_fail;

	ret = btrfs_unlink_trans(trans, root, old_dir, old_dentry);
	if (ret)
		goto out_fail;

	if (new_inode) {
		new_inode->i_ctime = CURRENT_TIME;
		di = btrfs_lookup_dir_index_item(trans, root, path,
						 new_dir->i_ino,
						 new_inode->i_ino,
						 new_dentry->d_name.name,
						 new_dentry->d_name.len, -1);
		if (di && !IS_ERR(di)) {
			btrfs_del_item(trans, root, path);
			btrfs_release_path(root, path);
		}
		if (S_ISDIR(new_inode->i_mode))
			clear_nlink(new_inode);
		else
			drop_nlink(new_inode);
		btrfs_update_inode(trans, root, new_inode);
	}
out_fail:
	btrfs_free_path(path);
	btrfs_end_transaction(trans, root);
	mutex_unlock(&root->fs_info->fs_mutex);
	return ret;
}

static struct file_system_type btrfs_fs_type = {
	.owner		= THIS_MODULE,
	.name		= "btrfs",
@@ -2531,6 +2638,7 @@ static struct inode_operations btrfs_dir_inode_operations = {
	.unlink		= btrfs_unlink,
	.mkdir		= btrfs_mkdir,
	.rmdir		= btrfs_rmdir,
	.rename		= btrfs_rename,
};

static struct inode_operations btrfs_dir_ro_inode_operations = {