root-tree.c 9.0 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
	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;
}
278

279
#if 0 /* this will get used when snapshot deletion is implemented */
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *tree_root,
		       u64 root_id, u8 type, u64 ref_id)
{
	struct btrfs_key key;
	int ret;
	struct btrfs_path *path;

	path = btrfs_alloc_path();

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

	ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
	BUG_ON(ret);

	ret = btrfs_del_item(trans, tree_root, path);
	BUG_ON(ret);

	btrfs_free_path(path);
	return ret;
}
303
#endif
304

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
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;
}


321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
/*
 * 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,
		       u64 root_id, u8 type, u64 ref_id,
		       u64 dirid, u64 sequence,
		       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();

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

	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);

	btrfs_free_path(path);
	return ret;
}