mirror of
https://github.com/kdave/btrfs-progs
synced 2025-05-06 01:47:56 +00:00
Update btrfs-progs to match kernel sources
This commit is contained in:
parent
088f78aeaa
commit
7777e63b42
6
Makefile
6
Makefile
@ -3,7 +3,7 @@ AM_CFLAGS = -Wall -fno-strict-aliasing -D_FILE_OFFSET_BITS=64
|
||||
CFLAGS = -g -Werror
|
||||
objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
|
||||
root-tree.o dir-item.o hash.o file-item.o inode-item.o \
|
||||
inode-map.o crc32c.o rbtree.o extent-cache.o \
|
||||
inode-map.o crc32c.o rbtree.o extent-cache.o extent_map.o \
|
||||
#
|
||||
CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \
|
||||
-Wuninitialized -Wshadow -Wundef
|
||||
@ -35,8 +35,8 @@ btrfsctl: btrfsctl.o
|
||||
btrfsck: $(objects) btrfsck.o bit-radix.o
|
||||
gcc $(CFLAGS) -o btrfsck btrfsck.o $(objects) bit-radix.o $(LDFLAGS)
|
||||
|
||||
mkfs.btrfs: $(objects) mkfs.o
|
||||
gcc $(CFLAGS) -o mkfs.btrfs $(objects) mkfs.o -luuid $(LDFLAGS)
|
||||
mkfs.btrfs: $(objects) mkfs.o utils.o
|
||||
gcc $(CFLAGS) -o mkfs.btrfs $(objects) mkfs.o utils.o -luuid $(LDFLAGS)
|
||||
|
||||
debug-tree: $(objects) debug-tree.o
|
||||
gcc $(CFLAGS) -o debug-tree $(objects) debug-tree.o -luuid $(LDFLAGS)
|
||||
|
201
btrfsck.c
201
btrfsck.c
@ -63,22 +63,24 @@ struct block_info {
|
||||
|
||||
static int check_node(struct btrfs_root *root,
|
||||
struct btrfs_disk_key *parent_key,
|
||||
struct btrfs_node *node)
|
||||
struct extent_buffer *buf)
|
||||
{
|
||||
int i;
|
||||
u32 nritems = btrfs_header_nritems(&node->header);
|
||||
struct btrfs_key cpukey;
|
||||
struct btrfs_disk_key key;
|
||||
u32 nritems = btrfs_header_nritems(buf);
|
||||
|
||||
if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(root))
|
||||
return 1;
|
||||
if (parent_key->type) {
|
||||
if (memcmp(parent_key, &node->ptrs[0].key,
|
||||
sizeof(struct btrfs_disk_key)))
|
||||
btrfs_node_key(buf, &key, 0);
|
||||
if (memcmp(parent_key, &key, sizeof(key)))
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; nritems > 1 && i < nritems - 2; i++) {
|
||||
struct btrfs_key cpukey;
|
||||
btrfs_disk_key_to_cpu(&cpukey, &node->ptrs[i + 1].key);
|
||||
if (btrfs_comp_keys(&node->ptrs[i].key, &cpukey) >= 0)
|
||||
btrfs_node_key(buf, &key, i);
|
||||
btrfs_node_key_to_cpu(buf, &cpukey, i + 1);
|
||||
if (btrfs_comp_keys(&key, &cpukey) >= 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -86,44 +88,44 @@ static int check_node(struct btrfs_root *root,
|
||||
|
||||
static int check_leaf(struct btrfs_root *root,
|
||||
struct btrfs_disk_key *parent_key,
|
||||
struct btrfs_leaf *leaf)
|
||||
struct extent_buffer *buf)
|
||||
{
|
||||
int i;
|
||||
u32 nritems = btrfs_header_nritems(&leaf->header);
|
||||
struct btrfs_key cpukey;
|
||||
struct btrfs_disk_key key;
|
||||
u32 nritems = btrfs_header_nritems(buf);
|
||||
|
||||
if (btrfs_header_level(&leaf->header) != 0) {
|
||||
if (btrfs_header_level(buf) != 0) {
|
||||
fprintf(stderr, "leaf is not a leaf %llu\n",
|
||||
(unsigned long long)btrfs_header_bytenr(&leaf->header));
|
||||
(unsigned long long)btrfs_header_bytenr(buf));
|
||||
return 1;
|
||||
}
|
||||
if (btrfs_leaf_free_space(root, leaf) < 0) {
|
||||
if (btrfs_leaf_free_space(root, buf) < 0) {
|
||||
fprintf(stderr, "leaf free space incorrect %llu %d\n",
|
||||
(unsigned long long)btrfs_header_bytenr(&leaf->header),
|
||||
btrfs_leaf_free_space(root, leaf));
|
||||
(unsigned long long)btrfs_header_bytenr(buf),
|
||||
btrfs_leaf_free_space(root, buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nritems == 0)
|
||||
return 0;
|
||||
|
||||
if (parent_key->type && memcmp(parent_key, &leaf->items[0].key,
|
||||
sizeof(struct btrfs_disk_key))) {
|
||||
btrfs_item_key(buf, &key, 0);
|
||||
if (parent_key->type && memcmp(parent_key, &key, sizeof(key))) {
|
||||
fprintf(stderr, "leaf parent key incorrect %llu\n",
|
||||
(unsigned long long)btrfs_header_bytenr(&leaf->header));
|
||||
(unsigned long long)btrfs_header_bytenr(buf));
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; nritems > 1 && i < nritems - 2; i++) {
|
||||
struct btrfs_key cpukey;
|
||||
btrfs_disk_key_to_cpu(&cpukey, &leaf->items[i + 1].key);
|
||||
if (btrfs_comp_keys(&leaf->items[i].key,
|
||||
&cpukey) >= 0)
|
||||
btrfs_item_key(buf, &key, i);
|
||||
btrfs_item_key_to_cpu(buf, &cpukey, i + 1);
|
||||
if (btrfs_comp_keys(&key, &cpukey) >= 0)
|
||||
return 1;
|
||||
if (btrfs_item_offset(leaf->items + i) !=
|
||||
btrfs_item_end(leaf->items + i + 1))
|
||||
if (btrfs_item_offset_nr(buf, i) !=
|
||||
btrfs_item_end_nr(buf, i + 1))
|
||||
return 1;
|
||||
if (i == 0) {
|
||||
if (btrfs_item_offset(leaf->items + i) +
|
||||
btrfs_item_size(leaf->items + i) !=
|
||||
if (btrfs_item_end_nr(buf, i) !=
|
||||
BTRFS_LEAF_DATA_SIZE(root))
|
||||
return 1;
|
||||
}
|
||||
@ -206,20 +208,20 @@ static int maybe_free_extent_rec(struct cache_tree *extent_cache,
|
||||
|
||||
static int check_block(struct btrfs_root *root,
|
||||
struct cache_tree *extent_cache,
|
||||
struct btrfs_buffer *buf)
|
||||
struct extent_buffer *buf)
|
||||
{
|
||||
struct extent_record *rec;
|
||||
struct cache_extent *cache;
|
||||
int ret = 1;
|
||||
|
||||
cache = find_cache_extent(extent_cache, buf->bytenr, buf->size);
|
||||
cache = find_cache_extent(extent_cache, buf->start, buf->len);
|
||||
if (!cache)
|
||||
return 1;
|
||||
rec = container_of(cache, struct extent_record, cache);
|
||||
if (btrfs_is_leaf(&buf->node)) {
|
||||
ret = check_leaf(root, &rec->parent_key, &buf->leaf);
|
||||
if (btrfs_is_leaf(buf)) {
|
||||
ret = check_leaf(root, &rec->parent_key, buf);
|
||||
} else {
|
||||
ret = check_node(root, &rec->parent_key, &buf->node);
|
||||
ret = check_node(root, &rec->parent_key, buf);
|
||||
}
|
||||
rec->checked = 1;
|
||||
if (!ret)
|
||||
@ -470,7 +472,7 @@ static int pick_next_pending(struct cache_tree *pending,
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static struct btrfs_buffer reada_buf;
|
||||
static struct extent_buffer reada_buf;
|
||||
|
||||
static int run_next_block(struct btrfs_root *root,
|
||||
struct block_info *bits,
|
||||
@ -482,16 +484,14 @@ static int run_next_block(struct btrfs_root *root,
|
||||
struct cache_tree *nodes,
|
||||
struct cache_tree *extent_cache)
|
||||
{
|
||||
struct btrfs_buffer *buf;
|
||||
struct extent_buffer *buf;
|
||||
u64 bytenr;
|
||||
u32 size;
|
||||
int ret;
|
||||
int i;
|
||||
int nritems;
|
||||
struct btrfs_extent_ref *ref;
|
||||
struct btrfs_leaf *leaf;
|
||||
struct btrfs_node *node;
|
||||
struct btrfs_disk_key *disk_key;
|
||||
struct btrfs_disk_key disk_key;
|
||||
struct cache_extent *cache;
|
||||
int reada_bits;
|
||||
|
||||
@ -534,41 +534,41 @@ static int run_next_block(struct btrfs_root *root,
|
||||
}
|
||||
|
||||
buf = read_tree_block(root, bytenr, size);
|
||||
nritems = btrfs_header_nritems(&buf->node.header);
|
||||
nritems = btrfs_header_nritems(buf);
|
||||
ret = check_block(root, extent_cache, buf);
|
||||
if (ret) {
|
||||
fprintf(stderr, "bad block %llu\n",
|
||||
(unsigned long long)bytenr);
|
||||
}
|
||||
if (btrfs_is_leaf(&buf->node)) {
|
||||
leaf = &buf->leaf;
|
||||
btree_space_waste += btrfs_leaf_free_space(root, leaf);
|
||||
if (btrfs_is_leaf(buf)) {
|
||||
btree_space_waste += btrfs_leaf_free_space(root, buf);
|
||||
for (i = 0; i < nritems; i++) {
|
||||
struct btrfs_file_extent_item *fi;
|
||||
disk_key = &leaf->items[i].key;
|
||||
if (btrfs_disk_key_type(disk_key) ==
|
||||
btrfs_item_key(buf, &disk_key, i);
|
||||
if (btrfs_disk_key_type(&disk_key) ==
|
||||
BTRFS_EXTENT_ITEM_KEY) {
|
||||
struct btrfs_key found;
|
||||
struct btrfs_extent_item *ei;
|
||||
btrfs_disk_key_to_cpu(&found, disk_key);
|
||||
ei = btrfs_item_ptr(leaf, i,
|
||||
btrfs_disk_key_to_cpu(&found, &disk_key);
|
||||
ei = btrfs_item_ptr(buf, i,
|
||||
struct btrfs_extent_item);
|
||||
add_extent_rec(extent_cache, NULL, 0,
|
||||
found.objectid,
|
||||
found.offset,
|
||||
btrfs_extent_refs(ei), 0, 0);
|
||||
btrfs_extent_refs(buf, ei),
|
||||
0, 0);
|
||||
continue;
|
||||
}
|
||||
if (btrfs_disk_key_type(disk_key) ==
|
||||
if (btrfs_disk_key_type(&disk_key) ==
|
||||
BTRFS_CSUM_ITEM_KEY) {
|
||||
total_csum_bytes +=
|
||||
btrfs_item_size(leaf->items + i);
|
||||
btrfs_item_size_nr(buf, i);
|
||||
continue;
|
||||
}
|
||||
if (btrfs_disk_key_type(disk_key) ==
|
||||
if (btrfs_disk_key_type(&disk_key) ==
|
||||
BTRFS_BLOCK_GROUP_ITEM_KEY) {
|
||||
struct btrfs_block_group_item *bi;
|
||||
bi = btrfs_item_ptr(leaf, i,
|
||||
bi = btrfs_item_ptr(buf, i,
|
||||
struct btrfs_block_group_item);
|
||||
#if 0
|
||||
fprintf(stderr,"block group %Lu %Lu used %Lu ",
|
||||
@ -579,64 +579,64 @@ static int run_next_block(struct btrfs_root *root,
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (btrfs_disk_key_type(disk_key) ==
|
||||
if (btrfs_disk_key_type(&disk_key) ==
|
||||
BTRFS_EXTENT_REF_KEY) {
|
||||
ref = btrfs_item_ptr(leaf, i,
|
||||
ref = btrfs_item_ptr(buf, i,
|
||||
struct btrfs_extent_ref);
|
||||
|
||||
add_backref(extent_cache,
|
||||
btrfs_disk_key_objectid(disk_key),
|
||||
btrfs_ref_root(ref),
|
||||
btrfs_ref_generation(ref),
|
||||
btrfs_ref_objectid(ref),
|
||||
btrfs_ref_offset(ref), 0);
|
||||
btrfs_disk_key_objectid(&disk_key),
|
||||
btrfs_ref_root(buf, ref),
|
||||
btrfs_ref_generation(buf, ref),
|
||||
btrfs_ref_objectid(buf, ref),
|
||||
btrfs_ref_offset(buf, ref), 0);
|
||||
continue;
|
||||
}
|
||||
if (btrfs_disk_key_type(disk_key) !=
|
||||
if (btrfs_disk_key_type(&disk_key) !=
|
||||
BTRFS_EXTENT_DATA_KEY)
|
||||
continue;
|
||||
fi = btrfs_item_ptr(leaf, i,
|
||||
fi = btrfs_item_ptr(buf, i,
|
||||
struct btrfs_file_extent_item);
|
||||
if (btrfs_file_extent_type(fi) !=
|
||||
if (btrfs_file_extent_type(buf, fi) !=
|
||||
BTRFS_FILE_EXTENT_REG)
|
||||
continue;
|
||||
if (btrfs_file_extent_disk_bytenr(fi) == 0)
|
||||
if (btrfs_file_extent_disk_bytenr(buf, fi) == 0)
|
||||
continue;
|
||||
|
||||
data_bytes_allocated +=
|
||||
btrfs_file_extent_disk_num_bytes(fi);
|
||||
btrfs_file_extent_disk_num_bytes(buf, fi);
|
||||
data_bytes_referenced +=
|
||||
btrfs_file_extent_num_bytes(fi);
|
||||
btrfs_file_extent_num_bytes(buf, fi);
|
||||
ret = add_extent_rec(extent_cache, NULL, bytenr,
|
||||
btrfs_file_extent_disk_bytenr(fi),
|
||||
btrfs_file_extent_disk_num_bytes(fi),
|
||||
btrfs_file_extent_disk_bytenr(buf, fi),
|
||||
btrfs_file_extent_disk_num_bytes(buf, fi),
|
||||
0, 1, 1);
|
||||
add_backref(extent_cache,
|
||||
btrfs_file_extent_disk_bytenr(fi),
|
||||
btrfs_header_owner(&leaf->header),
|
||||
btrfs_header_generation(&leaf->header),
|
||||
btrfs_disk_key_objectid(disk_key),
|
||||
btrfs_disk_key_offset(disk_key), 1);
|
||||
btrfs_file_extent_disk_bytenr(buf, fi),
|
||||
btrfs_header_owner(buf),
|
||||
btrfs_header_generation(buf),
|
||||
btrfs_disk_key_objectid(&disk_key),
|
||||
btrfs_disk_key_offset(&disk_key), 1);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
} else {
|
||||
int level;
|
||||
node = &buf->node;
|
||||
level = btrfs_header_level(&node->header);
|
||||
level = btrfs_header_level(buf);
|
||||
for (i = 0; i < nritems; i++) {
|
||||
u64 ptr = btrfs_node_blockptr(node, i);
|
||||
u64 ptr = btrfs_node_blockptr(buf, i);
|
||||
u32 size = btrfs_level_size(root, level - 1);
|
||||
btrfs_node_key(buf, &disk_key, i);
|
||||
ret = add_extent_rec(extent_cache,
|
||||
&node->ptrs[i].key,
|
||||
&disk_key,
|
||||
bytenr, ptr, size,
|
||||
0, 1, 0);
|
||||
BUG_ON(ret);
|
||||
|
||||
add_backref(extent_cache, ptr,
|
||||
btrfs_header_owner(&node->header),
|
||||
btrfs_header_generation(&node->header),
|
||||
btrfs_header_owner(buf),
|
||||
btrfs_header_generation(buf),
|
||||
level - 1,
|
||||
btrfs_disk_key_objectid(&node->ptrs[i].key), 1);
|
||||
btrfs_disk_key_objectid(&disk_key), 1);
|
||||
|
||||
if (level > 1) {
|
||||
add_pending(nodes, seen, ptr, size);
|
||||
@ -647,12 +647,12 @@ static int run_next_block(struct btrfs_root *root,
|
||||
btree_space_waste += (BTRFS_NODEPTRS_PER_BLOCK(root) -
|
||||
nritems) * sizeof(struct btrfs_key_ptr);
|
||||
}
|
||||
total_btree_bytes += buf->size;
|
||||
btrfs_block_release(root, buf);
|
||||
total_btree_bytes += buf->len;
|
||||
free_extent_buffer(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_root_to_pending(struct btrfs_buffer *buf,
|
||||
static int add_root_to_pending(struct extent_buffer *buf,
|
||||
struct block_info *bits,
|
||||
int bits_nr,
|
||||
struct cache_tree *extent_cache,
|
||||
@ -661,16 +661,16 @@ static int add_root_to_pending(struct btrfs_buffer *buf,
|
||||
struct cache_tree *reada,
|
||||
struct cache_tree *nodes, u64 root_objectid)
|
||||
{
|
||||
if (btrfs_header_level(&buf->node.header) > 0)
|
||||
add_pending(nodes, seen, buf->bytenr, buf->size);
|
||||
if (btrfs_header_level(buf) > 0)
|
||||
add_pending(nodes, seen, buf->start, buf->len);
|
||||
else
|
||||
add_pending(pending, seen, buf->bytenr, buf->size);
|
||||
add_extent_rec(extent_cache, NULL, 0, buf->bytenr, buf->size,
|
||||
add_pending(pending, seen, buf->start, buf->len);
|
||||
add_extent_rec(extent_cache, NULL, 0, buf->start, buf->len,
|
||||
0, 1, 0);
|
||||
|
||||
add_backref(extent_cache, buf->bytenr, root_objectid,
|
||||
btrfs_header_generation(&buf->node.header),
|
||||
btrfs_header_level(&buf->node.header), 0, 1);
|
||||
add_backref(extent_cache, buf->start, root_objectid,
|
||||
btrfs_header_generation(buf),
|
||||
btrfs_header_level(buf), 0, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -710,7 +710,6 @@ int check_extent_refs(struct btrfs_root *root,
|
||||
}
|
||||
|
||||
int main(int ac, char **av) {
|
||||
struct btrfs_super_block super;
|
||||
struct btrfs_root *root;
|
||||
struct cache_tree extent_cache;
|
||||
struct cache_tree seen;
|
||||
@ -724,9 +723,9 @@ int main(int ac, char **av) {
|
||||
u64 last = 0;
|
||||
struct block_info *bits;
|
||||
int bits_nr;
|
||||
struct btrfs_leaf *leaf;
|
||||
struct extent_buffer *leaf;
|
||||
int slot;
|
||||
struct btrfs_root_item *ri;
|
||||
struct btrfs_root_item ri;
|
||||
|
||||
radix_tree_init();
|
||||
cache_tree_init(&extent_cache);
|
||||
@ -735,7 +734,7 @@ int main(int ac, char **av) {
|
||||
cache_tree_init(&nodes);
|
||||
cache_tree_init(&reada);
|
||||
|
||||
root = open_ctree(av[1], &super);
|
||||
root = open_ctree(av[1], 0);
|
||||
|
||||
bits_nr = 1024;
|
||||
bits = malloc(bits_nr * sizeof(struct block_info));
|
||||
@ -756,30 +755,30 @@ int main(int ac, char **av) {
|
||||
&key, &path, 0, 0);
|
||||
BUG_ON(ret < 0);
|
||||
while(1) {
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
leaf = path.nodes[0];
|
||||
slot = path.slots[0];
|
||||
if (slot >= btrfs_header_nritems(&leaf->header)) {
|
||||
if (slot >= btrfs_header_nritems(path.nodes[0])) {
|
||||
ret = btrfs_next_leaf(root, &path);
|
||||
if (ret != 0)
|
||||
break;
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
leaf = path.nodes[0];
|
||||
slot = path.slots[0];
|
||||
}
|
||||
btrfs_disk_key_to_cpu(&found_key,
|
||||
&leaf->items[path.slots[0]].key);
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path.slots[0]);
|
||||
if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) {
|
||||
struct btrfs_buffer *buf;
|
||||
unsigned long offset;
|
||||
struct extent_buffer *buf;
|
||||
|
||||
ri = btrfs_item_ptr(leaf, path.slots[0],
|
||||
struct btrfs_root_item);
|
||||
offset = btrfs_item_ptr_offset(leaf, path.slots[0]);
|
||||
read_extent_buffer(leaf, &ri, offset, sizeof(ri));
|
||||
buf = read_tree_block(root->fs_info->tree_root,
|
||||
btrfs_root_bytenr(ri),
|
||||
btrfs_root_bytenr(&ri),
|
||||
btrfs_level_size(root,
|
||||
btrfs_root_level(ri)));
|
||||
btrfs_root_level(&ri)));
|
||||
add_root_to_pending(buf, bits, bits_nr, &extent_cache,
|
||||
&pending, &seen, &reada, &nodes,
|
||||
found_key.objectid);
|
||||
btrfs_block_release(root->fs_info->tree_root, buf);
|
||||
free_extent_buffer(buf);
|
||||
}
|
||||
path.slots[0]++;
|
||||
}
|
||||
@ -791,7 +790,7 @@ int main(int ac, char **av) {
|
||||
break;
|
||||
}
|
||||
ret = check_extent_refs(root, &extent_cache);
|
||||
close_ctree(root, &super);
|
||||
close_ctree(root);
|
||||
printf("found %llu bytes used err is %d\n",
|
||||
(unsigned long long)bytes_used, ret);
|
||||
printf("total csum bytes: %llu\n",(unsigned long long)total_csum_bytes);
|
||||
|
747
ctree.h
747
ctree.h
@ -23,10 +23,13 @@
|
||||
#include "kerncompat.h"
|
||||
#include "radix-tree.h"
|
||||
#include "extent-cache.h"
|
||||
#include "extent_map.h"
|
||||
|
||||
struct btrfs_root;
|
||||
struct btrfs_trans_handle;
|
||||
#define BTRFS_MAGIC "_B2RfS_M"
|
||||
|
||||
#define BTRFS_MAX_LEVEL 8
|
||||
#define BTRFS_ROOT_TREE_OBJECTID 1ULL
|
||||
#define BTRFS_EXTENT_TREE_OBJECTID 2ULL
|
||||
#define BTRFS_FS_TREE_OBJECTID 3ULL
|
||||
@ -43,6 +46,7 @@ struct btrfs_trans_handle;
|
||||
#define BTRFS_CSUM_SIZE 32
|
||||
/* four bytes for CRC32 */
|
||||
#define BTRFS_CRC32_SIZE 4
|
||||
#define BTRFS_EMPTY_DIR_SIZE 0
|
||||
|
||||
#define BTRFS_FT_UNKNOWN 0
|
||||
#define BTRFS_FT_REG_FILE 1
|
||||
@ -81,12 +85,13 @@ struct btrfs_key {
|
||||
u64 offset;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
#define BTRFS_FSID_SIZE 16
|
||||
/*
|
||||
* every tree block (leaf or node) starts with this header.
|
||||
*/
|
||||
struct btrfs_header {
|
||||
u8 csum[BTRFS_CSUM_SIZE];
|
||||
u8 fsid[16]; /* FS specific uuid */
|
||||
u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
|
||||
__le64 bytenr; /* which block this node is supposed to live in */
|
||||
__le64 generation;
|
||||
__le64 owner;
|
||||
@ -95,16 +100,14 @@ struct btrfs_header {
|
||||
u8 level;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
#define BTRFS_MAX_LEVEL 8
|
||||
#define BTRFS_NODEPTRS_PER_BLOCK(r) (((r)->nodesize - \
|
||||
sizeof(struct btrfs_header)) / \
|
||||
sizeof(struct btrfs_key_ptr))
|
||||
sizeof(struct btrfs_key_ptr))
|
||||
#define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header))
|
||||
#define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize))
|
||||
#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
|
||||
sizeof(struct btrfs_item) - \
|
||||
sizeof(struct btrfs_file_extent_item))
|
||||
struct btrfs_buffer;
|
||||
/*
|
||||
* the super block basically lists the main trees of the FS
|
||||
* it currently lacks any block count etc etc
|
||||
@ -112,7 +115,7 @@ struct btrfs_buffer;
|
||||
struct btrfs_super_block {
|
||||
u8 csum[BTRFS_CSUM_SIZE];
|
||||
/* the first 3 fields must match struct btrfs_header */
|
||||
u8 fsid[16]; /* FS specific uuid */
|
||||
u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
|
||||
__le64 bytenr; /* this block number */
|
||||
__le64 magic;
|
||||
__le64 generation;
|
||||
@ -173,8 +176,10 @@ struct btrfs_node {
|
||||
* used while walking the tree.
|
||||
*/
|
||||
struct btrfs_path {
|
||||
struct btrfs_buffer *nodes[BTRFS_MAX_LEVEL];
|
||||
struct extent_buffer *nodes[BTRFS_MAX_LEVEL];
|
||||
int slots[BTRFS_MAX_LEVEL];
|
||||
int reada;
|
||||
int lowest_level;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -224,11 +229,6 @@ struct btrfs_inode_item {
|
||||
struct btrfs_inode_timespec otime;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* inline data is just a blob of bytes */
|
||||
struct btrfs_inline_data_item {
|
||||
u8 data;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct btrfs_dir_item {
|
||||
struct btrfs_disk_key location;
|
||||
__le16 data_len;
|
||||
@ -276,15 +276,15 @@ struct btrfs_file_extent_item {
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct btrfs_csum_item {
|
||||
u8 csum[BTRFS_CSUM_SIZE];
|
||||
u8 csum;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* tag for the radix tree of block groups in ram */
|
||||
#define BTRFS_BLOCK_GROUP_DIRTY 0
|
||||
#define BTRFS_BLOCK_GROUP_SIZE (256 * 1024 * 1024)
|
||||
|
||||
|
||||
#define BTRFS_BLOCK_GROUP_DATA 1
|
||||
#define BTRFS_BLOCK_GROUP_MIXED 2
|
||||
|
||||
struct btrfs_block_group_item {
|
||||
__le64 used;
|
||||
u8 flags;
|
||||
@ -294,28 +294,34 @@ struct btrfs_block_group_cache {
|
||||
struct cache_extent cache;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_block_group_item item;
|
||||
int dirty;
|
||||
int data;
|
||||
int cached;
|
||||
u64 pinned;
|
||||
};
|
||||
|
||||
struct btrfs_fs_info {
|
||||
u8 fsid[BTRFS_FSID_SIZE];
|
||||
struct btrfs_root *fs_root;
|
||||
struct btrfs_root *extent_root;
|
||||
struct btrfs_root *tree_root;
|
||||
struct btrfs_key last_insert;
|
||||
struct cache_tree extent_cache;
|
||||
struct cache_tree block_group_cache;
|
||||
struct cache_tree pending_tree;
|
||||
struct cache_tree pinned_tree;
|
||||
struct cache_tree del_pending;
|
||||
struct list_head trans;
|
||||
struct list_head cache;
|
||||
u64 last_inode_alloc;
|
||||
u64 last_inode_alloc_dirid;
|
||||
|
||||
struct extent_map_tree extent_cache;
|
||||
struct extent_map_tree free_space_cache;
|
||||
struct extent_map_tree block_group_cache;
|
||||
struct extent_map_tree pending_tree;
|
||||
struct extent_map_tree pinned_extents;
|
||||
struct extent_map_tree del_pending;
|
||||
struct extent_map_tree pending_del;
|
||||
struct extent_map_tree extent_ins;
|
||||
|
||||
u64 generation;
|
||||
int cache_size;
|
||||
int fp;
|
||||
u64 last_trans_committed;
|
||||
struct btrfs_trans_handle *running_transaction;
|
||||
struct btrfs_super_block *disk_super;
|
||||
struct btrfs_super_block super_copy;
|
||||
struct extent_buffer *sb_buffer;
|
||||
struct mutex fs_mutex;
|
||||
int fp;
|
||||
u64 total_pinned;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -323,11 +329,13 @@ struct btrfs_fs_info {
|
||||
* and for the extent tree extent_root root.
|
||||
*/
|
||||
struct btrfs_root {
|
||||
struct btrfs_buffer *node;
|
||||
struct btrfs_buffer *commit_root;
|
||||
struct extent_buffer *node;
|
||||
struct extent_buffer *commit_root;
|
||||
struct btrfs_root_item root_item;
|
||||
struct btrfs_key root_key;
|
||||
struct btrfs_fs_info *fs_info;
|
||||
u64 objectid;
|
||||
u64 last_trans;
|
||||
|
||||
/* data allocations are done in sectorsize units */
|
||||
u32 sectorsize;
|
||||
@ -342,14 +350,11 @@ struct btrfs_root {
|
||||
u32 stripesize;
|
||||
|
||||
int ref_cows;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
/* the lower bits in the key flags defines the item type */
|
||||
#define BTRFS_KEY_TYPE_MAX 256
|
||||
#define BTRFS_KEY_TYPE_SHIFT 24
|
||||
#define BTRFS_KEY_TYPE_MASK (((u32)BTRFS_KEY_TYPE_MAX - 1) << \
|
||||
BTRFS_KEY_TYPE_SHIFT)
|
||||
u32 type;
|
||||
u64 highest_inode;
|
||||
u64 last_inode_alloc;
|
||||
};
|
||||
|
||||
/*
|
||||
* inode items have the data typically returned from stat and store other
|
||||
@ -403,6 +408,50 @@ struct btrfs_root {
|
||||
*/
|
||||
#define BTRFS_STRING_ITEM_KEY 253
|
||||
|
||||
|
||||
#define read_eb_member(eb, ptr, type, member, result) ( \
|
||||
read_extent_buffer(eb, (char *)(result), \
|
||||
((unsigned long)(ptr)) + \
|
||||
offsetof(type, member), \
|
||||
sizeof(((type *)0)->member)))
|
||||
|
||||
#define write_eb_member(eb, ptr, type, member, result) ( \
|
||||
write_extent_buffer(eb, (char *)(result), \
|
||||
((unsigned long)(ptr)) + \
|
||||
offsetof(type, member), \
|
||||
sizeof(((type *)0)->member)))
|
||||
|
||||
#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \
|
||||
static inline u##bits btrfs_##name(struct extent_buffer *eb) \
|
||||
{ \
|
||||
struct btrfs_header *h = (struct btrfs_header *)eb->data; \
|
||||
return le##bits##_to_cpu(h->member); \
|
||||
} \
|
||||
static inline void btrfs_set_##name(struct extent_buffer *eb, \
|
||||
u##bits val) \
|
||||
{ \
|
||||
struct btrfs_header *h = (struct btrfs_header *)eb->data; \
|
||||
h->member = cpu_to_le##bits(val); \
|
||||
}
|
||||
|
||||
#define BTRFS_SETGET_FUNCS(name, type, member, bits) \
|
||||
static inline u##bits btrfs_##name(struct extent_buffer *eb, \
|
||||
type *s) \
|
||||
{ \
|
||||
unsigned long offset = (unsigned long)s + \
|
||||
offsetof(type, member); \
|
||||
__le##bits *tmp = (__le##bits *)(eb->data + offset); \
|
||||
return le##bits##_to_cpu(*tmp); \
|
||||
} \
|
||||
static inline void btrfs_set_##name(struct extent_buffer *eb, \
|
||||
type *s, u##bits val) \
|
||||
{ \
|
||||
unsigned long offset = (unsigned long)s + \
|
||||
offsetof(type, member); \
|
||||
__le##bits *tmp = (__le##bits *)(eb->data + offset); \
|
||||
*tmp = cpu_to_le##bits(val); \
|
||||
}
|
||||
|
||||
#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \
|
||||
static inline u##bits btrfs_##name(type *s) \
|
||||
{ \
|
||||
@ -413,78 +462,253 @@ static inline void btrfs_set_##name(type *s, u##bits val) \
|
||||
s->member = cpu_to_le##bits(val); \
|
||||
}
|
||||
|
||||
/* struct btrfs_block_group_item */
|
||||
BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item,
|
||||
used, 64);
|
||||
BTRFS_SETGET_FUNCS(disk_block_group_used, struct btrfs_block_group_item,
|
||||
used, 64);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_generation, struct btrfs_inode_item,
|
||||
/* struct btrfs_inode_ref */
|
||||
BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
|
||||
|
||||
/* struct btrfs_inode_item */
|
||||
BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64);
|
||||
BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64);
|
||||
BTRFS_SETGET_FUNCS(inode_nblocks, struct btrfs_inode_item, nblocks, 64);
|
||||
BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64);
|
||||
BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32);
|
||||
BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32);
|
||||
BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32);
|
||||
BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32);
|
||||
BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 32);
|
||||
BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 16);
|
||||
BTRFS_SETGET_FUNCS(inode_compat_flags, struct btrfs_inode_item,
|
||||
compat_flags, 16);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_generation,
|
||||
struct btrfs_inode_item, generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_size,
|
||||
struct btrfs_inode_item, size, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_nblocks,
|
||||
struct btrfs_inode_item, nblocks, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group,
|
||||
struct btrfs_inode_item, block_group, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink,
|
||||
struct btrfs_inode_item, nlink, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_uid,
|
||||
struct btrfs_inode_item, uid, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_gid,
|
||||
struct btrfs_inode_item, gid, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_mode,
|
||||
struct btrfs_inode_item, mode, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev,
|
||||
struct btrfs_inode_item, rdev, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_flags,
|
||||
struct btrfs_inode_item, flags, 16);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_compat_flags,
|
||||
struct btrfs_inode_item, compat_flags, 16);
|
||||
|
||||
static inline struct btrfs_inode_timespec *
|
||||
btrfs_inode_atime(struct btrfs_inode_item *inode_item)
|
||||
{
|
||||
unsigned long ptr = (unsigned long)inode_item;
|
||||
ptr += offsetof(struct btrfs_inode_item, atime);
|
||||
return (struct btrfs_inode_timespec *)ptr;
|
||||
}
|
||||
|
||||
static inline struct btrfs_inode_timespec *
|
||||
btrfs_inode_mtime(struct btrfs_inode_item *inode_item)
|
||||
{
|
||||
unsigned long ptr = (unsigned long)inode_item;
|
||||
ptr += offsetof(struct btrfs_inode_item, mtime);
|
||||
return (struct btrfs_inode_timespec *)ptr;
|
||||
}
|
||||
|
||||
static inline struct btrfs_inode_timespec *
|
||||
btrfs_inode_ctime(struct btrfs_inode_item *inode_item)
|
||||
{
|
||||
unsigned long ptr = (unsigned long)inode_item;
|
||||
ptr += offsetof(struct btrfs_inode_item, ctime);
|
||||
return (struct btrfs_inode_timespec *)ptr;
|
||||
}
|
||||
|
||||
static inline struct btrfs_inode_timespec *
|
||||
btrfs_inode_otime(struct btrfs_inode_item *inode_item)
|
||||
{
|
||||
unsigned long ptr = (unsigned long)inode_item;
|
||||
ptr += offsetof(struct btrfs_inode_item, otime);
|
||||
return (struct btrfs_inode_timespec *)ptr;
|
||||
}
|
||||
|
||||
BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_inode_timespec, sec, 64);
|
||||
BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_inode_timespec, nsec, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_inode_timespec,
|
||||
sec, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_inode_timespec,
|
||||
nsec, 32);
|
||||
|
||||
/* struct btrfs_extent_item */
|
||||
BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
|
||||
|
||||
/* struct btrfs_extent_ref */
|
||||
BTRFS_SETGET_FUNCS(ref_root, struct btrfs_extent_ref, root, 64);
|
||||
BTRFS_SETGET_FUNCS(ref_generation, struct btrfs_extent_ref, generation, 64);
|
||||
BTRFS_SETGET_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64);
|
||||
BTRFS_SETGET_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 64);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_ref_root, struct btrfs_extent_ref, root, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_ref_generation, struct btrfs_extent_ref,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_ref_objectid, struct btrfs_extent_ref,
|
||||
objectid, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_ref_offset, struct btrfs_extent_ref, offset, 64);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_size, struct btrfs_inode_item, size, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_nblocks, struct btrfs_inode_item, nblocks, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_block_group, struct btrfs_inode_item,
|
||||
block_group, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_flags, struct btrfs_inode_item, flags, 16);
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_compat_flags, struct btrfs_inode_item,
|
||||
compat_flags, 16);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item,
|
||||
refs, 32);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(timpsec_sec, struct btrfs_inode_timespec, sec, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(timpsec_nsec, struct btrfs_inode_timespec, nsec, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
|
||||
/* struct btrfs_node */
|
||||
BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64);
|
||||
BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(inode_ref_name_len, struct btrfs_inode_ref,
|
||||
name_len, 16);
|
||||
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(ref_root, struct btrfs_extent_ref, root, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(ref_generation, struct btrfs_extent_ref,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 64);
|
||||
|
||||
static inline u64 btrfs_node_blockptr(struct btrfs_node *n, int nr)
|
||||
static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr)
|
||||
{
|
||||
return le64_to_cpu(n->ptrs[nr].blockptr);
|
||||
unsigned long ptr;
|
||||
ptr = offsetof(struct btrfs_node, ptrs) +
|
||||
sizeof(struct btrfs_key_ptr) * nr;
|
||||
return btrfs_key_blockptr(eb, (struct btrfs_key_ptr *)ptr);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_node_blockptr(struct btrfs_node *n, int nr,
|
||||
u64 val)
|
||||
static inline void btrfs_set_node_blockptr(struct extent_buffer *eb,
|
||||
int nr, u64 val)
|
||||
{
|
||||
n->ptrs[nr].blockptr = cpu_to_le64(val);
|
||||
unsigned long ptr;
|
||||
ptr = offsetof(struct btrfs_node, ptrs) +
|
||||
sizeof(struct btrfs_key_ptr) * nr;
|
||||
btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_node_ptr_generation(struct btrfs_node *n, int nr)
|
||||
static inline u64 btrfs_node_ptr_generation(struct extent_buffer *eb, int nr)
|
||||
{
|
||||
return le64_to_cpu(n->ptrs[nr].generation);
|
||||
unsigned long ptr;
|
||||
ptr = offsetof(struct btrfs_node, ptrs) +
|
||||
sizeof(struct btrfs_key_ptr) * nr;
|
||||
return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_node_ptr_generation(struct btrfs_node *n, int nr,
|
||||
u64 val)
|
||||
static inline void btrfs_set_node_ptr_generation(struct extent_buffer *eb,
|
||||
int nr, u64 val)
|
||||
{
|
||||
n->ptrs[nr].generation = cpu_to_le64(val);
|
||||
unsigned long ptr;
|
||||
ptr = offsetof(struct btrfs_node, ptrs) +
|
||||
sizeof(struct btrfs_key_ptr) * nr;
|
||||
btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val);
|
||||
}
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(item_offset, struct btrfs_item, offset, 32);
|
||||
|
||||
static inline u32 btrfs_item_end(struct btrfs_item *item)
|
||||
static inline unsigned long btrfs_node_key_ptr_offset(int nr)
|
||||
{
|
||||
return le32_to_cpu(item->offset) + le32_to_cpu(item->size);
|
||||
return offsetof(struct btrfs_node, ptrs) +
|
||||
sizeof(struct btrfs_key_ptr) * nr;
|
||||
}
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(item_size, struct btrfs_item, size, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
|
||||
BTRFS_SETGET_STACK_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
|
||||
BTRFS_SETGET_STACK_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
|
||||
static inline void btrfs_node_key(struct extent_buffer *eb,
|
||||
struct btrfs_disk_key *disk_key, int nr)
|
||||
{
|
||||
unsigned long ptr;
|
||||
ptr = btrfs_node_key_ptr_offset(nr);
|
||||
read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
|
||||
struct btrfs_key_ptr, key, disk_key);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_node_key(struct extent_buffer *eb,
|
||||
struct btrfs_disk_key *disk_key, int nr)
|
||||
{
|
||||
unsigned long ptr;
|
||||
ptr = btrfs_node_key_ptr_offset(nr);
|
||||
write_eb_member(eb, (struct btrfs_key_ptr *)ptr,
|
||||
struct btrfs_key_ptr, key, disk_key);
|
||||
}
|
||||
|
||||
/* struct btrfs_item */
|
||||
BTRFS_SETGET_FUNCS(item_offset, struct btrfs_item, offset, 32);
|
||||
BTRFS_SETGET_FUNCS(item_size, struct btrfs_item, size, 32);
|
||||
|
||||
static inline unsigned long btrfs_item_nr_offset(int nr)
|
||||
{
|
||||
return offsetof(struct btrfs_leaf, items) +
|
||||
sizeof(struct btrfs_item) * nr;
|
||||
}
|
||||
|
||||
static inline struct btrfs_item *btrfs_item_nr(struct extent_buffer *eb,
|
||||
int nr)
|
||||
{
|
||||
return (struct btrfs_item *)btrfs_item_nr_offset(nr);
|
||||
}
|
||||
|
||||
static inline u32 btrfs_item_end(struct extent_buffer *eb,
|
||||
struct btrfs_item *item)
|
||||
{
|
||||
return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item);
|
||||
}
|
||||
|
||||
static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr)
|
||||
{
|
||||
return btrfs_item_end(eb, btrfs_item_nr(eb, nr));
|
||||
}
|
||||
|
||||
static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)
|
||||
{
|
||||
return btrfs_item_offset(eb, btrfs_item_nr(eb, nr));
|
||||
}
|
||||
|
||||
static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr)
|
||||
{
|
||||
return btrfs_item_size(eb, btrfs_item_nr(eb, nr));
|
||||
}
|
||||
|
||||
static inline void btrfs_item_key(struct extent_buffer *eb,
|
||||
struct btrfs_disk_key *disk_key, int nr)
|
||||
{
|
||||
struct btrfs_item *item = btrfs_item_nr(eb, nr);
|
||||
read_eb_member(eb, item, struct btrfs_item, key, disk_key);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_item_key(struct extent_buffer *eb,
|
||||
struct btrfs_disk_key *disk_key, int nr)
|
||||
{
|
||||
struct btrfs_item *item = btrfs_item_nr(eb, nr);
|
||||
write_eb_member(eb, item, struct btrfs_item, key, disk_key);
|
||||
}
|
||||
|
||||
/* struct btrfs_dir_item */
|
||||
BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
|
||||
BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
|
||||
BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
|
||||
|
||||
static inline void btrfs_dir_item_key(struct extent_buffer *eb,
|
||||
struct btrfs_dir_item *item,
|
||||
struct btrfs_disk_key *key)
|
||||
{
|
||||
read_eb_member(eb, item, struct btrfs_dir_item, location, key);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_dir_item_key(struct extent_buffer *eb,
|
||||
struct btrfs_dir_item *item,
|
||||
struct btrfs_disk_key *key)
|
||||
{
|
||||
write_eb_member(eb, item, struct btrfs_dir_item, location, key);
|
||||
}
|
||||
|
||||
/* struct btrfs_disk_key */
|
||||
BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key,
|
||||
objectid, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8);
|
||||
|
||||
static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu,
|
||||
struct btrfs_disk_key *disk)
|
||||
{
|
||||
cpu->offset = le64_to_cpu(disk->offset);
|
||||
cpu->type = le32_to_cpu(disk->type);
|
||||
cpu->type = disk->type;
|
||||
cpu->objectid = le64_to_cpu(disk->objectid);
|
||||
}
|
||||
|
||||
@ -492,14 +716,35 @@ static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk,
|
||||
struct btrfs_key *cpu)
|
||||
{
|
||||
disk->offset = cpu_to_le64(cpu->offset);
|
||||
disk->type = cpu_to_le32(cpu->type);
|
||||
disk->type = cpu->type;
|
||||
disk->objectid = cpu_to_le64(cpu->objectid);
|
||||
}
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key,
|
||||
objectid, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8);
|
||||
static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb,
|
||||
struct btrfs_key *key, int nr)
|
||||
{
|
||||
struct btrfs_disk_key disk_key;
|
||||
btrfs_node_key(eb, &disk_key, nr);
|
||||
btrfs_disk_key_to_cpu(key, &disk_key);
|
||||
}
|
||||
|
||||
static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb,
|
||||
struct btrfs_key *key, int nr)
|
||||
{
|
||||
struct btrfs_disk_key disk_key;
|
||||
btrfs_item_key(eb, &disk_key, nr);
|
||||
btrfs_disk_key_to_cpu(key, &disk_key);
|
||||
}
|
||||
|
||||
static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb,
|
||||
struct btrfs_dir_item *item,
|
||||
struct btrfs_key *key)
|
||||
{
|
||||
struct btrfs_disk_key disk_key;
|
||||
btrfs_dir_item_key(eb, item, &disk_key);
|
||||
btrfs_disk_key_to_cpu(key, &disk_key);
|
||||
}
|
||||
|
||||
|
||||
static inline u8 btrfs_key_type(struct btrfs_key *key)
|
||||
{
|
||||
@ -511,44 +756,73 @@ static inline void btrfs_set_key_type(struct btrfs_key *key, u8 val)
|
||||
key->type = val;
|
||||
}
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(header_generation, struct btrfs_header,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(header_owner, struct btrfs_header, owner, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(header_flags, struct btrfs_header, flags, 16);
|
||||
/* struct btrfs_header */
|
||||
BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64);
|
||||
BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);
|
||||
BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
|
||||
BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 16);
|
||||
BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);
|
||||
|
||||
static inline int btrfs_header_level(struct btrfs_header *h)
|
||||
static inline u8 *btrfs_header_fsid(struct extent_buffer *eb)
|
||||
{
|
||||
return h->level;
|
||||
unsigned long ptr = offsetof(struct btrfs_header, fsid);
|
||||
return (u8 *)ptr;
|
||||
}
|
||||
|
||||
static inline void btrfs_set_header_level(struct btrfs_header *h, int level)
|
||||
static inline u8 *btrfs_super_fsid(struct extent_buffer *eb)
|
||||
{
|
||||
BUG_ON(level > BTRFS_MAX_LEVEL);
|
||||
h->level = level;
|
||||
unsigned long ptr = offsetof(struct btrfs_super_block, fsid);
|
||||
return (u8 *)ptr;
|
||||
}
|
||||
|
||||
static inline int btrfs_is_leaf(struct btrfs_node *n)
|
||||
static inline u8 *btrfs_header_csum(struct extent_buffer *eb)
|
||||
{
|
||||
return (btrfs_header_level(&n->header) == 0);
|
||||
unsigned long ptr = offsetof(struct btrfs_header, csum);
|
||||
return (u8 *)ptr;
|
||||
}
|
||||
|
||||
static inline struct btrfs_node *btrfs_buffer_node(struct extent_buffer *eb)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct btrfs_leaf *btrfs_buffer_leaf(struct extent_buffer *eb)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct btrfs_header *btrfs_buffer_header(struct extent_buffer *eb)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int btrfs_is_leaf(struct extent_buffer *eb)
|
||||
{
|
||||
return (btrfs_header_level(eb) == 0);
|
||||
}
|
||||
|
||||
/* struct btrfs_root_item */
|
||||
BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32);
|
||||
BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64);
|
||||
BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(root_byte_limit, struct btrfs_root_item,
|
||||
byte_limit, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8);
|
||||
BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(root_bytes_used, struct btrfs_root_item,
|
||||
bytes_used, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
|
||||
|
||||
/* struct btrfs_super_block */
|
||||
BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block,
|
||||
root_level, 8);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block,
|
||||
total_bytes, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block,
|
||||
@ -564,73 +838,139 @@ BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block,
|
||||
BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block,
|
||||
root_dir_objectid, 64);
|
||||
|
||||
static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l)
|
||||
static inline unsigned long btrfs_leaf_data(struct extent_buffer *l)
|
||||
{
|
||||
return (u8 *)l->items;
|
||||
return offsetof(struct btrfs_leaf, items);
|
||||
}
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(file_extent_type, struct btrfs_file_extent_item,
|
||||
type, 8);
|
||||
/* struct btrfs_file_extent_item */
|
||||
BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
|
||||
|
||||
static inline char *btrfs_file_extent_inline_start(struct
|
||||
static inline unsigned long btrfs_file_extent_inline_start(struct
|
||||
btrfs_file_extent_item *e)
|
||||
{
|
||||
return (char *)(&e->disk_bytenr);
|
||||
unsigned long offset = (unsigned long)e;
|
||||
offset += offsetof(struct btrfs_file_extent_item, disk_bytenr);
|
||||
return offset;
|
||||
}
|
||||
|
||||
static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
|
||||
{
|
||||
return (unsigned long)(&((struct
|
||||
btrfs_file_extent_item *)NULL)->disk_bytenr) + datasize;
|
||||
return offsetof(struct btrfs_file_extent_item, disk_bytenr) + datasize;
|
||||
}
|
||||
|
||||
static inline u32 btrfs_file_extent_inline_len(struct btrfs_item *e)
|
||||
static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
|
||||
struct btrfs_item *e)
|
||||
{
|
||||
struct btrfs_file_extent_item *fe = NULL;
|
||||
return btrfs_item_size(e) - (unsigned long)(&fe->disk_bytenr);
|
||||
unsigned long offset;
|
||||
offset = offsetof(struct btrfs_file_extent_item, disk_bytenr);
|
||||
return btrfs_item_size(eb, e) - offset;
|
||||
}
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
|
||||
disk_bytenr, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(file_extent_generation, struct btrfs_file_extent_item,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(file_extent_disk_num_bytes,
|
||||
struct btrfs_file_extent_item, disk_num_bytes, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(file_extent_offset, struct btrfs_file_extent_item,
|
||||
offset, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item,
|
||||
num_bytes, 64);
|
||||
BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
|
||||
disk_bytenr, 64);
|
||||
BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item,
|
||||
disk_num_bytes, 64);
|
||||
BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item,
|
||||
offset, 64);
|
||||
BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item,
|
||||
num_bytes, 64);
|
||||
|
||||
/* helper function to cast into the data area of the leaf. */
|
||||
#define btrfs_item_ptr(leaf, slot, type) \
|
||||
((type *)(btrfs_leaf_data(leaf) + \
|
||||
btrfs_item_offset((leaf)->items + (slot))))
|
||||
#define btrfs_item_ptr_offset(leaf, slot) \
|
||||
((unsigned long)(btrfs_leaf_data(leaf) + \
|
||||
btrfs_item_offset_nr(leaf, slot)))
|
||||
|
||||
static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
|
||||
{
|
||||
static inline u32 btrfs_level_size(struct btrfs_root *root, int level) {
|
||||
if (level == 0)
|
||||
return root->leafsize;
|
||||
return root->nodesize;
|
||||
}
|
||||
int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2);
|
||||
struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u32 blocksize);
|
||||
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_buffer *buf);
|
||||
|
||||
/* helper function to cast into the data area of the leaf. */
|
||||
#define btrfs_item_ptr(leaf, slot, type) \
|
||||
((type *)(btrfs_leaf_data(leaf) + \
|
||||
btrfs_item_offset_nr(leaf, slot)))
|
||||
|
||||
#define btrfs_item_ptr_offset(leaf, slot) \
|
||||
((unsigned long)(btrfs_leaf_data(leaf) + \
|
||||
btrfs_item_offset_nr(leaf, slot)))
|
||||
|
||||
/* extent-tree.c */
|
||||
u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
|
||||
struct btrfs_path *count_path,
|
||||
u64 first_extent);
|
||||
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_map_tree *copy);
|
||||
struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
|
||||
btrfs_fs_info *info,
|
||||
u64 bytenr);
|
||||
struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
|
||||
struct btrfs_block_group_cache
|
||||
*hint, u64 search_start,
|
||||
int data, int owner);
|
||||
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 owner_objectid);
|
||||
struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u32 size,
|
||||
u64 root_objectid,
|
||||
u64 hint, u64 empty_size);
|
||||
struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u32 blocksize,
|
||||
u64 root_objectid,
|
||||
u64 ref_generation,
|
||||
u64 first_objectid,
|
||||
int level,
|
||||
u64 hint,
|
||||
u64 empty_size);
|
||||
int btrfs_grow_extent_tree(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 new_size);
|
||||
int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size);
|
||||
int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 bytenr,
|
||||
u64 root_objectid, u64 ref_generation,
|
||||
u64 owner, u64 owner_offset);
|
||||
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 num_bytes, u64 root_objectid, u64 ref_generation,
|
||||
u64 owner, u64 owner_offset,
|
||||
u64 empty_size, u64 hint_byte,
|
||||
u64 search_end, struct btrfs_key *ins, int data);
|
||||
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct extent_buffer *buf);
|
||||
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 bytenr, u64 num_bytes,
|
||||
u64 root_objectid, u64 root_generation,
|
||||
u64 owner, u64 owner_offset, int pin);
|
||||
u64 root_objectid, u64 ref_generation,
|
||||
u64 owner_objectid, u64 owner_offset, int pin);
|
||||
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct extent_map_tree *unpin);
|
||||
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 bytenr, u64 num_bytes,
|
||||
u64 root_objectid, u64 ref_generation,
|
||||
u64 owner, u64 owner_offset);
|
||||
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
int btrfs_free_block_groups(struct btrfs_fs_info *info);
|
||||
int btrfs_read_block_groups(struct btrfs_root *root);
|
||||
int btrfs_make_block_groups(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
u64 btrfs_hash_extent_ref(u64 root_objectid, u64 ref_generation,
|
||||
u64 owner, u64 owner_offset);
|
||||
int btrfs_update_block_group(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 bytenr, u64 num,
|
||||
int alloc, int mark_free, int data);
|
||||
/* ctree.c */
|
||||
int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2);
|
||||
int btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_buffer *buf,
|
||||
struct btrfs_buffer *parent, int parent_slot,
|
||||
struct btrfs_buffer **cow_ret);
|
||||
struct btrfs_root *root, struct extent_buffer *buf,
|
||||
struct extent_buffer *parent, int parent_slot,
|
||||
struct extent_buffer **cow_ret);
|
||||
int btrfs_copy_root(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct extent_buffer *buf,
|
||||
struct extent_buffer **cow_ret, u64 new_root_objectid);
|
||||
int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_path *path, u32 data_size);
|
||||
int btrfs_truncate_item(struct btrfs_trans_handle *trans,
|
||||
@ -640,7 +980,13 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
|
||||
int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_key *key, struct btrfs_path *p, int
|
||||
ins_len, int cow);
|
||||
int btrfs_realloc_node(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct extent_buffer *parent,
|
||||
int start_slot, int cache_only, u64 *last_ret,
|
||||
struct btrfs_key *progress);
|
||||
void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
|
||||
struct btrfs_path *btrfs_alloc_path(void);
|
||||
void btrfs_free_path(struct btrfs_path *p);
|
||||
void btrfs_init_path(struct btrfs_path *p);
|
||||
int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_path *path);
|
||||
@ -650,11 +996,13 @@ int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_path *path, struct btrfs_key
|
||||
*cpu_key, u32 data_size);
|
||||
int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
|
||||
int btrfs_leaf_free_space(struct btrfs_root *root, struct btrfs_leaf *leaf);
|
||||
int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
|
||||
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
|
||||
int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_buffer *snap);
|
||||
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
|
||||
btrfs_root *root);
|
||||
*root);
|
||||
|
||||
|
||||
/* root-item.c */
|
||||
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_key *key);
|
||||
int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
@ -665,12 +1013,23 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*item);
|
||||
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
|
||||
btrfs_root_item *item, struct btrfs_key *key);
|
||||
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid,
|
||||
struct btrfs_root *latest_root);
|
||||
/* dir-item.c */
|
||||
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, char *name, int name_len, u64 dir,
|
||||
*root, const char *name, int name_len, u64 dir,
|
||||
struct btrfs_key *location, u8 type);
|
||||
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
u64 dir, char *name, int name_len, int mod);
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 dir,
|
||||
const char *name, int name_len,
|
||||
int mod);
|
||||
struct btrfs_dir_item *
|
||||
btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 dir,
|
||||
u64 objectid, const char *name, int name_len,
|
||||
int mod);
|
||||
struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
const char *name, int name_len);
|
||||
@ -678,38 +1037,64 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
struct btrfs_dir_item *di);
|
||||
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);
|
||||
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 dir,
|
||||
const char *name, u16 name_len,
|
||||
int mod);
|
||||
/* inode-map.c */
|
||||
int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *fs_root,
|
||||
u64 dirid, u64 *objectid);
|
||||
int btrfs_insert_inode(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 objectid, struct btrfs_inode_item
|
||||
*inode_item);
|
||||
int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_path *path, u64 objectid, int mod);
|
||||
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
int btrfs_free_block_groups(struct btrfs_fs_info *info);
|
||||
int btrfs_read_block_groups(struct btrfs_root *root);
|
||||
int btrfs_insert_block_group(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_key *key,
|
||||
struct btrfs_block_group_item *bi);
|
||||
/* file-item.c */
|
||||
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 objectid, u64 pos, u64 offset,
|
||||
u64 disk_num_bytes, u64 num_bytes);
|
||||
int btrfs_insert_inline_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 objectid,
|
||||
u64 offset, char *buffer, size_t size);
|
||||
int btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_path *path, u64 objectid,
|
||||
u64 offset, int cow, struct btrfs_csum_item **item_ret);
|
||||
int btrfs_csum_file_block(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_inode_item *inode,
|
||||
u64 objectid, u64 offset, char *data, size_t len);
|
||||
int btrfs_find_highest_inode(struct btrfs_root *fs_root, u64 *objectid);
|
||||
|
||||
/* inode-item.c */
|
||||
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);
|
||||
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);
|
||||
int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 objectid);
|
||||
int btrfs_insert_inode(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 objectid, struct btrfs_inode_item
|
||||
*inode_item);
|
||||
int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_path *path,
|
||||
struct btrfs_key *location, int mod);
|
||||
|
||||
/* file-item.c */
|
||||
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 objectid, u64 pos, u64 offset,
|
||||
u64 disk_num_bytes,
|
||||
u64 num_bytes);
|
||||
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 objectid,
|
||||
u64 offset, char *buffer, size_t size);
|
||||
int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 objectid,
|
||||
u64 bytenr, int mod);
|
||||
int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_inode_item *inode,
|
||||
u64 objectid, u64 offset,
|
||||
char *data, size_t len);
|
||||
struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
u64 objectid, u64 offset,
|
||||
int cow);
|
||||
int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
u64 isize);
|
||||
#endif
|
||||
|
31
debug-tree.c
31
debug-tree.c
@ -27,12 +27,11 @@
|
||||
#include "transaction.h"
|
||||
|
||||
int main(int ac, char **av) {
|
||||
struct btrfs_super_block super;
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_path path;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_root_item *ri;
|
||||
struct btrfs_leaf *leaf;
|
||||
struct btrfs_root_item ri;
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_key found_key;
|
||||
char uuidbuf[37];
|
||||
int ret;
|
||||
@ -43,7 +42,7 @@ int main(int ac, char **av) {
|
||||
exit(1);
|
||||
}
|
||||
radix_tree_init();
|
||||
root = open_ctree(av[1], &super);
|
||||
root = open_ctree(av[1], 0);
|
||||
if (!root) {
|
||||
fprintf(stderr, "unable to open %s\n", av[1]);
|
||||
exit(1);
|
||||
@ -59,23 +58,23 @@ int main(int ac, char **av) {
|
||||
&key, &path, 0, 0);
|
||||
BUG_ON(ret < 0);
|
||||
while(1) {
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
leaf = path.nodes[0];
|
||||
slot = path.slots[0];
|
||||
if (slot >= btrfs_header_nritems(&leaf->header)) {
|
||||
if (slot >= btrfs_header_nritems(leaf)) {
|
||||
ret = btrfs_next_leaf(root, &path);
|
||||
if (ret != 0)
|
||||
break;
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
leaf = path.nodes[0];
|
||||
slot = path.slots[0];
|
||||
}
|
||||
btrfs_disk_key_to_cpu(&found_key,
|
||||
&leaf->items[path.slots[0]].key);
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path.slots[0]);
|
||||
if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) {
|
||||
struct btrfs_buffer *buf;
|
||||
ri = btrfs_item_ptr(leaf, path.slots[0],
|
||||
struct btrfs_root_item);
|
||||
unsigned long offset;
|
||||
struct extent_buffer *buf;
|
||||
offset = btrfs_item_ptr_offset(leaf, slot);
|
||||
read_extent_buffer(leaf, &ri, offset, sizeof(ri));
|
||||
buf = read_tree_block(root->fs_info->tree_root,
|
||||
btrfs_root_bytenr(ri),
|
||||
btrfs_root_bytenr(&ri),
|
||||
root->leafsize);
|
||||
switch(found_key.objectid) {
|
||||
case BTRFS_ROOT_TREE_OBJECTID:
|
||||
@ -95,11 +94,11 @@ int main(int ac, char **av) {
|
||||
}
|
||||
btrfs_release_path(root, &path);
|
||||
printf("total bytes %llu\n",
|
||||
(unsigned long long)btrfs_super_total_bytes(&super));
|
||||
(unsigned long long)btrfs_super_total_bytes(&root->fs_info->super_copy));
|
||||
printf("bytes used %llu\n",
|
||||
(unsigned long long)btrfs_super_bytes_used(&super));
|
||||
(unsigned long long)btrfs_super_bytes_used(&root->fs_info->super_copy));
|
||||
uuidbuf[36] = '\0';
|
||||
uuid_unparse(super.fsid, uuidbuf);
|
||||
uuid_unparse(root->fs_info->super_copy.fsid, uuidbuf);
|
||||
printf("uuid %s\n", uuidbuf);
|
||||
return 0;
|
||||
}
|
||||
|
280
dir-item.c
280
dir-item.c
@ -16,17 +16,13 @@
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "kerncompat.h"
|
||||
#include "radix-tree.h"
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "hash.h"
|
||||
#include "transaction.h"
|
||||
|
||||
static struct btrfs_dir_item *insert_with_overflow(struct
|
||||
btrfs_trans_handle *trans,
|
||||
static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
|
||||
*trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
struct btrfs_key *cpu_key,
|
||||
@ -37,110 +33,183 @@ static struct btrfs_dir_item *insert_with_overflow(struct
|
||||
int ret;
|
||||
char *ptr;
|
||||
struct btrfs_item *item;
|
||||
struct btrfs_leaf *leaf;
|
||||
struct extent_buffer *leaf;
|
||||
|
||||
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 NULL;
|
||||
return ERR_PTR(-EEXIST);
|
||||
ret = btrfs_extend_item(trans, root, path, data_size);
|
||||
WARN_ON(ret > 0);
|
||||
}
|
||||
BUG_ON(ret > 0);
|
||||
if (ret)
|
||||
return NULL;
|
||||
leaf = &path->nodes[0]->leaf;
|
||||
item = leaf->items + path->slots[0];
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
WARN_ON(ret > 0);
|
||||
leaf = path->nodes[0];
|
||||
item = btrfs_item_nr(leaf, path->slots[0]);
|
||||
ptr = btrfs_item_ptr(leaf, path->slots[0], char);
|
||||
BUG_ON(data_size > btrfs_item_size(item));
|
||||
ptr += btrfs_item_size(item) - data_size;
|
||||
BUG_ON(data_size > btrfs_item_size(leaf, item));
|
||||
ptr += btrfs_item_size(leaf, item) - data_size;
|
||||
return (struct btrfs_dir_item *)ptr;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = btrfs_name_hash(name, name_len, &key.offset);
|
||||
BUG_ON(ret);
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, char *name, int name_len, u64 dir,
|
||||
*root, const char *name, int name_len, u64 dir,
|
||||
struct btrfs_key *location, u8 type)
|
||||
{
|
||||
int ret = 0;
|
||||
struct btrfs_path path;
|
||||
int ret2 = 0;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_dir_item *dir_item;
|
||||
char *name_ptr;
|
||||
struct extent_buffer *leaf;
|
||||
unsigned long name_ptr;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_disk_key disk_key;
|
||||
u32 data_size;
|
||||
|
||||
key.objectid = dir;
|
||||
btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
|
||||
if (name_len == 1 && *name == '.')
|
||||
key.offset = 1;
|
||||
else if (name_len == 2 && name[0] == '.' && name[1] == '.')
|
||||
key.offset = 2;
|
||||
else
|
||||
ret = btrfs_name_hash(name, name_len, &key.offset);
|
||||
ret = btrfs_name_hash(name, name_len, &key.offset);
|
||||
BUG_ON(ret);
|
||||
btrfs_init_path(&path);
|
||||
path = btrfs_alloc_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 (!dir_item) {
|
||||
ret = -1;
|
||||
if (IS_ERR(dir_item)) {
|
||||
ret = PTR_ERR(dir_item);
|
||||
if (ret == -EEXIST)
|
||||
goto second_insert;
|
||||
goto out;
|
||||
}
|
||||
btrfs_cpu_key_to_disk(&dir_item->location, location);
|
||||
btrfs_set_dir_type(dir_item, type);
|
||||
btrfs_set_dir_name_len(dir_item, name_len);
|
||||
btrfs_set_dir_data_len(dir_item, 0);
|
||||
name_ptr = (char *)(dir_item + 1);
|
||||
memcpy(name_ptr, name, name_len);
|
||||
|
||||
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, type);
|
||||
btrfs_set_dir_data_len(leaf, dir_item, 0);
|
||||
btrfs_set_dir_name_len(leaf, dir_item, name_len);
|
||||
name_ptr = (unsigned long)(dir_item + 1);
|
||||
|
||||
write_extent_buffer(leaf, name, name_ptr, name_len);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
|
||||
second_insert:
|
||||
/* FIXME, use some real flag for selecting the extra index */
|
||||
if (root == root->fs_info->tree_root)
|
||||
if (root == root->fs_info->tree_root) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
btrfs_release_path(root, path);
|
||||
|
||||
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 (!dir_item) {
|
||||
ret = -1;
|
||||
if (IS_ERR(dir_item)) {
|
||||
ret2 = PTR_ERR(dir_item);
|
||||
goto out;
|
||||
}
|
||||
btrfs_cpu_key_to_disk(&dir_item->location, location);
|
||||
btrfs_set_dir_type(dir_item, type);
|
||||
btrfs_set_dir_name_len(dir_item, name_len);
|
||||
btrfs_set_dir_data_len(dir_item, 0);
|
||||
name_ptr = (char *)(dir_item + 1);
|
||||
memcpy(name_ptr, name, name_len);
|
||||
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, type);
|
||||
btrfs_set_dir_data_len(leaf, dir_item, 0);
|
||||
btrfs_set_dir_name_len(leaf, dir_item, name_len);
|
||||
name_ptr = (unsigned long)(dir_item + 1);
|
||||
write_extent_buffer(leaf, name, name_ptr, name_len);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
out:
|
||||
btrfs_release_path(root, &path);
|
||||
return ret;
|
||||
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,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 dir,
|
||||
char *name, int name_len, int mod)
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 dir,
|
||||
const char *name, int name_len,
|
||||
int mod)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_key key;
|
||||
int ins_len = mod < 0 ? -1 : 0;
|
||||
int cow = mod != 0;
|
||||
struct btrfs_key found_key;
|
||||
struct btrfs_leaf *leaf;
|
||||
struct extent_buffer *leaf;
|
||||
|
||||
key.objectid = dir;
|
||||
btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
|
||||
|
||||
ret = btrfs_name_hash(name, name_len, &key.offset);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
return ERR_PTR(ret);
|
||||
if (ret > 0) {
|
||||
if (path->slots[0] == 0)
|
||||
return NULL;
|
||||
path->slots[0]--;
|
||||
}
|
||||
|
||||
leaf = &path->nodes[0]->leaf;
|
||||
btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key);
|
||||
leaf = path->nodes[0];
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||
|
||||
if (found_key.objectid != dir ||
|
||||
btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY ||
|
||||
@ -150,27 +219,89 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
|
||||
return btrfs_match_dir_item_name(root, path, name, name_len);
|
||||
}
|
||||
|
||||
struct btrfs_dir_item *
|
||||
btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 dir,
|
||||
u64 objectid, const char *name, int name_len,
|
||||
int mod)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_key key;
|
||||
int ins_len = mod < 0 ? -1 : 0;
|
||||
int cow = mod != 0;
|
||||
|
||||
key.objectid = dir;
|
||||
btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
|
||||
key.offset = objectid;
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
if (ret > 0)
|
||||
return ERR_PTR(-ENOENT);
|
||||
return btrfs_match_dir_item_name(root, path, name, name_len);
|
||||
}
|
||||
|
||||
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 dir,
|
||||
const char *name, u16 name_len,
|
||||
int mod)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_key key;
|
||||
int ins_len = mod < 0 ? -1 : 0;
|
||||
int cow = mod != 0;
|
||||
struct btrfs_key found_key;
|
||||
struct extent_buffer *leaf;
|
||||
|
||||
key.objectid = dir;
|
||||
btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
|
||||
ret = btrfs_name_hash(name, name_len, &key.offset);
|
||||
BUG_ON(ret);
|
||||
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
if (ret > 0) {
|
||||
if (path->slots[0] == 0)
|
||||
return NULL;
|
||||
path->slots[0]--;
|
||||
}
|
||||
|
||||
leaf = path->nodes[0];
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||
|
||||
if (found_key.objectid != dir ||
|
||||
btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY ||
|
||||
found_key.offset != key.offset)
|
||||
return NULL;
|
||||
|
||||
return btrfs_match_dir_item_name(root, path, name, name_len);
|
||||
}
|
||||
|
||||
struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
const char *name, int name_len)
|
||||
{
|
||||
struct btrfs_dir_item *dir_item;
|
||||
unsigned long name_ptr;
|
||||
u32 total_len;
|
||||
u32 cur = 0;
|
||||
u32 this_len;
|
||||
u32 total_len;
|
||||
char *name_ptr;
|
||||
struct btrfs_leaf *leaf;
|
||||
struct btrfs_dir_item *dir_item;
|
||||
struct extent_buffer *leaf;
|
||||
|
||||
leaf = &path->nodes[0]->leaf;
|
||||
leaf = path->nodes[0];
|
||||
dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
|
||||
total_len = btrfs_item_size(leaf->items + path->slots[0]);
|
||||
total_len = btrfs_item_size_nr(leaf, path->slots[0]);
|
||||
while(cur < total_len) {
|
||||
this_len = sizeof(*dir_item) + btrfs_dir_name_len(dir_item) +
|
||||
btrfs_dir_data_len(dir_item);
|
||||
name_ptr = (char *)(dir_item + 1);
|
||||
this_len = sizeof(*dir_item) +
|
||||
btrfs_dir_name_len(leaf, dir_item) +
|
||||
btrfs_dir_data_len(leaf, dir_item);
|
||||
name_ptr = (unsigned long)(dir_item + 1);
|
||||
|
||||
if (btrfs_dir_name_len(dir_item) == name_len &&
|
||||
memcmp(name, name_ptr, name_len) == 0)
|
||||
if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
|
||||
memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
|
||||
return dir_item;
|
||||
|
||||
cur += this_len;
|
||||
@ -186,21 +317,24 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_dir_item *di)
|
||||
{
|
||||
|
||||
struct btrfs_leaf *leaf;
|
||||
struct extent_buffer *leaf;
|
||||
u32 sub_item_len;
|
||||
u32 item_len;
|
||||
int ret = 0;
|
||||
|
||||
leaf = &path->nodes[0]->leaf;
|
||||
sub_item_len = sizeof(*di) + btrfs_dir_name_len(di) +
|
||||
btrfs_dir_data_len(di);
|
||||
item_len = btrfs_item_size(leaf->items + path->slots[0]);
|
||||
leaf = path->nodes[0];
|
||||
sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
|
||||
btrfs_dir_data_len(leaf, di);
|
||||
item_len = btrfs_item_size_nr(leaf, path->slots[0]);
|
||||
if (sub_item_len == item_len) {
|
||||
ret = btrfs_del_item(trans, root, path);
|
||||
} else {
|
||||
char *ptr = (char *)di;
|
||||
char *start = btrfs_item_ptr(leaf, path->slots[0], char);
|
||||
memmove(ptr, ptr + sub_item_len,
|
||||
/* MARKER */
|
||||
unsigned long ptr = (unsigned long)di;
|
||||
unsigned long start;
|
||||
|
||||
start = btrfs_item_ptr_offset(leaf, path->slots[0]);
|
||||
memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
|
||||
item_len - (ptr + sub_item_len - start));
|
||||
ret = btrfs_truncate_item(trans, root, path,
|
||||
item_len - sub_item_len, 1);
|
||||
|
711
disk-io.c
711
disk-io.c
@ -31,215 +31,130 @@
|
||||
#include "transaction.h"
|
||||
#include "crc32c.h"
|
||||
|
||||
static u64 allocated_bytes = 0;
|
||||
int cache_max = 10000;
|
||||
|
||||
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct btrfs_buffer *bh,
|
||||
u64 logical)
|
||||
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct extent_buffer *buf,
|
||||
u64 logical)
|
||||
{
|
||||
bh->fd = root->fs_info->fp;
|
||||
bh->dev_bytenr = logical;
|
||||
buf->fd = root->fs_info->fp;
|
||||
buf->dev_bytenr = logical;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf)
|
||||
static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
|
||||
{
|
||||
if (buf->bytenr != btrfs_header_bytenr(&buf->node.header))
|
||||
if (buf->start != btrfs_header_bytenr(buf))
|
||||
BUG();
|
||||
if (memcmp(root->fs_info->disk_super->fsid, buf->node.header.fsid,
|
||||
sizeof(buf->node.header.fsid)))
|
||||
|
||||
if (memcmp_extent_buffer(buf, root->fs_info->fsid,
|
||||
(unsigned long)btrfs_header_fsid(buf),
|
||||
BTRFS_FSID_SIZE))
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int free_some_buffers(struct btrfs_root *root)
|
||||
u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len)
|
||||
{
|
||||
struct list_head *node, *next;
|
||||
struct btrfs_buffer *b;
|
||||
if (root->fs_info->cache_size < cache_max)
|
||||
return 0;
|
||||
list_for_each_safe(node, next, &root->fs_info->cache) {
|
||||
b = list_entry(node, struct btrfs_buffer, cache);
|
||||
if (b->count == 1) {
|
||||
BUG_ON(!list_empty(&b->dirty));
|
||||
list_del_init(&b->cache);
|
||||
btrfs_block_release(root, b);
|
||||
if (root->fs_info->cache_size < cache_max)
|
||||
break;
|
||||
return crc32c(seed, data, len);
|
||||
}
|
||||
|
||||
void btrfs_csum_final(u32 crc, char *result)
|
||||
{
|
||||
*(__le32 *)result = ~cpu_to_le32(crc);
|
||||
}
|
||||
|
||||
static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
|
||||
int verify)
|
||||
{
|
||||
char result[BTRFS_CRC32_SIZE];
|
||||
u32 len;
|
||||
u32 crc = ~(u32)0;
|
||||
|
||||
len = buf->len - BTRFS_CSUM_SIZE;
|
||||
crc = crc32c(crc, buf->data + BTRFS_CSUM_SIZE, len);
|
||||
btrfs_csum_final(crc, result);
|
||||
|
||||
if (verify) {
|
||||
if (memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) {
|
||||
printk("checksum verify failed on %llu\n", buf->start);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
write_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize)
|
||||
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
|
||||
u64 bytenr, u32 blocksize)
|
||||
{
|
||||
return find_extent_buffer(&root->fs_info->extent_cache,
|
||||
bytenr, blocksize);
|
||||
}
|
||||
|
||||
struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
|
||||
u64 bytenr, u32 blocksize)
|
||||
{
|
||||
return alloc_extent_buffer(&root->fs_info->extent_cache, bytenr,
|
||||
blocksize);
|
||||
}
|
||||
|
||||
int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize)
|
||||
{
|
||||
struct btrfs_buffer *buf;
|
||||
int ret;
|
||||
struct extent_buffer *eb;
|
||||
|
||||
buf = malloc(sizeof(struct btrfs_buffer) + blocksize);
|
||||
if (!buf)
|
||||
return buf;
|
||||
allocated_bytes += blocksize;
|
||||
|
||||
buf->bytenr = bytenr;
|
||||
buf->count = 2;
|
||||
buf->size = blocksize;
|
||||
buf->cache_node.start = bytenr;
|
||||
buf->cache_node.size = blocksize;
|
||||
|
||||
INIT_LIST_HEAD(&buf->dirty);
|
||||
free_some_buffers(root);
|
||||
|
||||
ret = insert_existing_cache_extent(&root->fs_info->extent_cache,
|
||||
&buf->cache_node);
|
||||
|
||||
list_add_tail(&buf->cache, &root->fs_info->cache);
|
||||
root->fs_info->cache_size += blocksize;
|
||||
if (ret) {
|
||||
free(buf);
|
||||
eb = btrfs_find_create_tree_block(root, bytenr, blocksize);
|
||||
if (!eb)
|
||||
return NULL;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize)
|
||||
{
|
||||
struct btrfs_buffer *buf;
|
||||
struct cache_extent *cache;
|
||||
|
||||
cache = find_cache_extent(&root->fs_info->extent_cache,
|
||||
bytenr, blocksize);
|
||||
if (cache) {
|
||||
buf = container_of(cache, struct btrfs_buffer, cache_node);
|
||||
buf->count++;
|
||||
} else {
|
||||
buf = alloc_tree_block(root, bytenr, blocksize);
|
||||
if (!buf) {
|
||||
BUG();
|
||||
if (!btrfs_buffer_uptodate(eb)) {
|
||||
btrfs_map_bh_to_logical(root, eb, eb->start);
|
||||
ret = read_extent_from_disk(eb);
|
||||
if (ret) {
|
||||
free_extent_buffer(eb);
|
||||
return NULL;
|
||||
}
|
||||
btrfs_set_buffer_uptodate(eb);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize)
|
||||
{
|
||||
struct btrfs_buffer *buf;
|
||||
int ret;
|
||||
struct cache_extent *cache;
|
||||
|
||||
cache = find_cache_extent(&root->fs_info->extent_cache,
|
||||
bytenr, blocksize);
|
||||
if (cache) {
|
||||
buf = container_of(cache, struct btrfs_buffer, cache_node);
|
||||
buf->count++;
|
||||
if (check_tree_block(root, buf))
|
||||
BUG();
|
||||
} else {
|
||||
buf = alloc_tree_block(root, bytenr, blocksize);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
btrfs_map_bh_to_logical(root, buf, bytenr);
|
||||
ret = pread(buf->fd, &buf->node, blocksize,
|
||||
buf->dev_bytenr);
|
||||
if (ret != blocksize) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
if (check_tree_block(root, buf))
|
||||
BUG();
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_buffer *buf)
|
||||
{
|
||||
if (!list_empty(&buf->dirty))
|
||||
return 0;
|
||||
list_add_tail(&buf->dirty, &root->fs_info->trans);
|
||||
buf->count++;
|
||||
if (check_tree_block(root, buf))
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_buffer *buf)
|
||||
{
|
||||
if (!list_empty(&buf->dirty)) {
|
||||
list_del_init(&buf->dirty);
|
||||
btrfs_block_release(root, buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_csum_node(struct btrfs_root *root, struct btrfs_node *node)
|
||||
{
|
||||
u32 crc = ~(u32)0;
|
||||
size_t len = btrfs_level_size(root, btrfs_header_level(&node->header)) -
|
||||
BTRFS_CSUM_SIZE;
|
||||
|
||||
crc = crc32c(crc, (char *)(node) + BTRFS_CSUM_SIZE, len);
|
||||
crc = ~cpu_to_le32(crc);
|
||||
memcpy(node->header.csum, &crc, BTRFS_CRC32_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_csum_super(struct btrfs_root *root, struct btrfs_super_block *super)
|
||||
{
|
||||
u32 crc = ~(u32)0;
|
||||
char block[512];
|
||||
size_t len = 512 - BTRFS_CSUM_SIZE;
|
||||
|
||||
memset(block, 0, 512);
|
||||
memcpy(block, super, sizeof(*super));
|
||||
|
||||
crc = crc32c(crc, block + BTRFS_CSUM_SIZE, len);
|
||||
crc = ~cpu_to_le32(crc);
|
||||
memcpy(super->csum, &crc, BTRFS_CRC32_SIZE);
|
||||
return 0;
|
||||
return eb;
|
||||
}
|
||||
|
||||
int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_buffer *buf)
|
||||
struct extent_buffer *eb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (buf->bytenr != btrfs_header_bytenr(&buf->node.header))
|
||||
if (check_tree_block(root, eb))
|
||||
BUG();
|
||||
btrfs_map_bh_to_logical(root, buf, buf->bytenr);
|
||||
if (check_tree_block(root, buf))
|
||||
if (!btrfs_buffer_uptodate(eb))
|
||||
BUG();
|
||||
|
||||
btrfs_csum_node(root, &buf->node);
|
||||
|
||||
ret = pwrite(buf->fd, &buf->node, buf->size,
|
||||
buf->dev_bytenr);
|
||||
if (ret != buf->size)
|
||||
return ret;
|
||||
return 0;
|
||||
btrfs_map_bh_to_logical(root, eb, eb->start);
|
||||
csum_tree_block(root, eb, 0);
|
||||
return write_extent_to_disk(eb);
|
||||
}
|
||||
|
||||
static int __commit_transaction(struct btrfs_trans_handle *trans, struct
|
||||
btrfs_root *root)
|
||||
static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||
u32 stripesize, struct btrfs_root *root,
|
||||
struct btrfs_fs_info *fs_info, u64 objectid)
|
||||
{
|
||||
struct btrfs_buffer *b;
|
||||
int ret = 0;
|
||||
int wret;
|
||||
while(!list_empty(&root->fs_info->trans)) {
|
||||
b = list_entry(root->fs_info->trans.next, struct btrfs_buffer,
|
||||
dirty);
|
||||
list_del_init(&b->dirty);
|
||||
wret = write_tree_block(trans, root, b);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
btrfs_block_release(root, b);
|
||||
}
|
||||
return ret;
|
||||
root->node = NULL;
|
||||
root->commit_root = NULL;
|
||||
root->sectorsize = sectorsize;
|
||||
root->nodesize = nodesize;
|
||||
root->leafsize = leafsize;
|
||||
root->stripesize = stripesize;
|
||||
root->ref_cows = 0;
|
||||
root->fs_info = fs_info;
|
||||
root->objectid = objectid;
|
||||
root->last_trans = 0;
|
||||
root->highest_inode = 0;
|
||||
root->last_inode_alloc = 0;
|
||||
memset(&root->root_key, 0, sizeof(root->root_key));
|
||||
memset(&root->root_item, 0, sizeof(root->root_item));
|
||||
root->root_key.objectid = objectid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int commit_tree_roots(struct btrfs_trans_handle *trans,
|
||||
@ -253,12 +168,12 @@ static int commit_tree_roots(struct btrfs_trans_handle *trans,
|
||||
btrfs_write_dirty_block_groups(trans, fs_info->extent_root);
|
||||
while(1) {
|
||||
old_extent_bytenr = btrfs_root_bytenr(&extent_root->root_item);
|
||||
if (old_extent_bytenr == extent_root->node->bytenr)
|
||||
if (old_extent_bytenr == extent_root->node->start)
|
||||
break;
|
||||
btrfs_set_root_bytenr(&extent_root->root_item,
|
||||
extent_root->node->bytenr);
|
||||
extent_root->node->start);
|
||||
extent_root->root_item.level =
|
||||
btrfs_header_level(&extent_root->node->node.header);
|
||||
btrfs_header_level(extent_root->node);
|
||||
ret = btrfs_update_root(trans, tree_root,
|
||||
&extent_root->root_key,
|
||||
&extent_root->root_item);
|
||||
@ -268,96 +183,187 @@ static int commit_tree_roots(struct btrfs_trans_handle *trans,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct
|
||||
btrfs_root *root, struct btrfs_super_block *s)
|
||||
static int __commit_transaction(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
int ret = 0;
|
||||
struct btrfs_buffer *snap = root->commit_root;
|
||||
struct btrfs_key snap_key;
|
||||
u64 start;
|
||||
u64 end;
|
||||
struct extent_buffer *eb;
|
||||
struct extent_map_tree *tree = &root->fs_info->extent_cache;
|
||||
int ret;
|
||||
|
||||
if (root->commit_root == root->node)
|
||||
return 0;
|
||||
|
||||
memcpy(&snap_key, &root->root_key, sizeof(snap_key));
|
||||
root->root_key.offset = trans->transid;
|
||||
|
||||
btrfs_set_root_bytenr(&root->root_item, root->node->bytenr);
|
||||
root->root_item.level =
|
||||
btrfs_header_level(&root->node->node.header);
|
||||
ret = btrfs_insert_root(trans, root->fs_info->tree_root,
|
||||
&root->root_key, &root->root_item);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = commit_tree_roots(trans, root->fs_info);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = __commit_transaction(trans, root);
|
||||
BUG_ON(ret);
|
||||
|
||||
write_ctree_super(trans, root, s);
|
||||
btrfs_finish_extent_commit(trans, root->fs_info->extent_root);
|
||||
btrfs_finish_extent_commit(trans, root->fs_info->tree_root);
|
||||
|
||||
root->commit_root = root->node;
|
||||
root->node->count++;
|
||||
ret = btrfs_drop_snapshot(trans, root, snap);
|
||||
BUG_ON(ret);
|
||||
ret = btrfs_del_root(trans, root->fs_info->tree_root, &snap_key);
|
||||
BUG_ON(ret);
|
||||
btrfs_free_transaction(root, trans);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __setup_root(struct btrfs_super_block *super,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
u64 objectid, int fp)
|
||||
{
|
||||
root->node = NULL;
|
||||
root->commit_root = NULL;
|
||||
root->sectorsize = btrfs_super_sectorsize(super);
|
||||
root->nodesize = btrfs_super_nodesize(super);
|
||||
root->leafsize = btrfs_super_leafsize(super);
|
||||
root->stripesize = btrfs_super_stripesize(super);
|
||||
root->ref_cows = 0;
|
||||
root->fs_info = fs_info;
|
||||
memset(&root->root_key, 0, sizeof(root->root_key));
|
||||
memset(&root->root_item, 0, sizeof(root->root_item));
|
||||
root->root_key.objectid = objectid;
|
||||
while(1) {
|
||||
ret = find_first_extent_bit(tree, 0, &start, &end,
|
||||
EXTENT_DIRTY);
|
||||
if (ret)
|
||||
break;
|
||||
while(start <= end) {
|
||||
eb = find_first_extent_buffer(tree, start);
|
||||
BUG_ON(!eb || eb->start != start);
|
||||
ret = write_tree_block(trans, root, eb);
|
||||
BUG_ON(ret);
|
||||
start += eb->len;
|
||||
clear_extent_buffer_dirty(eb);
|
||||
free_extent_buffer(eb);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct btrfs_buffer *read_root_block(struct btrfs_root *root, u64 bytenr,
|
||||
u8 level)
|
||||
int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_buffer *node;
|
||||
u32 size = btrfs_level_size(root, level);
|
||||
int ret = 0;
|
||||
struct btrfs_root *new_root = NULL;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
|
||||
node = read_tree_block(root, bytenr, size);
|
||||
BUG_ON(!node);
|
||||
return node;
|
||||
if (root->commit_root == root->node)
|
||||
goto commit_tree;
|
||||
|
||||
new_root = malloc(sizeof(*new_root));
|
||||
if (!new_root)
|
||||
return -ENOMEM;
|
||||
memcpy(new_root, root, sizeof(*new_root));
|
||||
new_root->node = root->commit_root;
|
||||
root->commit_root = NULL;
|
||||
|
||||
root->root_key.offset = trans->transid;
|
||||
btrfs_set_root_bytenr(&root->root_item, root->node->start);
|
||||
root->root_item.level = btrfs_header_level(root->node);
|
||||
ret = btrfs_insert_root(trans, fs_info->tree_root,
|
||||
&root->root_key, &root->root_item);
|
||||
BUG_ON(ret);
|
||||
|
||||
btrfs_set_root_refs(&new_root->root_item, 0);
|
||||
ret = btrfs_update_root(trans, root->fs_info->tree_root,
|
||||
&new_root->root_key, &new_root->root_item);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = commit_tree_roots(trans, fs_info);
|
||||
BUG_ON(ret);
|
||||
ret = __commit_transaction(trans, root);
|
||||
BUG_ON(ret);
|
||||
write_ctree_super(trans, root);
|
||||
btrfs_finish_extent_commit(trans, fs_info->extent_root,
|
||||
&fs_info->pinned_extents);
|
||||
btrfs_free_transaction(root, trans);
|
||||
fs_info->running_transaction = NULL;
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
ret = btrfs_drop_snapshot(trans, new_root);
|
||||
BUG_ON(ret);
|
||||
ret = btrfs_del_root(trans, fs_info->tree_root, &new_root->root_key);
|
||||
BUG_ON(ret);
|
||||
commit_tree:
|
||||
ret = commit_tree_roots(trans, fs_info);
|
||||
BUG_ON(ret);
|
||||
ret = __commit_transaction(trans, root);
|
||||
BUG_ON(ret);
|
||||
write_ctree_super(trans, root);
|
||||
btrfs_finish_extent_commit(trans, fs_info->extent_root,
|
||||
&fs_info->pinned_extents);
|
||||
btrfs_free_transaction(root, trans);
|
||||
free_extent_buffer(root->commit_root);
|
||||
root->commit_root = NULL;
|
||||
fs_info->running_transaction = NULL;
|
||||
if (new_root) {
|
||||
free_extent_buffer(new_root->node);
|
||||
free(new_root);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_and_setup_root(struct btrfs_super_block *super,
|
||||
struct btrfs_root *tree_root,
|
||||
static int find_and_setup_root(struct btrfs_root *tree_root,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
u64 objectid,
|
||||
struct btrfs_root *root, int fp)
|
||||
u64 objectid, struct btrfs_root *root)
|
||||
{
|
||||
int ret;
|
||||
u32 blocksize;
|
||||
|
||||
__setup_root(super, root, fs_info, objectid, fp);
|
||||
__setup_root(tree_root->nodesize, tree_root->leafsize,
|
||||
tree_root->sectorsize, tree_root->stripesize,
|
||||
root, fs_info, objectid);
|
||||
ret = btrfs_find_last_root(tree_root, objectid,
|
||||
&root->root_item, &root->root_key);
|
||||
BUG_ON(ret);
|
||||
root->node = read_root_block(root,
|
||||
btrfs_root_bytenr(&root->root_item),
|
||||
root->root_item.level);
|
||||
|
||||
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
|
||||
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
|
||||
blocksize);
|
||||
BUG_ON(!root->node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super)
|
||||
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
|
||||
{
|
||||
if (root->node)
|
||||
free_extent_buffer(root->node);
|
||||
if (root->commit_root)
|
||||
free_extent_buffer(root->commit_root);
|
||||
|
||||
free(root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_key *location)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_root *tree_root = fs_info->tree_root;
|
||||
struct btrfs_path *path;
|
||||
struct extent_buffer *l;
|
||||
u32 blocksize;
|
||||
int ret = 0;
|
||||
|
||||
root = malloc(sizeof(*root));
|
||||
if (!root)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
memset(root, 0, sizeof(*root));
|
||||
if (location->offset == (u64)-1) {
|
||||
ret = find_and_setup_root(tree_root, fs_info,
|
||||
location->objectid, root);
|
||||
if (ret) {
|
||||
free(root);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
goto insert;
|
||||
}
|
||||
|
||||
__setup_root(tree_root->nodesize, tree_root->leafsize,
|
||||
tree_root->sectorsize, tree_root->stripesize,
|
||||
root, fs_info, location->objectid);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
|
||||
if (ret != 0) {
|
||||
if (ret > 0)
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
l = path->nodes[0];
|
||||
read_extent_buffer(l, &root->root_item,
|
||||
btrfs_item_ptr_offset(l, path->slots[0]),
|
||||
sizeof(root->root_item));
|
||||
memcpy(&root->root_key, location, sizeof(*location));
|
||||
ret = 0;
|
||||
out:
|
||||
btrfs_release_path(root, path);
|
||||
btrfs_free_path(path);
|
||||
if (ret) {
|
||||
free(root);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
|
||||
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
|
||||
blocksize);
|
||||
BUG_ON(!root->node);
|
||||
insert:
|
||||
root->ref_cows = 1;
|
||||
return root;
|
||||
}
|
||||
|
||||
struct btrfs_root *open_ctree(char *filename, u64 sb_bytenr)
|
||||
{
|
||||
int fp;
|
||||
|
||||
@ -365,145 +371,164 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super)
|
||||
if (fp < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return open_ctree_fd(fp, super);
|
||||
return open_ctree_fd(fp, sb_bytenr);
|
||||
}
|
||||
|
||||
struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super)
|
||||
struct btrfs_root *open_ctree_fd(int fp, u64 sb_bytenr)
|
||||
{
|
||||
u32 sectorsize;
|
||||
u32 nodesize;
|
||||
u32 leafsize;
|
||||
u32 blocksize;
|
||||
u32 stripesize;
|
||||
struct btrfs_root *root = malloc(sizeof(struct btrfs_root));
|
||||
struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root));
|
||||
struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root));
|
||||
struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root));
|
||||
struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info));
|
||||
int ret;
|
||||
struct btrfs_super_block *disk_super;
|
||||
|
||||
if (sb_bytenr == 0)
|
||||
sb_bytenr = BTRFS_SUPER_INFO_OFFSET;
|
||||
|
||||
INIT_LIST_HEAD(&fs_info->trans);
|
||||
INIT_LIST_HEAD(&fs_info->cache);
|
||||
cache_tree_init(&fs_info->extent_cache);
|
||||
cache_tree_init(&fs_info->pending_tree);
|
||||
cache_tree_init(&fs_info->pinned_tree);
|
||||
cache_tree_init(&fs_info->del_pending);
|
||||
cache_tree_init(&fs_info->block_group_cache);
|
||||
fs_info->cache_size = 0;
|
||||
fs_info->fp = fp;
|
||||
fs_info->running_transaction = NULL;
|
||||
fs_info->fs_root = root;
|
||||
fs_info->tree_root = tree_root;
|
||||
fs_info->extent_root = extent_root;
|
||||
fs_info->last_inode_alloc = 0;
|
||||
fs_info->last_inode_alloc_dirid = 0;
|
||||
fs_info->disk_super = super;
|
||||
memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert));
|
||||
|
||||
ret = pread(fp, super, sizeof(struct btrfs_super_block),
|
||||
BTRFS_SUPER_INFO_OFFSET);
|
||||
if (ret == 0 || btrfs_super_root(super) == 0) {
|
||||
BUG();
|
||||
return NULL;
|
||||
}
|
||||
BUG_ON(ret < 0);
|
||||
extent_map_tree_init(&fs_info->extent_cache);
|
||||
extent_map_tree_init(&fs_info->free_space_cache);
|
||||
extent_map_tree_init(&fs_info->pending_tree);
|
||||
extent_map_tree_init(&fs_info->pinned_extents);
|
||||
extent_map_tree_init(&fs_info->del_pending);
|
||||
extent_map_tree_init(&fs_info->block_group_cache);
|
||||
|
||||
__setup_root(super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID, fp);
|
||||
tree_root->node = read_root_block(tree_root, btrfs_super_root(super),
|
||||
btrfs_super_root_level(super));
|
||||
mutex_init(&fs_info->fs_mutex);
|
||||
|
||||
__setup_root(512, 512, 512, 512, tree_root,
|
||||
fs_info, BTRFS_ROOT_TREE_OBJECTID);
|
||||
|
||||
fs_info->sb_buffer = read_tree_block(tree_root, sb_bytenr, 512);
|
||||
BUG_ON(!fs_info->sb_buffer);
|
||||
read_extent_buffer(fs_info->sb_buffer, &fs_info->super_copy, 0,
|
||||
sizeof(fs_info->super_copy));
|
||||
read_extent_buffer(fs_info->sb_buffer, fs_info->fsid,
|
||||
(unsigned long)btrfs_super_fsid(fs_info->sb_buffer),
|
||||
BTRFS_FSID_SIZE);
|
||||
disk_super = &fs_info->super_copy;
|
||||
|
||||
nodesize = btrfs_super_nodesize(disk_super);
|
||||
leafsize = btrfs_super_leafsize(disk_super);
|
||||
sectorsize = btrfs_super_sectorsize(disk_super);
|
||||
stripesize = btrfs_super_stripesize(disk_super);
|
||||
tree_root->nodesize = nodesize;
|
||||
tree_root->leafsize = leafsize;
|
||||
tree_root->sectorsize = sectorsize;
|
||||
tree_root->stripesize = stripesize;
|
||||
|
||||
blocksize = btrfs_level_size(tree_root,
|
||||
btrfs_super_root_level(disk_super));
|
||||
tree_root->node = read_tree_block(tree_root,
|
||||
btrfs_super_root(disk_super),
|
||||
blocksize);
|
||||
BUG_ON(!tree_root->node);
|
||||
|
||||
ret = find_and_setup_root(super, tree_root, fs_info,
|
||||
BTRFS_EXTENT_TREE_OBJECTID, extent_root, fp);
|
||||
ret = find_and_setup_root(tree_root, fs_info,
|
||||
BTRFS_EXTENT_TREE_OBJECTID, extent_root);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = find_and_setup_root(super, tree_root, fs_info,
|
||||
BTRFS_FS_TREE_OBJECTID, root, fp);
|
||||
ret = find_and_setup_root(tree_root, fs_info,
|
||||
BTRFS_FS_TREE_OBJECTID, root);
|
||||
BUG_ON(ret);
|
||||
|
||||
root->commit_root = root->node;
|
||||
root->node->count++;
|
||||
root->ref_cows = 1;
|
||||
root->fs_info->generation = btrfs_super_generation(super) + 1;
|
||||
fs_info->generation = btrfs_super_generation(disk_super) + 1;
|
||||
btrfs_read_block_groups(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_super_block *s)
|
||||
int write_ctree_super(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
int ret;
|
||||
btrfs_set_super_root(s, root->fs_info->tree_root->node->bytenr);
|
||||
btrfs_set_super_generation(s, trans->transid);
|
||||
btrfs_set_super_root_level(s,
|
||||
btrfs_header_level(&root->fs_info->tree_root->node->node.header));
|
||||
btrfs_csum_super(root, s);
|
||||
|
||||
ret = pwrite(root->fs_info->fp, s, sizeof(*s),
|
||||
BTRFS_SUPER_INFO_OFFSET);
|
||||
if (ret != sizeof(*s)) {
|
||||
struct btrfs_root *tree_root = root->fs_info->tree_root;
|
||||
btrfs_set_super_generation(&root->fs_info->super_copy,
|
||||
trans->transid);
|
||||
btrfs_set_super_root(&root->fs_info->super_copy,
|
||||
tree_root->node->start);
|
||||
btrfs_set_super_root_level(&root->fs_info->super_copy,
|
||||
btrfs_header_level(tree_root->node));
|
||||
write_extent_buffer(root->fs_info->sb_buffer,
|
||||
&root->fs_info->super_copy, 0,
|
||||
sizeof(root->fs_info->super_copy));
|
||||
ret = write_tree_block(trans, root, root->fs_info->sb_buffer);
|
||||
if (ret)
|
||||
fprintf(stderr, "failed to write new super block err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int drop_cache(struct btrfs_root *root)
|
||||
{
|
||||
while(!list_empty(&root->fs_info->cache)) {
|
||||
struct btrfs_buffer *b = list_entry(root->fs_info->cache.next,
|
||||
struct btrfs_buffer,
|
||||
cache);
|
||||
list_del_init(&b->cache);
|
||||
btrfs_block_release(root, b);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s)
|
||||
int close_ctree(struct btrfs_root *root)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
btrfs_commit_transaction(trans, root, s);
|
||||
btrfs_commit_transaction(trans, root);
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
ret = commit_tree_roots(trans, root->fs_info);
|
||||
BUG_ON(ret);
|
||||
ret = __commit_transaction(trans, root);
|
||||
BUG_ON(ret);
|
||||
write_ctree_super(trans, root, s);
|
||||
write_ctree_super(trans, root);
|
||||
btrfs_free_transaction(root, trans);
|
||||
drop_cache(root);
|
||||
BUG_ON(!list_empty(&root->fs_info->trans));
|
||||
btrfs_free_block_groups(root->fs_info);
|
||||
close(root->fs_info->fp);
|
||||
if (root->node)
|
||||
btrfs_block_release(root, root->node);
|
||||
free_extent_buffer(root->node);
|
||||
if (root->fs_info->extent_root->node)
|
||||
btrfs_block_release(root->fs_info->extent_root,
|
||||
root->fs_info->extent_root->node);
|
||||
free_extent_buffer(root->fs_info->extent_root->node);
|
||||
if (root->fs_info->tree_root->node)
|
||||
btrfs_block_release(root->fs_info->tree_root,
|
||||
root->fs_info->tree_root->node);
|
||||
btrfs_block_release(root, root->commit_root);
|
||||
free(root);
|
||||
printf("on close %llu blocks are allocated\n",
|
||||
(unsigned long long)allocated_bytes);
|
||||
free_extent_buffer(root->fs_info->tree_root->node);
|
||||
free_extent_buffer(root->commit_root);
|
||||
free_extent_buffer(root->fs_info->sb_buffer);
|
||||
|
||||
extent_map_tree_cleanup(&fs_info->extent_cache);
|
||||
extent_map_tree_cleanup(&fs_info->free_space_cache);
|
||||
extent_map_tree_cleanup(&fs_info->pending_tree);
|
||||
extent_map_tree_cleanup(&fs_info->pinned_extents);
|
||||
extent_map_tree_cleanup(&fs_info->del_pending);
|
||||
extent_map_tree_cleanup(&fs_info->block_group_cache);
|
||||
|
||||
free(fs_info->tree_root);
|
||||
free(fs_info->extent_root);
|
||||
free(fs_info->fs_root);
|
||||
free(fs_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf)
|
||||
int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct extent_buffer *eb)
|
||||
{
|
||||
buf->count--;
|
||||
if (buf->count < 0)
|
||||
BUG();
|
||||
if (buf->count == 0) {
|
||||
BUG_ON(!list_empty(&buf->cache));
|
||||
BUG_ON(!list_empty(&buf->dirty));
|
||||
|
||||
remove_cache_extent(&root->fs_info->extent_cache,
|
||||
&buf->cache_node);
|
||||
BUG_ON(allocated_bytes == 0);
|
||||
allocated_bytes -= buf->size;
|
||||
BUG_ON(root->fs_info->cache_size == 0);
|
||||
root->fs_info->cache_size -= buf->size;
|
||||
|
||||
memset(buf, 0, sizeof(*buf));
|
||||
free(buf);
|
||||
}
|
||||
return clear_extent_buffer_dirty(eb);
|
||||
}
|
||||
|
||||
int wait_on_tree_block_writeback(struct btrfs_root *root,
|
||||
struct extent_buffer *eb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void btrfs_mark_buffer_dirty(struct extent_buffer *eb)
|
||||
{
|
||||
set_extent_buffer_dirty(eb);
|
||||
}
|
||||
|
||||
int btrfs_buffer_uptodate(struct extent_buffer *eb)
|
||||
{
|
||||
return extent_buffer_uptodate(eb);
|
||||
}
|
||||
|
||||
int btrfs_set_buffer_uptodate(struct extent_buffer *eb)
|
||||
{
|
||||
return set_extent_buffer_uptodate(eb);
|
||||
}
|
||||
|
68
disk-io.h
68
disk-io.h
@ -18,46 +18,36 @@
|
||||
|
||||
#ifndef __DISKIO__
|
||||
#define __DISKIO__
|
||||
#include "extent-cache.h"
|
||||
#include "list.h"
|
||||
|
||||
struct btrfs_buffer {
|
||||
struct cache_extent cache_node;
|
||||
u64 bytenr;
|
||||
u64 dev_bytenr;
|
||||
u32 size;
|
||||
int count;
|
||||
int fd;
|
||||
struct list_head dirty;
|
||||
struct list_head cache;
|
||||
union {
|
||||
struct btrfs_node node;
|
||||
struct btrfs_leaf leaf;
|
||||
};
|
||||
};
|
||||
|
||||
struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize);
|
||||
struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize);
|
||||
int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_buffer *buf);
|
||||
int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_buffer *buf);
|
||||
int clean_tree_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_buffer *buf);
|
||||
int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_super_block *s);
|
||||
struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *s);
|
||||
struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super);
|
||||
int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s);
|
||||
void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf);
|
||||
int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_super_block *s);
|
||||
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct btrfs_buffer *bh,
|
||||
u64 logical);
|
||||
int btrfs_csum_super(struct btrfs_root *root, struct btrfs_super_block *super);
|
||||
int btrfs_csum_node(struct btrfs_root *root, struct btrfs_node *node);
|
||||
#define BTRFS_SUPER_INFO_OFFSET (16 * 1024)
|
||||
|
||||
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize);
|
||||
int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize);
|
||||
struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
|
||||
u64 bytenr, u32 blocksize);
|
||||
int clean_tree_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct extent_buffer *buf);
|
||||
struct btrfs_root *open_ctree(char *filename, u64 sb_bytenr);
|
||||
struct btrfs_root *open_ctree_fd(int fp, u64 sb_bytenr);
|
||||
int close_ctree(struct btrfs_root *root);
|
||||
int write_ctree_super(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct extent_buffer *bh,
|
||||
u64 logical);
|
||||
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
|
||||
u64 bytenr, u32 blocksize);
|
||||
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_key *location);
|
||||
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
|
||||
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
|
||||
int btrfs_buffer_uptodate(struct extent_buffer *buf);
|
||||
int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
|
||||
int wait_on_tree_block_writeback(struct btrfs_root *root,
|
||||
struct extent_buffer *buf);
|
||||
u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len);
|
||||
void btrfs_csum_final(u32 crc, char *result);
|
||||
|
||||
int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
#endif
|
||||
|
2198
extent-tree.c
2198
extent-tree.c
File diff suppressed because it is too large
Load Diff
328
file-item.c
328
file-item.c
@ -23,6 +23,7 @@
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "transaction.h"
|
||||
#include "print-tree.h"
|
||||
#include "crc32c.h"
|
||||
|
||||
#define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
|
||||
@ -35,86 +36,169 @@ int btrfs_create_file(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 objectid, u64 pos,
|
||||
u64 offset, u64 disk_num_bytes,
|
||||
u64 num_bytes)
|
||||
struct btrfs_root *root,
|
||||
u64 objectid, u64 pos, u64 offset,
|
||||
u64 disk_num_bytes, u64 num_bytes)
|
||||
{
|
||||
int ret = 0;
|
||||
struct btrfs_file_extent_item *item;
|
||||
struct btrfs_key file_key;
|
||||
struct btrfs_path path;
|
||||
struct btrfs_leaf *leaf;
|
||||
struct btrfs_path *path;
|
||||
struct extent_buffer *leaf;
|
||||
|
||||
|
||||
btrfs_init_path(&path);
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
file_key.objectid = objectid;
|
||||
file_key.offset = pos;
|
||||
btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
|
||||
|
||||
ret = btrfs_insert_empty_item(trans, root, &path, &file_key,
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &file_key,
|
||||
sizeof(*item));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
BUG_ON(ret);
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
item = btrfs_item_ptr(leaf, path.slots[0],
|
||||
leaf = path->nodes[0];
|
||||
item = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
btrfs_set_file_extent_disk_bytenr(item, offset);
|
||||
btrfs_set_file_extent_disk_num_bytes(item, disk_num_bytes);
|
||||
btrfs_set_file_extent_offset(item, 0);
|
||||
btrfs_set_file_extent_num_bytes(item, num_bytes);
|
||||
btrfs_set_file_extent_generation(item, trans->transid);
|
||||
btrfs_set_file_extent_type(item, BTRFS_FILE_EXTENT_REG);
|
||||
btrfs_set_file_extent_disk_bytenr(leaf, item, offset);
|
||||
btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes);
|
||||
btrfs_set_file_extent_offset(leaf, item, 0);
|
||||
btrfs_set_file_extent_num_bytes(leaf, item, num_bytes);
|
||||
btrfs_set_file_extent_generation(leaf, item, trans->transid);
|
||||
btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
out:
|
||||
btrfs_release_path(root, &path);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_insert_inline_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 objectid,
|
||||
u64 offset, char *buffer, size_t size)
|
||||
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 objectid,
|
||||
u64 offset, char *buffer, size_t size)
|
||||
{
|
||||
int ret;
|
||||
char *ptr;
|
||||
u32 datasize;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_path path;
|
||||
struct btrfs_leaf *leaf;
|
||||
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;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
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);
|
||||
BUG_ON(ret);
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
ei = btrfs_item_ptr(leaf, path.slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
btrfs_set_file_extent_generation(ei, trans->transid);
|
||||
btrfs_set_file_extent_type(ei, BTRFS_FILE_EXTENT_INLINE);
|
||||
ptr = btrfs_file_extent_inline_start(ei);
|
||||
memcpy(ptr, buffer, size);
|
||||
btrfs_release_path(root, &path);
|
||||
return 0;
|
||||
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
|
||||
if (ret < 0) {
|
||||
err = ret;
|
||||
goto fail;
|
||||
}
|
||||
if (ret == 1) {
|
||||
struct btrfs_key found_key;
|
||||
|
||||
if (path->slots[0] == 0)
|
||||
goto insert;
|
||||
|
||||
path->slots[0]--;
|
||||
leaf = path->nodes[0];
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||
|
||||
if (found_key.objectid != objectid)
|
||||
goto insert;
|
||||
|
||||
if (found_key.type != BTRFS_EXTENT_DATA_KEY)
|
||||
goto insert;
|
||||
ei = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
|
||||
if (btrfs_file_extent_type(leaf, ei) !=
|
||||
BTRFS_FILE_EXTENT_INLINE) {
|
||||
goto insert;
|
||||
}
|
||||
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret == 0) {
|
||||
u32 found_size;
|
||||
u64 found_end;
|
||||
|
||||
leaf = path->nodes[0];
|
||||
ei = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
|
||||
if (btrfs_file_extent_type(leaf, ei) !=
|
||||
BTRFS_FILE_EXTENT_INLINE) {
|
||||
err = ret;
|
||||
btrfs_print_leaf(root, leaf);
|
||||
printk("found wasn't inline offset %llu inode %llu\n",
|
||||
offset, objectid);
|
||||
goto fail;
|
||||
}
|
||||
found_size = btrfs_file_extent_inline_len(leaf,
|
||||
btrfs_item_nr(leaf, path->slots[0]));
|
||||
found_end = key.offset + found_size;
|
||||
|
||||
if (found_end < offset + size) {
|
||||
btrfs_release_path(root, path);
|
||||
ret = btrfs_search_slot(trans, root, &key, path,
|
||||
offset + size - found_end, 1);
|
||||
BUG_ON(ret != 0);
|
||||
|
||||
ret = btrfs_extend_item(trans, root, path,
|
||||
offset + size - found_end);
|
||||
if (ret) {
|
||||
err = ret;
|
||||
goto fail;
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
ei = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
}
|
||||
if (found_end < offset) {
|
||||
ptr = btrfs_file_extent_inline_start(ei) + found_size;
|
||||
memset_extent_buffer(leaf, 0, ptr, offset - found_end);
|
||||
}
|
||||
} else {
|
||||
insert:
|
||||
btrfs_release_path(root, path);
|
||||
datasize = offset + size - key.offset;
|
||||
datasize = btrfs_file_extent_calc_inline_size(datasize);
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||
datasize);
|
||||
if (ret) {
|
||||
err = ret;
|
||||
printk("got bad ret %d\n", 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);
|
||||
}
|
||||
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_lookup_csum(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
u64 objectid, u64 offset, int cow,
|
||||
struct btrfs_csum_item **item_ret)
|
||||
struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
u64 objectid, u64 offset, int cow)
|
||||
{
|
||||
int ret;
|
||||
int slot;
|
||||
struct btrfs_key file_key;
|
||||
struct btrfs_key found_key;
|
||||
struct btrfs_csum_item *item;
|
||||
struct btrfs_leaf *leaf;
|
||||
struct extent_buffer *leaf;
|
||||
u64 csum_offset = 0;
|
||||
int csums_in_item;
|
||||
|
||||
@ -124,35 +208,51 @@ int btrfs_lookup_csum(struct btrfs_trans_handle *trans,
|
||||
ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
leaf = &path->nodes[0]->leaf;
|
||||
leaf = path->nodes[0];
|
||||
if (ret > 0) {
|
||||
ret = 1;
|
||||
if (path->slots[0] == 0)
|
||||
goto fail;
|
||||
path->slots[0]--;
|
||||
|
||||
slot = path->slots[0];
|
||||
btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key);
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||
if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
|
||||
found_key.objectid != objectid) {
|
||||
goto fail;
|
||||
}
|
||||
csum_offset = (offset - found_key.offset) / root->sectorsize;
|
||||
csums_in_item = btrfs_item_size(&leaf->items[slot]);
|
||||
csum_offset = (offset - found_key.offset) >> root->sectorsize;
|
||||
csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]);
|
||||
csums_in_item /= BTRFS_CRC32_SIZE;
|
||||
|
||||
if (csum_offset >= csums_in_item) {
|
||||
ret = -EFBIG;
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
|
||||
item = (struct btrfs_csum_item *)((unsigned char *)item +
|
||||
csum_offset * BTRFS_CRC32_SIZE);
|
||||
*item_ret = item;
|
||||
return item;
|
||||
fail:
|
||||
if (ret > 0)
|
||||
ret = -ENOENT;
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
||||
int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 objectid,
|
||||
u64 offset, int mod)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_key file_key;
|
||||
int ins_len = mod < 0 ? -1 : 0;
|
||||
int cow = mod != 0;
|
||||
|
||||
file_key.objectid = objectid;
|
||||
file_key.offset = offset;
|
||||
btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
|
||||
ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -163,56 +263,53 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
|
||||
char *data, size_t len)
|
||||
{
|
||||
int ret;
|
||||
int slot;
|
||||
struct btrfs_key file_key;
|
||||
struct btrfs_key found_key;
|
||||
u64 next_offset = (u64)-1;
|
||||
int found_next = 0;
|
||||
struct btrfs_path path;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_csum_item *item;
|
||||
struct btrfs_leaf *leaf = NULL;
|
||||
struct extent_buffer *leaf = NULL;
|
||||
u64 csum_offset;
|
||||
u32 csum_result = ~(u32)0;
|
||||
u32 nritems;
|
||||
u32 ins_size;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
|
||||
file_key.objectid = objectid;
|
||||
file_key.offset = offset;
|
||||
btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
|
||||
|
||||
ret = btrfs_lookup_csum(trans, root, &path, objectid,
|
||||
offset, 1, &item);
|
||||
if (!ret) {
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1);
|
||||
if (!IS_ERR(item)) {
|
||||
leaf = path->nodes[0];
|
||||
goto found;
|
||||
}
|
||||
if (ret != -EFBIG && ret != -ENOENT)
|
||||
goto fail;
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
ret = PTR_ERR(item);
|
||||
if (ret == -EFBIG) {
|
||||
u32 item_size;
|
||||
slot = path.slots[0];
|
||||
/* we found one, but it isn't big enough yet */
|
||||
item_size = btrfs_item_size(&leaf->items[slot]);
|
||||
leaf = path->nodes[0];
|
||||
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
||||
if ((item_size / BTRFS_CRC32_SIZE) >= MAX_CSUM_ITEMS(root)) {
|
||||
/* already at max size, make a new one */
|
||||
goto insert;
|
||||
}
|
||||
} else {
|
||||
slot = path.slots[0] + 1;
|
||||
int slot = path->slots[0] + 1;
|
||||
/* we didn't find a csum item, insert one */
|
||||
nritems = btrfs_header_nritems(&leaf->header);
|
||||
if (path.slots[0] >= nritems - 1) {
|
||||
ret = btrfs_next_leaf(root, &path);
|
||||
nritems = btrfs_header_nritems(path->nodes[0]);
|
||||
if (path->slots[0] >= nritems - 1) {
|
||||
ret = btrfs_next_leaf(root, path);
|
||||
if (ret == 1)
|
||||
found_next = 1;
|
||||
if (ret != 0)
|
||||
goto insert;
|
||||
slot = 0;
|
||||
}
|
||||
btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key);
|
||||
btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
|
||||
if (found_key.objectid != objectid ||
|
||||
found_key.type != BTRFS_CSUM_ITEM_KEY) {
|
||||
found_next = 1;
|
||||
@ -227,68 +324,97 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
|
||||
* at this point, we know the tree has an item, but it isn't big
|
||||
* enough yet to put our csum in. Grow it
|
||||
*/
|
||||
btrfs_release_path(root, &path);
|
||||
ret = btrfs_search_slot(trans, root, &file_key, &path,
|
||||
btrfs_release_path(root, path);
|
||||
ret = btrfs_search_slot(trans, root, &file_key, path,
|
||||
BTRFS_CRC32_SIZE, 1);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
BUG_ON(ret == 0);
|
||||
if (path.slots[0] == 0) {
|
||||
if (ret == 0) {
|
||||
BUG();
|
||||
}
|
||||
if (path->slots[0] == 0) {
|
||||
goto insert;
|
||||
}
|
||||
path.slots[0]--;
|
||||
slot = path.slots[0];
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key);
|
||||
path->slots[0]--;
|
||||
leaf = path->nodes[0];
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||
csum_offset = (offset - found_key.offset) / root->sectorsize;
|
||||
if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
|
||||
found_key.objectid != objectid ||
|
||||
csum_offset >= MAX_CSUM_ITEMS(root)) {
|
||||
goto insert;
|
||||
}
|
||||
if (csum_offset >= btrfs_item_size(&leaf->items[slot]) /
|
||||
if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) /
|
||||
BTRFS_CRC32_SIZE) {
|
||||
u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE;
|
||||
diff = diff - btrfs_item_size(&leaf->items[slot]);
|
||||
diff = diff - btrfs_item_size_nr(leaf, path->slots[0]);
|
||||
if (diff != BTRFS_CRC32_SIZE)
|
||||
goto insert;
|
||||
ret = btrfs_extend_item(trans, root, &path, diff);
|
||||
ret = btrfs_extend_item(trans, root, path, diff);
|
||||
BUG_ON(ret);
|
||||
goto csum;
|
||||
}
|
||||
|
||||
insert:
|
||||
btrfs_release_path(root, &path);
|
||||
btrfs_release_path(root, path);
|
||||
csum_offset = 0;
|
||||
if (found_next) {
|
||||
u64 tmp;
|
||||
if (next_offset > btrfs_inode_size(inode))
|
||||
next_offset = btrfs_inode_size(inode);
|
||||
tmp = next_offset - offset + root->sectorsize - 1;
|
||||
u64 tmp = min(btrfs_stack_inode_size(inode), next_offset);
|
||||
tmp -= offset & ~((u64)root->sectorsize -1);
|
||||
tmp /= root->sectorsize;
|
||||
if (tmp > MAX_CSUM_ITEMS(root))
|
||||
tmp = MAX_CSUM_ITEMS(root);
|
||||
tmp = max((u64)1, tmp);
|
||||
tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root));
|
||||
ins_size = BTRFS_CRC32_SIZE * tmp;
|
||||
} else {
|
||||
ins_size = BTRFS_CRC32_SIZE;
|
||||
}
|
||||
ret = btrfs_insert_empty_item(trans, root, &path, &file_key,
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &file_key,
|
||||
ins_size);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
BUG_ON(ret != 0);
|
||||
if (ret != 0) {
|
||||
WARN_ON(1);
|
||||
goto fail;
|
||||
}
|
||||
csum:
|
||||
slot = path.slots[0];
|
||||
leaf = &path.nodes[0]->leaf;
|
||||
item = btrfs_item_ptr(leaf, slot, struct btrfs_csum_item);
|
||||
leaf = path->nodes[0];
|
||||
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
|
||||
ret = 0;
|
||||
item = (struct btrfs_csum_item *)((unsigned char *)item +
|
||||
csum_offset * BTRFS_CRC32_SIZE);
|
||||
found:
|
||||
csum_result = crc32c(csum_result, data, len);
|
||||
csum_result = ~cpu_to_le32(csum_result);
|
||||
memcpy(item, &csum_result, BTRFS_CRC32_SIZE);
|
||||
ret = 0;
|
||||
csum_result = btrfs_csum_data(root, data, csum_result, len);
|
||||
btrfs_csum_final(csum_result, (char *)&csum_result);
|
||||
write_extent_buffer(leaf, &csum_result, (unsigned long)item,
|
||||
BTRFS_CRC32_SIZE);
|
||||
btrfs_mark_buffer_dirty(path->nodes[0]);
|
||||
fail:
|
||||
btrfs_release_path(root, &path);
|
||||
btrfs_release_path(root, path);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
u64 isize)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
struct extent_buffer *leaf = path->nodes[0];
|
||||
int slot = path->slots[0];
|
||||
int ret;
|
||||
u32 new_item_size;
|
||||
u64 new_item_span;
|
||||
u64 blocks;
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &key, slot);
|
||||
if (isize <= key.offset)
|
||||
return 0;
|
||||
new_item_span = isize - key.offset;
|
||||
blocks = (new_item_span + root->sectorsize - 1) / root->sectorsize;
|
||||
new_item_size = blocks * BTRFS_CRC32_SIZE;
|
||||
if (new_item_size >= btrfs_item_size_nr(leaf, slot))
|
||||
return 0;
|
||||
ret = btrfs_truncate_item(trans, root, path, new_item_size, 1);
|
||||
BUG_ON(ret);
|
||||
return ret;
|
||||
}
|
||||
|
177
inode-item.c
177
inode-item.c
@ -16,23 +16,102 @@
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "kerncompat.h"
|
||||
#include "radix-tree.h"
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "transaction.h"
|
||||
|
||||
int find_name_in_backref(struct btrfs_path *path, const char * name,
|
||||
int name_len, struct btrfs_inode_ref **ref_ret)
|
||||
{
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_inode_ref *ref;
|
||||
unsigned long ptr;
|
||||
unsigned long name_ptr;
|
||||
u32 item_size;
|
||||
u32 cur_offset = 0;
|
||||
int len;
|
||||
|
||||
leaf = path->nodes[0];
|
||||
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
||||
ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
|
||||
while (cur_offset < item_size) {
|
||||
ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
|
||||
len = btrfs_inode_ref_name_len(leaf, ref);
|
||||
name_ptr = (unsigned long)(ref + 1);
|
||||
cur_offset += len + sizeof(*ref);
|
||||
if (len != name_len)
|
||||
continue;
|
||||
if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
|
||||
*ref_ret = ref;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_inode_ref *ref;
|
||||
char *ptr;
|
||||
unsigned long ptr;
|
||||
int ret;
|
||||
int ins_len = name_len + sizeof(*ref);
|
||||
|
||||
@ -40,11 +119,13 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
|
||||
key.offset = ref_objectid;
|
||||
btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
|
||||
|
||||
btrfs_init_path(&path);
|
||||
ret = btrfs_insert_empty_item(trans, root, &path, &key,
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||
ins_len);
|
||||
if (ret == -EEXIST) {
|
||||
#if 0
|
||||
u32 old_size;
|
||||
|
||||
if (find_name_in_backref(path, name, name_len, &ref))
|
||||
@ -59,21 +140,62 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
|
||||
ptr = (unsigned long)(ref + 1);
|
||||
ret = 0;
|
||||
#endif
|
||||
goto out;
|
||||
} else if (ret < 0) {
|
||||
goto out;
|
||||
} else {
|
||||
ref = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0],
|
||||
ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||
struct btrfs_inode_ref);
|
||||
btrfs_set_inode_ref_name_len(ref, name_len);
|
||||
ptr = (char *)(ref + 1);
|
||||
btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
|
||||
ptr = (unsigned long)(ref + 1);
|
||||
}
|
||||
memcpy(ptr, name, name_len);
|
||||
dirty_tree_block(trans, root, path.nodes[0]);
|
||||
write_extent_buffer(path->nodes[0], name, ptr, name_len);
|
||||
btrfs_mark_buffer_dirty(path->nodes[0]);
|
||||
|
||||
out:
|
||||
btrfs_release_path(root, &path);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 objectid)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
key.objectid = objectid;
|
||||
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
|
||||
key.offset = 0;
|
||||
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||
sizeof(struct btrfs_inode_item));
|
||||
if (ret == 0 && objectid > root->highest_inode)
|
||||
root->highest_inode = objectid;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_path *path,
|
||||
struct btrfs_key *location, int mod)
|
||||
{
|
||||
int ins_len = mod < 0 ? -1 : 0;
|
||||
int cow = mod != 0;
|
||||
int ret;
|
||||
int slot;
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_key found_key;
|
||||
|
||||
ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
|
||||
if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY &&
|
||||
location->offset == (u64)-1 && path->slots[0] != 0) {
|
||||
slot = path->slots[0] - 1;
|
||||
leaf = path->nodes[0];
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, slot);
|
||||
if (found_key.objectid == location->objectid &&
|
||||
btrfs_key_type(&found_key) == btrfs_key_type(location)) {
|
||||
path->slots[0]--;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -81,29 +203,14 @@ int btrfs_insert_inode(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 objectid, struct btrfs_inode_item
|
||||
*inode_item)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
struct btrfs_key key;
|
||||
|
||||
key.objectid = objectid;
|
||||
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
|
||||
key.type = BTRFS_INODE_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
ret = btrfs_insert_item(trans, root, &key, inode_item,
|
||||
sizeof(*inode_item));
|
||||
btrfs_release_path(root, &path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_path *path, u64 objectid, int mod)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
int ins_len = mod < 0 ? -1 : 0;
|
||||
int cow = mod != 0;
|
||||
|
||||
key.objectid = objectid;
|
||||
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
|
||||
key.offset = 0;
|
||||
return btrfs_search_slot(trans, root, &key, path, ins_len, cow);
|
||||
}
|
||||
|
79
inode-map.c
79
inode-map.c
@ -16,14 +16,42 @@
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "kerncompat.h"
|
||||
#include "radix-tree.h"
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "transaction.h"
|
||||
|
||||
int btrfs_find_highest_inode(struct btrfs_root *root, u64 *objectid)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
int ret;
|
||||
struct extent_buffer *l;
|
||||
struct btrfs_key search_key;
|
||||
struct btrfs_key found_key;
|
||||
int slot;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
|
||||
search_key.objectid = (u64)-1;
|
||||
search_key.offset = (u64)-1;
|
||||
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
BUG_ON(ret == 0);
|
||||
if (path->slots[0] > 0) {
|
||||
slot = path->slots[0] - 1;
|
||||
l = path->nodes[0];
|
||||
btrfs_item_key_to_cpu(l, &found_key, slot);
|
||||
*objectid = found_key.objectid;
|
||||
} else {
|
||||
*objectid = BTRFS_FIRST_FREE_OBJECTID;
|
||||
}
|
||||
ret = 0;
|
||||
error:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* walks the btree of allocated inodes and find a hole.
|
||||
*/
|
||||
@ -31,40 +59,38 @@ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 dirid, u64 *objectid)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
u64 hole_size = 0;
|
||||
int slot = 0;
|
||||
u64 last_ino = 0;
|
||||
int start_found;
|
||||
struct btrfs_leaf *l;
|
||||
struct extent_buffer *l;
|
||||
struct btrfs_key search_key;
|
||||
u64 search_start = dirid;
|
||||
|
||||
if (root->fs_info->last_inode_alloc_dirid == dirid)
|
||||
search_start = root->fs_info->last_inode_alloc;
|
||||
|
||||
if (search_start < BTRFS_FIRST_FREE_OBJECTID)
|
||||
search_start = BTRFS_FIRST_FREE_OBJECTID;
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
search_start = root->last_inode_alloc;
|
||||
search_start = max(search_start, BTRFS_FIRST_FREE_OBJECTID);
|
||||
search_key.objectid = search_start;
|
||||
search_key.type = 0;
|
||||
search_key.offset = 0;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
btrfs_init_path(path);
|
||||
start_found = 0;
|
||||
ret = btrfs_search_slot(trans, root, &search_key, &path, 0, 0);
|
||||
ret = btrfs_search_slot(trans, root, &search_key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
if (path.slots[0] > 0)
|
||||
path.slots[0]--;
|
||||
if (path->slots[0] > 0)
|
||||
path->slots[0]--;
|
||||
|
||||
while (1) {
|
||||
l = &path.nodes[0]->leaf;
|
||||
slot = path.slots[0];
|
||||
if (slot >= btrfs_header_nritems(&l->header)) {
|
||||
ret = btrfs_next_leaf(root, &path);
|
||||
l = path->nodes[0];
|
||||
slot = path->slots[0];
|
||||
if (slot >= btrfs_header_nritems(l)) {
|
||||
ret = btrfs_next_leaf(root, path);
|
||||
if (ret == 0)
|
||||
continue;
|
||||
if (ret < 0)
|
||||
@ -78,7 +104,7 @@ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
|
||||
last_ino : search_start;
|
||||
goto found;
|
||||
}
|
||||
btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
|
||||
btrfs_item_key_to_cpu(l, &key, slot);
|
||||
if (key.objectid >= search_start) {
|
||||
if (start_found) {
|
||||
if (last_ino < search_start)
|
||||
@ -92,16 +118,17 @@ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
start_found = 1;
|
||||
last_ino = key.objectid + 1;
|
||||
path.slots[0]++;
|
||||
path->slots[0]++;
|
||||
}
|
||||
// FIXME -ENOSPC
|
||||
found:
|
||||
root->fs_info->last_inode_alloc = *objectid;
|
||||
root->fs_info->last_inode_alloc_dirid = dirid;
|
||||
btrfs_release_path(root, &path);
|
||||
root->last_inode_alloc = *objectid;
|
||||
btrfs_release_path(root, path);
|
||||
btrfs_free_path(path);
|
||||
BUG_ON(*objectid < search_start);
|
||||
return 0;
|
||||
error:
|
||||
btrfs_release_path(root, &path);
|
||||
btrfs_release_path(root, path);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
84
kerncompat.h
84
kerncompat.h
@ -67,10 +67,36 @@ struct vm_area_struct {
|
||||
unsigned long vm_end;
|
||||
struct vma_shared shared;
|
||||
};
|
||||
|
||||
struct page {
|
||||
unsigned long index;
|
||||
};
|
||||
|
||||
struct mutex {
|
||||
unsigned long lock;
|
||||
};
|
||||
|
||||
#define mutex_init(m) \
|
||||
do { \
|
||||
(m)->lock = 1; \
|
||||
} while (0)
|
||||
|
||||
static inline void mutex_lock(struct mutex *m)
|
||||
{
|
||||
m->lock--;
|
||||
}
|
||||
|
||||
static inline void mutex_unlock(struct mutex *m)
|
||||
{
|
||||
m->lock++;
|
||||
}
|
||||
|
||||
static inline int mutex_is_locked(struct mutex *m)
|
||||
{
|
||||
return (m->lock != 1);
|
||||
}
|
||||
|
||||
#define cond_resched() do { } while (0)
|
||||
#define preempt_enable() do { } while (0)
|
||||
#define preempt_disable() do { } while (0)
|
||||
|
||||
@ -112,7 +138,61 @@ static inline int test_bit(int nr, const volatile unsigned long *addr)
|
||||
return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
|
||||
}
|
||||
|
||||
/*
|
||||
* error pointer
|
||||
*/
|
||||
#define MAX_ERRNO 4095
|
||||
#define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO)
|
||||
|
||||
static inline void *ERR_PTR(long error)
|
||||
{
|
||||
return (void *) error;
|
||||
}
|
||||
|
||||
static inline long PTR_ERR(const void *ptr)
|
||||
{
|
||||
return (long) ptr;
|
||||
}
|
||||
|
||||
static inline long IS_ERR(const void *ptr)
|
||||
{
|
||||
return IS_ERR_VALUE((unsigned long)ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* max/min macro
|
||||
*/
|
||||
#define min(x,y) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
typeof(y) _y = (y); \
|
||||
(void) (&_x == &_y); \
|
||||
_x < _y ? _x : _y; })
|
||||
|
||||
#define max(x,y) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
typeof(y) _y = (y); \
|
||||
(void) (&_x == &_y); \
|
||||
_x > _y ? _x : _y; })
|
||||
|
||||
#define min_t(type,x,y) \
|
||||
({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
|
||||
#define max_t(type,x,y) \
|
||||
({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
|
||||
|
||||
/*
|
||||
* printk
|
||||
*/
|
||||
#define printk(fmt, args...) fprintf(stderr, fmt, ##args)
|
||||
#define KERN_CRIT ""
|
||||
|
||||
/*
|
||||
* kmalloc/kfree
|
||||
*/
|
||||
#define kmalloc(x, y) malloc(x)
|
||||
#define kfree(x) free(x)
|
||||
|
||||
#define BUG_ON(c) do { if (c) abort(); } while (0)
|
||||
#define WARN_ON(c) do { if (c) abort(); } while (0)
|
||||
|
||||
#undef offsetof
|
||||
#ifdef __compiler_offsetof
|
||||
@ -162,3 +242,7 @@ typedef u64 __bitwise __be64;
|
||||
#define le16_to_cpu(x) ((__force u16)(__le16)(x))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef noinline
|
||||
#define noinline
|
||||
#endif
|
||||
|
269
mkfs.c
269
mkfs.c
@ -34,6 +34,7 @@
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "transaction.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef __CHECKER__
|
||||
#define BLKGETSIZE64 0
|
||||
@ -66,133 +67,32 @@ static u64 parse_size(char *s)
|
||||
return atol(s) * mult;
|
||||
}
|
||||
|
||||
static int __make_root_dir(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 objectid)
|
||||
{
|
||||
int ret;
|
||||
char buf[8];
|
||||
struct btrfs_key inode_map;
|
||||
struct btrfs_inode_item inode_item;
|
||||
|
||||
buf[0] = '.';
|
||||
buf[1] = '.';
|
||||
|
||||
inode_map.objectid = objectid;
|
||||
btrfs_set_key_type(&inode_map, BTRFS_INODE_ITEM_KEY);
|
||||
inode_map.offset = 0;
|
||||
|
||||
memset(&inode_item, 0, sizeof(inode_item));
|
||||
btrfs_set_inode_generation(&inode_item, root->fs_info->generation);
|
||||
btrfs_set_inode_size(&inode_item, 0);
|
||||
btrfs_set_inode_nlink(&inode_item, 1);
|
||||
btrfs_set_inode_nblocks(&inode_item, 0);
|
||||
btrfs_set_inode_mode(&inode_item, S_IFDIR | 0555);
|
||||
|
||||
if (root->fs_info->tree_root == root)
|
||||
btrfs_set_super_root_dir(root->fs_info->disk_super, objectid);
|
||||
|
||||
ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = btrfs_insert_inode_ref(trans, root, "..", 2, objectid, objectid);
|
||||
if (ret)
|
||||
goto error;
|
||||
btrfs_set_root_dirid(&root->root_item, objectid);
|
||||
ret = 0;
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int make_block_groups(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
u64 group_size;
|
||||
u64 total_bytes;
|
||||
u64 cur_start;
|
||||
int ret;
|
||||
u64 nr = 0;
|
||||
struct btrfs_block_group_cache *cache;
|
||||
struct cache_tree *bg_cache = &root->fs_info->block_group_cache;
|
||||
|
||||
root = root->fs_info->extent_root;
|
||||
|
||||
/* first we bootstrap the things into cache */
|
||||
group_size = BTRFS_BLOCK_GROUP_SIZE;
|
||||
cache = malloc(sizeof(*cache));
|
||||
cache->key.objectid = 0;
|
||||
cache->key.offset = group_size;
|
||||
cache->cache.start = 0;
|
||||
cache->cache.size = group_size;
|
||||
btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
|
||||
|
||||
memset(&cache->item, 0, sizeof(cache->item));
|
||||
btrfs_set_block_group_used(&cache->item,
|
||||
btrfs_super_bytes_used(root->fs_info->disk_super));
|
||||
ret = insert_existing_cache_extent(bg_cache, &cache->cache);
|
||||
BUG_ON(ret);
|
||||
|
||||
total_bytes = btrfs_super_total_bytes(root->fs_info->disk_super);
|
||||
cur_start = group_size;
|
||||
while(cur_start < total_bytes) {
|
||||
cache = malloc(sizeof(*cache));
|
||||
cache->key.objectid = cur_start;
|
||||
cache->key.offset = group_size;
|
||||
cache->cache.start = cur_start;
|
||||
cache->cache.size = group_size;
|
||||
btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
|
||||
memset(&cache->item, 0, sizeof(cache->item));
|
||||
if (nr % 3)
|
||||
cache->item.flags |= BTRFS_BLOCK_GROUP_DATA;
|
||||
|
||||
ret = insert_existing_cache_extent(bg_cache, &cache->cache);
|
||||
BUG_ON(ret);
|
||||
cur_start += group_size;
|
||||
nr++;
|
||||
}
|
||||
/* then insert all the items */
|
||||
cur_start = 0;
|
||||
while(cur_start < total_bytes) {
|
||||
struct cache_extent *ce;
|
||||
ce = find_first_cache_extent(bg_cache, cur_start);
|
||||
BUG_ON(!ce);
|
||||
cache = container_of(ce, struct btrfs_block_group_cache,
|
||||
cache);
|
||||
ret = btrfs_insert_block_group(trans, root, &cache->key,
|
||||
&cache->item);
|
||||
BUG_ON(ret);
|
||||
cur_start += group_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int make_root_dir(int fd) {
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_super_block super;
|
||||
struct btrfs_trans_handle *trans;
|
||||
int ret;
|
||||
struct btrfs_key location;
|
||||
int ret;
|
||||
|
||||
root = open_ctree_fd(fd, &super);
|
||||
root = open_ctree_fd(fd, 0);
|
||||
|
||||
if (!root) {
|
||||
fprintf(stderr, "ctree init failed\n");
|
||||
return -1;
|
||||
}
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
ret = make_block_groups(trans, root);
|
||||
ret = __make_root_dir(trans, root->fs_info->tree_root,
|
||||
ret = btrfs_make_block_groups(trans, root);
|
||||
ret = btrfs_make_root_dir(trans, root->fs_info->tree_root,
|
||||
BTRFS_ROOT_TREE_DIR_OBJECTID);
|
||||
if (ret)
|
||||
goto err;
|
||||
ret = __make_root_dir(trans, root, BTRFS_FIRST_FREE_OBJECTID);
|
||||
ret = btrfs_make_root_dir(trans, root, BTRFS_FIRST_FREE_OBJECTID);
|
||||
if (ret)
|
||||
goto err;
|
||||
memcpy(&location, &root->fs_info->fs_root->root_key, sizeof(location));
|
||||
location.offset = (u64)-1;
|
||||
ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
|
||||
"default", 7,
|
||||
btrfs_super_root_dir(root->fs_info->disk_super),
|
||||
btrfs_super_root_dir(&root->fs_info->super_copy),
|
||||
&location, BTRFS_FT_DIR);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -203,154 +103,12 @@ static int make_root_dir(int fd) {
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
btrfs_commit_transaction(trans, root, root->fs_info->disk_super);
|
||||
ret = close_ctree(root, &super);
|
||||
btrfs_commit_transaction(trans, root);
|
||||
ret = close_ctree(root);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mkfs(int fd, char *pathname, u64 num_bytes, u32 nodesize, u32 leafsize,
|
||||
u32 sectorsize, u32 stripesize)
|
||||
{
|
||||
struct btrfs_super_block super;
|
||||
struct btrfs_leaf *empty_leaf;
|
||||
struct btrfs_root_item root_item;
|
||||
struct btrfs_item item;
|
||||
struct btrfs_extent_item extent_item;
|
||||
struct btrfs_inode_item *inode_item;
|
||||
char *block;
|
||||
int ret;
|
||||
u32 itemoff;
|
||||
u32 start_block = BTRFS_SUPER_INFO_OFFSET;
|
||||
u32 first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize;
|
||||
|
||||
btrfs_set_super_generation(&super, 1);
|
||||
btrfs_set_super_bytenr(&super, start_block);
|
||||
btrfs_set_super_root_level(&super, 0);
|
||||
btrfs_set_super_root(&super, first_free);
|
||||
strcpy((char *)(&super.magic), BTRFS_MAGIC);
|
||||
|
||||
printf("blocksize is %d\n", leafsize);
|
||||
btrfs_set_super_sectorsize(&super, sectorsize);
|
||||
btrfs_set_super_leafsize(&super, leafsize);
|
||||
btrfs_set_super_nodesize(&super, nodesize);
|
||||
btrfs_set_super_stripesize(&super, stripesize);
|
||||
|
||||
num_bytes = (num_bytes / sectorsize) * sectorsize;
|
||||
btrfs_set_super_total_bytes(&super, num_bytes);
|
||||
btrfs_set_super_bytes_used(&super, start_block + 3 * leafsize +
|
||||
sectorsize);
|
||||
uuid_generate(super.fsid);
|
||||
|
||||
block = malloc(sectorsize);
|
||||
memset(block, 0, sectorsize);
|
||||
BUG_ON(sizeof(super) > sectorsize);
|
||||
memcpy(block, &super, sizeof(super));
|
||||
ret = pwrite(fd, block, sectorsize, BTRFS_SUPER_INFO_OFFSET);
|
||||
BUG_ON(ret != sectorsize);
|
||||
|
||||
/* create the tree of root objects */
|
||||
empty_leaf = malloc(leafsize);
|
||||
memset(empty_leaf, 0, leafsize);
|
||||
btrfs_set_header_bytenr(&empty_leaf->header, first_free);
|
||||
btrfs_set_header_nritems(&empty_leaf->header, 2);
|
||||
btrfs_set_header_generation(&empty_leaf->header, 1);
|
||||
btrfs_set_header_owner(&empty_leaf->header, BTRFS_ROOT_TREE_OBJECTID);
|
||||
memcpy(empty_leaf->header.fsid, super.fsid,
|
||||
sizeof(empty_leaf->header.fsid));
|
||||
|
||||
/* create the items for the root tree */
|
||||
inode_item = &root_item.inode;
|
||||
memset(inode_item, 0, sizeof(*inode_item));
|
||||
btrfs_set_inode_generation(inode_item, 1);
|
||||
btrfs_set_inode_size(inode_item, 3);
|
||||
btrfs_set_inode_nlink(inode_item, 1);
|
||||
btrfs_set_inode_nblocks(inode_item, 1);
|
||||
btrfs_set_inode_mode(inode_item, S_IFDIR | 0755);
|
||||
|
||||
// memset(&root_item, 0, sizeof(root_item));
|
||||
btrfs_set_root_dirid(&root_item, 0);
|
||||
btrfs_set_root_refs(&root_item, 1);
|
||||
btrfs_set_disk_key_offset(&item.key, 0);
|
||||
btrfs_set_item_size(&item, sizeof(root_item));
|
||||
btrfs_set_disk_key_type(&item.key, BTRFS_ROOT_ITEM_KEY);
|
||||
|
||||
itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(root_item);
|
||||
btrfs_set_root_bytenr(&root_item, first_free + leafsize);
|
||||
root_item.level = 0;
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
btrfs_set_disk_key_objectid(&item.key, BTRFS_EXTENT_TREE_OBJECTID);
|
||||
memcpy(empty_leaf->items, &item, sizeof(item));
|
||||
memcpy(btrfs_leaf_data(empty_leaf) + itemoff,
|
||||
&root_item, sizeof(root_item));
|
||||
|
||||
btrfs_set_root_bytenr(&root_item, first_free + leafsize * 2);
|
||||
btrfs_set_root_bytes_used(&root_item, 1);
|
||||
itemoff = itemoff - sizeof(root_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
btrfs_set_disk_key_objectid(&item.key, BTRFS_FS_TREE_OBJECTID);
|
||||
memcpy(empty_leaf->items + 1, &item, sizeof(item));
|
||||
memcpy(btrfs_leaf_data(empty_leaf) + itemoff,
|
||||
&root_item, sizeof(root_item));
|
||||
ret = pwrite(fd, empty_leaf, leafsize, first_free);
|
||||
|
||||
/* create the items for the extent tree */
|
||||
btrfs_set_header_bytenr(&empty_leaf->header, first_free + leafsize);
|
||||
btrfs_set_header_nritems(&empty_leaf->header, 4);
|
||||
|
||||
/* item1, reserve blocks 0-16 */
|
||||
btrfs_set_disk_key_objectid(&item.key, 0);
|
||||
btrfs_set_disk_key_offset(&item.key, first_free);
|
||||
btrfs_set_disk_key_type(&item.key, 0);
|
||||
btrfs_set_disk_key_type(&item.key, BTRFS_EXTENT_ITEM_KEY);
|
||||
itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) -
|
||||
sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
btrfs_set_item_size(&item, sizeof(struct btrfs_extent_item));
|
||||
btrfs_set_extent_refs(&extent_item, 1);
|
||||
memcpy(empty_leaf->items, &item, sizeof(item));
|
||||
memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
|
||||
&extent_item, btrfs_item_size(&item));
|
||||
|
||||
/* item2, give block 17 to the root */
|
||||
btrfs_set_disk_key_objectid(&item.key, first_free);
|
||||
btrfs_set_disk_key_offset(&item.key, leafsize);
|
||||
itemoff = itemoff - sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
memcpy(empty_leaf->items + 1, &item, sizeof(item));
|
||||
memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
|
||||
&extent_item, btrfs_item_size(&item));
|
||||
|
||||
/* item3, give block 18 to the extent root */
|
||||
btrfs_set_disk_key_objectid(&item.key, first_free + leafsize);
|
||||
btrfs_set_disk_key_offset(&item.key, leafsize);
|
||||
itemoff = itemoff - sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
memcpy(empty_leaf->items + 2, &item, sizeof(item));
|
||||
memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
|
||||
&extent_item, btrfs_item_size(&item));
|
||||
|
||||
/* item4, give block 19 to the FS root */
|
||||
btrfs_set_disk_key_objectid(&item.key, first_free + leafsize * 2);
|
||||
btrfs_set_disk_key_offset(&item.key, leafsize);
|
||||
itemoff = itemoff - sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
memcpy(empty_leaf->items + 3, &item, sizeof(item));
|
||||
memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
|
||||
&extent_item, btrfs_item_size(&item));
|
||||
ret = pwrite(fd, empty_leaf, leafsize, first_free + leafsize);
|
||||
if (ret != leafsize)
|
||||
return -1;
|
||||
|
||||
/* finally create the FS root */
|
||||
btrfs_set_header_bytenr(&empty_leaf->header, first_free + leafsize * 2);
|
||||
btrfs_set_header_nritems(&empty_leaf->header, 0);
|
||||
ret = pwrite(fd, empty_leaf, leafsize, first_free + leafsize * 2);
|
||||
if (ret != leafsize)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 device_size(int fd, struct stat *st)
|
||||
{
|
||||
u64 size;
|
||||
@ -384,8 +142,8 @@ int main(int ac, char **av)
|
||||
u32 sectorsize = 4096;
|
||||
u32 nodesize = 16 * 1024;
|
||||
u32 stripesize = 4096;
|
||||
u64 blocks[4];
|
||||
char *buf = malloc(sectorsize);
|
||||
char *realpath_name;
|
||||
|
||||
while(1) {
|
||||
int c;
|
||||
@ -459,9 +217,10 @@ int main(int ac, char **av)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
realpath_name = realpath(file, NULL);
|
||||
ret = mkfs(fd, realpath_name, block_count, nodesize, leafsize,
|
||||
sectorsize, stripesize);
|
||||
for (i = 0; i < 4; i++)
|
||||
blocks[i] = BTRFS_SUPER_INFO_OFFSET + leafsize * i;
|
||||
ret = make_btrfs(fd, blocks, block_count, nodesize, leafsize,
|
||||
sectorsize, stripesize);
|
||||
if (ret) {
|
||||
fprintf(stderr, "error during mkfs %d\n", ret);
|
||||
exit(1);
|
||||
|
192
print-tree.c
192
print-tree.c
@ -23,50 +23,62 @@
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
|
||||
static int print_dir_item(struct btrfs_item *item,
|
||||
static int print_dir_item(struct extent_buffer *eb, struct btrfs_item *item,
|
||||
struct btrfs_dir_item *di)
|
||||
{
|
||||
u32 total;
|
||||
u32 cur = 0;
|
||||
u32 len;
|
||||
total = btrfs_item_size(item);
|
||||
u32 name_len;
|
||||
u32 data_len;
|
||||
char namebuf[BTRFS_NAME_LEN];
|
||||
struct btrfs_disk_key location;
|
||||
|
||||
total = btrfs_item_size(eb, item);
|
||||
while(cur < total) {
|
||||
btrfs_dir_item_key(eb, di, &location);
|
||||
printf("\t\tdir index %llu type %u\n",
|
||||
(unsigned long long)btrfs_disk_key_objectid(&di->location),
|
||||
btrfs_dir_type(di));
|
||||
printf("\t\tname: %.*s\n",
|
||||
btrfs_dir_name_len(di),(char *)(di + 1));
|
||||
if (btrfs_dir_data_len(di))
|
||||
printf("\t\tdata: %.*s\n", btrfs_dir_data_len(di),
|
||||
(char *)((char *)(di + 1) + btrfs_dir_name_len(di)));
|
||||
len = sizeof(*di) + btrfs_dir_name_len(di) + btrfs_dir_data_len(di);
|
||||
(unsigned long long)btrfs_disk_key_objectid(&location),
|
||||
btrfs_dir_type(eb, di));
|
||||
name_len = btrfs_dir_name_len(eb, di);
|
||||
data_len = btrfs_dir_data_len(eb, di);
|
||||
len = (name_len <= sizeof(namebuf))? name_len: sizeof(namebuf);
|
||||
read_extent_buffer(eb, namebuf, (unsigned long)(di + 1), len);
|
||||
printf("\t\tnamelen %u datalen %u name: %.*s\n",
|
||||
name_len, data_len, len, namebuf);
|
||||
len = sizeof(*di) + name_len + data_len;
|
||||
di = (struct btrfs_dir_item *)((char *)di + len);
|
||||
cur += len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_inode_ref_item(struct btrfs_item *item,
|
||||
static int print_inode_ref_item(struct extent_buffer *eb, struct btrfs_item *item,
|
||||
struct btrfs_inode_ref *ref)
|
||||
{
|
||||
u32 total;
|
||||
u32 cur = 0;
|
||||
u32 len;
|
||||
total = btrfs_item_size(item);
|
||||
u32 name_len;
|
||||
char namebuf[BTRFS_NAME_LEN];
|
||||
total = btrfs_item_size(eb, item);
|
||||
while(cur < total) {
|
||||
len = btrfs_inode_ref_name_len(ref);
|
||||
printf("\t\tinode ref name: %.*s\n", len, (char *)(ref + 1));
|
||||
len += sizeof(*ref);
|
||||
name_len = btrfs_inode_ref_name_len(eb, ref);
|
||||
len = (name_len <= sizeof(namebuf))? name_len: sizeof(namebuf);
|
||||
read_extent_buffer(eb, namebuf, (unsigned long)(ref + 1), len);
|
||||
printf("\t\tinode ref namelen %u name: %.*s\n",
|
||||
name_len, len, namebuf);
|
||||
len = sizeof(*ref) + name_len;
|
||||
ref = (struct btrfs_inode_ref *)((char *)ref + len);
|
||||
cur += len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
|
||||
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
|
||||
{
|
||||
int i;
|
||||
u32 nr = btrfs_header_nritems(&l->header);
|
||||
char *str;
|
||||
struct btrfs_item *item;
|
||||
struct btrfs_extent_item *ei;
|
||||
struct btrfs_root_item *ri;
|
||||
@ -77,163 +89,167 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
|
||||
struct btrfs_block_group_item *bi;
|
||||
struct btrfs_extent_ref *ref;
|
||||
struct btrfs_inode_ref *iref;
|
||||
struct btrfs_disk_key disk_key;
|
||||
struct btrfs_root_item root_item;
|
||||
struct btrfs_block_group_item bg_item;
|
||||
u32 nr = btrfs_header_nritems(l);
|
||||
u32 type;
|
||||
|
||||
printf("leaf %llu ptrs %d free space %d generation %llu owner %llu\n",
|
||||
(unsigned long long)btrfs_header_bytenr(&l->header), nr,
|
||||
(unsigned long long)btrfs_header_bytenr(l), nr,
|
||||
btrfs_leaf_free_space(root, l),
|
||||
(unsigned long long)btrfs_header_generation(&l->header),
|
||||
(unsigned long long)btrfs_header_owner(&l->header));
|
||||
(unsigned long long)btrfs_header_generation(l),
|
||||
(unsigned long long)btrfs_header_owner(l));
|
||||
fflush(stdout);
|
||||
for (i = 0 ; i < nr ; i++) {
|
||||
item = l->items + i;
|
||||
type = btrfs_disk_key_type(&item->key);
|
||||
item = btrfs_item_nr(l, i);
|
||||
btrfs_item_key(l, &disk_key, i);
|
||||
type = btrfs_disk_key_type(&disk_key);
|
||||
printf("\titem %d key (%llu %x %llu) itemoff %d itemsize %d\n",
|
||||
i,
|
||||
(unsigned long long)btrfs_disk_key_objectid(&item->key),
|
||||
btrfs_disk_key_type(&item->key),
|
||||
(unsigned long long)btrfs_disk_key_offset(&item->key),
|
||||
btrfs_item_offset(item),
|
||||
btrfs_item_size(item));
|
||||
(unsigned long long)btrfs_disk_key_objectid(&disk_key),
|
||||
btrfs_disk_key_type(&disk_key),
|
||||
(unsigned long long)btrfs_disk_key_offset(&disk_key),
|
||||
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(ii),
|
||||
(unsigned long long)btrfs_inode_size(ii),
|
||||
(unsigned long long)btrfs_inode_block_group(ii),
|
||||
btrfs_inode_mode(ii),
|
||||
btrfs_inode_nlink(ii));
|
||||
(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->items + i, iref);
|
||||
print_inode_ref_item(l, item, iref);
|
||||
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_XATTR_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->items + i, di);
|
||||
print_dir_item(l, item, di);
|
||||
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\n",
|
||||
(unsigned long long)btrfs_root_bytenr(ri),
|
||||
ri->level,
|
||||
(unsigned long long)btrfs_root_dirid(ri),
|
||||
btrfs_root_refs(ri));
|
||||
if (1 || btrfs_root_refs(ri) == 0) {
|
||||
(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));
|
||||
if (1 || btrfs_root_refs(&root_item) == 0) {
|
||||
struct btrfs_key drop_key;
|
||||
btrfs_disk_key_to_cpu(&drop_key,
|
||||
&ri->drop_progress);
|
||||
&root_item.drop_progress);
|
||||
printf("\t\tdrop key %Lu %x %Lu level %d\n",
|
||||
(unsigned long long)drop_key.objectid,
|
||||
drop_key.type,
|
||||
(unsigned long long)drop_key.offset,
|
||||
ri->drop_level);
|
||||
root_item.drop_level);
|
||||
}
|
||||
break;
|
||||
case BTRFS_EXTENT_ITEM_KEY:
|
||||
ei = btrfs_item_ptr(l, i, struct btrfs_extent_item);
|
||||
printf("\t\textent data refs %u\n",
|
||||
btrfs_extent_refs(ei));
|
||||
btrfs_extent_refs(l, ei));
|
||||
break;
|
||||
case BTRFS_EXTENT_REF_KEY:
|
||||
ref = btrfs_item_ptr(l, i, struct btrfs_extent_ref);
|
||||
printf("\t\textent back ref root %llu gen %llu "
|
||||
"owner %llu offset %llu\n",
|
||||
(unsigned long long)btrfs_ref_root(ref),
|
||||
(unsigned long long)btrfs_ref_generation(ref),
|
||||
(unsigned long long)btrfs_ref_objectid(ref),
|
||||
(unsigned long long)btrfs_ref_offset(ref));
|
||||
(unsigned long long)btrfs_ref_root(l, ref),
|
||||
(unsigned long long)btrfs_ref_generation(l, ref),
|
||||
(unsigned long long)btrfs_ref_objectid(l, ref),
|
||||
(unsigned long long)btrfs_ref_offset(l, ref));
|
||||
break;
|
||||
case BTRFS_CSUM_ITEM_KEY:
|
||||
ci = btrfs_item_ptr(l, i,
|
||||
struct btrfs_csum_item);
|
||||
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) ==
|
||||
if (btrfs_file_extent_type(l, fi) ==
|
||||
BTRFS_FILE_EXTENT_INLINE) {
|
||||
printf("\t\tinline extent data size %u\n",
|
||||
btrfs_file_extent_inline_len(l->items + i));
|
||||
btrfs_file_extent_inline_len(l, item));
|
||||
break;
|
||||
}
|
||||
printf("\t\textent data disk byte %llu nr %llu\n",
|
||||
(unsigned long long)btrfs_file_extent_disk_bytenr(fi),
|
||||
(unsigned long long)btrfs_file_extent_disk_num_bytes(fi));
|
||||
(unsigned long long)btrfs_file_extent_disk_bytenr(l, fi),
|
||||
(unsigned long long)btrfs_file_extent_disk_num_bytes(l, fi));
|
||||
printf("\t\textent data offset %llu nr %llu\n",
|
||||
(unsigned long long)btrfs_file_extent_offset(fi),
|
||||
(unsigned long long)btrfs_file_extent_num_bytes(fi));
|
||||
(unsigned long long)btrfs_file_extent_offset(l, fi),
|
||||
(unsigned long long)btrfs_file_extent_num_bytes(l, 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 flags %x\n",
|
||||
(unsigned long long)btrfs_block_group_used(bi),
|
||||
bi->flags);
|
||||
(unsigned long long)btrfs_block_group_used(&bg_item),
|
||||
bg_item.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));
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
void btrfs_print_tree(struct btrfs_root *root, struct btrfs_buffer *t)
|
||||
void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb)
|
||||
{
|
||||
int i;
|
||||
u32 nr;
|
||||
struct btrfs_node *c;
|
||||
u32 size;
|
||||
struct btrfs_key key;
|
||||
|
||||
if (!t)
|
||||
if (!eb)
|
||||
return;
|
||||
c = &t->node;
|
||||
nr = btrfs_header_nritems(&c->header);
|
||||
if (btrfs_is_leaf(c)) {
|
||||
btrfs_print_leaf(root, (struct btrfs_leaf *)c);
|
||||
nr = btrfs_header_nritems(eb);
|
||||
if (btrfs_is_leaf(eb)) {
|
||||
btrfs_print_leaf(root, eb);
|
||||
return;
|
||||
}
|
||||
printf("node %llu level %d ptrs %d free %u generation %llu owner %llu\n",
|
||||
(unsigned long long)t->bytenr,
|
||||
btrfs_header_level(&c->header), nr,
|
||||
(unsigned long long)eb->start,
|
||||
btrfs_header_level(eb), nr,
|
||||
(u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr,
|
||||
(unsigned long long)btrfs_header_generation(&c->header),
|
||||
(unsigned long long)btrfs_header_owner(&c->header));
|
||||
(unsigned long long)btrfs_header_generation(eb),
|
||||
(unsigned long long)btrfs_header_owner(eb));
|
||||
fflush(stdout);
|
||||
size = btrfs_level_size(root, btrfs_header_level(&c->header) - 1);
|
||||
size = btrfs_level_size(root, btrfs_header_level(eb) - 1);
|
||||
for (i = 0; i < nr; i++) {
|
||||
u64 blocknr = btrfs_node_blockptr(c, i);
|
||||
u64 blocknr = btrfs_node_blockptr(eb, i);
|
||||
btrfs_item_key_to_cpu(eb, &key, i);
|
||||
printf("\tkey %d (%llu %x %llu) block %llu (%llu) gen %llu\n",
|
||||
i,
|
||||
(unsigned long long)c->ptrs[i].key.objectid,
|
||||
c->ptrs[i].key.type,
|
||||
(unsigned long long)c->ptrs[i].key.offset,
|
||||
(unsigned long long)key.objectid,
|
||||
key.type,
|
||||
(unsigned long long)key.offset,
|
||||
(unsigned long long)blocknr,
|
||||
(unsigned long long)blocknr / size,
|
||||
(unsigned long long)btrfs_node_ptr_generation(c, i));
|
||||
(unsigned long long)btrfs_node_ptr_generation(eb, i));
|
||||
fflush(stdout);
|
||||
}
|
||||
for (i = 0; i < nr; i++) {
|
||||
struct btrfs_buffer *next_buf = read_tree_block(root,
|
||||
btrfs_node_blockptr(c, i),
|
||||
size);
|
||||
struct btrfs_node *next = &next_buf->node;
|
||||
struct extent_buffer *next = read_tree_block(root,
|
||||
btrfs_node_blockptr(eb, i),
|
||||
size);
|
||||
if (btrfs_is_leaf(next) &&
|
||||
btrfs_header_level(&c->header) != 1)
|
||||
btrfs_header_level(eb) != 1)
|
||||
BUG();
|
||||
if (btrfs_header_level(&next->header) !=
|
||||
btrfs_header_level(&c->header) - 1)
|
||||
if (btrfs_header_level(next) !=
|
||||
btrfs_header_level(eb) - 1)
|
||||
BUG();
|
||||
btrfs_print_tree(root, next_buf);
|
||||
btrfs_block_release(root, next_buf);
|
||||
btrfs_print_tree(root, next);
|
||||
free_extent_buffer(next);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,6 @@
|
||||
|
||||
#ifndef __PRINT_TREE_
|
||||
#define __PRINT_TREE_
|
||||
void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l);
|
||||
void btrfs_print_tree(struct btrfs_root *root, struct btrfs_buffer *t);
|
||||
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l);
|
||||
void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *t);
|
||||
#endif
|
||||
|
153
root-tree.c
153
root-tree.c
@ -16,20 +16,18 @@
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "kerncompat.h"
|
||||
#include "radix-tree.h"
|
||||
#include "ctree.h"
|
||||
#include "transaction.h"
|
||||
#include "disk-io.h"
|
||||
#include "print-tree.h"
|
||||
|
||||
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_path *path;
|
||||
struct btrfs_key search_key;
|
||||
struct btrfs_leaf *l;
|
||||
struct btrfs_key found_key;
|
||||
struct extent_buffer *l;
|
||||
int ret;
|
||||
int slot;
|
||||
|
||||
@ -37,24 +35,28 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
|
||||
search_key.type = (u8)-1;
|
||||
search_key.offset = (u64)-1;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
ret = btrfs_search_slot(NULL, root, &search_key, &path, 0, 0);
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
BUG_ON(ret == 0);
|
||||
l = &path.nodes[0]->leaf;
|
||||
BUG_ON(path.slots[0] == 0);
|
||||
slot = path.slots[0] - 1;
|
||||
if (btrfs_disk_key_objectid(&l->items[slot].key) != objectid) {
|
||||
l = path->nodes[0];
|
||||
BUG_ON(path->slots[0] == 0);
|
||||
slot = path->slots[0] - 1;
|
||||
btrfs_item_key_to_cpu(l, &found_key, slot);
|
||||
if (found_key.objectid != objectid) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
memcpy(item, btrfs_item_ptr(l, slot, struct btrfs_root_item),
|
||||
sizeof(*item));
|
||||
btrfs_disk_key_to_cpu(key, &l->items[slot].key);
|
||||
btrfs_release_path(root, &path);
|
||||
read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot),
|
||||
sizeof(*item));
|
||||
memcpy(key, &found_key, sizeof(found_key));
|
||||
ret = 0;
|
||||
out:
|
||||
btrfs_release_path(root, path);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -62,22 +64,26 @@ 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 btrfs_leaf *l;
|
||||
struct btrfs_path *path;
|
||||
struct extent_buffer *l;
|
||||
int ret;
|
||||
int slot;
|
||||
unsigned long ptr;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
ret = btrfs_search_slot(trans, root, key, &path, 0, 1);
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
ret = btrfs_search_slot(trans, root, key, path, 0, 1);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
BUG_ON(ret != 0);
|
||||
l = &path.nodes[0]->leaf;
|
||||
slot = path.slots[0];
|
||||
memcpy(btrfs_item_ptr(l, slot, struct btrfs_root_item), item,
|
||||
sizeof(*item));
|
||||
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_release_path(root, &path);
|
||||
btrfs_release_path(root, path);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -87,23 +93,108 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
{
|
||||
int ret;
|
||||
ret = btrfs_insert_item(trans, root, key, item, sizeof(*item));
|
||||
BUG_ON(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid,
|
||||
struct btrfs_root *latest)
|
||||
{
|
||||
struct btrfs_root *dead_root;
|
||||
struct btrfs_item *item;
|
||||
struct btrfs_root_item *ri;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_path *path;
|
||||
int ret;
|
||||
u32 nritems;
|
||||
struct extent_buffer *leaf;
|
||||
int slot;
|
||||
|
||||
key.objectid = objectid;
|
||||
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
|
||||
key.offset = 0;
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
while(1) {
|
||||
leaf = path->nodes[0];
|
||||
nritems = btrfs_header_nritems(leaf);
|
||||
slot = path->slots[0];
|
||||
if (slot >= nritems) {
|
||||
ret = btrfs_next_leaf(root, path);
|
||||
if (ret)
|
||||
break;
|
||||
leaf = path->nodes[0];
|
||||
nritems = btrfs_header_nritems(leaf);
|
||||
slot = path->slots[0];
|
||||
}
|
||||
item = btrfs_item_nr(leaf, slot);
|
||||
btrfs_item_key_to_cpu(leaf, &key, slot);
|
||||
if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY)
|
||||
goto next;
|
||||
|
||||
if (key.objectid < objectid)
|
||||
goto next;
|
||||
|
||||
if (key.objectid > objectid)
|
||||
break;
|
||||
|
||||
ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item);
|
||||
if (btrfs_disk_root_refs(leaf, ri) != 0)
|
||||
goto next;
|
||||
|
||||
dead_root = btrfs_read_fs_root_no_radix(root->fs_info, &key);
|
||||
if (IS_ERR(dead_root)) {
|
||||
ret = PTR_ERR(dead_root);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = btrfs_add_dead_root(dead_root, latest,
|
||||
&root->fs_info->dead_roots);
|
||||
if (ret)
|
||||
goto err;
|
||||
next:
|
||||
slot++;
|
||||
path->slots[0]++;
|
||||
}
|
||||
ret = 0;
|
||||
err:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_key *key)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_path *path;
|
||||
int ret;
|
||||
u32 refs;
|
||||
struct btrfs_root_item *ri;
|
||||
struct extent_buffer *leaf;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
ret = btrfs_search_slot(trans, root, key, &path, -1, 1);
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
ret = btrfs_search_slot(trans, root, key, path, -1, 1);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (ret) {
|
||||
btrfs_print_leaf(root, path->nodes[0]);
|
||||
printk("failed to del %Lu %u %Lu\n", key->objectid, key->type, key->offset);
|
||||
|
||||
}
|
||||
BUG_ON(ret != 0);
|
||||
ret = btrfs_del_item(trans, root, &path);
|
||||
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_release_path(root, path);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
@ -21,8 +21,11 @@
|
||||
|
||||
struct btrfs_trans_handle {
|
||||
u64 transid;
|
||||
u64 alloc_exclude_start;
|
||||
u64 alloc_exclude_nr;
|
||||
unsigned long blocks_reserved;
|
||||
unsigned long blocks_used;
|
||||
struct btrfs_block_group_cache *block_group;
|
||||
};
|
||||
|
||||
static inline struct btrfs_trans_handle *
|
||||
@ -30,11 +33,20 @@ btrfs_start_transaction(struct btrfs_root *root, int num_blocks)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct btrfs_trans_handle *h = malloc(sizeof(*h));
|
||||
|
||||
BUG_ON(root->commit_root);
|
||||
BUG_ON(fs_info->running_transaction);
|
||||
fs_info->running_transaction = h;
|
||||
fs_info->generation++;
|
||||
h->transid = fs_info->generation;
|
||||
h->alloc_exclude_start = 0;
|
||||
h->alloc_exclude_nr = 0;
|
||||
h->blocks_reserved = num_blocks;
|
||||
h->blocks_used = 0;
|
||||
h->block_group = NULL;
|
||||
root->last_trans = h->transid;
|
||||
root->commit_root = root->node;
|
||||
extent_buffer_get(root->node);
|
||||
return h;
|
||||
}
|
||||
|
||||
|
236
utils.c
Normal file
236
utils.c
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Oracle. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License v2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 600
|
||||
#define __USE_XOPEN2K
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "kerncompat.h"
|
||||
#include "radix-tree.h"
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "transaction.h"
|
||||
#include "crc32c.h"
|
||||
#include "utils.h"
|
||||
|
||||
static u64 reference_root_table[4] = {
|
||||
[0] = 0,
|
||||
[1] = BTRFS_ROOT_TREE_OBJECTID,
|
||||
[2] = BTRFS_EXTENT_TREE_OBJECTID,
|
||||
[3] = BTRFS_FS_TREE_OBJECTID,
|
||||
};
|
||||
|
||||
int make_btrfs(int fd, u64 blocks[4], u64 num_bytes, u32 nodesize,
|
||||
u32 leafsize, u32 sectorsize, u32 stripesize)
|
||||
{
|
||||
struct btrfs_super_block super;
|
||||
struct extent_buffer *buf;
|
||||
struct btrfs_root_item root_item;
|
||||
struct btrfs_disk_key disk_key;
|
||||
struct btrfs_extent_ref *extent_ref;
|
||||
struct btrfs_extent_item *extent_item;
|
||||
struct btrfs_inode_item *inode_item;
|
||||
int i;
|
||||
int ret;
|
||||
u32 itemoff;
|
||||
u32 nritems = 0;
|
||||
u64 hash;
|
||||
u64 first_free;
|
||||
u64 ref_gen;
|
||||
u64 ref_root;
|
||||
|
||||
first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize * 2 - 1;
|
||||
first_free &= ~((u64)sectorsize - 1);
|
||||
|
||||
num_bytes = (num_bytes / sectorsize) * sectorsize;
|
||||
uuid_generate(super.fsid);
|
||||
btrfs_set_super_bytenr(&super, blocks[0]);
|
||||
strcpy((char *)(&super.magic), BTRFS_MAGIC);
|
||||
btrfs_set_super_generation(&super, 1);
|
||||
btrfs_set_super_root(&super, blocks[1]);
|
||||
btrfs_set_super_total_bytes(&super, num_bytes);
|
||||
btrfs_set_super_bytes_used(&super, first_free + 3 * leafsize);
|
||||
btrfs_set_super_root_dir(&super, 0);
|
||||
btrfs_set_super_sectorsize(&super, sectorsize);
|
||||
btrfs_set_super_leafsize(&super, leafsize);
|
||||
btrfs_set_super_nodesize(&super, nodesize);
|
||||
btrfs_set_super_stripesize(&super, stripesize);
|
||||
btrfs_set_super_root_level(&super, 0);
|
||||
|
||||
buf = malloc(sizeof(*buf) + max(sectorsize, leafsize));
|
||||
|
||||
BUG_ON(sizeof(super) > sectorsize);
|
||||
memset(buf->data, 0, sectorsize);
|
||||
memcpy(buf->data, &super, sizeof(super));
|
||||
ret = pwrite(fd, buf->data, sectorsize, blocks[0]);
|
||||
BUG_ON(ret != sectorsize);
|
||||
|
||||
/* create the tree of root objects */
|
||||
memset(buf->data, 0, leafsize);
|
||||
btrfs_set_header_bytenr(buf, blocks[1]);
|
||||
btrfs_set_header_nritems(buf, 2);
|
||||
btrfs_set_header_generation(buf, 1);
|
||||
btrfs_set_header_owner(buf, BTRFS_ROOT_TREE_OBJECTID);
|
||||
write_extent_buffer(buf, super.fsid, (unsigned long)
|
||||
btrfs_header_fsid(buf), BTRFS_FSID_SIZE);
|
||||
|
||||
/* create the items for the root tree */
|
||||
memset(&root_item, 0, sizeof(root_item));
|
||||
inode_item = &root_item.inode;
|
||||
btrfs_set_stack_inode_generation(inode_item, 1);
|
||||
btrfs_set_stack_inode_size(inode_item, 3);
|
||||
btrfs_set_stack_inode_nlink(inode_item, 1);
|
||||
btrfs_set_stack_inode_nblocks(inode_item, 1);
|
||||
btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
|
||||
btrfs_set_root_refs(&root_item, 1);
|
||||
btrfs_set_root_used(&root_item, leafsize);
|
||||
|
||||
memset(&disk_key, 0, sizeof(disk_key));
|
||||
btrfs_set_disk_key_type(&disk_key, BTRFS_ROOT_ITEM_KEY);
|
||||
btrfs_set_disk_key_offset(&disk_key, 0);
|
||||
|
||||
itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(root_item);
|
||||
btrfs_set_root_bytenr(&root_item, blocks[2]);
|
||||
btrfs_set_disk_key_objectid(&disk_key, BTRFS_EXTENT_TREE_OBJECTID);
|
||||
btrfs_set_item_key(buf, &disk_key, 0);
|
||||
btrfs_set_item_offset(buf, btrfs_item_nr(buf, 0), itemoff);
|
||||
btrfs_set_item_size(buf, btrfs_item_nr(buf, 0), sizeof(root_item));
|
||||
write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, 0),
|
||||
sizeof(root_item));
|
||||
|
||||
itemoff = itemoff - sizeof(root_item);
|
||||
btrfs_set_root_bytenr(&root_item, blocks[3]);
|
||||
btrfs_set_disk_key_objectid(&disk_key, BTRFS_FS_TREE_OBJECTID);
|
||||
btrfs_set_item_key(buf, &disk_key, 1);
|
||||
btrfs_set_item_offset(buf, btrfs_item_nr(buf, 1), itemoff);
|
||||
btrfs_set_item_size(buf, btrfs_item_nr(buf, 1), sizeof(root_item));
|
||||
write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, 1),
|
||||
sizeof(root_item));
|
||||
ret = pwrite(fd, buf->data, leafsize, blocks[1]);
|
||||
BUG_ON(ret != leafsize);
|
||||
|
||||
/* create the items for the extent tree */
|
||||
itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) -
|
||||
sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_disk_key_objectid(&disk_key, 0);
|
||||
btrfs_set_disk_key_offset(&disk_key, first_free);
|
||||
btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_ITEM_KEY);
|
||||
btrfs_set_item_key(buf, &disk_key, nritems);
|
||||
btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems), itemoff);
|
||||
btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems),
|
||||
sizeof(struct btrfs_extent_item));
|
||||
extent_item = btrfs_item_ptr(buf, nritems, struct btrfs_extent_item);
|
||||
btrfs_set_extent_refs(buf, extent_item, 1);
|
||||
nritems++;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (blocks[i] < first_free) {
|
||||
BUG_ON(i > 0);
|
||||
continue;
|
||||
}
|
||||
/* create extent item */
|
||||
itemoff = itemoff - sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
|
||||
btrfs_set_disk_key_offset(&disk_key, leafsize);
|
||||
btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_ITEM_KEY);
|
||||
btrfs_set_item_key(buf, &disk_key, nritems);
|
||||
btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems),
|
||||
itemoff);
|
||||
btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems),
|
||||
sizeof(struct btrfs_extent_item));
|
||||
extent_item = btrfs_item_ptr(buf, nritems,
|
||||
struct btrfs_extent_item);
|
||||
btrfs_set_extent_refs(buf, extent_item, 1);
|
||||
nritems++;
|
||||
|
||||
/* create extent ref */
|
||||
ref_root = reference_root_table[i];
|
||||
if (ref_root == BTRFS_FS_TREE_OBJECTID)
|
||||
ref_gen = 1;
|
||||
else
|
||||
ref_gen = 0;
|
||||
|
||||
hash = btrfs_hash_extent_ref(ref_root, ref_gen, 0, 0);
|
||||
itemoff = itemoff - sizeof(struct btrfs_extent_ref);
|
||||
btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
|
||||
btrfs_set_disk_key_offset(&disk_key, hash);
|
||||
btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_REF_KEY);
|
||||
btrfs_set_item_key(buf, &disk_key, nritems);
|
||||
btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems),
|
||||
itemoff);
|
||||
btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems),
|
||||
sizeof(struct btrfs_extent_ref));
|
||||
extent_ref = btrfs_item_ptr(buf, nritems,
|
||||
struct btrfs_extent_ref);
|
||||
btrfs_set_ref_root(buf, extent_ref, ref_root);
|
||||
btrfs_set_ref_generation(buf, extent_ref, ref_gen);
|
||||
btrfs_set_ref_objectid(buf, extent_ref, 0);
|
||||
btrfs_set_ref_offset(buf, extent_ref, 0);
|
||||
nritems++;
|
||||
}
|
||||
btrfs_set_header_bytenr(buf, blocks[2]);
|
||||
btrfs_set_header_owner(buf, BTRFS_EXTENT_TREE_OBJECTID);
|
||||
btrfs_set_header_nritems(buf, nritems);
|
||||
ret = pwrite(fd, buf->data, leafsize, blocks[2]);
|
||||
BUG_ON(ret != leafsize);
|
||||
|
||||
/* finally create the FS root */
|
||||
btrfs_set_header_bytenr(buf, blocks[3]);
|
||||
btrfs_set_header_owner(buf, BTRFS_FS_TREE_OBJECTID);
|
||||
btrfs_set_header_nritems(buf, 0);
|
||||
ret = pwrite(fd, buf->data, leafsize, blocks[3]);
|
||||
BUG_ON(ret != leafsize);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 objectid)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_inode_item inode_item;
|
||||
|
||||
memset(&inode_item, 0, sizeof(inode_item));
|
||||
btrfs_set_stack_inode_generation(&inode_item, trans->transid);
|
||||
btrfs_set_stack_inode_size(&inode_item, 0);
|
||||
btrfs_set_stack_inode_nlink(&inode_item, 1);
|
||||
btrfs_set_stack_inode_nblocks(&inode_item, 1);
|
||||
btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0555);
|
||||
|
||||
if (root->fs_info->tree_root == root)
|
||||
btrfs_set_super_root_dir(&root->fs_info->super_copy, objectid);
|
||||
|
||||
ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = btrfs_insert_inode_ref(trans, root, "..", 2, objectid, objectid);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
btrfs_set_root_dirid(&root->root_item, objectid);
|
||||
ret = 0;
|
||||
error:
|
||||
return ret;
|
||||
}
|
25
utils.h
Normal file
25
utils.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Oracle. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License v2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __UTILS__
|
||||
#define __UTILS__
|
||||
int make_btrfs(int fd, u64 new_blocks[4], u64 num_bytes, u32 nodesize,
|
||||
u32 leafsize, u32 sectorsize, u32 stripesize);
|
||||
int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 objectid);
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user