static int do_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; size_t name_len = strlen(name); int ret = 0; if (name_len + size > BTRFS_MAX_XATTR_SIZE(root)) return -ENOSPC; path = btrfs_alloc_path(); if (!path) return -ENOMEM; /* first lets see if we already have this xattr */ di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name, strlen(name), -1); if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; } /* ok we already have this xattr, lets remove it */ if (di) { /* if we want create only exit */ if (flags & XATTR_CREATE) { ret = -EEXIST; goto out; } ret = btrfs_delete_one_dir_name(trans, root, path, di); BUG_ON(ret); btrfs_release_path(root, path); /* if we don't have a value then we are removing the xattr */ if (!value) goto out; } else { btrfs_release_path(root, path); if (flags & XATTR_REPLACE) { /* we couldn't find the attr to replace */ ret = -ENODATA; goto out; } } /* ok we have to create a completely new xattr */ ret = btrfs_insert_xattr_item(trans, root, path, inode->i_ino, name, name_len, value, size); BUG_ON(ret); out: btrfs_free_path(path); return ret; }
static int map_one_extent(struct btrfs_fs_info *fs_info, u64 *logical_ret, u64 *len_ret, int search_forward) { struct btrfs_path *path; struct btrfs_key key; u64 logical; u64 len = 0; int ret = 0; BUG_ON(!logical_ret); logical = *logical_ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = logical; key.type = 0; key.offset = 0; ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); if (ret < 0) goto out; BUG_ON(ret == 0); ret = 0; again: btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); if ((search_forward && key.objectid < logical) || (!search_forward && key.objectid > logical) || (key.type != BTRFS_EXTENT_ITEM_KEY && key.type != BTRFS_METADATA_ITEM_KEY)) { if (!search_forward) ret = btrfs_previous_extent_item(fs_info->extent_root, path, 0); else ret = btrfs_next_extent_item(fs_info->extent_root, path, 0); if (ret) goto out; goto again; } logical = key.objectid; if (key.type == BTRFS_METADATA_ITEM_KEY) len = fs_info->nodesize; else len = key.offset; out: btrfs_free_path(path); if (!ret) { *logical_ret = logical; if (len_ret) *len_ret = len; } return ret; }
int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, const char *name, int name_len) { int ret; struct btrfs_key key; struct btrfs_dir_item *di; int data_size; struct extent_buffer *leaf; int slot; struct btrfs_path *path; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = dir; key.type = BTRFS_DIR_ITEM_KEY; key.offset = btrfs_name_hash(name, name_len); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); /* return back any errors */ if (ret < 0) goto out; /* nothing found, we're safe */ if (ret > 0) { ret = 0; goto out; } /* we found an item, look for our name in the item */ di = btrfs_match_dir_item_name(root, path, name, name_len); if (di) { /* our exact name was found */ ret = -EEXIST; goto out; } /* * see if there is room in the item to insert this * name */ data_size = sizeof(*di) + name_len; leaf = path->nodes[0]; slot = path->slots[0]; if (data_size + btrfs_item_size_nr(leaf, slot) + sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) { ret = -EOVERFLOW; } else { /* plenty of insertion room */ ret = 0; } out: btrfs_free_path(path); return ret; }
ssize_t __btrfs_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; struct extent_buffer *leaf; int ret = 0; unsigned long data_ptr; path = btrfs_alloc_path(); if (!path) return -ENOMEM; /* lookup the xattr by name */ di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name, strlen(name), 0); if (!di) { ret = -ENODATA; goto out; } else if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; } leaf = path->nodes[0]; /* if size is 0, that means we want the size of the attr */ if (!size) { ret = btrfs_dir_data_len(leaf, di); goto out; } /* now get the data out of our dir_item */ if (btrfs_dir_data_len(leaf, di) > size) { ret = -ERANGE; goto out; } /* * The way things are packed into the leaf is like this * |struct btrfs_dir_item|name|data| * where name is the xattr name, so security.foo, and data is the * content of the xattr. data_ptr points to the location in memory * where the data starts in the in memory leaf */ data_ptr = (unsigned long)((char *)(di + 1) + btrfs_dir_name_len(leaf, di)); read_extent_buffer(leaf, buffer, data_ptr, btrfs_dir_data_len(leaf, di)); ret = btrfs_dir_data_len(leaf, di); out: btrfs_free_path(path); return ret; }
ssize_t __btrfs_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; struct extent_buffer *leaf; int ret = 0; unsigned long data_ptr; path = btrfs_alloc_path(); if (!path) return -ENOMEM; /* */ di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name, strlen(name), 0); if (!di) { ret = -ENODATA; goto out; } else if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; } leaf = path->nodes[0]; /* */ if (!size) { ret = btrfs_dir_data_len(leaf, di); goto out; } /* */ if (btrfs_dir_data_len(leaf, di) > size) { ret = -ERANGE; goto out; } /* */ data_ptr = (unsigned long)((char *)(di + 1) + btrfs_dir_name_len(leaf, di)); read_extent_buffer(leaf, buffer, data_ptr, btrfs_dir_data_len(leaf, di)); ret = btrfs_dir_data_len(leaf, di); out: btrfs_free_path(path); return ret; }
static int remove_extent_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid) { struct btrfs_trans_handle trans; struct btrfs_extent_item *item; struct btrfs_path *path; struct btrfs_key key; u64 refs; int ret; btrfs_init_dummy_trans(&trans); key.objectid = bytenr; key.type = BTRFS_EXTENT_ITEM_KEY; key.offset = num_bytes; path = btrfs_alloc_path(); if (!path) { test_msg("Couldn't allocate path\n"); return -ENOMEM; } path->leave_spinning = 1; ret = btrfs_search_slot(&trans, root, &key, path, 0, 1); if (ret) { test_msg("Couldn't find extent ref\n"); btrfs_free_path(path); return ret; } item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_extent_item); refs = btrfs_extent_refs(path->nodes[0], item); btrfs_set_extent_refs(path->nodes[0], item, refs - 1); btrfs_release_path(path); key.objectid = bytenr; if (parent) { key.type = BTRFS_SHARED_BLOCK_REF_KEY; key.offset = parent; } else { key.type = BTRFS_TREE_BLOCK_REF_KEY; key.offset = root_objectid; } ret = btrfs_search_slot(&trans, root, &key, path, -1, 1); if (ret) { test_msg("Couldn't find backref %d\n", ret); btrfs_free_path(path); return ret; } btrfs_del_item(&trans, root, path); btrfs_free_path(path); return ret; }
static int copy_metadata(struct btrfs_root *root, int fd, struct btrfs_key *key) { struct btrfs_path *path; struct btrfs_inode_item *inode_item; int ret; path = btrfs_alloc_path(); if (!path) { fprintf(stderr, "ERROR: Ran out of memory\n"); return -ENOMEM; } ret = btrfs_lookup_inode(NULL, root, path, key, 0); if (ret == 0) { struct btrfs_timespec *bts; struct timespec times[2]; inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); ret = fchown(fd, btrfs_inode_uid(path->nodes[0], inode_item), btrfs_inode_gid(path->nodes[0], inode_item)); if (ret) { fprintf(stderr, "ERROR: Failed to change owner: %s\n", strerror(errno)); goto out; } ret = fchmod(fd, btrfs_inode_mode(path->nodes[0], inode_item)); if (ret) { fprintf(stderr, "ERROR: Failed to change mode: %s\n", strerror(errno)); goto out; } bts = btrfs_inode_atime(inode_item); times[0].tv_sec = btrfs_timespec_sec(path->nodes[0], bts); times[0].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts); bts = btrfs_inode_mtime(inode_item); times[1].tv_sec = btrfs_timespec_sec(path->nodes[0], bts); times[1].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts); ret = futimens(fd, times); if (ret) { fprintf(stderr, "ERROR: Failed to set times: %s\n", strerror(errno)); goto out; } } out: btrfs_free_path(path); return ret; }
static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key, const char *file) { struct extent_buffer *leaf; struct btrfs_path *path; struct btrfs_file_extent_item *fi; struct btrfs_inode_item *inode_item; struct btrfs_timespec *bts; struct btrfs_key found_key; int ret; int extent_type; int compression; int loops = 0; u64 found_size = 0; struct timespec times[2]; int times_ok = 0; path = btrfs_alloc_path(); if (!path) { fprintf(stderr, "Ran out of memory\n"); return -ENOMEM; } ret = btrfs_lookup_inode(NULL, root, path, key, 0); if (ret == 0) { inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); found_size = btrfs_inode_size(path->nodes[0], inode_item); if (restore_metadata) { /* * Change the ownership and mode now, set times when * copyout is finished. */ ret = fchown(fd, btrfs_inode_uid(path->nodes[0], inode_item), btrfs_inode_gid(path->nodes[0], inode_item)); if (ret && !ignore_errors) goto out; ret = fchmod(fd, btrfs_inode_mode(path->nodes[0], inode_item)); if (ret && !ignore_errors) goto out; bts = btrfs_inode_atime(inode_item); times[0].tv_sec = btrfs_timespec_sec(path->nodes[0], bts); times[0].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts); bts = btrfs_inode_mtime(inode_item); times[1].tv_sec = btrfs_timespec_sec(path->nodes[0], bts); times[1].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts); times_ok = 1; } }
int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, u64 inode_objectid, u64 ref_objectid) { struct btrfs_path *path; struct btrfs_key key; struct btrfs_inode_ref *ref; struct extent_buffer *leaf; unsigned long ptr; unsigned long item_start; u32 item_size; u32 sub_item_len; int ret; int del_len = name_len + sizeof(*ref); key.objectid = inode_objectid; key.offset = ref_objectid; btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) { ret = -ENOENT; goto out; } else if (ret < 0) { goto out; } if (!find_name_in_backref(path, name, name_len, &ref)) { ret = -ENOENT; goto out; } leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); if (del_len == item_size) { ret = btrfs_del_item(trans, root, path); goto out; } ptr = (unsigned long)ref; sub_item_len = name_len + sizeof(*ref); item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, item_size - (ptr + sub_item_len - item_start)); ret = btrfs_truncate_item(trans, root, path, item_size - sub_item_len, 1); BUG_ON(ret); out: btrfs_free_path(path); return ret; }
/* * xattrs work a lot like directories, this inserts an xattr item * into the tree */ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, u16 name_len, const void *data, u16 data_len, u64 dir) { int ret = 0; struct btrfs_path *path; struct btrfs_dir_item *dir_item; unsigned long name_ptr, data_ptr; struct btrfs_key key, location; struct btrfs_disk_key disk_key; struct extent_buffer *leaf; u32 data_size; key.objectid = dir; btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); key.offset = btrfs_name_hash(name, name_len); path = btrfs_alloc_path(); if (!path) return -ENOMEM; if (name_len + data_len + sizeof(struct btrfs_dir_item) > BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item)) return -ENOSPC; data_size = sizeof(*dir_item) + name_len + data_len; dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); /* * FIXME: at some point we should handle xattr's that are larger than * what we can fit in our leaf. We set location to NULL b/c we arent * pointing at anything else, that will change if we store the xattr * data in a separate inode. */ BUG_ON(IS_ERR(dir_item)); memset(&location, 0, sizeof(location)); leaf = path->nodes[0]; btrfs_cpu_key_to_disk(&disk_key, &location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); btrfs_set_dir_name_len(leaf, dir_item, name_len); btrfs_set_dir_transid(leaf, dir_item, trans->transid); btrfs_set_dir_data_len(leaf, dir_item, data_len); name_ptr = (unsigned long)(dir_item + 1); data_ptr = (unsigned long)((char *)name_ptr + name_len); write_extent_buffer(leaf, name, name_ptr, name_len); write_extent_buffer(leaf, data, data_ptr, data_len); btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_free_path(path); return ret; }
static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid) { struct btrfs_trans_handle trans; struct btrfs_extent_item *item; struct btrfs_extent_inline_ref *iref; struct btrfs_tree_block_info *block_info; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_key ins; u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info); int ret; btrfs_init_dummy_trans(&trans); ins.objectid = bytenr; ins.type = BTRFS_EXTENT_ITEM_KEY; ins.offset = num_bytes; path = btrfs_alloc_path(); if (!path) { test_msg("Couldn't allocate path\n"); return -ENOMEM; } path->leave_spinning = 1; ret = btrfs_insert_empty_item(&trans, root, path, &ins, size); if (ret) { test_msg("Couldn't insert ref %d\n", ret); btrfs_free_path(path); return ret; } leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); btrfs_set_extent_refs(leaf, item, 1); btrfs_set_extent_generation(leaf, item, 1); btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK); block_info = (struct btrfs_tree_block_info *)(item + 1); btrfs_set_tree_block_level(leaf, block_info, 1); iref = (struct btrfs_extent_inline_ref *)(block_info + 1); if (parent > 0) { btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_SHARED_BLOCK_REF_KEY); btrfs_set_extent_inline_ref_offset(leaf, iref, parent); } else { btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY); btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid); } btrfs_free_path(path); return 0; }
int btrfs_find_orphan_roots(struct btrfs_root *tree_root) { struct extent_buffer *leaf; struct btrfs_path *path; struct btrfs_key key; int err = 0; int ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = BTRFS_ORPHAN_OBJECTID; key.type = BTRFS_ORPHAN_ITEM_KEY; key.offset = 0; while (1) { ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0); if (ret < 0) { err = ret; break; } leaf = path->nodes[0]; if (path->slots[0] >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(tree_root, path); if (ret < 0) err = ret; if (ret != 0) break; leaf = path->nodes[0]; } btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); btrfs_release_path(tree_root, path); if (key.objectid != BTRFS_ORPHAN_OBJECTID || key.type != BTRFS_ORPHAN_ITEM_KEY) break; ret = btrfs_find_dead_roots(tree_root, key.offset); if (ret) { err = ret; break; } key.offset++; } btrfs_free_path(path); return err; }
/* * Find a free inode index for later btrfs_add_link(). * Currently just search from the largest dir_index and +1. */ static int btrfs_find_free_dir_index(struct btrfs_root *root, u64 dir_ino, u64 *ret_ino) { struct btrfs_path *path; struct btrfs_key key; struct btrfs_key found_key; u64 ret_val = 2; int ret = 0; if (!ret_ino) return 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = dir_ino; key.type = BTRFS_DIR_INDEX_KEY; key.offset = (u64)-1; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; ret = 0; if (path->slots[0] == 0) { ret = btrfs_prev_leaf(root, path); if (ret < 0) goto out; if (ret > 0) { /* * This shouldn't happen since there must be a leaf * containing the DIR_ITEM. * Can only happen when the previous leaf is corrupted. */ ret = -EIO; goto out; } } else { path->slots[0]--; } btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); if (found_key.objectid != dir_ino || found_key.type != BTRFS_DIR_INDEX_KEY) goto out; ret_val = found_key.offset + 1; out: btrfs_free_path(path); if (ret == 0) *ret_ino = ret_val; return ret; }
static struct dentry *btrfs_get_parent(struct dentry *child) { struct inode *dir = d_inode(child); struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_root_ref *ref; struct btrfs_key key; struct btrfs_key found_key; int ret; path = btrfs_alloc_path(); if (!path) return ERR_PTR(-ENOMEM); if (btrfs_ino(BTRFS_I(dir)) == BTRFS_FIRST_FREE_OBJECTID) { key.objectid = root->root_key.objectid; key.type = BTRFS_ROOT_BACKREF_KEY; key.offset = (u64)-1; root = fs_info->tree_root; } else { key.objectid = btrfs_ino(BTRFS_I(dir)); key.type = BTRFS_INODE_REF_KEY; key.offset = (u64)-1; } ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto fail; BUG_ON(ret == 0); /* Key with offset of -1 found */ if (path->slots[0] == 0) { ret = -ENOENT; goto fail; } path->slots[0]--; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); if (found_key.objectid != key.objectid || found_key.type != key.type) { ret = -ENOENT; goto fail; } if (found_key.type == BTRFS_ROOT_BACKREF_KEY) { ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); key.objectid = btrfs_root_ref_dirid(leaf, ref); } else {
int load_free_space_tree(struct btrfs_caching_control *caching_ctl) { struct btrfs_block_group_cache *block_group; struct btrfs_fs_info *fs_info; struct btrfs_free_space_info *info; struct btrfs_path *path; u32 extent_count, flags; int ret; block_group = caching_ctl->block_group; fs_info = block_group->fs_info; path = btrfs_alloc_path(); if (!path) return -ENOMEM; /* * Just like caching_thread() doesn't want to deadlock on the extent * tree, we don't want to deadlock on the free space tree. */ path->skip_locking = 1; path->search_commit_root = 1; path->reada = 1; info = search_free_space_info(NULL, fs_info, block_group, path, 0); if (IS_ERR(info)) { ret = PTR_ERR(info); goto out; } extent_count = btrfs_free_space_extent_count(path->nodes[0], info); flags = btrfs_free_space_flags(path->nodes[0], info); /* * We left path pointing to the free space info item, so now * load_free_space_foo can just iterate through the free space tree from * there. */ if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) ret = load_free_space_bitmaps(caching_ctl, path, extent_count); else ret = load_free_space_extents(caching_ctl, path, extent_count); out: btrfs_free_path(path); return ret; }
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 offset, char *buffer, size_t size) { struct btrfs_key key; struct btrfs_path *path; struct extent_buffer *leaf; unsigned long ptr; struct btrfs_file_extent_item *ei; u32 datasize; int err = 0; int ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = objectid; key.offset = offset; btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); datasize = btrfs_file_extent_calc_inline_size(size); ret = btrfs_insert_empty_item(trans, root, path, &key, datasize); if (ret) { err = ret; goto fail; } leaf = path->nodes[0]; ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); btrfs_set_file_extent_generation(leaf, ei, trans->transid); btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); btrfs_set_file_extent_ram_bytes(leaf, ei, size); btrfs_set_file_extent_compression(leaf, ei, 0); btrfs_set_file_extent_encryption(leaf, ei, 0); btrfs_set_file_extent_other_encoding(leaf, ei, 0); ptr = btrfs_file_extent_inline_start(ei) + offset - key.offset; write_extent_buffer(leaf, buffer, ptr, size); btrfs_mark_buffer_dirty(leaf); fail: btrfs_free_path(path); return err; }
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 pos, u64 disk_offset, u64 disk_num_bytes, u64 num_bytes, u64 offset, u64 ram_bytes, u8 compression, u8 encryption, u16 other_encoding) { int ret = 0; struct btrfs_file_extent_item *item; struct btrfs_key file_key; struct btrfs_path *path; struct extent_buffer *leaf; path = btrfs_alloc_path(); if (!path) return -ENOMEM; file_key.objectid = objectid; file_key.offset = pos; btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); path->leave_spinning = 1; ret = btrfs_insert_empty_item(trans, root, path, &file_key, sizeof(*item)); if (ret < 0) goto out; BUG_ON(ret); /* Can't happen */ leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); btrfs_set_file_extent_offset(leaf, item, offset); btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes); btrfs_set_file_extent_generation(leaf, item, trans->transid); btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); btrfs_set_file_extent_compression(leaf, item, compression); btrfs_set_file_extent_encryption(leaf, item, encryption); btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); btrfs_mark_buffer_dirty(leaf); out: btrfs_free_path(path); return ret; }
static int ondisk_del(struct btrfs_trans_handle *trans, struct btrfs_dedup_info *dedup_info, u64 bytenr) { struct btrfs_root *dedup_root = dedup_info->dedup_root; struct btrfs_path *path; struct btrfs_key key; int ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = bytenr; key.type = BTRFS_DEDUP_BYTENR_ITEM_KEY; key.offset = 0; mutex_lock(&dedup_info->lock); ret = ondisk_search_bytenr(trans, dedup_info, path, bytenr, 1); if (ret <= 0) goto out; btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); btrfs_del_item(trans, dedup_root, path); btrfs_release_path(path); /* Search for hash item and delete it */ key.objectid = key.offset; key.type = BTRFS_DEDUP_HASH_ITEM_KEY; key.offset = bytenr; ret = btrfs_search_slot(trans, dedup_root, &key, path, -1, 1); if (WARN_ON(ret > 0)) { ret = -ENOENT; goto out; } if (ret < 0) goto out; btrfs_del_item(trans, dedup_root, path); out: btrfs_free_path(path); mutex_unlock(&dedup_info->lock); return ret; }
int btrfs_dedup_resume(struct btrfs_fs_info *fs_info, struct btrfs_root *dedup_root) { struct btrfs_dedup_status_item *status; struct btrfs_key key; struct btrfs_path *path; u64 blocksize; u64 limit; u16 type; u16 backend; int ret = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = 0; key.type = BTRFS_DEDUP_STATUS_ITEM_KEY; key.offset = 0; ret = btrfs_search_slot(NULL, dedup_root, &key, path, 0, 0); if (ret > 0) { ret = -ENOENT; goto out; } else if (ret < 0) { goto out; } status = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_dedup_status_item); blocksize = btrfs_dedup_status_blocksize(path->nodes[0], status); limit = btrfs_dedup_status_limit(path->nodes[0], status); type = btrfs_dedup_status_hash_type(path->nodes[0], status); backend = btrfs_dedup_status_backend(path->nodes[0], status); ret = init_dedup_info(fs_info, type, backend, blocksize, limit); if (ret < 0) goto out; fs_info->dedup_info->dedup_root = dedup_root; out: btrfs_free_path(path); return ret; }
/* * lookup the root with the highest offset for a given objectid. The key we do * find is copied into 'key'. If we find something return 0, otherwise 1, < 0 * on error. */ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct btrfs_root_item *item, struct btrfs_key *key) { struct btrfs_path *path; struct btrfs_key search_key; struct btrfs_key found_key; struct extent_buffer *l; int ret; int slot; search_key.objectid = objectid; search_key.type = BTRFS_ROOT_ITEM_KEY; search_key.offset = (u64)-1; path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); if (ret < 0) goto out; BUG_ON(ret == 0); if (path->slots[0] == 0) { ret = 1; goto out; } l = path->nodes[0]; slot = path->slots[0] - 1; btrfs_item_key_to_cpu(l, &found_key, slot); if (found_key.objectid != objectid || found_key.type != BTRFS_ROOT_ITEM_KEY) { ret = 1; goto out; } if (item) read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot), sizeof(*item)); if (key) memcpy(key, &found_key, sizeof(found_key)); ret = 0; out: btrfs_free_path(path); return ret; }
int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset) { struct btrfs_path *path; struct btrfs_key key; int ret; key.objectid = BTRFS_ORPHAN_OBJECTID; key.type = BTRFS_ORPHAN_ITEM_KEY; key.offset = offset; path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); btrfs_free_path(path); return ret; }
int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 offset) { struct btrfs_path *path; struct btrfs_key key; int ret = 0; key.objectid = BTRFS_ORPHAN_OBJECTID; btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY); key.offset = offset; path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = btrfs_insert_empty_item(trans, root, path, &key, 0); btrfs_free_path(path); return ret; }
int btrfs_del_root_ref(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root, u64 root_id, u64 ref_id, u64 dirid, u64 *sequence, const char *name, int name_len) { struct btrfs_path *path; struct btrfs_root_ref *ref; struct extent_buffer *leaf; struct btrfs_key key; unsigned long ptr; int err = 0; int ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = root_id; key.type = BTRFS_ROOT_BACKREF_KEY; key.offset = ref_id; again: ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); BUG_ON(ret < 0); if (ret == 0) { leaf = path->nodes[0]; ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid); WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len); ptr = (unsigned long)(ref + 1); WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len)); *sequence = btrfs_root_ref_sequence(leaf, ref); ret = btrfs_del_item(trans, tree_root, path); if (ret) { err = ret; goto out; } } else
/* * search forward for a root, starting with objectid 'search_start' * if a root key is found, the objectid we find is filled into 'found_objectid' * and 0 is returned. < 0 is returned on error, 1 if there is nothing * left in the tree. */ int btrfs_search_root(struct btrfs_root *root, u64 search_start, u64 *found_objectid) { struct btrfs_path *path; struct btrfs_key search_key; int ret; root = root->fs_info->tree_root; search_key.objectid = search_start; search_key.type = (u8)-1; search_key.offset = (u64)-1; path = btrfs_alloc_path(); BUG_ON(!path); again: ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); if (ret < 0) goto out; if (ret == 0) { ret = 1; goto out; } if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { ret = btrfs_next_leaf(root, path); if (ret) goto out; } btrfs_item_key_to_cpu(path->nodes[0], &search_key, path->slots[0]); if (search_key.type != BTRFS_ROOT_ITEM_KEY) { search_key.offset++; btrfs_release_path(root, path); goto again; } ret = 0; *found_objectid = search_key.objectid; out: btrfs_free_path(path); return ret; }
static int clear_free_space_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root) { struct btrfs_path *path; struct btrfs_key key; int nr; int ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; path->leave_spinning = 1; key.objectid = 0; key.type = 0; key.offset = 0; while (1) { ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret < 0) goto out; nr = btrfs_header_nritems(path->nodes[0]); if (!nr) break; path->slots[0] = 0; ret = btrfs_del_items(trans, root, path, 0, nr); if (ret) goto out; btrfs_release_path(path); } ret = 0; out: btrfs_free_path(path); return ret; }
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, u64 inode_objectid, u64 ref_objectid, u64 index) { struct btrfs_path *path; struct btrfs_key key; struct btrfs_inode_ref *ref; unsigned long ptr; int ret; int ins_len = name_len + sizeof(*ref); key.objectid = inode_objectid; key.offset = ref_objectid; btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = btrfs_insert_empty_item(trans, root, path, &key, ins_len); if (ret == -EEXIST) { u32 old_size; if (find_name_in_backref(path, name, name_len, &ref)) goto out; old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); ret = btrfs_extend_item(trans, root, path, ins_len); BUG_ON(ret); ref = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_ref); ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); btrfs_set_inode_ref_index(path->nodes[0], ref, index); ptr = (unsigned long)(ref + 1); ret = 0; } else if (ret < 0) {
/* drop the root item for 'key' from 'root' */ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key) { struct btrfs_path *path; int ret; u32 refs; struct btrfs_root_item *ri; struct extent_buffer *leaf; path = btrfs_alloc_path(); BUG_ON(!path); ret = btrfs_search_slot(trans, root, key, path, -1, 1); if (ret < 0) goto out; BUG_ON(ret != 0); leaf = path->nodes[0]; ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item); refs = btrfs_disk_root_refs(leaf, ri); BUG_ON(refs != 0); ret = btrfs_del_item(trans, root, path); out: btrfs_release_path(root, path); btrfs_free_path(path); return ret; } #if 0 /* this will get used when snapshot deletion is implemented */ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root, u64 root_id, u8 type, u64 ref_id) { struct btrfs_key key; int ret; struct btrfs_path *path; path = btrfs_alloc_path(); key.objectid = root_id; key.type = type; key.offset = ref_id; ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); BUG_ON(ret); ret = btrfs_del_item(trans, tree_root, path); BUG_ON(ret); btrfs_free_path(path); return ret; }
/* drop the root item for 'key' from 'root' */ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key) { struct btrfs_path *path; int ret; struct btrfs_root_item *ri; struct extent_buffer *leaf; path = btrfs_alloc_path(); BUG_ON(!path); ret = btrfs_search_slot(trans, root, key, path, -1, 1); if (ret < 0) goto out; BUG_ON(ret != 0); leaf = path->nodes[0]; ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item); ret = btrfs_del_item(trans, root, path); out: btrfs_free_path(path); return ret; }
/* * copy the data in 'item' into the btree */ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_root_item *item) { struct btrfs_path *path; struct extent_buffer *l; int ret; int slot; unsigned long ptr; path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = btrfs_search_slot(trans, root, key, path, 0, 1); if (ret < 0) { btrfs_abort_transaction(trans, root, ret); goto out; } if (ret != 0) { btrfs_print_leaf(root, path->nodes[0]); printk(KERN_CRIT "unable to update root key %llu %u %llu\n", (unsigned long long)key->objectid, key->type, (unsigned long long)key->offset); BUG_ON(1); } l = path->nodes[0]; slot = path->slots[0]; ptr = btrfs_item_ptr_offset(l, slot); write_extent_buffer(l, item, ptr, sizeof(*item)); btrfs_mark_buffer_dirty(path->nodes[0]); out: btrfs_free_path(path); return ret; }
/* * Punch hole ranged [offset,len) for the file given by ino and root. * * Unlink kernel punch_hole, which will not zero/free existing extent, * instead it will return -EEXIST if there is any extents in the hole * range. */ int btrfs_punch_hole(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 ino, u64 offset, u64 len) { struct btrfs_path *path; int ret = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = btrfs_get_extent(NULL, root, path, ino, offset, len, 0); if (ret < 0) goto out; if (ret == 0) { ret = -EEXIST; goto out; } ret = btrfs_insert_file_extent(trans, root, ino, offset, 0, 0, len); out: btrfs_free_path(path); return ret; }