cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

brec.c (13972B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  linux/fs/hfs/brec.c
      4 *
      5 * Copyright (C) 2001
      6 * Brad Boyer (flar@allandria.com)
      7 * (C) 2003 Ardis Technologies <roman@ardistech.com>
      8 *
      9 * Handle individual btree records
     10 */
     11
     12#include "btree.h"
     13
     14static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd);
     15static int hfs_brec_update_parent(struct hfs_find_data *fd);
     16static int hfs_btree_inc_height(struct hfs_btree *tree);
     17
     18/* Get the length and offset of the given record in the given node */
     19u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off)
     20{
     21	__be16 retval[2];
     22	u16 dataoff;
     23
     24	dataoff = node->tree->node_size - (rec + 2) * 2;
     25	hfs_bnode_read(node, retval, dataoff, 4);
     26	*off = be16_to_cpu(retval[1]);
     27	return be16_to_cpu(retval[0]) - *off;
     28}
     29
     30/* Get the length of the key from a keyed record */
     31u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
     32{
     33	u16 retval, recoff;
     34
     35	if (node->type != HFS_NODE_INDEX && node->type != HFS_NODE_LEAF)
     36		return 0;
     37
     38	if ((node->type == HFS_NODE_INDEX) &&
     39	   !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
     40		if (node->tree->attributes & HFS_TREE_BIGKEYS)
     41			retval = node->tree->max_key_len + 2;
     42		else
     43			retval = node->tree->max_key_len + 1;
     44	} else {
     45		recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
     46		if (!recoff)
     47			return 0;
     48		if (node->tree->attributes & HFS_TREE_BIGKEYS) {
     49			retval = hfs_bnode_read_u16(node, recoff) + 2;
     50			if (retval > node->tree->max_key_len + 2) {
     51				pr_err("keylen %d too large\n", retval);
     52				retval = 0;
     53			}
     54		} else {
     55			retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
     56			if (retval > node->tree->max_key_len + 1) {
     57				pr_err("keylen %d too large\n", retval);
     58				retval = 0;
     59			}
     60		}
     61	}
     62	return retval;
     63}
     64
     65int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
     66{
     67	struct hfs_btree *tree;
     68	struct hfs_bnode *node, *new_node;
     69	int size, key_len, rec;
     70	int data_off, end_off;
     71	int idx_rec_off, data_rec_off, end_rec_off;
     72	__be32 cnid;
     73
     74	tree = fd->tree;
     75	if (!fd->bnode) {
     76		if (!tree->root)
     77			hfs_btree_inc_height(tree);
     78		node = hfs_bnode_find(tree, tree->leaf_head);
     79		if (IS_ERR(node))
     80			return PTR_ERR(node);
     81		fd->bnode = node;
     82		fd->record = -1;
     83	}
     84	new_node = NULL;
     85	key_len = (fd->search_key->key_len | 1) + 1;
     86again:
     87	/* new record idx and complete record size */
     88	rec = fd->record + 1;
     89	size = key_len + entry_len;
     90
     91	node = fd->bnode;
     92	hfs_bnode_dump(node);
     93	/* get last offset */
     94	end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
     95	end_off = hfs_bnode_read_u16(node, end_rec_off);
     96	end_rec_off -= 2;
     97	hfs_dbg(BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
     98		rec, size, end_off, end_rec_off);
     99	if (size > end_rec_off - end_off) {
    100		if (new_node)
    101			panic("not enough room!\n");
    102		new_node = hfs_bnode_split(fd);
    103		if (IS_ERR(new_node))
    104			return PTR_ERR(new_node);
    105		goto again;
    106	}
    107	if (node->type == HFS_NODE_LEAF) {
    108		tree->leaf_count++;
    109		mark_inode_dirty(tree->inode);
    110	}
    111	node->num_recs++;
    112	/* write new last offset */
    113	hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
    114	hfs_bnode_write_u16(node, end_rec_off, end_off + size);
    115	data_off = end_off;
    116	data_rec_off = end_rec_off + 2;
    117	idx_rec_off = tree->node_size - (rec + 1) * 2;
    118	if (idx_rec_off == data_rec_off)
    119		goto skip;
    120	/* move all following entries */
    121	do {
    122		data_off = hfs_bnode_read_u16(node, data_rec_off + 2);
    123		hfs_bnode_write_u16(node, data_rec_off, data_off + size);
    124		data_rec_off += 2;
    125	} while (data_rec_off < idx_rec_off);
    126
    127	/* move data away */
    128	hfs_bnode_move(node, data_off + size, data_off,
    129		       end_off - data_off);
    130
    131skip:
    132	hfs_bnode_write(node, fd->search_key, data_off, key_len);
    133	hfs_bnode_write(node, entry, data_off + key_len, entry_len);
    134	hfs_bnode_dump(node);
    135
    136	/*
    137	 * update parent key if we inserted a key
    138	 * at the start of the node and it is not the new node
    139	 */
    140	if (!rec && new_node != node) {
    141		hfs_bnode_read_key(node, fd->search_key, data_off + size);
    142		hfs_brec_update_parent(fd);
    143	}
    144
    145	if (new_node) {
    146		hfs_bnode_put(fd->bnode);
    147		if (!new_node->parent) {
    148			hfs_btree_inc_height(tree);
    149			new_node->parent = tree->root;
    150		}
    151		fd->bnode = hfs_bnode_find(tree, new_node->parent);
    152
    153		/* create index data entry */
    154		cnid = cpu_to_be32(new_node->this);
    155		entry = &cnid;
    156		entry_len = sizeof(cnid);
    157
    158		/* get index key */
    159		hfs_bnode_read_key(new_node, fd->search_key, 14);
    160		__hfs_brec_find(fd->bnode, fd);
    161
    162		hfs_bnode_put(new_node);
    163		new_node = NULL;
    164
    165		if (tree->attributes & HFS_TREE_VARIDXKEYS)
    166			key_len = fd->search_key->key_len + 1;
    167		else {
    168			fd->search_key->key_len = tree->max_key_len;
    169			key_len = tree->max_key_len + 1;
    170		}
    171		goto again;
    172	}
    173
    174	return 0;
    175}
    176
    177int hfs_brec_remove(struct hfs_find_data *fd)
    178{
    179	struct hfs_btree *tree;
    180	struct hfs_bnode *node, *parent;
    181	int end_off, rec_off, data_off, size;
    182
    183	tree = fd->tree;
    184	node = fd->bnode;
    185again:
    186	rec_off = tree->node_size - (fd->record + 2) * 2;
    187	end_off = tree->node_size - (node->num_recs + 1) * 2;
    188
    189	if (node->type == HFS_NODE_LEAF) {
    190		tree->leaf_count--;
    191		mark_inode_dirty(tree->inode);
    192	}
    193	hfs_bnode_dump(node);
    194	hfs_dbg(BNODE_MOD, "remove_rec: %d, %d\n",
    195		fd->record, fd->keylength + fd->entrylength);
    196	if (!--node->num_recs) {
    197		hfs_bnode_unlink(node);
    198		if (!node->parent)
    199			return 0;
    200		parent = hfs_bnode_find(tree, node->parent);
    201		if (IS_ERR(parent))
    202			return PTR_ERR(parent);
    203		hfs_bnode_put(node);
    204		node = fd->bnode = parent;
    205
    206		__hfs_brec_find(node, fd);
    207		goto again;
    208	}
    209	hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
    210
    211	if (rec_off == end_off)
    212		goto skip;
    213	size = fd->keylength + fd->entrylength;
    214
    215	do {
    216		data_off = hfs_bnode_read_u16(node, rec_off);
    217		hfs_bnode_write_u16(node, rec_off + 2, data_off - size);
    218		rec_off -= 2;
    219	} while (rec_off >= end_off);
    220
    221	/* fill hole */
    222	hfs_bnode_move(node, fd->keyoffset, fd->keyoffset + size,
    223		       data_off - fd->keyoffset - size);
    224skip:
    225	hfs_bnode_dump(node);
    226	if (!fd->record)
    227		hfs_brec_update_parent(fd);
    228	return 0;
    229}
    230
    231static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
    232{
    233	struct hfs_btree *tree;
    234	struct hfs_bnode *node, *new_node, *next_node;
    235	struct hfs_bnode_desc node_desc;
    236	int num_recs, new_rec_off, new_off, old_rec_off;
    237	int data_start, data_end, size;
    238
    239	tree = fd->tree;
    240	node = fd->bnode;
    241	new_node = hfs_bmap_alloc(tree);
    242	if (IS_ERR(new_node))
    243		return new_node;
    244	hfs_bnode_get(node);
    245	hfs_dbg(BNODE_MOD, "split_nodes: %d - %d - %d\n",
    246		node->this, new_node->this, node->next);
    247	new_node->next = node->next;
    248	new_node->prev = node->this;
    249	new_node->parent = node->parent;
    250	new_node->type = node->type;
    251	new_node->height = node->height;
    252
    253	if (node->next)
    254		next_node = hfs_bnode_find(tree, node->next);
    255	else
    256		next_node = NULL;
    257
    258	if (IS_ERR(next_node)) {
    259		hfs_bnode_put(node);
    260		hfs_bnode_put(new_node);
    261		return next_node;
    262	}
    263
    264	size = tree->node_size / 2 - node->num_recs * 2 - 14;
    265	old_rec_off = tree->node_size - 4;
    266	num_recs = 1;
    267	for (;;) {
    268		data_start = hfs_bnode_read_u16(node, old_rec_off);
    269		if (data_start > size)
    270			break;
    271		old_rec_off -= 2;
    272		if (++num_recs < node->num_recs)
    273			continue;
    274		/* panic? */
    275		hfs_bnode_put(node);
    276		hfs_bnode_put(new_node);
    277		if (next_node)
    278			hfs_bnode_put(next_node);
    279		return ERR_PTR(-ENOSPC);
    280	}
    281
    282	if (fd->record + 1 < num_recs) {
    283		/* new record is in the lower half,
    284		 * so leave some more space there
    285		 */
    286		old_rec_off += 2;
    287		num_recs--;
    288		data_start = hfs_bnode_read_u16(node, old_rec_off);
    289	} else {
    290		hfs_bnode_put(node);
    291		hfs_bnode_get(new_node);
    292		fd->bnode = new_node;
    293		fd->record -= num_recs;
    294		fd->keyoffset -= data_start - 14;
    295		fd->entryoffset -= data_start - 14;
    296	}
    297	new_node->num_recs = node->num_recs - num_recs;
    298	node->num_recs = num_recs;
    299
    300	new_rec_off = tree->node_size - 2;
    301	new_off = 14;
    302	size = data_start - new_off;
    303	num_recs = new_node->num_recs;
    304	data_end = data_start;
    305	while (num_recs) {
    306		hfs_bnode_write_u16(new_node, new_rec_off, new_off);
    307		old_rec_off -= 2;
    308		new_rec_off -= 2;
    309		data_end = hfs_bnode_read_u16(node, old_rec_off);
    310		new_off = data_end - size;
    311		num_recs--;
    312	}
    313	hfs_bnode_write_u16(new_node, new_rec_off, new_off);
    314	hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start);
    315
    316	/* update new bnode header */
    317	node_desc.next = cpu_to_be32(new_node->next);
    318	node_desc.prev = cpu_to_be32(new_node->prev);
    319	node_desc.type = new_node->type;
    320	node_desc.height = new_node->height;
    321	node_desc.num_recs = cpu_to_be16(new_node->num_recs);
    322	node_desc.reserved = 0;
    323	hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
    324
    325	/* update previous bnode header */
    326	node->next = new_node->this;
    327	hfs_bnode_read(node, &node_desc, 0, sizeof(node_desc));
    328	node_desc.next = cpu_to_be32(node->next);
    329	node_desc.num_recs = cpu_to_be16(node->num_recs);
    330	hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));
    331
    332	/* update next bnode header */
    333	if (next_node) {
    334		next_node->prev = new_node->this;
    335		hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
    336		node_desc.prev = cpu_to_be32(next_node->prev);
    337		hfs_bnode_write(next_node, &node_desc, 0, sizeof(node_desc));
    338		hfs_bnode_put(next_node);
    339	} else if (node->this == tree->leaf_tail) {
    340		/* if there is no next node, this might be the new tail */
    341		tree->leaf_tail = new_node->this;
    342		mark_inode_dirty(tree->inode);
    343	}
    344
    345	hfs_bnode_dump(node);
    346	hfs_bnode_dump(new_node);
    347	hfs_bnode_put(node);
    348
    349	return new_node;
    350}
    351
    352static int hfs_brec_update_parent(struct hfs_find_data *fd)
    353{
    354	struct hfs_btree *tree;
    355	struct hfs_bnode *node, *new_node, *parent;
    356	int newkeylen, diff;
    357	int rec, rec_off, end_rec_off;
    358	int start_off, end_off;
    359
    360	tree = fd->tree;
    361	node = fd->bnode;
    362	new_node = NULL;
    363	if (!node->parent)
    364		return 0;
    365
    366again:
    367	parent = hfs_bnode_find(tree, node->parent);
    368	if (IS_ERR(parent))
    369		return PTR_ERR(parent);
    370	__hfs_brec_find(parent, fd);
    371	if (fd->record < 0)
    372		return -ENOENT;
    373	hfs_bnode_dump(parent);
    374	rec = fd->record;
    375
    376	/* size difference between old and new key */
    377	if (tree->attributes & HFS_TREE_VARIDXKEYS)
    378		newkeylen = (hfs_bnode_read_u8(node, 14) | 1) + 1;
    379	else
    380		fd->keylength = newkeylen = tree->max_key_len + 1;
    381	hfs_dbg(BNODE_MOD, "update_rec: %d, %d, %d\n",
    382		rec, fd->keylength, newkeylen);
    383
    384	rec_off = tree->node_size - (rec + 2) * 2;
    385	end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
    386	diff = newkeylen - fd->keylength;
    387	if (!diff)
    388		goto skip;
    389	if (diff > 0) {
    390		end_off = hfs_bnode_read_u16(parent, end_rec_off);
    391		if (end_rec_off - end_off < diff) {
    392
    393			printk(KERN_DEBUG "splitting index node...\n");
    394			fd->bnode = parent;
    395			new_node = hfs_bnode_split(fd);
    396			if (IS_ERR(new_node))
    397				return PTR_ERR(new_node);
    398			parent = fd->bnode;
    399			rec = fd->record;
    400			rec_off = tree->node_size - (rec + 2) * 2;
    401			end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
    402		}
    403	}
    404
    405	end_off = start_off = hfs_bnode_read_u16(parent, rec_off);
    406	hfs_bnode_write_u16(parent, rec_off, start_off + diff);
    407	start_off -= 4;	/* move previous cnid too */
    408
    409	while (rec_off > end_rec_off) {
    410		rec_off -= 2;
    411		end_off = hfs_bnode_read_u16(parent, rec_off);
    412		hfs_bnode_write_u16(parent, rec_off, end_off + diff);
    413	}
    414	hfs_bnode_move(parent, start_off + diff, start_off,
    415		       end_off - start_off);
    416skip:
    417	hfs_bnode_copy(parent, fd->keyoffset, node, 14, newkeylen);
    418	if (!(tree->attributes & HFS_TREE_VARIDXKEYS))
    419		hfs_bnode_write_u8(parent, fd->keyoffset, newkeylen - 1);
    420	hfs_bnode_dump(parent);
    421
    422	hfs_bnode_put(node);
    423	node = parent;
    424
    425	if (new_node) {
    426		__be32 cnid;
    427
    428		if (!new_node->parent) {
    429			hfs_btree_inc_height(tree);
    430			new_node->parent = tree->root;
    431		}
    432		fd->bnode = hfs_bnode_find(tree, new_node->parent);
    433		/* create index key and entry */
    434		hfs_bnode_read_key(new_node, fd->search_key, 14);
    435		cnid = cpu_to_be32(new_node->this);
    436
    437		__hfs_brec_find(fd->bnode, fd);
    438		hfs_brec_insert(fd, &cnid, sizeof(cnid));
    439		hfs_bnode_put(fd->bnode);
    440		hfs_bnode_put(new_node);
    441
    442		if (!rec) {
    443			if (new_node == node)
    444				goto out;
    445			/* restore search_key */
    446			hfs_bnode_read_key(node, fd->search_key, 14);
    447		}
    448		new_node = NULL;
    449	}
    450
    451	if (!rec && node->parent)
    452		goto again;
    453out:
    454	fd->bnode = node;
    455	return 0;
    456}
    457
    458static int hfs_btree_inc_height(struct hfs_btree *tree)
    459{
    460	struct hfs_bnode *node, *new_node;
    461	struct hfs_bnode_desc node_desc;
    462	int key_size, rec;
    463	__be32 cnid;
    464
    465	node = NULL;
    466	if (tree->root) {
    467		node = hfs_bnode_find(tree, tree->root);
    468		if (IS_ERR(node))
    469			return PTR_ERR(node);
    470	}
    471	new_node = hfs_bmap_alloc(tree);
    472	if (IS_ERR(new_node)) {
    473		hfs_bnode_put(node);
    474		return PTR_ERR(new_node);
    475	}
    476
    477	tree->root = new_node->this;
    478	if (!tree->depth) {
    479		tree->leaf_head = tree->leaf_tail = new_node->this;
    480		new_node->type = HFS_NODE_LEAF;
    481		new_node->num_recs = 0;
    482	} else {
    483		new_node->type = HFS_NODE_INDEX;
    484		new_node->num_recs = 1;
    485	}
    486	new_node->parent = 0;
    487	new_node->next = 0;
    488	new_node->prev = 0;
    489	new_node->height = ++tree->depth;
    490
    491	node_desc.next = cpu_to_be32(new_node->next);
    492	node_desc.prev = cpu_to_be32(new_node->prev);
    493	node_desc.type = new_node->type;
    494	node_desc.height = new_node->height;
    495	node_desc.num_recs = cpu_to_be16(new_node->num_recs);
    496	node_desc.reserved = 0;
    497	hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
    498
    499	rec = tree->node_size - 2;
    500	hfs_bnode_write_u16(new_node, rec, 14);
    501
    502	if (node) {
    503		/* insert old root idx into new root */
    504		node->parent = tree->root;
    505		if (node->type == HFS_NODE_LEAF ||
    506		    tree->attributes & HFS_TREE_VARIDXKEYS)
    507			key_size = hfs_bnode_read_u8(node, 14) + 1;
    508		else
    509			key_size = tree->max_key_len + 1;
    510		hfs_bnode_copy(new_node, 14, node, 14, key_size);
    511
    512		if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
    513			key_size = tree->max_key_len + 1;
    514			hfs_bnode_write_u8(new_node, 14, tree->max_key_len);
    515		}
    516		key_size = (key_size + 1) & -2;
    517		cnid = cpu_to_be32(node->this);
    518		hfs_bnode_write(new_node, &cnid, 14 + key_size, 4);
    519
    520		rec -= 2;
    521		hfs_bnode_write_u16(new_node, rec, 14 + key_size + 4);
    522
    523		hfs_bnode_put(node);
    524	}
    525	hfs_bnode_put(new_node);
    526	mark_inode_dirty(tree->inode);
    527
    528	return 0;
    529}