Update btrfs-progs to match kernel sources

master
Yan 2008-01-04 10:38:22 -05:00 committed by David Woodhouse
parent 088f78aeaa
commit 7777e63b42
20 changed files with 5579 additions and 2565 deletions

View File

@ -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
View File

@ -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);

2343
ctree.c

File diff suppressed because it is too large Load Diff

747
ctree.h
View File

@ -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

View File

@ -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;
}

View File

@ -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
View File

@ -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);
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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
View File

@ -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);

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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 100644
View 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 100644
View 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