aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2015-12-24 00:41:57 -0200
committerPaulo Alcantara <pcacjr@zytor.com>2015-12-24 00:41:57 -0200
commit4620b95f3b6511850093c56bc3646625fdd14a4c (patch)
tree68537eaf1731e453241600fc0b63d355dc0760a9
parent721a0af2f0ba111c31685c5f6c5481eb25346971 (diff)
downloadsyslinux-btrfs-fixes.tar.gz
syslinux-btrfs-fixes.tar.xz
syslinux-btrfs-fixes.zip
btrfs fixesbtrfs-fixes
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r--core/fs/btrfs/btrfs.c110
-rw-r--r--core/fs/btrfs/btrfs.h45
2 files changed, 138 insertions, 17 deletions
diff --git a/core/fs/btrfs/btrfs.c b/core/fs/btrfs/btrfs.c
index 53e11050..2031b8e0 100644
--- a/core/fs/btrfs/btrfs.c
+++ b/core/fs/btrfs/btrfs.c
@@ -22,6 +22,18 @@
#include <minmax.h>
#include "btrfs.h"
+#define btrfs_debug(fmt, args...) \
+ ({ \
+ dprintf("%s:%u: btrfs - [debug] " fmt "\n", __func__, \
+ __LINE__, ## args); \
+ })
+
+#define btrfs_error(fmt, args...) \
+ ({ \
+ dprintf("%s:%u: btrfs - [error] " fmt "\n", __func__, \
+ __LINE__, ## args); \
+ })
+
union tree_buf {
struct btrfs_header header;
struct btrfs_node node;
@@ -73,6 +85,9 @@ static int bin_search(void *ptr, int item_size, void *cmp_item, cmp_func func,
static int btrfs_comp_chunk_map(struct btrfs_chunk_map_item *m1,
struct btrfs_chunk_map_item *m2)
{
+ btrfs_debug("in");
+ btrfs_debug("m1->logical %d", m1->logical);
+ btrfs_debug("m2->logical %d", m2->logical);
if (m1->logical > m2->logical)
return 1;
if (m1->logical < m2->logical)
@@ -113,6 +128,24 @@ static void insert_map(struct fs_info *fs, struct btrfs_chunk_map_item *item)
chunk_map->cur_length++;
}
+static void insert_stripes_to_map(struct fs_info *fs,
+ const struct btrfs_disk_key *key,
+ const struct btrfs_chunk *chunk)
+{
+ struct btrfs_stripe *stripe = &chunk->stripe;
+ struct btrfs_stripe *stripe_end = stripe + chunk->num_stripes;
+ struct btrfs_chunk_map_item item;
+
+ for ( ; stripe < stripe_end; stripe++) {
+ item.logical = key->offset;
+ item.length = chunk->length;
+ item.devid = stripe->devid;
+ item.physical = stripe->offset;
+ btrfs_debug("item.logical %d", item.logical);
+ insert_map(fs, &item);
+ }
+}
+
/*
* from sys_chunk_array or chunk_tree, we can convert a logical address to
* a physical address we can not support multi device case yet
@@ -124,6 +157,9 @@ static u64 logical_physical(struct fs_info *fs, u64 logical)
struct btrfs_chunk_map_item item;
int slot, ret;
+ btrfs_debug("in");
+ btrfs_debug("logical %d", logical);
+
item.logical = logical;
ret = bin_search(chunk_map->map, sizeof(chunk_map->map[0]), &item,
(cmp_func)btrfs_comp_chunk_map, 0,
@@ -241,10 +277,17 @@ static int search_tree(struct fs_info *fs, u64 loffset,
int slot, ret;
u64 offset;
+ btrfs_debug("in");
+ btrfs_debug("loffset %d", loffset);
+
offset = logical_physical(fs, loffset);
+ btrfs_debug("offset %d", offset);
cache_read(fs, &tree_buf->header, offset, sizeof(tree_buf->header));
+ btrfs_debug("nritems %d", tree_buf->header.nritems);
+ btrfs_debug("level %d", tree_buf->header.level);
if (tree_buf->header.level) {
/* inner node */
+ btrfs_debug("inner node");
cache_read(fs, (char *)&tree_buf->node.ptrs[0],
offset + sizeof tree_buf->header,
bfs->sb.nodesize - sizeof tree_buf->header);
@@ -262,6 +305,10 @@ static int search_tree(struct fs_info *fs, u64 loffset,
key, path);
} else {
/* leaf node */
+ btrfs_debug("leaf node");
+ btrfs_debug("sizeof btrfs_header %d", sizeof(struct btrfs_header));
+ btrfs_debug("cache_read: offset %d", offset + sizeof tree_buf->header);
+ btrfs_debug("cache_read: size %d", bfs->sb.leafsize - sizeof tree_buf->header);
cache_read(fs, (char *)&tree_buf->leaf.items[0],
offset + sizeof tree_buf->header,
bfs->sb.leafsize - sizeof tree_buf->header);
@@ -276,7 +323,12 @@ static int search_tree(struct fs_info *fs, u64 loffset,
slot--;
path->slots[tree_buf->header.level] = slot;
path->item = tree_buf->leaf.items[slot];
- cache_read(fs, (char *)&path->data,
+ btrfs_debug("items slot offs: %d", tree_buf->leaf.items[slot].offset);
+ btrfs_debug("cache_read: offset %d",
+ offset + sizeof tree_buf->header +
+ tree_buf->leaf.items[slot].offset);
+ btrfs_debug("cache_read: size %d", tree_buf->leaf.items[slot].size);
+ cache_read(fs, (char *)&path->data[0],
offset + sizeof tree_buf->header +
tree_buf->leaf.items[slot].offset,
tree_buf->leaf.items[slot].size);
@@ -330,11 +382,12 @@ static int next_slot(struct fs_info *fs, struct btrfs_disk_key *key,
static void btrfs_read_sys_chunk_array(struct fs_info *fs)
{
struct btrfs_info * const bfs = fs->fs_info;
- struct btrfs_chunk_map_item item;
struct btrfs_disk_key *key;
struct btrfs_chunk *chunk;
int cur;
+ btrfs_debug("in");
+
/* read chunk array in superblock */
cur = 0;
while (cur < bfs->sb.sys_chunk_array_size) {
@@ -342,13 +395,9 @@ static void btrfs_read_sys_chunk_array(struct fs_info *fs)
cur += sizeof(*key);
chunk = (struct btrfs_chunk *)(bfs->sb.sys_chunk_array + cur);
cur += btrfs_chunk_item_size(chunk->num_stripes);
- /* insert to mapping table, ignore multi stripes */
- item.logical = key->offset;
- item.length = chunk->length;
- item.devid = chunk->stripe.devid;
- item.physical = chunk->stripe.offset;/*ignore other stripes */
- insert_map(fs, &item);
+ insert_stripes_to_map(fs, key, chunk);
}
+ btrfs_debug("out");
}
/* read chunk items from chunk_tree and insert them to chunk map */
@@ -357,9 +406,10 @@ static void btrfs_read_chunk_tree(struct fs_info *fs)
struct btrfs_info * const bfs = fs->fs_info;
struct btrfs_disk_key search_key;
struct btrfs_chunk *chunk;
- struct btrfs_chunk_map_item item;
struct btrfs_path path;
+ btrfs_debug("in");
+
if (!(bfs->sb.flags & BTRFS_SUPER_FLAG_METADUMP)) {
if (bfs->sb.num_devices > 1)
printf("warning: only support single device btrfs\n");
@@ -367,20 +417,21 @@ static void btrfs_read_chunk_tree(struct fs_info *fs)
search_key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
search_key.type = BTRFS_CHUNK_ITEM_KEY;
search_key.offset = 0;
+ btrfs_debug("objectid %d", search_key.objectid);
+ btrfs_debug("type %d", search_key.type);
+ btrfs_debug("offset %d", search_key.offset);
clear_path(&path);
search_tree(fs, bfs->sb.chunk_root, &search_key, &path);
do {
do {
+ #if 0
if (btrfs_comp_keys_type(&search_key,
&path.item.key))
break;
+ #endif
chunk = (struct btrfs_chunk *)(path.data);
- /* insert to mapping table, ignore stripes */
- item.logical = path.item.key.offset;
- item.length = chunk->length;
- item.devid = chunk->stripe.devid;
- item.physical = chunk->stripe.offset;
- insert_map(fs, &item);
+ insert_stripes_to_map(fs, &path.item.key,
+ chunk);
} while (!next_slot(fs, &search_key, &path));
if (btrfs_comp_keys_type(&search_key, &path.item.key))
break;
@@ -402,12 +453,19 @@ static struct inode *btrfs_iget_by_inr(struct fs_info *fs, u64 inr)
struct btrfs_path path;
int ret;
+ btrfs_debug("in");
+ btrfs_debug("inr %d", inr);
+
/* FIXME: some BTRFS inode member are u64, while our logical inode
is u32, we may need change them to u64 later */
search_key.objectid = inr;
search_key.type = BTRFS_INODE_ITEM_KEY;
search_key.offset = 0;
clear_path(&path);
+ btrfs_debug("objectid %d", search_key.objectid);
+ btrfs_debug("type %d", search_key.type);
+ btrfs_debug("offset %d", search_key.offset);
+ btrfs_debug("bfs->fs_tree %d", bfs->fs_tree);
ret = search_tree(fs, bfs->fs_tree, &search_key, &path);
if (ret)
return NULL;
@@ -443,6 +501,7 @@ static struct inode *btrfs_iget_by_inr(struct fs_info *fs, u64 inr)
static struct inode *btrfs_iget_root(struct fs_info *fs)
{
+ btrfs_debug("in");
/* BTRFS_FIRST_CHUNK_TREE_OBJECTID(256) actually is first OBJECTID for FS_TREE */
return btrfs_iget_by_inr(fs, BTRFS_FIRST_CHUNK_TREE_OBJECTID);
}
@@ -456,6 +515,9 @@ static struct inode *btrfs_iget(const char *name, struct inode *parent)
struct btrfs_dir_item dir_item;
int ret;
+ btrfs_debug("in");
+ btrfs_debug("parent->ino %d name %s", parent->ino, name);
+
search_key.objectid = parent->ino;
search_key.type = BTRFS_DIR_ITEM_KEY;
search_key.offset = btrfs_name_hash(name, strlen(name));
@@ -465,6 +527,8 @@ static struct inode *btrfs_iget(const char *name, struct inode *parent)
return NULL;
dir_item = *(struct btrfs_dir_item *)path.data;
+ btrfs_debug("out");
+
return btrfs_iget_by_inr(fs, dir_item.location.objectid);
}
@@ -631,13 +695,19 @@ static void btrfs_get_fs_tree(struct fs_info *fs)
/* find fs_tree from tree_root */
if (subvol_ok)
search_key.objectid = path.item.key.offset;
- else /* "default" volume */
+ else /* "default" volume */ {
+ btrfs_debug("default subvolume");
search_key.objectid = BTRFS_FS_TREE_OBJECTID;
+ }
search_key.type = BTRFS_ROOT_ITEM_KEY;
search_key.offset = -1;
clear_path(&path);
+ btrfs_debug("bfs->sb.root %d", bfs->sb.root);
search_tree(fs, bfs->sb.root, &search_key, &path);
tree = (struct btrfs_root_item *)path.data;
+ btrfs_debug("bytenr %d", tree->bytenr);
+ btrfs_debug("level %d", tree->level);
+ btrfs_debug("dirid %d", tree->root_dirid);
bfs->fs_tree = tree->bytenr;
}
@@ -647,8 +717,10 @@ static int btrfs_fs_init(struct fs_info *fs)
struct disk *disk = fs->fs_dev->disk;
struct btrfs_info *bfs;
+ btrfs_debug("in");
+
btrfs_init_crc32c();
-
+
bfs = zalloc(sizeof(struct btrfs_info));
if (!bfs)
return -1;
@@ -663,6 +735,8 @@ static int btrfs_fs_init(struct fs_info *fs)
/* Initialize the block cache */
cache_init(fs->fs_dev, fs->block_shift);
+ btrfs_debug("cache init: %d", fs->fs_dev->cache_init);
+
btrfs_read_super_block(fs);
if (bfs->sb.magic != BTRFS_MAGIC_N)
return -1;
@@ -673,6 +747,8 @@ static int btrfs_fs_init(struct fs_info *fs)
btrfs_read_chunk_tree(fs);
btrfs_get_fs_tree(fs);
+ btrfs_debug("out");
+
return fs->block_shift;
}
diff --git a/core/fs/btrfs/btrfs.h b/core/fs/btrfs/btrfs.h
index 8f519a9c..a60a5043 100644
--- a/core/fs/btrfs/btrfs.h
+++ b/core/fs/btrfs/btrfs.h
@@ -241,6 +241,21 @@ struct btrfs_inode_item {
struct btrfs_timespec otime;
} __attribute__ ((__packed__));
+struct btrfs_root_item_v0 {
+ struct btrfs_inode_item inode;
+ __le64 generation;
+ __le64 root_dirid;
+ __le64 bytenr;
+ __le64 byte_limit;
+ __le64 bytes_used;
+ __le64 last_snapshot;
+ __le64 flags;
+ __le32 refs;
+ struct btrfs_disk_key drop_progress;
+ u8 drop_level;
+ u8 level;
+} __attribute__ ((__packed__));
+
struct btrfs_root_item {
struct btrfs_inode_item inode;
__le64 generation;
@@ -254,6 +269,36 @@ struct btrfs_root_item {
struct btrfs_disk_key drop_progress;
u8 drop_level;
u8 level;
+
+ /*
+ * The following fields appear after subvol_uuids+subvol_times
+ * were introduced.
+ */
+
+ /*
+ * This generation number is used to test if the new fields are valid
+ * and up to date while reading the root item. Everytime the root item
+ * is written out, the "generation" field is copied into this field. If
+ * anyone ever mounted the fs with an older kernel, we will have
+ * mismatching generation values here and thus must invalidate the
+ * new fields. See btrfs_update_root and btrfs_find_last_root for
+ * details.
+ * the offset of generation_v2 is also used as the start for the memset
+ * when invalidating the fields.
+ */
+ __le64 generation_v2;
+ u8 uuid[BTRFS_UUID_SIZE];
+ u8 parent_uuid[BTRFS_UUID_SIZE];
+ u8 received_uuid[BTRFS_UUID_SIZE];
+ __le64 ctransid; /* updated when an inode changes */
+ __le64 otransid; /* trans when created */
+ __le64 stransid; /* trans when sent. non-zero for received subvol */
+ __le64 rtransid; /* trans when received. non-zero for received subvol */
+ struct btrfs_timespec ctime;
+ struct btrfs_timespec otime;
+ struct btrfs_timespec stime;
+ struct btrfs_timespec rtime;
+ __le64 reserved[8]; /* for future */
} __attribute__ ((__packed__));
struct btrfs_dir_item {