static void print_inode_item(struct extent_buffer *eb, struct btrfs_inode_item *ii) { char flags_str[256]; memset(flags_str, 0, sizeof(flags_str)); inode_flags_to_str(btrfs_inode_flags(eb, ii), flags_str); printf("\t\tinode generation %llu transid %llu size %llu nbytes %llu\n" "\t\tblock group %llu mode %o links %u uid %u gid %u rdev %llu\n" "\t\tsequence %llu flags 0x%llx(%s)\n", (unsigned long long)btrfs_inode_generation(eb, ii), (unsigned long long)btrfs_inode_transid(eb, ii), (unsigned long long)btrfs_inode_size(eb, ii), (unsigned long long)btrfs_inode_nbytes(eb, ii), (unsigned long long)btrfs_inode_block_group(eb,ii), btrfs_inode_mode(eb, ii), btrfs_inode_nlink(eb, ii), btrfs_inode_uid(eb, ii), btrfs_inode_gid(eb, ii), (unsigned long long)btrfs_inode_rdev(eb,ii), (unsigned long long)btrfs_inode_flags(eb,ii), (unsigned long long)btrfs_inode_sequence(eb, ii), flags_str); print_timespec(eb, btrfs_inode_atime(ii), "\t\tatime ", "\n"); print_timespec(eb, btrfs_inode_ctime(ii), "\t\tctime ", "\n"); print_timespec(eb, btrfs_inode_mtime(ii), "\t\tmtime ", "\n"); print_timespec(eb, btrfs_inode_otime(ii), "\t\totime ", "\n"); }
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_key found_key; int ret; int extent_type; int compression; int loops = 0; u64 found_size = 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); }
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; } }
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) { int i; char *str; struct btrfs_item *item; struct btrfs_dir_item *di; struct btrfs_inode_item *ii; struct btrfs_file_extent_item *fi; struct btrfs_block_group_item *bi; struct btrfs_extent_data_ref *dref; struct btrfs_shared_data_ref *sref; struct btrfs_inode_ref *iref; struct btrfs_inode_extref *iref2; struct btrfs_dev_extent *dev_extent; struct btrfs_disk_key disk_key; struct btrfs_block_group_item bg_item; struct btrfs_dir_log_item *dlog; struct btrfs_qgroup_info_item *qg_info; struct btrfs_qgroup_limit_item *qg_limit; struct btrfs_qgroup_status_item *qg_status; u32 nr = btrfs_header_nritems(l); u64 objectid; u32 type; printf("leaf %llu items %d free space %d generation %llu owner %llu\n", (unsigned long long)btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l), (unsigned long long)btrfs_header_generation(l), (unsigned long long)btrfs_header_owner(l)); print_uuids(l); fflush(stdout); for (i = 0 ; i < nr ; i++) { item = btrfs_item_nr(l, i); btrfs_item_key(l, &disk_key, i); objectid = btrfs_disk_key_objectid(&disk_key); type = btrfs_disk_key_type(&disk_key); printf("\titem %d ", i); btrfs_print_key(&disk_key); printf(" itemoff %d itemsize %d\n", btrfs_item_offset(l, item), btrfs_item_size(l, item)); if (type == 0 && objectid == BTRFS_FREE_SPACE_OBJECTID) print_free_space_header(l, i); switch (type) { case BTRFS_INODE_ITEM_KEY: ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); printf("\t\tinode generation %llu transid %llu size %llu block group %llu mode %o links %u\n", (unsigned long long)btrfs_inode_generation(l, ii), (unsigned long long)btrfs_inode_transid(l, ii), (unsigned long long)btrfs_inode_size(l, ii), (unsigned long long)btrfs_inode_block_group(l,ii), btrfs_inode_mode(l, ii), btrfs_inode_nlink(l, ii)); break; case BTRFS_INODE_REF_KEY: iref = btrfs_item_ptr(l, i, struct btrfs_inode_ref); print_inode_ref_item(l, item, iref); break; case BTRFS_INODE_EXTREF_KEY: iref2 = btrfs_item_ptr(l, i, struct btrfs_inode_extref); print_inode_extref_item(l, item, iref2); break; case BTRFS_DIR_ITEM_KEY: case BTRFS_DIR_INDEX_KEY: case BTRFS_XATTR_ITEM_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); print_dir_item(l, item, di); break; case BTRFS_DIR_LOG_INDEX_KEY: case BTRFS_DIR_LOG_ITEM_KEY: dlog = btrfs_item_ptr(l, i, struct btrfs_dir_log_item); printf("\t\tdir log end %Lu\n", (unsigned long long)btrfs_dir_log_end(l, dlog)); break; case BTRFS_ORPHAN_ITEM_KEY: printf("\t\torphan item\n"); break; case BTRFS_ROOT_ITEM_KEY: print_root(l, i); break; case BTRFS_ROOT_REF_KEY: print_root_ref(l, i, "ref"); break; case BTRFS_ROOT_BACKREF_KEY: print_root_ref(l, i, "backref"); break; case BTRFS_EXTENT_ITEM_KEY: print_extent_item(l, i, 0); break; case BTRFS_METADATA_ITEM_KEY: print_extent_item(l, i, 1); break; case BTRFS_TREE_BLOCK_REF_KEY: printf("\t\ttree block backref\n"); break; case BTRFS_SHARED_BLOCK_REF_KEY: printf("\t\tshared block backref\n"); break; case BTRFS_EXTENT_DATA_REF_KEY: dref = btrfs_item_ptr(l, i, struct btrfs_extent_data_ref); printf("\t\textent data backref root %llu " "objectid %llu offset %llu count %u\n", (unsigned long long)btrfs_extent_data_ref_root(l, dref), (unsigned long long)btrfs_extent_data_ref_objectid(l, dref), (unsigned long long)btrfs_extent_data_ref_offset(l, dref), btrfs_extent_data_ref_count(l, dref)); break; case BTRFS_SHARED_DATA_REF_KEY: sref = btrfs_item_ptr(l, i, struct btrfs_shared_data_ref); printf("\t\tshared data backref count %u\n", btrfs_shared_data_ref_count(l, sref)); break; case BTRFS_EXTENT_REF_V0_KEY: #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 print_extent_ref_v0(l, i); #else BUG(); #endif break; case BTRFS_CSUM_ITEM_KEY: printf("\t\tcsum item\n"); break; case BTRFS_EXTENT_CSUM_KEY: printf("\t\textent csum item\n"); break; case BTRFS_EXTENT_DATA_KEY: fi = btrfs_item_ptr(l, i, struct btrfs_file_extent_item); print_file_extent_item(l, item, fi); break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, struct btrfs_block_group_item); read_extent_buffer(l, &bg_item, (unsigned long)bi, sizeof(bg_item)); printf("\t\tblock group used %llu chunk_objectid %llu flags %llu\n", (unsigned long long)btrfs_block_group_used(&bg_item), (unsigned long long)btrfs_block_group_chunk_objectid(&bg_item), (unsigned long long)btrfs_block_group_flags(&bg_item)); break; case BTRFS_CHUNK_ITEM_KEY: print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk)); break; case BTRFS_DEV_ITEM_KEY: print_dev_item(l, btrfs_item_ptr(l, i, struct btrfs_dev_item)); break; case BTRFS_DEV_EXTENT_KEY: dev_extent = btrfs_item_ptr(l, i, struct btrfs_dev_extent); printf("\t\tdev extent chunk_tree %llu\n" "\t\tchunk objectid %llu chunk offset %llu " "length %llu\n", (unsigned long long) btrfs_dev_extent_chunk_tree(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_objectid(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_offset(l, dev_extent), (unsigned long long) btrfs_dev_extent_length(l, dev_extent)); break; case BTRFS_QGROUP_STATUS_KEY: qg_status = btrfs_item_ptr(l, i, struct btrfs_qgroup_status_item); printf("\t\tversion %llu generation %llu flags %#llx " "scan %lld\n", (unsigned long long) btrfs_qgroup_status_version(l, qg_status), (unsigned long long) btrfs_qgroup_status_generation(l, qg_status), (unsigned long long) btrfs_qgroup_status_flags(l, qg_status), (unsigned long long) btrfs_qgroup_status_scan(l, qg_status)); break; case BTRFS_QGROUP_RELATION_KEY: break; case BTRFS_QGROUP_INFO_KEY: qg_info = btrfs_item_ptr(l, i, struct btrfs_qgroup_info_item); printf("\t\tgeneration %llu\n" "\t\treferenced %lld referenced compressed %lld\n" "\t\texclusive %lld exclusive compressed %lld\n", (unsigned long long) btrfs_qgroup_info_generation(l, qg_info), (long long) btrfs_qgroup_info_referenced(l, qg_info), (long long) btrfs_qgroup_info_referenced_compressed(l, qg_info), (long long) btrfs_qgroup_info_exclusive(l, qg_info), (long long) btrfs_qgroup_info_exclusive_compressed(l, qg_info)); break; case BTRFS_QGROUP_LIMIT_KEY: qg_limit = btrfs_item_ptr(l, i, struct btrfs_qgroup_limit_item); printf("\t\tflags %llx\n" "\t\tmax referenced %lld max exclusive %lld\n" "\t\trsv referenced %lld rsv exclusive %lld\n", (unsigned long long) btrfs_qgroup_limit_flags(l, qg_limit), (long long) btrfs_qgroup_limit_max_referenced(l, qg_limit), (long long) btrfs_qgroup_limit_max_exclusive(l, qg_limit), (long long) btrfs_qgroup_limit_rsv_referenced(l, qg_limit), (long long) btrfs_qgroup_limit_rsv_exclusive(l, qg_limit)); break; case BTRFS_STRING_ITEM_KEY: /* dirty, but it's simple */ str = l->data + btrfs_item_ptr_offset(l, i); printf("\t\titem data %.*s\n", btrfs_item_size(l, item), str); break; case BTRFS_DEV_STATS_KEY: printf("\t\tdevice stats\n"); break; }; fflush(stdout); } }
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) { int i; u32 type; u32 nr = btrfs_header_nritems(l); struct btrfs_item *item; struct btrfs_root_item *ri; struct btrfs_dir_item *di; struct btrfs_inode_item *ii; struct btrfs_block_group_item *bi; struct btrfs_file_extent_item *fi; struct btrfs_extent_data_ref *dref; struct btrfs_shared_data_ref *sref; struct btrfs_dev_extent *dev_extent; struct btrfs_key key; struct btrfs_key found_key; printk(KERN_INFO "leaf %llu total ptrs %d free space %d\n", (unsigned long long)btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l)); for (i = 0 ; i < nr ; i++) { item = btrfs_item_nr(l, i); btrfs_item_key_to_cpu(l, &key, i); type = btrfs_key_type(&key); printk(KERN_INFO "\titem %d key (%llu %x %llu) itemoff %d " "itemsize %d\n", i, (unsigned long long)key.objectid, type, (unsigned long long)key.offset, btrfs_item_offset(l, item), btrfs_item_size(l, item)); switch (type) { case BTRFS_INODE_ITEM_KEY: ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); printk(KERN_INFO "\t\tinode generation %llu size %llu " "mode %o\n", (unsigned long long) btrfs_inode_generation(l, ii), (unsigned long long)btrfs_inode_size(l, ii), btrfs_inode_mode(l, ii)); break; case BTRFS_DIR_ITEM_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); btrfs_dir_item_key_to_cpu(l, di, &found_key); printk(KERN_INFO "\t\tdir oid %llu type %u\n", (unsigned long long)found_key.objectid, btrfs_dir_type(l, di)); break; case BTRFS_ROOT_ITEM_KEY: ri = btrfs_item_ptr(l, i, struct btrfs_root_item); printk(KERN_INFO "\t\troot data bytenr %llu refs %u\n", (unsigned long long) btrfs_disk_root_bytenr(l, ri), btrfs_disk_root_refs(l, ri)); break; case BTRFS_EXTENT_ITEM_KEY: print_extent_item(l, i); break; case BTRFS_TREE_BLOCK_REF_KEY: printk(KERN_INFO "\t\ttree block backref\n"); break; case BTRFS_SHARED_BLOCK_REF_KEY: printk(KERN_INFO "\t\tshared block backref\n"); break; case BTRFS_EXTENT_DATA_REF_KEY: dref = btrfs_item_ptr(l, i, struct btrfs_extent_data_ref); print_extent_data_ref(l, dref); break; case BTRFS_SHARED_DATA_REF_KEY: sref = btrfs_item_ptr(l, i, struct btrfs_shared_data_ref); printk(KERN_INFO "\t\tshared data backref count %u\n", btrfs_shared_data_ref_count(l, sref)); break; case BTRFS_EXTENT_DATA_KEY: fi = btrfs_item_ptr(l, i, struct btrfs_file_extent_item); if (btrfs_file_extent_type(l, fi) == BTRFS_FILE_EXTENT_INLINE) { printk(KERN_INFO "\t\tinline extent data " "size %u\n", btrfs_file_extent_inline_len(l, fi)); break; } printk(KERN_INFO "\t\textent data disk bytenr %llu " "nr %llu\n", (unsigned long long) btrfs_file_extent_disk_bytenr(l, fi), (unsigned long long) btrfs_file_extent_disk_num_bytes(l, fi)); printk(KERN_INFO "\t\textent data offset %llu " "nr %llu ram %llu\n", (unsigned long long) btrfs_file_extent_offset(l, fi), (unsigned long long) btrfs_file_extent_num_bytes(l, fi), (unsigned long long) btrfs_file_extent_ram_bytes(l, fi)); break; case BTRFS_EXTENT_REF_V0_KEY: #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 print_extent_ref_v0(l, i); #else BUG(); #endif break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, struct btrfs_block_group_item); printk(KERN_INFO "\t\tblock group used %llu\n", (unsigned long long) btrfs_disk_block_group_used(l, bi)); break; case BTRFS_CHUNK_ITEM_KEY: print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk)); break; case BTRFS_DEV_ITEM_KEY: print_dev_item(l, btrfs_item_ptr(l, i, struct btrfs_dev_item)); break; case BTRFS_DEV_EXTENT_KEY: dev_extent = btrfs_item_ptr(l, i, struct btrfs_dev_extent); printk(KERN_INFO "\t\tdev extent chunk_tree %llu\n" "\t\tchunk objectid %llu chunk offset %llu " "length %llu\n", (unsigned long long) btrfs_dev_extent_chunk_tree(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_objectid(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_offset(l, dev_extent), (unsigned long long) btrfs_dev_extent_length(l, dev_extent)); }; } }
void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l) { unsigned int i; u32 nr = btrfs_header_nritems(&l->header); struct btrfs_item *item; struct btrfs_extent_item *ei; struct btrfs_root_item *ri; struct btrfs_dir_item *di; struct btrfs_inode_item *ii; struct btrfs_file_extent_item *fi; struct btrfs_csum_item *ci; struct btrfs_block_group_item *bi; u32 type; printf("leaf %llu ptrs %d free space %d generation %llu owner %llu\n", (u64)btrfs_header_blocknr(&l->header), nr, btrfs_leaf_free_space(root, l), (u64)btrfs_header_generation(&l->header), (u64)btrfs_header_owner(&l->header)); fflush(stdout); for (i = 0 ; i < nr ; i++) { item = l->items + i; type = btrfs_disk_key_type(&item->key); printf("\titem %d key (%llu %x %llu) itemoff %d itemsize %d\n", i, (u64)btrfs_disk_key_objectid(&item->key), btrfs_disk_key_flags(&item->key), (u64)btrfs_disk_key_offset(&item->key), btrfs_item_offset(item), btrfs_item_size(item)); switch (type) { case BTRFS_INODE_ITEM_KEY: ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); printf("\t\tinode generation %llu size %llu block group %llu mode %o\n", (u64)btrfs_inode_generation(ii), (u64)btrfs_inode_size(ii), (u64)btrfs_inode_block_group(ii), btrfs_inode_mode(ii)); break; case BTRFS_DIR_ITEM_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); print_dir_item(l->items + i, di); break; case BTRFS_DIR_INDEX_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); print_dir_item(l->items + i, di); break; case BTRFS_ROOT_ITEM_KEY: ri = btrfs_item_ptr(l, i, struct btrfs_root_item); printf("\t\troot data blocknr %llu dirid %llu refs %u\n", (u64)btrfs_root_blocknr(ri), (u64)btrfs_root_dirid(ri), btrfs_root_refs(ri)); break; case BTRFS_EXTENT_ITEM_KEY: ei = btrfs_item_ptr(l, i, struct btrfs_extent_item); printf("\t\textent data refs %u owner %llu\n", btrfs_extent_refs(ei), (u64)btrfs_extent_owner(ei)); break; case BTRFS_CSUM_ITEM_KEY: ci = btrfs_item_ptr(l, i, struct btrfs_csum_item); printf("\t\tcsum item\n"); break; case BTRFS_EXTENT_DATA_KEY: fi = btrfs_item_ptr(l, i, struct btrfs_file_extent_item); if (btrfs_file_extent_type(fi) == BTRFS_FILE_EXTENT_INLINE) { printf("\t\tinline extent data size %u\n", btrfs_file_extent_inline_len(l->items + i)); break; } printf("\t\textent data disk block %llu nr %llu\n", (u64)btrfs_file_extent_disk_blocknr(fi), (u64)btrfs_file_extent_disk_num_blocks(fi)); printf("\t\textent data offset %llu nr %llu\n", (u64)btrfs_file_extent_offset(fi), (u64)btrfs_file_extent_num_blocks(fi)); break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, struct btrfs_block_group_item); printf("\t\tblock group used %llu flags %x\n", (u64)btrfs_block_group_used(bi), bi->flags); break; case BTRFS_STRING_ITEM_KEY: printf("\t\titem data %.*s\n", btrfs_item_size(item), btrfs_leaf_data(l) + btrfs_item_offset(item)); break; }; fflush(stdout); } }
/* * Unlink an inode, which will remove its backref and corresponding dir_index/ * dir_item if any of them exists. * * If an inode's nlink is reduced to 0 and 'add_orphan' is true, it will be * added to orphan inode and waiting to be deleted by next kernel mount. */ int btrfs_unlink(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 ino, u64 parent_ino, u64 index, const char *name, int namelen, int add_orphan) { struct btrfs_path *path; struct btrfs_key key; struct btrfs_inode_item *inode_item; struct btrfs_inode_ref *inode_ref; struct btrfs_dir_item *dir_item; u64 inode_size; u32 nlinks; int del_inode_ref = 0; int del_dir_item = 0; int del_dir_index = 0; int ret = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; /* check the ref and backref exists */ inode_ref = btrfs_lookup_inode_ref(trans, root, path, name, namelen, ino, parent_ino, index, 0); if (IS_ERR(inode_ref)) { ret = PTR_ERR(inode_ref); goto out; } if (inode_ref) del_inode_ref = 1; btrfs_release_path(path); dir_item = btrfs_lookup_dir_item(NULL, root, path, parent_ino, name, namelen, 0); if (IS_ERR(dir_item)) { ret = PTR_ERR(dir_item); goto out; } if (dir_item) del_dir_item = 1; btrfs_release_path(path); dir_item = btrfs_lookup_dir_index(NULL, root, path, parent_ino, name, namelen, index, 0); /* * Since lookup_dir_index() will return -ENOENT when not found, * we need to do extra check. */ if (IS_ERR(dir_item) && PTR_ERR(dir_item) == -ENOENT) dir_item = NULL; if (IS_ERR(dir_item)) { ret = PTR_ERR(dir_item); goto out; } if (dir_item) del_dir_index = 1; btrfs_release_path(path); if (!del_inode_ref && !del_dir_item && !del_dir_index) { /* All not found, shouldn't happen */ ret = -ENOENT; goto out; } if (del_inode_ref) { /* Only decrease nlink when deleting inode_ref */ key.objectid = ino; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret) { if (ret > 0) ret = -ENOENT; goto out; } inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); nlinks = btrfs_inode_nlink(path->nodes[0], inode_item); if (nlinks > 0) nlinks--; btrfs_set_inode_nlink(path->nodes[0], inode_item, nlinks); btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_release_path(path); /* For nlinks == 0, add it to orphan list if needed */ if (nlinks == 0 && add_orphan) { ret = btrfs_add_orphan_item(trans, root, path, ino); if (ret < 0) goto out; btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_release_path(path); } ret = btrfs_del_inode_ref(trans, root, name, namelen, ino, parent_ino, &index); if (ret < 0) goto out; } if (del_dir_index) { dir_item = btrfs_lookup_dir_index(trans, root, path, parent_ino, name, namelen, index, -1); if (IS_ERR(dir_item)) { ret = PTR_ERR(dir_item); goto out; } if (!dir_item) { ret = -ENOENT; goto out; } ret = btrfs_delete_one_dir_name(trans, root, path, dir_item); if (ret) goto out; btrfs_release_path(path); /* Update inode size of the parent inode */ key.objectid = parent_ino; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; ret = btrfs_search_slot(trans, root, &key, path, 1, 1); if (ret) goto out; inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); inode_size = btrfs_inode_size(path->nodes[0], inode_item); if (inode_size >= namelen) inode_size -= namelen; btrfs_set_inode_size(path->nodes[0], inode_item, inode_size); btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_release_path(path); } if (del_dir_item) { dir_item = btrfs_lookup_dir_item(trans, root, path, parent_ino, name, namelen, -1); if (IS_ERR(dir_item)) { ret = PTR_ERR(dir_item); goto out; } if (!dir_item) { ret = -ENOENT; goto out; } ret = btrfs_delete_one_dir_name(trans, root, path, dir_item); if (ret < 0) goto out; btrfs_release_path(path); /* Update inode size of the parent inode */ key.objectid = parent_ino; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; ret = btrfs_search_slot(trans, root, &key, path, 1, 1); if (ret) goto out; inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); inode_size = btrfs_inode_size(path->nodes[0], inode_item); if (inode_size >= namelen) inode_size -= namelen; btrfs_set_inode_size(path->nodes[0], inode_item, inode_size); btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_release_path(path); } out: btrfs_free_path(path); return ret; }
/* * Add dir_item/index for 'parent_ino' if add_backref is true, also insert a * backref from the ino to parent dir and update the nlink(Kernel version does * not do this thing) * * Currently only supports adding link from an inode to another inode. */ int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 ino, u64 parent_ino, char *name, int namelen, u8 type, u64 *index, int add_backref) { struct btrfs_path *path; struct btrfs_key key; struct btrfs_inode_item *inode_item; u32 nlink; u64 inode_size; u64 ret_index = 0; int ret = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; if (index && *index) { ret_index = *index; } else { ret = btrfs_find_free_dir_index(root, parent_ino, &ret_index); if (ret < 0) goto out; } ret = check_dir_conflict(root, name, namelen, parent_ino, ret_index); if (ret < 0) goto out; /* Add inode ref */ if (add_backref) { ret = btrfs_insert_inode_ref(trans, root, name, namelen, ino, parent_ino, ret_index); if (ret < 0) goto out; /* Update nlinks for the inode */ key.objectid = ino; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; ret = btrfs_search_slot(trans, root, &key, path, 1, 1); if (ret) { if (ret > 0) ret = -ENOENT; goto out; } inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); nlink = btrfs_inode_nlink(path->nodes[0], inode_item); nlink++; btrfs_set_inode_nlink(path->nodes[0], inode_item, nlink); btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_release_path(path); } /* Add dir_item and dir_index */ key.objectid = ino; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; ret = btrfs_insert_dir_item(trans, root, name, namelen, parent_ino, &key, type, ret_index); if (ret < 0) goto out; /* Update inode size of the parent inode */ key.objectid = parent_ino; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; ret = btrfs_search_slot(trans, root, &key, path, 1, 1); if (ret) goto out; inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); inode_size = btrfs_inode_size(path->nodes[0], inode_item); inode_size += namelen * 2; btrfs_set_inode_size(path->nodes[0], inode_item, inode_size); btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_release_path(path); out: btrfs_free_path(path); if (ret == 0 && index) *index = ret_index; return ret; }
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) { int i; u32 type, nr; struct btrfs_item *item; struct btrfs_root_item *ri; struct btrfs_dir_item *di; struct btrfs_inode_item *ii; struct btrfs_block_group_item *bi; struct btrfs_file_extent_item *fi; struct btrfs_extent_data_ref *dref; struct btrfs_shared_data_ref *sref; struct btrfs_dev_extent *dev_extent; struct btrfs_key key; struct btrfs_key found_key; if (!l) return; nr = btrfs_header_nritems(l); btrfs_info(root->fs_info, "leaf %llu total ptrs %d free space %d", btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l)); for (i = 0 ; i < nr ; i++) { item = btrfs_item_nr(i); btrfs_item_key_to_cpu(l, &key, i); type = key.type; printk(KERN_INFO "\titem %d key (%llu %u %llu) itemoff %d " "itemsize %d\n", i, key.objectid, type, key.offset, btrfs_item_offset(l, item), btrfs_item_size(l, item)); switch (type) { case BTRFS_INODE_ITEM_KEY: ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); printk(KERN_INFO "\t\tinode generation %llu size %llu " "mode %o\n", btrfs_inode_generation(l, ii), btrfs_inode_size(l, ii), btrfs_inode_mode(l, ii)); break; case BTRFS_DIR_ITEM_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); btrfs_dir_item_key_to_cpu(l, di, &found_key); printk(KERN_INFO "\t\tdir oid %llu type %u\n", found_key.objectid, btrfs_dir_type(l, di)); break; case BTRFS_ROOT_ITEM_KEY: ri = btrfs_item_ptr(l, i, struct btrfs_root_item); printk(KERN_INFO "\t\troot data bytenr %llu refs %u\n", btrfs_disk_root_bytenr(l, ri), btrfs_disk_root_refs(l, ri)); break; case BTRFS_EXTENT_ITEM_KEY: case BTRFS_METADATA_ITEM_KEY: print_extent_item(l, i, type); break; case BTRFS_TREE_BLOCK_REF_KEY: printk(KERN_INFO "\t\ttree block backref\n"); break; case BTRFS_SHARED_BLOCK_REF_KEY: printk(KERN_INFO "\t\tshared block backref\n"); break; case BTRFS_EXTENT_DATA_REF_KEY: dref = btrfs_item_ptr(l, i, struct btrfs_extent_data_ref); print_extent_data_ref(l, dref); break; case BTRFS_SHARED_DATA_REF_KEY: sref = btrfs_item_ptr(l, i, struct btrfs_shared_data_ref); printk(KERN_INFO "\t\tshared data backref count %u\n", btrfs_shared_data_ref_count(l, sref)); break; case BTRFS_EXTENT_DATA_KEY: fi = btrfs_item_ptr(l, i, struct btrfs_file_extent_item); if (btrfs_file_extent_type(l, fi) == BTRFS_FILE_EXTENT_INLINE) { printk(KERN_INFO "\t\tinline extent data " "size %u\n", btrfs_file_extent_inline_len(l, i, fi)); break; } printk(KERN_INFO "\t\textent data disk bytenr %llu " "nr %llu\n", btrfs_file_extent_disk_bytenr(l, fi), btrfs_file_extent_disk_num_bytes(l, fi)); printk(KERN_INFO "\t\textent data offset %llu " "nr %llu ram %llu\n", btrfs_file_extent_offset(l, fi), btrfs_file_extent_num_bytes(l, fi), btrfs_file_extent_ram_bytes(l, fi)); break; case BTRFS_EXTENT_REF_V0_KEY: #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 print_extent_ref_v0(l, i); #else BUG(); #endif break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, struct btrfs_block_group_item); printk(KERN_INFO "\t\tblock group used %llu\n", btrfs_disk_block_group_used(l, bi)); break; case BTRFS_CHUNK_ITEM_KEY: print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk)); break; case BTRFS_DEV_ITEM_KEY: print_dev_item(l, btrfs_item_ptr(l, i, struct btrfs_dev_item)); break; case BTRFS_DEV_EXTENT_KEY: dev_extent = btrfs_item_ptr(l, i, struct btrfs_dev_extent); printk(KERN_INFO "\t\tdev extent chunk_tree %llu\n" "\t\tchunk objectid %llu chunk offset %llu " "length %llu\n", btrfs_dev_extent_chunk_tree(l, dev_extent), btrfs_dev_extent_chunk_objectid(l, dev_extent), btrfs_dev_extent_chunk_offset(l, dev_extent), btrfs_dev_extent_length(l, dev_extent)); break; case BTRFS_PERSISTENT_ITEM_KEY: printk(KERN_INFO "\t\tpersistent item objectid %llu offset %llu\n", key.objectid, key.offset); switch (key.objectid) { case BTRFS_DEV_STATS_OBJECTID: printk(KERN_INFO "\t\tdevice stats\n"); break; default: printk(KERN_INFO "\t\tunknown persistent item\n"); } break; case BTRFS_TEMPORARY_ITEM_KEY: printk(KERN_INFO "\t\ttemporary item objectid %llu offset %llu\n", key.objectid, key.offset); switch (key.objectid) { case BTRFS_BALANCE_OBJECTID: printk(KERN_INFO "\t\tbalance status\n"); break; default: printk(KERN_INFO "\t\tunknown temporary item\n"); } break; case BTRFS_DEV_REPLACE_KEY: printk(KERN_INFO "\t\tdev replace\n"); break; case BTRFS_UUID_KEY_SUBVOL: case BTRFS_UUID_KEY_RECEIVED_SUBVOL: print_uuid_item(l, btrfs_item_ptr_offset(l, i), btrfs_item_size_nr(l, i)); break; }; } }
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) { int i; char *str; struct btrfs_item *item; struct btrfs_root_item *ri; struct btrfs_dir_item *di; struct btrfs_inode_item *ii; struct btrfs_file_extent_item *fi; struct btrfs_block_group_item *bi; struct btrfs_extent_data_ref *dref; struct btrfs_shared_data_ref *sref; struct btrfs_inode_ref *iref; struct btrfs_dev_extent *dev_extent; struct btrfs_disk_key disk_key; struct btrfs_root_item root_item; struct btrfs_block_group_item bg_item; struct btrfs_dir_log_item *dlog; u32 nr = btrfs_header_nritems(l); u32 type; printf("leaf %llu items %d free space %d generation %llu owner %llu\n", (unsigned long long)btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l), (unsigned long long)btrfs_header_generation(l), (unsigned long long)btrfs_header_owner(l)); print_uuids(l); fflush(stdout); for (i = 0 ; i < nr ; i++) { item = btrfs_item_nr(l, i); btrfs_item_key(l, &disk_key, i); type = btrfs_disk_key_type(&disk_key); printf("\titem %d ", i); btrfs_print_key(&disk_key); printf(" itemoff %d itemsize %d\n", btrfs_item_offset(l, item), btrfs_item_size(l, item)); switch (type) { case BTRFS_INODE_ITEM_KEY: ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); printf("\t\tinode generation %llu size %llu block group %llu mode %o links %u\n", (unsigned long long)btrfs_inode_generation(l, ii), (unsigned long long)btrfs_inode_size(l, ii), (unsigned long long)btrfs_inode_block_group(l,ii), btrfs_inode_mode(l, ii), btrfs_inode_nlink(l, ii)); break; case BTRFS_INODE_REF_KEY: iref = btrfs_item_ptr(l, i, struct btrfs_inode_ref); print_inode_ref_item(l, item, iref); break; case BTRFS_DIR_ITEM_KEY: case BTRFS_DIR_INDEX_KEY: case BTRFS_XATTR_ITEM_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); print_dir_item(l, item, di); break; case BTRFS_DIR_LOG_INDEX_KEY: case BTRFS_DIR_LOG_ITEM_KEY: dlog = btrfs_item_ptr(l, i, struct btrfs_dir_log_item); printf("\t\tdir log end %Lu\n", (unsigned long long)btrfs_dir_log_end(l, dlog)); break; case BTRFS_ORPHAN_ITEM_KEY: printf("\t\torphan item\n"); break; case BTRFS_ROOT_ITEM_KEY: ri = btrfs_item_ptr(l, i, struct btrfs_root_item); read_extent_buffer(l, &root_item, (unsigned long)ri, sizeof(root_item)); printf("\t\troot data bytenr %llu level %d dirid %llu refs %u gen %llu\n", (unsigned long long)btrfs_root_bytenr(&root_item), btrfs_root_level(&root_item), (unsigned long long)btrfs_root_dirid(&root_item), btrfs_root_refs(&root_item), (unsigned long long)btrfs_root_generation(&root_item)); if (btrfs_root_refs(&root_item) == 0) { struct btrfs_key drop_key; btrfs_disk_key_to_cpu(&drop_key, &root_item.drop_progress); printf("\t\tdrop "); btrfs_print_key(&root_item.drop_progress); printf(" level %d\n", root_item.drop_level); } break; case BTRFS_ROOT_REF_KEY: print_root_ref(l, i, "ref"); break; case BTRFS_ROOT_BACKREF_KEY: print_root_ref(l, i, "backref"); break; case BTRFS_EXTENT_ITEM_KEY: print_extent_item(l, i); break; case BTRFS_TREE_BLOCK_REF_KEY: printf("\t\ttree block backref\n"); break; case BTRFS_SHARED_BLOCK_REF_KEY: printf("\t\tshared block backref\n"); break; case BTRFS_EXTENT_DATA_REF_KEY: dref = btrfs_item_ptr(l, i, struct btrfs_extent_data_ref); printf("\t\textent data backref root %llu " "objectid %llu offset %llu count %u\n", (unsigned long long)btrfs_extent_data_ref_root(l, dref), (unsigned long long)btrfs_extent_data_ref_objectid(l, dref), (unsigned long long)btrfs_extent_data_ref_offset(l, dref), btrfs_extent_data_ref_count(l, dref)); break; case BTRFS_SHARED_DATA_REF_KEY: sref = btrfs_item_ptr(l, i, struct btrfs_shared_data_ref); printf("\t\tshared data backref count %u\n", btrfs_shared_data_ref_count(l, sref)); break; case BTRFS_EXTENT_REF_V0_KEY: #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 print_extent_ref_v0(l, i); #else BUG(); #endif break; case BTRFS_CSUM_ITEM_KEY: printf("\t\tcsum item\n"); break; case BTRFS_EXTENT_CSUM_KEY: printf("\t\textent csum item\n"); break; case BTRFS_EXTENT_DATA_KEY: fi = btrfs_item_ptr(l, i, struct btrfs_file_extent_item); print_file_extent_item(l, item, fi); break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, struct btrfs_block_group_item); read_extent_buffer(l, &bg_item, (unsigned long)bi, sizeof(bg_item)); printf("\t\tblock group used %llu chunk_objectid %llu flags %llu\n", (unsigned long long)btrfs_block_group_used(&bg_item), (unsigned long long)btrfs_block_group_chunk_objectid(&bg_item), (unsigned long long)btrfs_block_group_flags(&bg_item)); break; case BTRFS_CHUNK_ITEM_KEY: print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk)); break; case BTRFS_DEV_ITEM_KEY: print_dev_item(l, btrfs_item_ptr(l, i, struct btrfs_dev_item)); break; case BTRFS_DEV_EXTENT_KEY: dev_extent = btrfs_item_ptr(l, i, struct btrfs_dev_extent); printf("\t\tdev extent chunk_tree %llu\n" "\t\tchunk objectid %llu chunk offset %llu " "length %llu\n", (unsigned long long) btrfs_dev_extent_chunk_tree(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_objectid(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_offset(l, dev_extent), (unsigned long long) btrfs_dev_extent_length(l, dev_extent)); break; case BTRFS_STRING_ITEM_KEY: /* dirty, but it's simple */ str = l->data + btrfs_item_ptr_offset(l, i); printf("\t\titem data %.*s\n", btrfs_item_size(l, item), str); break; }; fflush(stdout); } }