Esempio n. 1
0
int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
{
	struct hfs_btree *tree;
	struct hfs_bnode *node, *new_node;
	int size, key_len, rec;
	int data_off, end_off;
	int idx_rec_off, data_rec_off, end_rec_off;
	__be32 cnid;

	tree = fd->tree;
	if (!fd->bnode) {
		if (!tree->root)
			hfs_btree_inc_height(tree);
		fd->bnode = hfs_bnode_find(tree, tree->leaf_head);
		if (IS_ERR(fd->bnode))
			return PTR_ERR(fd->bnode);
		fd->record = -1;
	}
	new_node = NULL;
	key_len = (fd->search_key->key_len | 1) + 1;
again:
	/* new record idx and complete record size */
	rec = fd->record + 1;
	size = key_len + entry_len;

	node = fd->bnode;
	hfs_bnode_dump(node);
	/* get last offset */
	end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
	end_off = hfs_bnode_read_u16(node, end_rec_off);
	end_rec_off -= 2;
	dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", rec, size, end_off, end_rec_off);
	if (size > end_rec_off - end_off) {
		if (new_node)
			panic("not enough room!\n");
		new_node = hfs_bnode_split(fd);
		if (IS_ERR(new_node))
			return PTR_ERR(new_node);
		goto again;
	}
	if (node->type == HFS_NODE_LEAF) {
		tree->leaf_count++;
		mark_inode_dirty(tree->inode);
	}
	node->num_recs++;
	/* write new last offset */
	hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
	hfs_bnode_write_u16(node, end_rec_off, end_off + size);
	data_off = end_off;
	data_rec_off = end_rec_off + 2;
	idx_rec_off = tree->node_size - (rec + 1) * 2;
	if (idx_rec_off == data_rec_off)
		goto skip;
	/* move all following entries */
	do {
		data_off = hfs_bnode_read_u16(node, data_rec_off + 2);
		hfs_bnode_write_u16(node, data_rec_off, data_off + size);
		data_rec_off += 2;
	} while (data_rec_off < idx_rec_off);

	/* move data away */
	hfs_bnode_move(node, data_off + size, data_off,
		       end_off - data_off);

skip:
	hfs_bnode_write(node, fd->search_key, data_off, key_len);
	hfs_bnode_write(node, entry, data_off + key_len, entry_len);
	hfs_bnode_dump(node);

	if (new_node) {
		/* update parent key if we inserted a key
		 * at the start of the first node
		 */
		if (!rec && new_node != node)
			hfs_brec_update_parent(fd);

		hfs_bnode_put(fd->bnode);
		if (!new_node->parent) {
			hfs_btree_inc_height(tree);
			new_node->parent = tree->root;
		}
		fd->bnode = hfs_bnode_find(tree, new_node->parent);

		/* create index data entry */
		cnid = cpu_to_be32(new_node->this);
		entry = &cnid;
		entry_len = sizeof(cnid);

		/* get index key */
		hfs_bnode_read_key(new_node, fd->search_key, 14);
		__hfs_brec_find(fd->bnode, fd);

		hfs_bnode_put(new_node);
		new_node = NULL;

		if (tree->attributes & HFS_TREE_VARIDXKEYS)
			key_len = fd->search_key->key_len + 1;
		else {
			fd->search_key->key_len = tree->max_key_len;
			key_len = tree->max_key_len + 1;
		}
		goto again;
	}

	if (!rec)
		hfs_brec_update_parent(fd);

	return 0;
}
Esempio n. 2
0
/*
 * del_root()
 *
 * Description:
 *   Delete the current root bnode.
 * Input Variable(s):
 *   struct hfs_bnode_ref *root: reference to the root bnode
 * Output Variable(s):
 *   NONE
 * Returns:
 *   int: 0 on success, error code on failure
 * Preconditions:
 *   'root' refers to the root bnode with HFS_LOCK_WRITE access.
 *   None of 'root's children are held with HFS_LOCK_WRITE access.
 * Postconditions:
 *   The current 'root' node is removed from the tree and the depth
 *    of the tree is reduced by one.
 *   If 'root' is an index node with exactly one child, then that
 *    child becomes the new root of the tree.
 *   If 'root' is an empty leaf node the tree becomes empty.
 *   Upon return access to 'root' is relinquished.
 */
static int del_root(struct hfs_bnode_ref *root)
{
	struct hfs_btree *tree = root->bn->tree;
	struct hfs_bnode_ref child;
	hfs_u32 node;

	if (root->bn->ndNRecs > 1) {
		return 0;
	} else if (root->bn->ndNRecs == 0) {
		/* tree is empty */
		tree->bthRoot = 0;
		tree->root = NULL;
		tree->bthRoot = 0;
		tree->bthFNode = 0;
		tree->bthLNode = 0;
		--tree->bthDepth;
		tree->dirt = 1;
		if (tree->bthDepth) {
			hfs_warn("hfs_bdelete: empty tree with bthDepth=%d\n",
				 tree->bthDepth);
			goto bail;
		}
		return hfs_bnode_free(root);
	} else if (root->bn->ndType == ndIndxNode) {
		/* tree is non-empty */
		node = hfs_get_hl(bkey_record(bnode_datastart(root->bn)));

		child = hfs_bnode_find(tree, node, HFS_LOCK_READ);
		if (!child.bn) {
			hfs_warn("hfs_bdelete: can't read child node.\n");
			goto bail;
		}
			
		child.bn->sticky = HFS_STICKY;
        	if (child.bn->next) {
                	child.bn->next->prev = child.bn->prev;
        	}
        	if (child.bn->prev) {
                	child.bn->prev->next = child.bn->next;
        	}
        	if (bhash(tree, child.bn->node) == child.bn) {
                	bhash(tree, child.bn->node) = child.bn->next;
        	}
		child.bn->next = NULL;
		child.bn->prev = NULL;

		tree->bthRoot = child.bn->node;
		tree->root = child.bn;

		/* re-assign bthFNode and bthLNode if the new root is
                   a leaf node. */
		if (child.bn->ndType == ndLeafNode) {
			tree->bthFNode = node;
			tree->bthLNode = node;
		}
		hfs_bnode_relse(&child);

		tree->bthRoot = node;
		--tree->bthDepth;
		tree->dirt = 1;
		if (!tree->bthDepth) {
			hfs_warn("hfs_bdelete: non-empty tree with "
				 "bthDepth == 0\n");
			goto bail;
		}
		return hfs_bnode_free(root);	/* marks tree dirty */
	}
	hfs_bnode_relse(root);
	return 0;

bail:
	hfs_bnode_relse(root);
	return -EIO;
}
Esempio n. 3
0
static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
{
	struct hfs_btree *tree;
	struct hfs_bnode *node, *new_node, *next_node;
	struct hfs_bnode_desc node_desc;
	int num_recs, new_rec_off, new_off, old_rec_off;
	int data_start, data_end, size;

	tree = fd->tree;
	node = fd->bnode;
	new_node = hfs_bmap_alloc(tree);
	if (IS_ERR(new_node))
		return new_node;
	hfs_bnode_get(node);
	dprint(DBG_BNODE_MOD, "split_nodes: %d - %d - %d\n",
		node->this, new_node->this, node->next);
	new_node->next = node->next;
	new_node->prev = node->this;
	new_node->parent = node->parent;
	new_node->type = node->type;
	new_node->height = node->height;

	if (node->next)
		next_node = hfs_bnode_find(tree, node->next);
	else
		next_node = NULL;

	if (IS_ERR(next_node)) {
		hfs_bnode_put(node);
		hfs_bnode_put(new_node);
		return next_node;
	}

	size = tree->node_size / 2 - node->num_recs * 2 - 14;
	old_rec_off = tree->node_size - 4;
	num_recs = 1;
	for (;;) {
		data_start = hfs_bnode_read_u16(node, old_rec_off);
		if (data_start > size)
			break;
		old_rec_off -= 2;
		if (++num_recs < node->num_recs)
			continue;
		/* panic? */
		hfs_bnode_put(node);
		hfs_bnode_put(new_node);
		if (next_node)
			hfs_bnode_put(next_node);
		return ERR_PTR(-ENOSPC);
	}

	if (fd->record + 1 < num_recs) {
		/* new record is in the lower half,
		 * so leave some more space there
		 */
		old_rec_off += 2;
		num_recs--;
		data_start = hfs_bnode_read_u16(node, old_rec_off);
	} else {
		hfs_bnode_put(node);
		hfs_bnode_get(new_node);
		fd->bnode = new_node;
		fd->record -= num_recs;
		fd->keyoffset -= data_start - 14;
		fd->entryoffset -= data_start - 14;
	}
	new_node->num_recs = node->num_recs - num_recs;
	node->num_recs = num_recs;

	new_rec_off = tree->node_size - 2;
	new_off = 14;
	size = data_start - new_off;
	num_recs = new_node->num_recs;
	data_end = data_start;
	while (num_recs) {
		hfs_bnode_write_u16(new_node, new_rec_off, new_off);
		old_rec_off -= 2;
		new_rec_off -= 2;
		data_end = hfs_bnode_read_u16(node, old_rec_off);
		new_off = data_end - size;
		num_recs--;
	}
	hfs_bnode_write_u16(new_node, new_rec_off, new_off);
	hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start);

	/* update new bnode header */
	node_desc.next = cpu_to_be32(new_node->next);
	node_desc.prev = cpu_to_be32(new_node->prev);
	node_desc.type = new_node->type;
	node_desc.height = new_node->height;
	node_desc.num_recs = cpu_to_be16(new_node->num_recs);
	node_desc.reserved = 0;
	hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));

	/* update previous bnode header */
	node->next = new_node->this;
	hfs_bnode_read(node, &node_desc, 0, sizeof(node_desc));
	node_desc.next = cpu_to_be32(node->next);
	node_desc.num_recs = cpu_to_be16(node->num_recs);
	hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));

	/* update next bnode header */
	if (next_node) {
		next_node->prev = new_node->this;
		hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
		node_desc.prev = cpu_to_be32(next_node->prev);
		hfs_bnode_write(next_node, &node_desc, 0, sizeof(node_desc));
		hfs_bnode_put(next_node);
	} else if (node->this == tree->leaf_tail) {
Esempio n. 4
0
/*
 * bdelete()
 *
 * Delete the given record from a B-tree.
 */
static int bdelete(struct hfs_brec *brec)
{
	struct hfs_btree *tree = brec->tree;
	struct hfs_belem *belem = brec->bottom;
	struct hfs_belem *parent = (belem-1);
	struct hfs_bnode *bnode;
	hfs_u32 left_node, right_node;
	struct hfs_bnode_ref left, right;
	int left_space, right_space, min_space;
	int fix_right_key;
	int fix_key;
	
	while ((belem > brec->top) &&
	       (belem->flags & (HFS_BPATH_UNDERFLOW | HFS_BPATH_FIRST))) {
		bnode = belem->bnr.bn;
		fix_key = belem->flags & HFS_BPATH_FIRST;
		fix_right_key = 0;

		bdelete_nonempty(brec, belem);

		if (bnode->node == tree->root->node) {
			del_root(&belem->bnr);
			--brec->bottom;
			goto done;
		}

		/* check for btree corruption which could lead to deadlock */
		left_node = bnode->ndBLink;
		right_node = bnode->ndFLink;
		if ((left_node && hfs_bnode_in_brec(left_node, brec)) ||
		    (right_node && hfs_bnode_in_brec(right_node, brec)) ||
		    (left_node == right_node)) {
			hfs_warn("hfs_bdelete: corrupt btree\n");
			hfs_brec_relse(brec, NULL);
			return -EIO;
		}

		/* grab the left neighbor if it exists */
		if (left_node) {
			hfs_bnode_lock(&belem->bnr, HFS_LOCK_RESRV);
			left = hfs_bnode_find(tree,left_node,HFS_LOCK_WRITE);
			if (!left.bn) {
				hfs_warn("hfs_bdelete: unable to read left "
					 "neighbor.\n");
				hfs_brec_relse(brec, NULL);
				return -EIO;
			}
			hfs_bnode_lock(&belem->bnr, HFS_LOCK_WRITE);
			if (parent->record != 1) {
				left_space = bnode_freespace(left.bn);
			} else {
				left_space = NO_SPACE;
			}
		} else {
			left.bn = NULL;
			left_space = NO_SPACE;
		}

		/* grab the right neighbor if it exists */
		if (right_node) {
			right = hfs_bnode_find(tree,right_node,HFS_LOCK_WRITE);
			if (!right.bn) {
				hfs_warn("hfs_bdelete: unable to read right "
					 "neighbor.\n");
				hfs_bnode_relse(&left);
				hfs_brec_relse(brec, NULL);
				return -EIO;
			}
			if (parent->record < parent->bnr.bn->ndNRecs) {
				right_space = bnode_freespace(right.bn);
			} else {
				right_space = NO_SPACE;
			}
		} else {
			right.bn = NULL;
			right_space = NO_SPACE;
		}

		if (left_space < right_space) {
			min_space = left_space;
		} else {
			min_space = right_space;
		}

		if (min_space == NO_SPACE) {
			hfs_warn("hfs_bdelete: no siblings?\n");
			hfs_brec_relse(brec, NULL);
			return -EIO;
		}

		if (bnode->ndNRecs == 0) {
			delete_empty_bnode(left_node, &left, &belem->bnr,
					   right_node, &right);
		} else if (min_space + bnode_freespace(bnode) >= FULL) {
			if ((right_space == NO_SPACE) ||
			    ((right_space == min_space) &&
			     (left_space != NO_SPACE))) {
				hfs_bnode_shift_left(left.bn, bnode,
						     bnode->ndNRecs);
			} else {
				hfs_bnode_shift_right(bnode, right.bn, 1);
				fix_right_key = 1;
			}
			delete_empty_bnode(left_node, &left, &belem->bnr,
					   right_node, &right);
		} else if (min_space == right_space) {
			balance(bnode, right.bn);
			fix_right_key = 1;
		} else {
			balance(left.bn, bnode);
			fix_key = 1;
		}

		if (fix_right_key) {
			hfs_bnode_update_key(brec, belem, right.bn, 1);
		}

		hfs_bnode_relse(&left);
		hfs_bnode_relse(&right);

		if (bnode->ndNRecs) {
			if (fix_key) {
				hfs_bnode_update_key(brec, belem, bnode, 0);
			}
			goto done;
		}

		hfs_bnode_free(&belem->bnr);
		--brec->bottom;
		belem = parent;
		--parent;
	}

	if (belem < brec->top) {
		hfs_warn("hfs_bdelete: Missing parent.\n");
		hfs_brec_relse(brec, NULL);
		return -EIO;
	}

	bdelete_nonempty(brec, belem);

done:
	hfs_brec_relse(brec, NULL);
	return 0;
}