root-tree.c 6.8 KB
Newer Older
C
Chris Mason 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * 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.
 */

19
#include "ctree.h"
20
#include "transaction.h"
21 22 23
#include "disk-io.h"
#include "print-tree.h"

24
/*
C
Chris Mason 已提交
25 26 27 28
 *  search forward for a root, starting with objectid 'search_start'
 *  if a root key is found, the objectid we find is filled into 'found_objectid'
 *  and 0 is returned.  < 0 is returned on error, 1 if there is nothing
 *  left in the tree.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
 */
int btrfs_search_root(struct btrfs_root *root, u64 search_start,
		      u64 *found_objectid)
{
	struct btrfs_path *path;
	struct btrfs_key search_key;
	int ret;

	root = root->fs_info->tree_root;
	search_key.objectid = search_start;
	search_key.type = (u8)-1;
	search_key.offset = (u64)-1;

	path = btrfs_alloc_path();
	BUG_ON(!path);
again:
	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
	if (ret < 0)
		goto out;
	if (ret == 0) {
		ret = 1;
		goto out;
	}
	if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
		ret = btrfs_next_leaf(root, path);
		if (ret)
			goto out;
	}
	btrfs_item_key_to_cpu(path->nodes[0], &search_key, path->slots[0]);
	if (search_key.type != BTRFS_ROOT_ITEM_KEY) {
		search_key.offset++;
		btrfs_release_path(root, path);
		goto again;
	}
	ret = 0;
	*found_objectid = search_key.objectid;

out:
	btrfs_free_path(path);
	return ret;
}

C
Chris Mason 已提交
71 72 73 74 75
/*
 * lookup the root with the highest offset for a given objectid.  The key we do
 * find is copied into 'key'.  If we find something return 0, otherwise 1, < 0
 * on error.
 */
76 77 78
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
			struct btrfs_root_item *item, struct btrfs_key *key)
{
79
	struct btrfs_path *path;
80
	struct btrfs_key search_key;
81 82
	struct btrfs_key found_key;
	struct extent_buffer *l;
83 84 85 86
	int ret;
	int slot;

	search_key.objectid = objectid;
87
	search_key.type = (u8)-1;
88
	search_key.offset = (u64)-1;
89

90 91 92
	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
93 94
	if (ret < 0)
		goto out;
95

96
	BUG_ON(ret == 0);
97
	l = path->nodes[0];
98 99
	BUG_ON(path->slots[0] == 0);
	slot = path->slots[0] - 1;
100 101
	btrfs_item_key_to_cpu(l, &found_key, slot);
	if (found_key.objectid != objectid) {
102 103 104
		ret = 1;
		goto out;
	}
105 106 107
	read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot),
			   sizeof(*item));
	memcpy(key, &found_key, sizeof(found_key));
108 109
	ret = 0;
out:
110
	btrfs_free_path(path);
111 112 113
	return ret;
}

C
Chris Mason 已提交
114 115 116
/*
 * copy the data in 'item' into the btree
 */
117 118 119
int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
120
{
121
	struct btrfs_path *path;
122
	struct extent_buffer *l;
123 124
	int ret;
	int slot;
125
	unsigned long ptr;
126

127 128 129
	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
130 131
	if (ret < 0)
		goto out;
C
Chris Mason 已提交
132 133 134 135 136 137 138 139

	if (ret != 0) {
		btrfs_print_leaf(root, path->nodes[0]);
		printk("unable to update root key %Lu %u %Lu\n",
		       key->objectid, key->type, key->offset);
		BUG_ON(1);
	}

140
	l = path->nodes[0];
141
	slot = path->slots[0];
142 143
	ptr = btrfs_item_ptr_offset(l, slot);
	write_extent_buffer(l, item, ptr, sizeof(*item));
144
	btrfs_mark_buffer_dirty(path->nodes[0]);
145
out:
146 147
	btrfs_release_path(root, path);
	btrfs_free_path(path);
148 149 150
	return ret;
}

151 152 153
int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
154 155
{
	int ret;
156
	ret = btrfs_insert_item(trans, root, key, item, sizeof(*item));
157 158 159
	return ret;
}

C
Chris Mason 已提交
160 161 162 163 164 165
/*
 * at mount time we want to find all the old transaction snapshots that were in
 * the process of being deleted if we crashed.  This is any root item with an offset
 * lower than the latest root.  They need to be queued for deletion to finish
 * what was happening when we crashed.
 */
166 167
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid,
			  struct btrfs_root *latest)
168 169 170 171 172
{
	struct btrfs_root *dead_root;
	struct btrfs_item *item;
	struct btrfs_root_item *ri;
	struct btrfs_key key;
173
	struct btrfs_key found_key;
174 175 176
	struct btrfs_path *path;
	int ret;
	u32 nritems;
177
	struct extent_buffer *leaf;
178 179
	int slot;

180
	key.objectid = objectid;
181 182 183 184 185
	btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
	key.offset = 0;
	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
186 187

again:
188 189 190 191
	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	if (ret < 0)
		goto err;
	while(1) {
192 193
		leaf = path->nodes[0];
		nritems = btrfs_header_nritems(leaf);
194 195 196 197 198
		slot = path->slots[0];
		if (slot >= nritems) {
			ret = btrfs_next_leaf(root, path);
			if (ret)
				break;
199 200
			leaf = path->nodes[0];
			nritems = btrfs_header_nritems(leaf);
201 202
			slot = path->slots[0];
		}
203 204
		item = btrfs_item_nr(leaf, slot);
		btrfs_item_key_to_cpu(leaf, &key, slot);
205 206
		if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY)
			goto next;
207 208 209 210 211 212 213

		if (key.objectid < objectid)
			goto next;

		if (key.objectid > objectid)
			break;

214
		ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item);
215
		if (btrfs_disk_root_refs(leaf, ri) != 0)
216
			goto next;
217

218 219 220
		memcpy(&found_key, &key, sizeof(key));
		key.offset++;
		btrfs_release_path(root, path);
221 222 223
		dead_root =
			btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
						    &found_key);
A
Aneesh 已提交
224 225
		if (IS_ERR(dead_root)) {
			ret = PTR_ERR(dead_root);
226 227
			goto err;
		}
228

Z
Zheng Yan 已提交
229 230 231 232
		if (objectid == BTRFS_TREE_RELOC_OBJECTID)
			ret = btrfs_add_dead_reloc_root(dead_root);
		else
			ret = btrfs_add_dead_root(dead_root, latest);
233 234
		if (ret)
			goto err;
235
		goto again;
236 237 238 239 240 241 242 243 244 245
next:
		slot++;
		path->slots[0]++;
	}
	ret = 0;
err:
	btrfs_free_path(path);
	return ret;
}

C
Chris Mason 已提交
246
/* drop the root item for 'key' from 'root' */
247 248
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		   struct btrfs_key *key)
249
{
250
	struct btrfs_path *path;
251
	int ret;
C
Chris Mason 已提交
252 253
	u32 refs;
	struct btrfs_root_item *ri;
254
	struct extent_buffer *leaf;
255

256 257 258
	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, -1, 1);
259 260
	if (ret < 0)
		goto out;
261 262 263 264 265
	if (ret) {
btrfs_print_leaf(root, path->nodes[0]);
printk("failed to del %Lu %u %Lu\n", key->objectid, key->type, key->offset);

	}
266
	BUG_ON(ret != 0);
267 268
	leaf = path->nodes[0];
	ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item);
C
Chris Mason 已提交
269

270
	refs = btrfs_disk_root_refs(leaf, ri);
271 272
	BUG_ON(refs != 0);
	ret = btrfs_del_item(trans, root, path);
273
out:
274 275
	btrfs_release_path(root, path);
	btrfs_free_path(path);
276 277
	return ret;
}