mirror of
https://github.com/kdave/btrfs-progs
synced 2025-02-23 05:16:55 +00:00
update btrfs-progs for seed device support
This patch does the following: 1) Update device management code to match the kernel code. 2) Allocator fixes. 3) Add a program called btrfstune to set/clear the SEEDING super block flags.
This commit is contained in:
parent
95470dfaf1
commit
4d1d3a59d6
5
Makefile
5
Makefile
@ -15,7 +15,7 @@ prefix ?= /usr/local
|
||||
bindir = $(prefix)/bin
|
||||
LIBS=-luuid
|
||||
|
||||
progs = btrfsctl btrfsck mkfs.btrfs debug-tree btrfs-show btrfs-vol
|
||||
progs = btrfsctl btrfsck mkfs.btrfs debug-tree btrfs-show btrfs-vol btrfstune
|
||||
|
||||
# make C=1 to enable sparse
|
||||
ifdef C
|
||||
@ -52,6 +52,9 @@ mkfs.btrfs: $(objects) mkfs.o
|
||||
debug-tree: $(objects) debug-tree.o
|
||||
gcc $(CFLAGS) -o debug-tree $(objects) debug-tree.o $(LDFLAGS) $(LIBS)
|
||||
|
||||
btrfstune: $(objects) btrfstune.o
|
||||
gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS)
|
||||
|
||||
dir-test: $(objects) dir-test.o
|
||||
gcc $(CFLAGS) -o dir-test $(objects) dir-test.o $(LDFLAGS) $(LIBS)
|
||||
|
||||
|
126
btrfstune.c
Normal file
126
btrfstune.c
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 500
|
||||
#define _GNU_SOURCE 1
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include "kerncompat.h"
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "transaction.h"
|
||||
#include "utils.h"
|
||||
#include "version.h"
|
||||
|
||||
static char *device;
|
||||
|
||||
int update_seeding_flag(struct btrfs_root *root, int set_flag)
|
||||
{
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_super_block *disk_super;
|
||||
u64 super_flags;
|
||||
|
||||
disk_super = &root->fs_info->super_copy;
|
||||
super_flags = btrfs_super_flags(disk_super);
|
||||
if (set_flag) {
|
||||
if (super_flags & BTRFS_SUPER_FLAG_SEEDING) {
|
||||
fprintf(stderr, "seeding flag is already set on %s\n",
|
||||
device);
|
||||
return 1;
|
||||
}
|
||||
super_flags |= BTRFS_SUPER_FLAG_SEEDING;
|
||||
} else {
|
||||
if (!(super_flags & BTRFS_SUPER_FLAG_SEEDING)) {
|
||||
fprintf(stderr, "seeding flag is not set on %s\n",
|
||||
device);
|
||||
return 1;
|
||||
}
|
||||
super_flags &= ~BTRFS_SUPER_FLAG_SEEDING;
|
||||
}
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
btrfs_set_super_flags(disk_super, super_flags);
|
||||
btrfs_commit_transaction(trans, root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: btrfstune [options] device\n");
|
||||
fprintf(stderr, "\t-S value\tenable/disable seeding\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
int success = 0;
|
||||
int seeding_flag = 0;
|
||||
int seeding_value = 0;
|
||||
int ret;
|
||||
|
||||
while(1) {
|
||||
int c = getopt(argc, argv, "S:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'S':
|
||||
seeding_flag = 1;
|
||||
seeding_value = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
argc = argc - optind;
|
||||
device = argv[optind];
|
||||
if (argc != 1) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (check_mounted(device)) {
|
||||
fprintf(stderr, "%s is mounted\n", device);
|
||||
return 1;
|
||||
}
|
||||
|
||||
root = open_ctree(device, 0, 1);
|
||||
|
||||
if (seeding_flag) {
|
||||
ret = update_seeding_flag(root, seeding_value);
|
||||
if (!ret)
|
||||
success++;
|
||||
}
|
||||
|
||||
if (success > 0) {
|
||||
ret = 0;
|
||||
} else {
|
||||
root->fs_info->readonly = 1;
|
||||
ret = 1;
|
||||
}
|
||||
close_ctree(root);
|
||||
|
||||
return ret;
|
||||
}
|
8
ctree.c
8
ctree.c
@ -112,6 +112,10 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_header_owner(cow, new_root_objectid);
|
||||
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
|
||||
|
||||
write_extent_buffer(cow, root->fs_info->fsid,
|
||||
(unsigned long)btrfs_header_fsid(cow),
|
||||
BTRFS_FSID_SIZE);
|
||||
|
||||
WARN_ON(btrfs_header_generation(buf) > trans->transid);
|
||||
ret = btrfs_inc_ref(trans, new_root, buf, cow, NULL);
|
||||
kfree(new_root);
|
||||
@ -161,6 +165,10 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_header_owner(cow, root->root_key.objectid);
|
||||
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
|
||||
|
||||
write_extent_buffer(cow, root->fs_info->fsid,
|
||||
(unsigned long)btrfs_header_fsid(cow),
|
||||
BTRFS_FSID_SIZE);
|
||||
|
||||
WARN_ON(btrfs_header_generation(buf) > trans->transid);
|
||||
if (btrfs_header_generation(buf) != trans->transid) {
|
||||
different_trans = 1;
|
||||
|
18
ctree.h
18
ctree.h
@ -160,6 +160,9 @@ struct btrfs_dev_item {
|
||||
/* type and info about this device */
|
||||
__le64 type;
|
||||
|
||||
/* expected generation for this device */
|
||||
__le64 generation;
|
||||
|
||||
/* grouping information for allocation decisions */
|
||||
__le32 dev_group;
|
||||
|
||||
@ -171,6 +174,9 @@ struct btrfs_dev_item {
|
||||
|
||||
/* btrfs generated uuid for this device */
|
||||
u8 uuid[BTRFS_UUID_SIZE];
|
||||
|
||||
/* uuid of FS who owns this device */
|
||||
u8 fsid[BTRFS_UUID_SIZE];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct btrfs_stripe {
|
||||
@ -246,6 +252,8 @@ struct btrfs_header {
|
||||
sizeof(struct btrfs_item) - \
|
||||
sizeof(struct btrfs_file_extent_item))
|
||||
|
||||
#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32)
|
||||
|
||||
/*
|
||||
* this is a very generous portion of the super block, giving us
|
||||
* room to translate 14 chunks with 3 stripes each.
|
||||
@ -524,6 +532,7 @@ struct btrfs_block_group_cache {
|
||||
u64 pinned;
|
||||
u64 flags;
|
||||
int cached;
|
||||
int ro;
|
||||
};
|
||||
|
||||
struct btrfs_extent_ops {
|
||||
@ -744,6 +753,7 @@ BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64);
|
||||
BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32);
|
||||
BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8);
|
||||
BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8);
|
||||
BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item,
|
||||
@ -763,12 +773,19 @@ BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item,
|
||||
seek_speed, 8);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item,
|
||||
bandwidth, 8);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item,
|
||||
generation, 64);
|
||||
|
||||
static inline char *btrfs_device_uuid(struct btrfs_dev_item *d)
|
||||
{
|
||||
return (char *)d + offsetof(struct btrfs_dev_item, uuid);
|
||||
}
|
||||
|
||||
static inline char *btrfs_device_fsid(struct btrfs_dev_item *d)
|
||||
{
|
||||
return (char *)d + offsetof(struct btrfs_dev_item, fsid);
|
||||
}
|
||||
|
||||
BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64);
|
||||
BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64);
|
||||
BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64);
|
||||
@ -1259,6 +1276,7 @@ BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
|
||||
|
||||
/* struct btrfs_super_block */
|
||||
BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 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);
|
||||
|
31
disk-io.c
31
disk-io.c
@ -37,14 +37,24 @@
|
||||
|
||||
static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
|
||||
{
|
||||
if (buf->start != btrfs_header_bytenr(buf))
|
||||
return 1;
|
||||
|
||||
if (memcmp_extent_buffer(buf, root->fs_info->fsid,
|
||||
(unsigned long)btrfs_header_fsid(buf),
|
||||
BTRFS_FSID_SIZE))
|
||||
return 1;
|
||||
return 0;
|
||||
struct btrfs_fs_devices *fs_devices;
|
||||
int ret = 1;
|
||||
|
||||
if (buf->start != btrfs_header_bytenr(buf))
|
||||
return ret;
|
||||
|
||||
fs_devices = root->fs_info->fs_devices;
|
||||
while (fs_devices) {
|
||||
if (!memcmp_extent_buffer(buf, fs_devices->fsid,
|
||||
(unsigned long)btrfs_header_fsid(buf),
|
||||
BTRFS_FSID_SIZE)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
fs_devices = fs_devices->seed;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len)
|
||||
@ -685,6 +695,10 @@ int write_all_supers(struct btrfs_root *root)
|
||||
dev_item);
|
||||
list_for_each(cur, head) {
|
||||
dev = list_entry(cur, struct btrfs_device, dev_list);
|
||||
if (!dev->writeable)
|
||||
continue;
|
||||
|
||||
btrfs_set_device_generation(sb, dev_item, 0);
|
||||
btrfs_set_device_type(sb, dev_item, dev->type);
|
||||
btrfs_set_device_id(sb, dev_item, dev->devid);
|
||||
btrfs_set_device_total_bytes(sb, dev_item, dev->total_bytes);
|
||||
@ -695,6 +709,9 @@ int write_all_supers(struct btrfs_root *root)
|
||||
write_extent_buffer(sb, dev->uuid,
|
||||
(unsigned long)btrfs_device_uuid(dev_item),
|
||||
BTRFS_UUID_SIZE);
|
||||
write_extent_buffer(sb, dev->fs_devices->fsid,
|
||||
(unsigned long)btrfs_device_fsid(dev_item),
|
||||
BTRFS_UUID_SIZE);
|
||||
sb->fd = dev->fd;
|
||||
sb->dev_bytenr = sb->start;
|
||||
btrfs_set_header_flag(sb, BTRFS_HEADER_FLAG_WRITTEN);
|
||||
|
@ -159,6 +159,35 @@ err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct btrfs_block_group_cache *btrfs_lookup_first_block_group(struct
|
||||
btrfs_fs_info *info,
|
||||
u64 bytenr)
|
||||
{
|
||||
struct extent_io_tree *block_group_cache;
|
||||
struct btrfs_block_group_cache *block_group = NULL;
|
||||
u64 ptr;
|
||||
u64 start;
|
||||
u64 end;
|
||||
int ret;
|
||||
|
||||
bytenr = max_t(u64, bytenr,
|
||||
BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE);
|
||||
block_group_cache = &info->block_group_cache;
|
||||
ret = find_first_extent_bit(block_group_cache,
|
||||
bytenr, &start, &end,
|
||||
BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA |
|
||||
BLOCK_GROUP_SYSTEM);
|
||||
if (ret) {
|
||||
return NULL;
|
||||
}
|
||||
ret = get_state_private(block_group_cache, start, &ptr);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
block_group = (struct btrfs_block_group_cache *)(unsigned long)ptr;
|
||||
return block_group;
|
||||
}
|
||||
|
||||
struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
|
||||
btrfs_fs_info *info,
|
||||
u64 bytenr)
|
||||
@ -203,7 +232,6 @@ static int noinline find_search_start(struct btrfs_root *root,
|
||||
u64 last;
|
||||
u64 start = 0;
|
||||
u64 end = 0;
|
||||
u64 cache_miss = 0;
|
||||
u64 search_start = *start_ret;
|
||||
int wrapped = 0;
|
||||
|
||||
@ -216,7 +244,7 @@ again:
|
||||
goto out;
|
||||
|
||||
last = max(search_start, cache->key.objectid);
|
||||
if (!block_group_bits(cache, data)) {
|
||||
if (cache->ro || !block_group_bits(cache, data)) {
|
||||
goto new_group;
|
||||
}
|
||||
|
||||
@ -224,20 +252,17 @@ again:
|
||||
ret = find_first_extent_bit(&root->fs_info->free_space_cache,
|
||||
last, &start, &end, EXTENT_DIRTY);
|
||||
if (ret) {
|
||||
if (!cache_miss)
|
||||
cache_miss = last;
|
||||
goto new_group;
|
||||
}
|
||||
|
||||
start = max(last, start);
|
||||
last = end + 1;
|
||||
if (last - start < num) {
|
||||
if (last == cache->key.objectid + cache->key.offset)
|
||||
cache_miss = start;
|
||||
continue;
|
||||
}
|
||||
if (start + num > cache->key.objectid + cache->key.offset)
|
||||
if (start + num > cache->key.objectid + cache->key.offset) {
|
||||
goto new_group;
|
||||
}
|
||||
*start_ret = start;
|
||||
return 0;
|
||||
}
|
||||
@ -253,7 +278,7 @@ out:
|
||||
new_group:
|
||||
last = cache->key.objectid + cache->key.offset;
|
||||
wrapped:
|
||||
cache = btrfs_lookup_block_group(root->fs_info, last);
|
||||
cache = btrfs_lookup_first_block_group(root->fs_info, last);
|
||||
if (!cache) {
|
||||
no_cache:
|
||||
if (!wrapped) {
|
||||
@ -263,16 +288,12 @@ no_cache:
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
if (cache_miss && !cache->cached) {
|
||||
cache_block_group(root, cache);
|
||||
last = cache_miss;
|
||||
cache = btrfs_lookup_block_group(root->fs_info, last);
|
||||
}
|
||||
cache = btrfs_find_block_group(root, cache, last, data, 0);
|
||||
cache = btrfs_find_block_group(root, cache, last, data, 0);
|
||||
if (!cache)
|
||||
goto no_cache;
|
||||
|
||||
*cache_ret = cache;
|
||||
cache_miss = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
@ -328,7 +349,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
|
||||
if (search_start) {
|
||||
struct btrfs_block_group_cache *shint;
|
||||
shint = btrfs_lookup_block_group(info, search_start);
|
||||
if (shint && block_group_bits(shint, data)) {
|
||||
if (shint && !shint->ro && block_group_bits(shint, data)) {
|
||||
used = btrfs_block_group_used(&shint->item);
|
||||
if (used + shint->pinned <
|
||||
div_factor(shint->key.offset, factor)) {
|
||||
@ -336,7 +357,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hint && block_group_bits(hint, data)) {
|
||||
if (hint && !hint->ro && block_group_bits(hint, data)) {
|
||||
used = btrfs_block_group_used(&hint->item);
|
||||
if (used + hint->pinned <
|
||||
div_factor(hint->key.offset, factor)) {
|
||||
@ -367,7 +388,7 @@ again:
|
||||
last = cache->key.objectid + cache->key.offset;
|
||||
used = btrfs_block_group_used(&cache->item);
|
||||
|
||||
if (block_group_bits(cache, data)) {
|
||||
if (!cache->ro && block_group_bits(cache, data)) {
|
||||
if (full_search)
|
||||
free_check = cache->key.offset;
|
||||
else
|
||||
@ -1705,11 +1726,8 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
|
||||
WARN_ON(num_bytes < root->sectorsize);
|
||||
btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
|
||||
|
||||
if (search_end == (u64)-1)
|
||||
search_end = btrfs_super_total_bytes(&info->super_copy);
|
||||
|
||||
if (hint_byte) {
|
||||
block_group = btrfs_lookup_block_group(info, hint_byte);
|
||||
block_group = btrfs_lookup_first_block_group(info, hint_byte);
|
||||
if (!block_group)
|
||||
hint_byte = search_start;
|
||||
block_group = btrfs_find_block_group(root, block_group,
|
||||
@ -1724,9 +1742,10 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
|
||||
|
||||
check_failed:
|
||||
if (!block_group) {
|
||||
block_group = btrfs_lookup_block_group(info, search_start);
|
||||
block_group = btrfs_lookup_first_block_group(info,
|
||||
search_start);
|
||||
if (!block_group)
|
||||
block_group = btrfs_lookup_block_group(info,
|
||||
block_group = btrfs_lookup_first_block_group(info,
|
||||
orig_search_start);
|
||||
}
|
||||
ret = find_search_start(root, &block_group, &search_start,
|
||||
@ -1738,9 +1757,6 @@ check_failed:
|
||||
ins->objectid = search_start;
|
||||
ins->offset = num_bytes;
|
||||
|
||||
if (ins->objectid + num_bytes >= search_end)
|
||||
goto enospc;
|
||||
|
||||
if (ins->objectid + num_bytes >
|
||||
block_group->key.objectid + block_group->key.offset) {
|
||||
search_start = block_group->key.objectid +
|
||||
@ -1775,8 +1791,8 @@ check_failed:
|
||||
return 0;
|
||||
|
||||
new_group:
|
||||
if (search_start + num_bytes >= search_end) {
|
||||
enospc:
|
||||
block_group = btrfs_lookup_first_block_group(info, search_start);
|
||||
if (!block_group) {
|
||||
search_start = orig_search_start;
|
||||
if (full_scan) {
|
||||
ret = -ENOSPC;
|
||||
@ -1789,7 +1805,6 @@ enospc:
|
||||
} else
|
||||
wrapped = 1;
|
||||
}
|
||||
block_group = btrfs_lookup_block_group(info, search_start);
|
||||
cond_resched();
|
||||
block_group = btrfs_find_block_group(root, block_group,
|
||||
search_start, data, 0);
|
||||
@ -2414,7 +2429,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||
cache = kmalloc(sizeof(*cache), GFP_NOFS);
|
||||
cache = kzalloc(sizeof(*cache), GFP_NOFS);
|
||||
if (!cache) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
@ -2438,6 +2453,8 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||
bit = BLOCK_GROUP_METADATA;
|
||||
}
|
||||
set_avail_alloc_bits(info, cache->flags);
|
||||
if (btrfs_chunk_readonly(root, cache->key.objectid))
|
||||
cache->ro = 1;
|
||||
|
||||
ret = update_space_info(info, cache->flags, found_key.offset,
|
||||
btrfs_block_group_used(&cache->item),
|
||||
@ -2451,10 +2468,6 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||
bit | EXTENT_LOCKED, GFP_NOFS);
|
||||
set_state_private(block_group_cache, found_key.objectid,
|
||||
(unsigned long)cache);
|
||||
|
||||
if (key.objectid >=
|
||||
btrfs_super_total_bytes(&info->super_copy))
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
error:
|
||||
|
8
utils.c
8
utils.c
@ -96,7 +96,7 @@ int make_btrfs(int fd, const char *device, const char *label,
|
||||
btrfs_set_super_root(&super, blocks[1]);
|
||||
btrfs_set_super_chunk_root(&super, blocks[3]);
|
||||
btrfs_set_super_total_bytes(&super, num_bytes);
|
||||
btrfs_set_super_bytes_used(&super, first_free + 5 * leafsize);
|
||||
btrfs_set_super_bytes_used(&super, 5 * leafsize);
|
||||
btrfs_set_super_sectorsize(&super, sectorsize);
|
||||
btrfs_set_super_leafsize(&super, leafsize);
|
||||
btrfs_set_super_nodesize(&super, nodesize);
|
||||
@ -252,6 +252,7 @@ int make_btrfs(int fd, const char *device, const char *label,
|
||||
|
||||
dev_item = btrfs_item_ptr(buf, nritems, struct btrfs_dev_item);
|
||||
btrfs_set_device_id(buf, dev_item, 1);
|
||||
btrfs_set_device_generation(buf, dev_item, 0);
|
||||
btrfs_set_device_total_bytes(buf, dev_item, num_bytes);
|
||||
btrfs_set_device_bytes_used(buf, dev_item,
|
||||
BTRFS_MKFS_SYSTEM_GROUP_SIZE);
|
||||
@ -263,6 +264,9 @@ int make_btrfs(int fd, const char *device, const char *label,
|
||||
write_extent_buffer(buf, super.dev_item.uuid,
|
||||
(unsigned long)btrfs_device_uuid(dev_item),
|
||||
BTRFS_UUID_SIZE);
|
||||
write_extent_buffer(buf, super.fsid,
|
||||
(unsigned long)btrfs_device_fsid(dev_item),
|
||||
BTRFS_UUID_SIZE);
|
||||
read_extent_buffer(buf, &super.dev_item, (unsigned long)dev_item,
|
||||
sizeof(*dev_item));
|
||||
|
||||
@ -456,6 +460,7 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
|
||||
device->io_align = io_align;
|
||||
device->sector_size = sectorsize;
|
||||
device->fd = fd;
|
||||
device->writeable = 1;
|
||||
device->total_bytes = block_count;
|
||||
device->bytes_used = 0;
|
||||
device->total_ios = 0;
|
||||
@ -489,6 +494,7 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
|
||||
|
||||
kfree(buf);
|
||||
list_add(&device->dev_list, &root->fs_info->fs_devices->devices);
|
||||
device->fs_devices = root->fs_info->fs_devices;
|
||||
ret = btrfs_bootstrap_super_map(&root->fs_info->mapping_tree,
|
||||
root->fs_info->fs_devices);
|
||||
BUG_ON(ret);
|
||||
|
110
volumes.c
110
volumes.c
@ -91,7 +91,7 @@ static int device_list_add(const char *path,
|
||||
|
||||
fs_devices = find_fsid(disk_super->fsid);
|
||||
if (!fs_devices) {
|
||||
fs_devices = kmalloc(sizeof(*fs_devices), GFP_NOFS);
|
||||
fs_devices = kzalloc(sizeof(*fs_devices), GFP_NOFS);
|
||||
if (!fs_devices)
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(&fs_devices->devices);
|
||||
@ -127,6 +127,7 @@ static int device_list_add(const char *path,
|
||||
device->bytes_used =
|
||||
btrfs_stack_device_bytes_used(&disk_super->dev_item);
|
||||
list_add(&device->dev_list, &fs_devices->devices);
|
||||
device->fs_devices = fs_devices;
|
||||
}
|
||||
|
||||
if (found_transid > fs_devices->latest_trans) {
|
||||
@ -142,15 +143,24 @@ static int device_list_add(const char *path,
|
||||
|
||||
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
||||
{
|
||||
struct list_head *head = &fs_devices->devices;
|
||||
struct btrfs_fs_devices *seed_devices;
|
||||
struct list_head *cur;
|
||||
struct btrfs_device *device;
|
||||
|
||||
list_for_each(cur, head) {
|
||||
again:
|
||||
list_for_each(cur, &fs_devices->devices) {
|
||||
device = list_entry(cur, struct btrfs_device, dev_list);
|
||||
close(device->fd);
|
||||
device->fd = -1;
|
||||
device->writeable = 0;
|
||||
}
|
||||
|
||||
seed_devices = fs_devices->seed;
|
||||
fs_devices->seed = NULL;
|
||||
if (seed_devices) {
|
||||
fs_devices = seed_devices;
|
||||
goto again;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -176,6 +186,8 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, int flags)
|
||||
if (device->devid == fs_devices->lowest_devid)
|
||||
fs_devices->lowest_bdev = fd;
|
||||
device->fd = fd;
|
||||
if (flags == O_RDWR)
|
||||
device->writeable = 1;
|
||||
}
|
||||
return 0;
|
||||
fail:
|
||||
@ -504,6 +516,7 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
|
||||
|
||||
device->devid = free_devid;
|
||||
btrfs_set_device_id(leaf, dev_item, device->devid);
|
||||
btrfs_set_device_generation(leaf, dev_item, 0);
|
||||
btrfs_set_device_type(leaf, dev_item, device->type);
|
||||
btrfs_set_device_io_align(leaf, dev_item, device->io_align);
|
||||
btrfs_set_device_io_width(leaf, dev_item, device->io_width);
|
||||
@ -516,6 +529,8 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
|
||||
|
||||
ptr = (unsigned long)btrfs_device_uuid(dev_item);
|
||||
write_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
|
||||
ptr = (unsigned long)btrfs_device_fsid(dev_item);
|
||||
write_extent_buffer(leaf, root->fs_info->fsid, ptr, BTRFS_UUID_SIZE);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
ret = 0;
|
||||
|
||||
@ -996,11 +1011,23 @@ out:
|
||||
}
|
||||
|
||||
struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
|
||||
u8 *uuid)
|
||||
u8 *uuid, u8 *fsid)
|
||||
{
|
||||
struct list_head *head = &root->fs_info->fs_devices->devices;
|
||||
struct btrfs_device *device;
|
||||
struct btrfs_fs_devices *cur_devices;
|
||||
|
||||
return __find_device(head, devid, uuid);
|
||||
cur_devices = root->fs_info->fs_devices;
|
||||
while (cur_devices) {
|
||||
if (!fsid ||
|
||||
!memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE)) {
|
||||
device = __find_device(&cur_devices->devices,
|
||||
devid, uuid);
|
||||
if (device)
|
||||
return device;
|
||||
}
|
||||
cur_devices = cur_devices->seed;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int btrfs_bootstrap_super_map(struct btrfs_mapping_tree *map_tree,
|
||||
@ -1056,6 +1083,28 @@ int btrfs_bootstrap_super_map(struct btrfs_mapping_tree *map_tree,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
|
||||
{
|
||||
struct cache_extent *ce;
|
||||
struct map_lookup *map;
|
||||
struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
|
||||
int readonly = 0;
|
||||
int i;
|
||||
|
||||
ce = find_first_cache_extent(&map_tree->cache_tree, chunk_offset);
|
||||
BUG_ON(!ce);
|
||||
|
||||
map = container_of(ce, struct map_lookup, ce);
|
||||
for (i = 0; i < map->num_stripes; i++) {
|
||||
if (!map->stripes[i].dev->writeable) {
|
||||
readonly = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return readonly;
|
||||
}
|
||||
|
||||
static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
|
||||
struct extent_buffer *leaf,
|
||||
struct btrfs_chunk *chunk)
|
||||
@ -1111,7 +1160,8 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
|
||||
read_extent_buffer(leaf, uuid, (unsigned long)
|
||||
btrfs_stripe_dev_uuid_nr(chunk, i),
|
||||
BTRFS_UUID_SIZE);
|
||||
map->stripes[i].dev = btrfs_find_device(root, devid, uuid);
|
||||
map->stripes[i].dev = btrfs_find_device(root, devid, uuid,
|
||||
NULL);
|
||||
if (!map->stripes[i].dev) {
|
||||
kfree(map);
|
||||
return -EIO;
|
||||
@ -1144,6 +1194,36 @@ static int fill_device_from_item(struct extent_buffer *leaf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
|
||||
{
|
||||
struct btrfs_fs_devices *fs_devices;
|
||||
int ret;
|
||||
|
||||
fs_devices = root->fs_info->fs_devices->seed;
|
||||
while (fs_devices) {
|
||||
if (!memcmp(fs_devices->fsid, fsid, BTRFS_UUID_SIZE)) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
fs_devices = fs_devices->seed;
|
||||
}
|
||||
|
||||
fs_devices = find_fsid(fsid);
|
||||
if (!fs_devices) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = btrfs_open_devices(fs_devices, O_RDONLY);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
fs_devices->seed = root->fs_info->fs_devices->seed;
|
||||
root->fs_info->fs_devices->seed = fs_devices;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_one_dev(struct btrfs_root *root,
|
||||
struct extent_buffer *leaf,
|
||||
struct btrfs_dev_item *dev_item)
|
||||
@ -1151,13 +1231,24 @@ static int read_one_dev(struct btrfs_root *root,
|
||||
struct btrfs_device *device;
|
||||
u64 devid;
|
||||
int ret = 0;
|
||||
u8 fs_uuid[BTRFS_UUID_SIZE];
|
||||
u8 dev_uuid[BTRFS_UUID_SIZE];
|
||||
|
||||
devid = btrfs_device_id(leaf, dev_item);
|
||||
read_extent_buffer(leaf, dev_uuid,
|
||||
(unsigned long)btrfs_device_uuid(dev_item),
|
||||
BTRFS_UUID_SIZE);
|
||||
device = btrfs_find_device(root, devid, dev_uuid);
|
||||
read_extent_buffer(leaf, fs_uuid,
|
||||
(unsigned long)btrfs_device_fsid(dev_item),
|
||||
BTRFS_UUID_SIZE);
|
||||
|
||||
if (memcmp(fs_uuid, root->fs_info->fsid, BTRFS_UUID_SIZE)) {
|
||||
ret = open_seed_devices(root, fs_uuid);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
device = btrfs_find_device(root, devid, dev_uuid, fs_uuid);
|
||||
if (!device) {
|
||||
printk("warning devid %llu not found already\n",
|
||||
(unsigned long long)devid);
|
||||
@ -1284,6 +1375,7 @@ again:
|
||||
struct btrfs_chunk *chunk;
|
||||
chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
|
||||
ret = read_one_chunk(root, &found_key, leaf, chunk);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
path->slots[0]++;
|
||||
}
|
||||
|
@ -21,11 +21,14 @@
|
||||
struct btrfs_device {
|
||||
struct list_head dev_list;
|
||||
struct btrfs_root *dev_root;
|
||||
struct btrfs_fs_devices *fs_devices;
|
||||
|
||||
u64 total_ios;
|
||||
|
||||
int fd;
|
||||
|
||||
int writeable;
|
||||
|
||||
char *name;
|
||||
|
||||
/* these are read off the super block, only in the progs */
|
||||
@ -69,6 +72,9 @@ struct btrfs_fs_devices {
|
||||
int lowest_bdev;
|
||||
struct list_head devices;
|
||||
struct list_head list;
|
||||
|
||||
int seeding;
|
||||
struct btrfs_fs_devices *seed;
|
||||
};
|
||||
|
||||
struct btrfs_bio_stripe {
|
||||
@ -120,4 +126,5 @@ struct list_head *btrfs_scanned_uuids(void);
|
||||
int btrfs_add_system_chunk(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_key *key,
|
||||
struct btrfs_chunk *chunk, int item_size);
|
||||
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user