hello,

This patch has following 3 things.

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.

Regards

Yan Zheng <[EMAIL PROTECTED]>

---
diff -urpN btrfs-progs-orig/btrfstune.c btrfs-progs-2/btrfstune.c
--- btrfs-progs-orig/btrfstune.c        1970-01-01 07:00:00.000000000 +0700
+++ btrfs-progs-2/btrfstune.c   2008-11-07 14:29:01.000000000 +0800
@@ -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;
+}
diff -urpN btrfs-progs-orig/ctree.c btrfs-progs-2/ctree.c
--- btrfs-progs-orig/ctree.c    2008-10-10 04:21:07.000000000 +0800
+++ btrfs-progs-2/ctree.c       2008-11-11 11:11:11.000000000 +0800
@@ -111,6 +111,10 @@ int btrfs_copy_root(struct btrfs_trans_h
        btrfs_set_header_generation(cow, trans->transid);
        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);
@@ -161,6 +165,10 @@ int __btrfs_cow_block(struct btrfs_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;
diff -urpN btrfs-progs-orig/ctree.h btrfs-progs-2/ctree.h
--- btrfs-progs-orig/ctree.h    2008-11-01 01:04:01.000000000 +0800
+++ btrfs-progs-2/ctree.h       2008-11-09 21:41:42.000000000 +0800
@@ -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 btr
 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_se
                         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_snaps
 
 /* 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);
diff -urpN btrfs-progs-orig/disk-io.c btrfs-progs-2/disk-io.c
--- btrfs-progs-orig/disk-io.c  2008-10-31 00:09:19.000000000 +0800
+++ btrfs-progs-2/disk-io.c     2008-11-07 17:23:00.000000000 +0800
@@ -37,14 +37,24 @@
 
 static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
 {
+
+       struct btrfs_fs_devices *fs_devices;
+       int ret = 1;
+
        if (buf->start != btrfs_header_bytenr(buf))
-               return 1;
+               return ret;
 
-       if (memcmp_extent_buffer(buf, root->fs_info->fsid,
-                                (unsigned long)btrfs_header_fsid(buf),
-                                BTRFS_FSID_SIZE))
-               return 1;
-       return 0;
+       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 *
                                                      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 *
                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);
diff -urpN btrfs-progs-orig/extent-tree.c btrfs-progs-2/extent-tree.c
--- btrfs-progs-orig/extent-tree.c      2008-10-10 04:21:07.000000000 +0800
+++ btrfs-progs-2/extent-tree.c 2008-11-07 11:12:54.000000000 +0800
@@ -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(st
        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_fi
        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_fi
                        }
                }
        }
-       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(str
        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(str
 
 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
                }
                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
                        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
                                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:
diff -urpN btrfs-progs-orig/Makefile btrfs-progs-2/Makefile
--- btrfs-progs-orig/Makefile   2008-09-30 16:50:58.000000000 +0800
+++ btrfs-progs-2/Makefile      2008-11-07 11:05:31.000000000 +0800
@@ -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)
 
diff -urpN btrfs-progs-orig/utils.c btrfs-progs-2/utils.c
--- btrfs-progs-orig/utils.c    2008-10-30 07:21:15.000000000 +0800
+++ btrfs-progs-2/utils.c       2008-11-08 10:58:43.000000000 +0800
@@ -96,7 +96,7 @@ int make_btrfs(int fd, const char *devic
        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 *devic
 
        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 *devic
        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
        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
 
        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);
diff -urpN btrfs-progs-orig/volumes.c btrfs-progs-2/volumes.c
--- btrfs-progs-orig/volumes.c  2008-09-30 16:50:58.000000000 +0800
+++ btrfs-progs-2/volumes.c     2008-11-09 21:42:32.000000000 +0800
@@ -91,7 +91,7 @@ static int device_list_add(const char *p
 
        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 *p
                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 *p
 
 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_d
                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_
 
        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_
 
        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;
-
-       return __find_device(head, devid, uuid);
+       struct btrfs_device *device;
+       struct btrfs_fs_devices *cur_devices;
+       
+       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 btr
        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_r
                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 
        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_roo
        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]++;
        }
diff -urpN btrfs-progs-orig/volumes.h btrfs-progs-2/volumes.h
--- btrfs-progs-orig/volumes.h  2008-09-30 16:50:58.000000000 +0800
+++ btrfs-progs-2/volumes.h     2008-11-07 11:05:33.000000000 +0800
@@ -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(vo
 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
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to