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

dir-item.c (12382B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2007 Oracle.  All rights reserved.
      4 */
      5
      6#include "ctree.h"
      7#include "disk-io.h"
      8#include "transaction.h"
      9
     10/*
     11 * insert a name into a directory, doing overflow properly if there is a hash
     12 * collision.  data_size indicates how big the item inserted should be.  On
     13 * success a struct btrfs_dir_item pointer is returned, otherwise it is
     14 * an ERR_PTR.
     15 *
     16 * The name is not copied into the dir item, you have to do that yourself.
     17 */
     18static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
     19						   *trans,
     20						   struct btrfs_root *root,
     21						   struct btrfs_path *path,
     22						   struct btrfs_key *cpu_key,
     23						   u32 data_size,
     24						   const char *name,
     25						   int name_len)
     26{
     27	struct btrfs_fs_info *fs_info = root->fs_info;
     28	int ret;
     29	char *ptr;
     30	struct extent_buffer *leaf;
     31
     32	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
     33	if (ret == -EEXIST) {
     34		struct btrfs_dir_item *di;
     35		di = btrfs_match_dir_item_name(fs_info, path, name, name_len);
     36		if (di)
     37			return ERR_PTR(-EEXIST);
     38		btrfs_extend_item(path, data_size);
     39	} else if (ret < 0)
     40		return ERR_PTR(ret);
     41	WARN_ON(ret > 0);
     42	leaf = path->nodes[0];
     43	ptr = btrfs_item_ptr(leaf, path->slots[0], char);
     44	ASSERT(data_size <= btrfs_item_size(leaf, path->slots[0]));
     45	ptr += btrfs_item_size(leaf, path->slots[0]) - data_size;
     46	return (struct btrfs_dir_item *)ptr;
     47}
     48
     49/*
     50 * xattrs work a lot like directories, this inserts an xattr item
     51 * into the tree
     52 */
     53int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
     54			    struct btrfs_root *root,
     55			    struct btrfs_path *path, u64 objectid,
     56			    const char *name, u16 name_len,
     57			    const void *data, u16 data_len)
     58{
     59	int ret = 0;
     60	struct btrfs_dir_item *dir_item;
     61	unsigned long name_ptr, data_ptr;
     62	struct btrfs_key key, location;
     63	struct btrfs_disk_key disk_key;
     64	struct extent_buffer *leaf;
     65	u32 data_size;
     66
     67	if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info))
     68		return -ENOSPC;
     69
     70	key.objectid = objectid;
     71	key.type = BTRFS_XATTR_ITEM_KEY;
     72	key.offset = btrfs_name_hash(name, name_len);
     73
     74	data_size = sizeof(*dir_item) + name_len + data_len;
     75	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
     76					name, name_len);
     77	if (IS_ERR(dir_item))
     78		return PTR_ERR(dir_item);
     79	memset(&location, 0, sizeof(location));
     80
     81	leaf = path->nodes[0];
     82	btrfs_cpu_key_to_disk(&disk_key, &location);
     83	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
     84	btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
     85	btrfs_set_dir_name_len(leaf, dir_item, name_len);
     86	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
     87	btrfs_set_dir_data_len(leaf, dir_item, data_len);
     88	name_ptr = (unsigned long)(dir_item + 1);
     89	data_ptr = (unsigned long)((char *)name_ptr + name_len);
     90
     91	write_extent_buffer(leaf, name, name_ptr, name_len);
     92	write_extent_buffer(leaf, data, data_ptr, data_len);
     93	btrfs_mark_buffer_dirty(path->nodes[0]);
     94
     95	return ret;
     96}
     97
     98/*
     99 * insert a directory item in the tree, doing all the magic for
    100 * both indexes. 'dir' indicates which objectid to insert it into,
    101 * 'location' is the key to stuff into the directory item, 'type' is the
    102 * type of the inode we're pointing to, and 'index' is the sequence number
    103 * to use for the second index (if one is created).
    104 * Will return 0 or -ENOMEM
    105 */
    106int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const char *name,
    107			  int name_len, struct btrfs_inode *dir,
    108			  struct btrfs_key *location, u8 type, u64 index)
    109{
    110	int ret = 0;
    111	int ret2 = 0;
    112	struct btrfs_root *root = dir->root;
    113	struct btrfs_path *path;
    114	struct btrfs_dir_item *dir_item;
    115	struct extent_buffer *leaf;
    116	unsigned long name_ptr;
    117	struct btrfs_key key;
    118	struct btrfs_disk_key disk_key;
    119	u32 data_size;
    120
    121	key.objectid = btrfs_ino(dir);
    122	key.type = BTRFS_DIR_ITEM_KEY;
    123	key.offset = btrfs_name_hash(name, name_len);
    124
    125	path = btrfs_alloc_path();
    126	if (!path)
    127		return -ENOMEM;
    128
    129	btrfs_cpu_key_to_disk(&disk_key, location);
    130
    131	data_size = sizeof(*dir_item) + name_len;
    132	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
    133					name, name_len);
    134	if (IS_ERR(dir_item)) {
    135		ret = PTR_ERR(dir_item);
    136		if (ret == -EEXIST)
    137			goto second_insert;
    138		goto out_free;
    139	}
    140
    141	leaf = path->nodes[0];
    142	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
    143	btrfs_set_dir_type(leaf, dir_item, type);
    144	btrfs_set_dir_data_len(leaf, dir_item, 0);
    145	btrfs_set_dir_name_len(leaf, dir_item, name_len);
    146	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
    147	name_ptr = (unsigned long)(dir_item + 1);
    148
    149	write_extent_buffer(leaf, name, name_ptr, name_len);
    150	btrfs_mark_buffer_dirty(leaf);
    151
    152second_insert:
    153	/* FIXME, use some real flag for selecting the extra index */
    154	if (root == root->fs_info->tree_root) {
    155		ret = 0;
    156		goto out_free;
    157	}
    158	btrfs_release_path(path);
    159
    160	ret2 = btrfs_insert_delayed_dir_index(trans, name, name_len, dir,
    161					      &disk_key, type, index);
    162out_free:
    163	btrfs_free_path(path);
    164	if (ret)
    165		return ret;
    166	if (ret2)
    167		return ret2;
    168	return 0;
    169}
    170
    171static struct btrfs_dir_item *btrfs_lookup_match_dir(
    172			struct btrfs_trans_handle *trans,
    173			struct btrfs_root *root, struct btrfs_path *path,
    174			struct btrfs_key *key, const char *name,
    175			int name_len, int mod)
    176{
    177	const int ins_len = (mod < 0 ? -1 : 0);
    178	const int cow = (mod != 0);
    179	int ret;
    180
    181	ret = btrfs_search_slot(trans, root, key, path, ins_len, cow);
    182	if (ret < 0)
    183		return ERR_PTR(ret);
    184	if (ret > 0)
    185		return ERR_PTR(-ENOENT);
    186
    187	return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
    188}
    189
    190/*
    191 * Lookup for a directory item by name.
    192 *
    193 * @trans:	The transaction handle to use. Can be NULL if @mod is 0.
    194 * @root:	The root of the target tree.
    195 * @path:	Path to use for the search.
    196 * @dir:	The inode number (objectid) of the directory.
    197 * @name:	The name associated to the directory entry we are looking for.
    198 * @name_len:	The length of the name.
    199 * @mod:	Used to indicate if the tree search is meant for a read only
    200 *		lookup, for a modification lookup or for a deletion lookup, so
    201 *		its value should be 0, 1 or -1, respectively.
    202 *
    203 * Returns: NULL if the dir item does not exists, an error pointer if an error
    204 * happened, or a pointer to a dir item if a dir item exists for the given name.
    205 */
    206struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
    207					     struct btrfs_root *root,
    208					     struct btrfs_path *path, u64 dir,
    209					     const char *name, int name_len,
    210					     int mod)
    211{
    212	struct btrfs_key key;
    213	struct btrfs_dir_item *di;
    214
    215	key.objectid = dir;
    216	key.type = BTRFS_DIR_ITEM_KEY;
    217	key.offset = btrfs_name_hash(name, name_len);
    218
    219	di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
    220	if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
    221		return NULL;
    222
    223	return di;
    224}
    225
    226int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
    227				   const char *name, int name_len)
    228{
    229	int ret;
    230	struct btrfs_key key;
    231	struct btrfs_dir_item *di;
    232	int data_size;
    233	struct extent_buffer *leaf;
    234	int slot;
    235	struct btrfs_path *path;
    236
    237	path = btrfs_alloc_path();
    238	if (!path)
    239		return -ENOMEM;
    240
    241	key.objectid = dir;
    242	key.type = BTRFS_DIR_ITEM_KEY;
    243	key.offset = btrfs_name_hash(name, name_len);
    244
    245	di = btrfs_lookup_match_dir(NULL, root, path, &key, name, name_len, 0);
    246	if (IS_ERR(di)) {
    247		ret = PTR_ERR(di);
    248		/* Nothing found, we're safe */
    249		if (ret == -ENOENT) {
    250			ret = 0;
    251			goto out;
    252		}
    253
    254		if (ret < 0)
    255			goto out;
    256	}
    257
    258	/* we found an item, look for our name in the item */
    259	if (di) {
    260		/* our exact name was found */
    261		ret = -EEXIST;
    262		goto out;
    263	}
    264
    265	/*
    266	 * see if there is room in the item to insert this
    267	 * name
    268	 */
    269	data_size = sizeof(*di) + name_len;
    270	leaf = path->nodes[0];
    271	slot = path->slots[0];
    272	if (data_size + btrfs_item_size(leaf, slot) +
    273	    sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
    274		ret = -EOVERFLOW;
    275	} else {
    276		/* plenty of insertion room */
    277		ret = 0;
    278	}
    279out:
    280	btrfs_free_path(path);
    281	return ret;
    282}
    283
    284/*
    285 * Lookup for a directory index item by name and index number.
    286 *
    287 * @trans:	The transaction handle to use. Can be NULL if @mod is 0.
    288 * @root:	The root of the target tree.
    289 * @path:	Path to use for the search.
    290 * @dir:	The inode number (objectid) of the directory.
    291 * @index:	The index number.
    292 * @name:	The name associated to the directory entry we are looking for.
    293 * @name_len:	The length of the name.
    294 * @mod:	Used to indicate if the tree search is meant for a read only
    295 *		lookup, for a modification lookup or for a deletion lookup, so
    296 *		its value should be 0, 1 or -1, respectively.
    297 *
    298 * Returns: NULL if the dir index item does not exists, an error pointer if an
    299 * error happened, or a pointer to a dir item if the dir index item exists and
    300 * matches the criteria (name and index number).
    301 */
    302struct btrfs_dir_item *
    303btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
    304			    struct btrfs_root *root,
    305			    struct btrfs_path *path, u64 dir,
    306			    u64 index, const char *name, int name_len,
    307			    int mod)
    308{
    309	struct btrfs_dir_item *di;
    310	struct btrfs_key key;
    311
    312	key.objectid = dir;
    313	key.type = BTRFS_DIR_INDEX_KEY;
    314	key.offset = index;
    315
    316	di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
    317	if (di == ERR_PTR(-ENOENT))
    318		return NULL;
    319
    320	return di;
    321}
    322
    323struct btrfs_dir_item *
    324btrfs_search_dir_index_item(struct btrfs_root *root,
    325			    struct btrfs_path *path, u64 dirid,
    326			    const char *name, int name_len)
    327{
    328	struct btrfs_dir_item *di;
    329	struct btrfs_key key;
    330	int ret;
    331
    332	key.objectid = dirid;
    333	key.type = BTRFS_DIR_INDEX_KEY;
    334	key.offset = 0;
    335
    336	btrfs_for_each_slot(root, &key, &key, path, ret) {
    337		if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
    338			break;
    339
    340		di = btrfs_match_dir_item_name(root->fs_info, path,
    341					       name, name_len);
    342		if (di)
    343			return di;
    344	}
    345	/* Adjust return code if the key was not found in the next leaf. */
    346	if (ret > 0)
    347		ret = 0;
    348
    349	return ERR_PTR(ret);
    350}
    351
    352struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
    353					  struct btrfs_root *root,
    354					  struct btrfs_path *path, u64 dir,
    355					  const char *name, u16 name_len,
    356					  int mod)
    357{
    358	struct btrfs_key key;
    359	struct btrfs_dir_item *di;
    360
    361	key.objectid = dir;
    362	key.type = BTRFS_XATTR_ITEM_KEY;
    363	key.offset = btrfs_name_hash(name, name_len);
    364
    365	di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
    366	if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
    367		return NULL;
    368
    369	return di;
    370}
    371
    372/*
    373 * helper function to look at the directory item pointed to by 'path'
    374 * this walks through all the entries in a dir item and finds one
    375 * for a specific name.
    376 */
    377struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
    378						 struct btrfs_path *path,
    379						 const char *name, int name_len)
    380{
    381	struct btrfs_dir_item *dir_item;
    382	unsigned long name_ptr;
    383	u32 total_len;
    384	u32 cur = 0;
    385	u32 this_len;
    386	struct extent_buffer *leaf;
    387
    388	leaf = path->nodes[0];
    389	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
    390
    391	total_len = btrfs_item_size(leaf, path->slots[0]);
    392	while (cur < total_len) {
    393		this_len = sizeof(*dir_item) +
    394			btrfs_dir_name_len(leaf, dir_item) +
    395			btrfs_dir_data_len(leaf, dir_item);
    396		name_ptr = (unsigned long)(dir_item + 1);
    397
    398		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
    399		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
    400			return dir_item;
    401
    402		cur += this_len;
    403		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
    404						     this_len);
    405	}
    406	return NULL;
    407}
    408
    409/*
    410 * given a pointer into a directory item, delete it.  This
    411 * handles items that have more than one entry in them.
    412 */
    413int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
    414			      struct btrfs_root *root,
    415			      struct btrfs_path *path,
    416			      struct btrfs_dir_item *di)
    417{
    418
    419	struct extent_buffer *leaf;
    420	u32 sub_item_len;
    421	u32 item_len;
    422	int ret = 0;
    423
    424	leaf = path->nodes[0];
    425	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
    426		btrfs_dir_data_len(leaf, di);
    427	item_len = btrfs_item_size(leaf, path->slots[0]);
    428	if (sub_item_len == item_len) {
    429		ret = btrfs_del_item(trans, root, path);
    430	} else {
    431		/* MARKER */
    432		unsigned long ptr = (unsigned long)di;
    433		unsigned long start;
    434
    435		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
    436		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
    437			item_len - (ptr + sub_item_len - start));
    438		btrfs_truncate_item(path, item_len - sub_item_len, 1);
    439	}
    440	return ret;
    441}