root-tree.c 11.2 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 = BTRFS_ROOT_ITEM_KEY;
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 98 99 100
	if (path->slots[0] == 0) {
		ret = 1;
		goto out;
	}
101
	l = path->nodes[0];
102
	slot = path->slots[0] - 1;
103
	btrfs_item_key_to_cpu(l, &found_key, slot);
104 105
	if (found_key.objectid != objectid ||
	    found_key.type != BTRFS_ROOT_ITEM_KEY) {
106 107 108
		ret = 1;
		goto out;
	}
109 110 111 112 113
	if (item)
		read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot),
				   sizeof(*item));
	if (key)
		memcpy(key, &found_key, sizeof(found_key));
114 115
	ret = 0;
out:
116
	btrfs_free_path(path);
117 118 119
	return ret;
}

120 121 122 123 124 125 126 127 128
int btrfs_set_root_node(struct btrfs_root_item *item,
			struct extent_buffer *node)
{
	btrfs_set_root_bytenr(item, node->start);
	btrfs_set_root_level(item, btrfs_header_level(node));
	btrfs_set_root_generation(item, btrfs_header_generation(node));
	return 0;
}

C
Chris Mason 已提交
129 130 131
/*
 * copy the data in 'item' into the btree
 */
132 133 134
int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
135
{
136
	struct btrfs_path *path;
137
	struct extent_buffer *l;
138 139
	int ret;
	int slot;
140
	unsigned long ptr;
141

142 143 144
	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
145 146
	if (ret < 0)
		goto out;
C
Chris Mason 已提交
147 148 149

	if (ret != 0) {
		btrfs_print_leaf(root, path->nodes[0]);
C
Chris Mason 已提交
150 151 152
		printk(KERN_CRIT "unable to update root key %llu %u %llu\n",
		       (unsigned long long)key->objectid, key->type,
		       (unsigned long long)key->offset);
C
Chris Mason 已提交
153 154 155
		BUG_ON(1);
	}

156
	l = path->nodes[0];
157
	slot = path->slots[0];
158 159
	ptr = btrfs_item_ptr_offset(l, slot);
	write_extent_buffer(l, item, ptr, sizeof(*item));
160
	btrfs_mark_buffer_dirty(path->nodes[0]);
161
out:
162
	btrfs_free_path(path);
163 164 165
	return ret;
}

166 167 168
int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
169 170
{
	int ret;
171
	ret = btrfs_insert_item(trans, root, key, item, sizeof(*item));
172 173 174
	return ret;
}

C
Chris Mason 已提交
175 176
/*
 * at mount time we want to find all the old transaction snapshots that were in
C
Chris Mason 已提交
177 178 179
 * 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.
C
Chris Mason 已提交
180
 */
181
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid)
182 183 184 185
{
	struct btrfs_root *dead_root;
	struct btrfs_root_item *ri;
	struct btrfs_key key;
186
	struct btrfs_key found_key;
187 188 189
	struct btrfs_path *path;
	int ret;
	u32 nritems;
190
	struct extent_buffer *leaf;
191 192
	int slot;

193
	key.objectid = objectid;
194 195 196 197 198
	btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
	key.offset = 0;
	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
199 200

again:
201 202 203
	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	if (ret < 0)
		goto err;
C
Chris Mason 已提交
204
	while (1) {
205 206
		leaf = path->nodes[0];
		nritems = btrfs_header_nritems(leaf);
207 208 209 210 211
		slot = path->slots[0];
		if (slot >= nritems) {
			ret = btrfs_next_leaf(root, path);
			if (ret)
				break;
212 213
			leaf = path->nodes[0];
			nritems = btrfs_header_nritems(leaf);
214 215
			slot = path->slots[0];
		}
216
		btrfs_item_key_to_cpu(leaf, &key, slot);
217 218
		if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY)
			goto next;
219 220 221 222 223 224 225

		if (key.objectid < objectid)
			goto next;

		if (key.objectid > objectid)
			break;

226
		ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item);
227
		if (btrfs_disk_root_refs(leaf, ri) != 0)
228
			goto next;
229

230 231 232
		memcpy(&found_key, &key, sizeof(key));
		key.offset++;
		btrfs_release_path(root, path);
233 234 235
		dead_root =
			btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
						    &found_key);
A
Aneesh 已提交
236 237
		if (IS_ERR(dead_root)) {
			ret = PTR_ERR(dead_root);
238 239
			goto err;
		}
240

241
		ret = btrfs_add_dead_root(dead_root);
242 243
		if (ret)
			goto err;
244
		goto again;
245 246 247 248 249 250 251 252 253 254
next:
		slot++;
		path->slots[0]++;
	}
	ret = 0;
err:
	btrfs_free_path(path);
	return ret;
}

255 256 257 258 259
int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
{
	struct extent_buffer *leaf;
	struct btrfs_path *path;
	struct btrfs_key key;
260 261
	struct btrfs_key root_key;
	struct btrfs_root *root;
262 263 264 265 266 267 268 269 270 271 272
	int err = 0;
	int ret;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;

	key.objectid = BTRFS_ORPHAN_OBJECTID;
	key.type = BTRFS_ORPHAN_ITEM_KEY;
	key.offset = 0;

273 274 275
	root_key.type = BTRFS_ROOT_ITEM_KEY;
	root_key.offset = (u64)-1;

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
	while (1) {
		ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
		if (ret < 0) {
			err = ret;
			break;
		}

		leaf = path->nodes[0];
		if (path->slots[0] >= btrfs_header_nritems(leaf)) {
			ret = btrfs_next_leaf(tree_root, path);
			if (ret < 0)
				err = ret;
			if (ret != 0)
				break;
			leaf = path->nodes[0];
		}

		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
		btrfs_release_path(tree_root, path);

		if (key.objectid != BTRFS_ORPHAN_OBJECTID ||
		    key.type != BTRFS_ORPHAN_ITEM_KEY)
			break;

300 301 302 303 304 305 306 307 308 309
		root_key.objectid = key.offset;
		key.offset++;

		root = btrfs_read_fs_root_no_name(tree_root->fs_info,
						  &root_key);
		if (!IS_ERR(root))
			continue;

		ret = PTR_ERR(root);
		if (ret != -ENOENT) {
310 311 312 313
			err = ret;
			break;
		}

314 315 316 317 318
		ret = btrfs_find_dead_roots(tree_root, root_key.objectid);
		if (ret) {
			err = ret;
			break;
		}
319 320 321 322 323 324
	}

	btrfs_free_path(path);
	return err;
}

C
Chris Mason 已提交
325
/* drop the root item for 'key' from 'root' */
326 327
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		   struct btrfs_key *key)
328
{
329
	struct btrfs_path *path;
330
	int ret;
C
Chris Mason 已提交
331
	struct btrfs_root_item *ri;
332
	struct extent_buffer *leaf;
333

334 335 336
	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, -1, 1);
337 338
	if (ret < 0)
		goto out;
339

340
	BUG_ON(ret != 0);
341 342
	leaf = path->nodes[0];
	ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item);
C
Chris Mason 已提交
343

344
	ret = btrfs_del_item(trans, root, path);
345
out:
346
	btrfs_free_path(path);
347 348
	return ret;
}
349 350 351

int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *tree_root,
352 353 354
		       u64 root_id, u64 ref_id, u64 dirid, u64 *sequence,
		       const char *name, int name_len)

355
{
356 357 358
	struct btrfs_path *path;
	struct btrfs_root_ref *ref;
	struct extent_buffer *leaf;
359
	struct btrfs_key key;
360 361
	unsigned long ptr;
	int err = 0;
362 363 364
	int ret;

	path = btrfs_alloc_path();
365 366
	if (!path)
		return -ENOMEM;
367 368

	key.objectid = root_id;
369
	key.type = BTRFS_ROOT_BACKREF_KEY;
370
	key.offset = ref_id;
371
again:
372
	ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
	BUG_ON(ret < 0);
	if (ret == 0) {
		leaf = path->nodes[0];
		ref = btrfs_item_ptr(leaf, path->slots[0],
				     struct btrfs_root_ref);

		WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid);
		WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len);
		ptr = (unsigned long)(ref + 1);
		WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len));
		*sequence = btrfs_root_ref_sequence(leaf, ref);

		ret = btrfs_del_item(trans, tree_root, path);
		BUG_ON(ret);
	} else
		err = -ENOENT;

	if (key.type == BTRFS_ROOT_BACKREF_KEY) {
		btrfs_release_path(tree_root, path);
		key.objectid = ref_id;
		key.type = BTRFS_ROOT_REF_KEY;
		key.offset = root_id;
		goto again;
	}
397 398

	btrfs_free_path(path);
399
	return err;
400 401
}

402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
int btrfs_find_root_ref(struct btrfs_root *tree_root,
		   struct btrfs_path *path,
		   u64 root_id, u64 ref_id)
{
	struct btrfs_key key;
	int ret;

	key.objectid = root_id;
	key.type = BTRFS_ROOT_REF_KEY;
	key.offset = ref_id;

	ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
	return ret;
}

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
/*
 * add a btrfs_root_ref item.  type is either BTRFS_ROOT_REF_KEY
 * or BTRFS_ROOT_BACKREF_KEY.
 *
 * The dirid, sequence, name and name_len refer to the directory entry
 * that is referencing the root.
 *
 * For a forward ref, the root_id is the id of the tree referencing
 * the root and ref_id is the id of the subvol  or snapshot.
 *
 * For a back ref the root_id is the id of the subvol or snapshot and
 * ref_id is the id of the tree referencing it.
 */
int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *tree_root,
432
		       u64 root_id, u64 ref_id, u64 dirid, u64 sequence,
433 434 435 436 437 438 439 440 441 442
		       const char *name, int name_len)
{
	struct btrfs_key key;
	int ret;
	struct btrfs_path *path;
	struct btrfs_root_ref *ref;
	struct extent_buffer *leaf;
	unsigned long ptr;

	path = btrfs_alloc_path();
443 444
	if (!path)
		return -ENOMEM;
445 446

	key.objectid = root_id;
447
	key.type = BTRFS_ROOT_BACKREF_KEY;
448
	key.offset = ref_id;
449
again:
450 451 452 453 454 455 456 457 458 459 460 461 462
	ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
				      sizeof(*ref) + name_len);
	BUG_ON(ret);

	leaf = path->nodes[0];
	ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
	btrfs_set_root_ref_dirid(leaf, ref, dirid);
	btrfs_set_root_ref_sequence(leaf, ref, sequence);
	btrfs_set_root_ref_name_len(leaf, ref, name_len);
	ptr = (unsigned long)(ref + 1);
	write_extent_buffer(leaf, name, ptr, name_len);
	btrfs_mark_buffer_dirty(leaf);

463 464 465 466 467 468 469 470
	if (key.type == BTRFS_ROOT_BACKREF_KEY) {
		btrfs_release_path(tree_root, path);
		key.objectid = ref_id;
		key.type = BTRFS_ROOT_REF_KEY;
		key.offset = root_id;
		goto again;
	}

471
	btrfs_free_path(path);
472
	return 0;
473
}