18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci/*
68c2ecf20Sopenharmony_ci *  Written by Anatoly P. Pinchuk pap@namesys.botik.ru
78c2ecf20Sopenharmony_ci *  Programm System Institute
88c2ecf20Sopenharmony_ci *  Pereslavl-Zalessky Russia
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/time.h>
128c2ecf20Sopenharmony_ci#include <linux/string.h>
138c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
148c2ecf20Sopenharmony_ci#include <linux/bio.h>
158c2ecf20Sopenharmony_ci#include "reiserfs.h"
168c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>
178c2ecf20Sopenharmony_ci#include <linux/quotaops.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* Does the buffer contain a disk block which is in the tree. */
208c2ecf20Sopenharmony_ciinline int B_IS_IN_TREE(const struct buffer_head *bh)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	RFALSE(B_LEVEL(bh) > MAX_HEIGHT,
248c2ecf20Sopenharmony_ci	       "PAP-1010: block (%b) has too big level (%z)", bh, bh);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	return (B_LEVEL(bh) != FREE_LEVEL);
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* to get item head in le form */
308c2ecf20Sopenharmony_ciinline void copy_item_head(struct item_head *to,
318c2ecf20Sopenharmony_ci			   const struct item_head *from)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	memcpy(to, from, IH_SIZE);
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/*
378c2ecf20Sopenharmony_ci * k1 is pointer to on-disk structure which is stored in little-endian
388c2ecf20Sopenharmony_ci * form. k2 is pointer to cpu variable. For key of items of the same
398c2ecf20Sopenharmony_ci * object this returns 0.
408c2ecf20Sopenharmony_ci * Returns: -1 if key1 < key2
418c2ecf20Sopenharmony_ci * 0 if key1 == key2
428c2ecf20Sopenharmony_ci * 1 if key1 > key2
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_ciinline int comp_short_keys(const struct reiserfs_key *le_key,
458c2ecf20Sopenharmony_ci			   const struct cpu_key *cpu_key)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	__u32 n;
488c2ecf20Sopenharmony_ci	n = le32_to_cpu(le_key->k_dir_id);
498c2ecf20Sopenharmony_ci	if (n < cpu_key->on_disk_key.k_dir_id)
508c2ecf20Sopenharmony_ci		return -1;
518c2ecf20Sopenharmony_ci	if (n > cpu_key->on_disk_key.k_dir_id)
528c2ecf20Sopenharmony_ci		return 1;
538c2ecf20Sopenharmony_ci	n = le32_to_cpu(le_key->k_objectid);
548c2ecf20Sopenharmony_ci	if (n < cpu_key->on_disk_key.k_objectid)
558c2ecf20Sopenharmony_ci		return -1;
568c2ecf20Sopenharmony_ci	if (n > cpu_key->on_disk_key.k_objectid)
578c2ecf20Sopenharmony_ci		return 1;
588c2ecf20Sopenharmony_ci	return 0;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci * k1 is pointer to on-disk structure which is stored in little-endian
638c2ecf20Sopenharmony_ci * form. k2 is pointer to cpu variable.
648c2ecf20Sopenharmony_ci * Compare keys using all 4 key fields.
658c2ecf20Sopenharmony_ci * Returns: -1 if key1 < key2 0
668c2ecf20Sopenharmony_ci * if key1 = key2 1 if key1 > key2
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_cistatic inline int comp_keys(const struct reiserfs_key *le_key,
698c2ecf20Sopenharmony_ci			    const struct cpu_key *cpu_key)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	int retval;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	retval = comp_short_keys(le_key, cpu_key);
748c2ecf20Sopenharmony_ci	if (retval)
758c2ecf20Sopenharmony_ci		return retval;
768c2ecf20Sopenharmony_ci	if (le_key_k_offset(le_key_version(le_key), le_key) <
778c2ecf20Sopenharmony_ci	    cpu_key_k_offset(cpu_key))
788c2ecf20Sopenharmony_ci		return -1;
798c2ecf20Sopenharmony_ci	if (le_key_k_offset(le_key_version(le_key), le_key) >
808c2ecf20Sopenharmony_ci	    cpu_key_k_offset(cpu_key))
818c2ecf20Sopenharmony_ci		return 1;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (cpu_key->key_length == 3)
848c2ecf20Sopenharmony_ci		return 0;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/* this part is needed only when tail conversion is in progress */
878c2ecf20Sopenharmony_ci	if (le_key_k_type(le_key_version(le_key), le_key) <
888c2ecf20Sopenharmony_ci	    cpu_key_k_type(cpu_key))
898c2ecf20Sopenharmony_ci		return -1;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (le_key_k_type(le_key_version(le_key), le_key) >
928c2ecf20Sopenharmony_ci	    cpu_key_k_type(cpu_key))
938c2ecf20Sopenharmony_ci		return 1;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return 0;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ciinline int comp_short_le_keys(const struct reiserfs_key *key1,
998c2ecf20Sopenharmony_ci			      const struct reiserfs_key *key2)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	__u32 *k1_u32, *k2_u32;
1028c2ecf20Sopenharmony_ci	int key_length = REISERFS_SHORT_KEY_LEN;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	k1_u32 = (__u32 *) key1;
1058c2ecf20Sopenharmony_ci	k2_u32 = (__u32 *) key2;
1068c2ecf20Sopenharmony_ci	for (; key_length--; ++k1_u32, ++k2_u32) {
1078c2ecf20Sopenharmony_ci		if (le32_to_cpu(*k1_u32) < le32_to_cpu(*k2_u32))
1088c2ecf20Sopenharmony_ci			return -1;
1098c2ecf20Sopenharmony_ci		if (le32_to_cpu(*k1_u32) > le32_to_cpu(*k2_u32))
1108c2ecf20Sopenharmony_ci			return 1;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci	return 0;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciinline void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	int version;
1188c2ecf20Sopenharmony_ci	to->on_disk_key.k_dir_id = le32_to_cpu(from->k_dir_id);
1198c2ecf20Sopenharmony_ci	to->on_disk_key.k_objectid = le32_to_cpu(from->k_objectid);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* find out version of the key */
1228c2ecf20Sopenharmony_ci	version = le_key_version(from);
1238c2ecf20Sopenharmony_ci	to->version = version;
1248c2ecf20Sopenharmony_ci	to->on_disk_key.k_offset = le_key_k_offset(version, from);
1258c2ecf20Sopenharmony_ci	to->on_disk_key.k_type = le_key_k_type(version, from);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/*
1298c2ecf20Sopenharmony_ci * this does not say which one is bigger, it only returns 1 if keys
1308c2ecf20Sopenharmony_ci * are not equal, 0 otherwise
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_ciinline int comp_le_keys(const struct reiserfs_key *k1,
1338c2ecf20Sopenharmony_ci			const struct reiserfs_key *k2)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	return memcmp(k1, k2, sizeof(struct reiserfs_key));
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/**************************************************************************
1398c2ecf20Sopenharmony_ci *  Binary search toolkit function                                        *
1408c2ecf20Sopenharmony_ci *  Search for an item in the array by the item key                       *
1418c2ecf20Sopenharmony_ci *  Returns:    1 if found,  0 if not found;                              *
1428c2ecf20Sopenharmony_ci *        *pos = number of the searched element if found, else the        *
1438c2ecf20Sopenharmony_ci *        number of the first element that is larger than key.            *
1448c2ecf20Sopenharmony_ci **************************************************************************/
1458c2ecf20Sopenharmony_ci/*
1468c2ecf20Sopenharmony_ci * For those not familiar with binary search: lbound is the leftmost item
1478c2ecf20Sopenharmony_ci * that it could be, rbound the rightmost item that it could be.  We examine
1488c2ecf20Sopenharmony_ci * the item halfway between lbound and rbound, and that tells us either
1498c2ecf20Sopenharmony_ci * that we can increase lbound, or decrease rbound, or that we have found it,
1508c2ecf20Sopenharmony_ci * or if lbound <= rbound that there are no possible items, and we have not
1518c2ecf20Sopenharmony_ci * found it. With each examination we cut the number of possible items it
1528c2ecf20Sopenharmony_ci * could be by one more than half rounded down, or we find it.
1538c2ecf20Sopenharmony_ci */
1548c2ecf20Sopenharmony_cistatic inline int bin_search(const void *key,	/* Key to search for. */
1558c2ecf20Sopenharmony_ci			     const void *base,	/* First item in the array. */
1568c2ecf20Sopenharmony_ci			     int num,	/* Number of items in the array. */
1578c2ecf20Sopenharmony_ci			     /*
1588c2ecf20Sopenharmony_ci			      * Item size in the array.  searched. Lest the
1598c2ecf20Sopenharmony_ci			      * reader be confused, note that this is crafted
1608c2ecf20Sopenharmony_ci			      * as a general function, and when it is applied
1618c2ecf20Sopenharmony_ci			      * specifically to the array of item headers in a
1628c2ecf20Sopenharmony_ci			      * node, width is actually the item header size
1638c2ecf20Sopenharmony_ci			      * not the item size.
1648c2ecf20Sopenharmony_ci			      */
1658c2ecf20Sopenharmony_ci			     int width,
1668c2ecf20Sopenharmony_ci			     int *pos /* Number of the searched for element. */
1678c2ecf20Sopenharmony_ci    )
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	int rbound, lbound, j;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	for (j = ((rbound = num - 1) + (lbound = 0)) / 2;
1728c2ecf20Sopenharmony_ci	     lbound <= rbound; j = (rbound + lbound) / 2)
1738c2ecf20Sopenharmony_ci		switch (comp_keys
1748c2ecf20Sopenharmony_ci			((struct reiserfs_key *)((char *)base + j * width),
1758c2ecf20Sopenharmony_ci			 (struct cpu_key *)key)) {
1768c2ecf20Sopenharmony_ci		case -1:
1778c2ecf20Sopenharmony_ci			lbound = j + 1;
1788c2ecf20Sopenharmony_ci			continue;
1798c2ecf20Sopenharmony_ci		case 1:
1808c2ecf20Sopenharmony_ci			rbound = j - 1;
1818c2ecf20Sopenharmony_ci			continue;
1828c2ecf20Sopenharmony_ci		case 0:
1838c2ecf20Sopenharmony_ci			*pos = j;
1848c2ecf20Sopenharmony_ci			return ITEM_FOUND;	/* Key found in the array.  */
1858c2ecf20Sopenharmony_ci		}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/*
1888c2ecf20Sopenharmony_ci	 * bin_search did not find given key, it returns position of key,
1898c2ecf20Sopenharmony_ci	 * that is minimal and greater than the given one.
1908c2ecf20Sopenharmony_ci	 */
1918c2ecf20Sopenharmony_ci	*pos = lbound;
1928c2ecf20Sopenharmony_ci	return ITEM_NOT_FOUND;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci/* Minimal possible key. It is never in the tree. */
1978c2ecf20Sopenharmony_ciconst struct reiserfs_key MIN_KEY = { 0, 0, {{0, 0},} };
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/* Maximal possible key. It is never in the tree. */
2008c2ecf20Sopenharmony_cistatic const struct reiserfs_key MAX_KEY = {
2018c2ecf20Sopenharmony_ci	cpu_to_le32(0xffffffff),
2028c2ecf20Sopenharmony_ci	cpu_to_le32(0xffffffff),
2038c2ecf20Sopenharmony_ci	{{cpu_to_le32(0xffffffff),
2048c2ecf20Sopenharmony_ci	  cpu_to_le32(0xffffffff)},}
2058c2ecf20Sopenharmony_ci};
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/*
2088c2ecf20Sopenharmony_ci * Get delimiting key of the buffer by looking for it in the buffers in the
2098c2ecf20Sopenharmony_ci * path, starting from the bottom of the path, and going upwards.  We must
2108c2ecf20Sopenharmony_ci * check the path's validity at each step.  If the key is not in the path,
2118c2ecf20Sopenharmony_ci * there is no delimiting key in the tree (buffer is first or last buffer
2128c2ecf20Sopenharmony_ci * in tree), and in this case we return a special key, either MIN_KEY or
2138c2ecf20Sopenharmony_ci * MAX_KEY.
2148c2ecf20Sopenharmony_ci */
2158c2ecf20Sopenharmony_cistatic inline const struct reiserfs_key *get_lkey(const struct treepath *chk_path,
2168c2ecf20Sopenharmony_ci						  const struct super_block *sb)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	int position, path_offset = chk_path->path_length;
2198c2ecf20Sopenharmony_ci	struct buffer_head *parent;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET,
2228c2ecf20Sopenharmony_ci	       "PAP-5010: invalid offset in the path");
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* While not higher in path than first element. */
2258c2ecf20Sopenharmony_ci	while (path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		RFALSE(!buffer_uptodate
2288c2ecf20Sopenharmony_ci		       (PATH_OFFSET_PBUFFER(chk_path, path_offset)),
2298c2ecf20Sopenharmony_ci		       "PAP-5020: parent is not uptodate");
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		/* Parent at the path is not in the tree now. */
2328c2ecf20Sopenharmony_ci		if (!B_IS_IN_TREE
2338c2ecf20Sopenharmony_ci		    (parent =
2348c2ecf20Sopenharmony_ci		     PATH_OFFSET_PBUFFER(chk_path, path_offset)))
2358c2ecf20Sopenharmony_ci			return &MAX_KEY;
2368c2ecf20Sopenharmony_ci		/* Check whether position in the parent is correct. */
2378c2ecf20Sopenharmony_ci		if ((position =
2388c2ecf20Sopenharmony_ci		     PATH_OFFSET_POSITION(chk_path,
2398c2ecf20Sopenharmony_ci					  path_offset)) >
2408c2ecf20Sopenharmony_ci		    B_NR_ITEMS(parent))
2418c2ecf20Sopenharmony_ci			return &MAX_KEY;
2428c2ecf20Sopenharmony_ci		/* Check whether parent at the path really points to the child. */
2438c2ecf20Sopenharmony_ci		if (B_N_CHILD_NUM(parent, position) !=
2448c2ecf20Sopenharmony_ci		    PATH_OFFSET_PBUFFER(chk_path,
2458c2ecf20Sopenharmony_ci					path_offset + 1)->b_blocknr)
2468c2ecf20Sopenharmony_ci			return &MAX_KEY;
2478c2ecf20Sopenharmony_ci		/*
2488c2ecf20Sopenharmony_ci		 * Return delimiting key if position in the parent
2498c2ecf20Sopenharmony_ci		 * is not equal to zero.
2508c2ecf20Sopenharmony_ci		 */
2518c2ecf20Sopenharmony_ci		if (position)
2528c2ecf20Sopenharmony_ci			return internal_key(parent, position - 1);
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci	/* Return MIN_KEY if we are in the root of the buffer tree. */
2558c2ecf20Sopenharmony_ci	if (PATH_OFFSET_PBUFFER(chk_path, FIRST_PATH_ELEMENT_OFFSET)->
2568c2ecf20Sopenharmony_ci	    b_blocknr == SB_ROOT_BLOCK(sb))
2578c2ecf20Sopenharmony_ci		return &MIN_KEY;
2588c2ecf20Sopenharmony_ci	return &MAX_KEY;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci/* Get delimiting key of the buffer at the path and its right neighbor. */
2628c2ecf20Sopenharmony_ciinline const struct reiserfs_key *get_rkey(const struct treepath *chk_path,
2638c2ecf20Sopenharmony_ci					   const struct super_block *sb)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	int position, path_offset = chk_path->path_length;
2668c2ecf20Sopenharmony_ci	struct buffer_head *parent;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET,
2698c2ecf20Sopenharmony_ci	       "PAP-5030: invalid offset in the path");
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	while (path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		RFALSE(!buffer_uptodate
2748c2ecf20Sopenharmony_ci		       (PATH_OFFSET_PBUFFER(chk_path, path_offset)),
2758c2ecf20Sopenharmony_ci		       "PAP-5040: parent is not uptodate");
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		/* Parent at the path is not in the tree now. */
2788c2ecf20Sopenharmony_ci		if (!B_IS_IN_TREE
2798c2ecf20Sopenharmony_ci		    (parent =
2808c2ecf20Sopenharmony_ci		     PATH_OFFSET_PBUFFER(chk_path, path_offset)))
2818c2ecf20Sopenharmony_ci			return &MIN_KEY;
2828c2ecf20Sopenharmony_ci		/* Check whether position in the parent is correct. */
2838c2ecf20Sopenharmony_ci		if ((position =
2848c2ecf20Sopenharmony_ci		     PATH_OFFSET_POSITION(chk_path,
2858c2ecf20Sopenharmony_ci					  path_offset)) >
2868c2ecf20Sopenharmony_ci		    B_NR_ITEMS(parent))
2878c2ecf20Sopenharmony_ci			return &MIN_KEY;
2888c2ecf20Sopenharmony_ci		/*
2898c2ecf20Sopenharmony_ci		 * Check whether parent at the path really points
2908c2ecf20Sopenharmony_ci		 * to the child.
2918c2ecf20Sopenharmony_ci		 */
2928c2ecf20Sopenharmony_ci		if (B_N_CHILD_NUM(parent, position) !=
2938c2ecf20Sopenharmony_ci		    PATH_OFFSET_PBUFFER(chk_path,
2948c2ecf20Sopenharmony_ci					path_offset + 1)->b_blocknr)
2958c2ecf20Sopenharmony_ci			return &MIN_KEY;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		/*
2988c2ecf20Sopenharmony_ci		 * Return delimiting key if position in the parent
2998c2ecf20Sopenharmony_ci		 * is not the last one.
3008c2ecf20Sopenharmony_ci		 */
3018c2ecf20Sopenharmony_ci		if (position != B_NR_ITEMS(parent))
3028c2ecf20Sopenharmony_ci			return internal_key(parent, position);
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* Return MAX_KEY if we are in the root of the buffer tree. */
3068c2ecf20Sopenharmony_ci	if (PATH_OFFSET_PBUFFER(chk_path, FIRST_PATH_ELEMENT_OFFSET)->
3078c2ecf20Sopenharmony_ci	    b_blocknr == SB_ROOT_BLOCK(sb))
3088c2ecf20Sopenharmony_ci		return &MAX_KEY;
3098c2ecf20Sopenharmony_ci	return &MIN_KEY;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci/*
3138c2ecf20Sopenharmony_ci * Check whether a key is contained in the tree rooted from a buffer at a path.
3148c2ecf20Sopenharmony_ci * This works by looking at the left and right delimiting keys for the buffer
3158c2ecf20Sopenharmony_ci * in the last path_element in the path.  These delimiting keys are stored
3168c2ecf20Sopenharmony_ci * at least one level above that buffer in the tree. If the buffer is the
3178c2ecf20Sopenharmony_ci * first or last node in the tree order then one of the delimiting keys may
3188c2ecf20Sopenharmony_ci * be absent, and in this case get_lkey and get_rkey return a special key
3198c2ecf20Sopenharmony_ci * which is MIN_KEY or MAX_KEY.
3208c2ecf20Sopenharmony_ci */
3218c2ecf20Sopenharmony_cistatic inline int key_in_buffer(
3228c2ecf20Sopenharmony_ci				/* Path which should be checked. */
3238c2ecf20Sopenharmony_ci				struct treepath *chk_path,
3248c2ecf20Sopenharmony_ci				/* Key which should be checked. */
3258c2ecf20Sopenharmony_ci				const struct cpu_key *key,
3268c2ecf20Sopenharmony_ci				struct super_block *sb
3278c2ecf20Sopenharmony_ci    )
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	RFALSE(!key || chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET
3318c2ecf20Sopenharmony_ci	       || chk_path->path_length > MAX_HEIGHT,
3328c2ecf20Sopenharmony_ci	       "PAP-5050: pointer to the key(%p) is NULL or invalid path length(%d)",
3338c2ecf20Sopenharmony_ci	       key, chk_path->path_length);
3348c2ecf20Sopenharmony_ci	RFALSE(!PATH_PLAST_BUFFER(chk_path)->b_bdev,
3358c2ecf20Sopenharmony_ci	       "PAP-5060: device must not be NODEV");
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (comp_keys(get_lkey(chk_path, sb), key) == 1)
3388c2ecf20Sopenharmony_ci		/* left delimiting key is bigger, that the key we look for */
3398c2ecf20Sopenharmony_ci		return 0;
3408c2ecf20Sopenharmony_ci	/*  if ( comp_keys(key, get_rkey(chk_path, sb)) != -1 ) */
3418c2ecf20Sopenharmony_ci	if (comp_keys(get_rkey(chk_path, sb), key) != 1)
3428c2ecf20Sopenharmony_ci		/* key must be less than right delimitiing key */
3438c2ecf20Sopenharmony_ci		return 0;
3448c2ecf20Sopenharmony_ci	return 1;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ciint reiserfs_check_path(struct treepath *p)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	RFALSE(p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET,
3508c2ecf20Sopenharmony_ci	       "path not properly relsed");
3518c2ecf20Sopenharmony_ci	return 0;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci/*
3558c2ecf20Sopenharmony_ci * Drop the reference to each buffer in a path and restore
3568c2ecf20Sopenharmony_ci * dirty bits clean when preparing the buffer for the log.
3578c2ecf20Sopenharmony_ci * This version should only be called from fix_nodes()
3588c2ecf20Sopenharmony_ci */
3598c2ecf20Sopenharmony_civoid pathrelse_and_restore(struct super_block *sb,
3608c2ecf20Sopenharmony_ci			   struct treepath *search_path)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	int path_offset = search_path->path_length;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	RFALSE(path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
3658c2ecf20Sopenharmony_ci	       "clm-4000: invalid path offset");
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	while (path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) {
3688c2ecf20Sopenharmony_ci		struct buffer_head *bh;
3698c2ecf20Sopenharmony_ci		bh = PATH_OFFSET_PBUFFER(search_path, path_offset--);
3708c2ecf20Sopenharmony_ci		reiserfs_restore_prepared_buffer(sb, bh);
3718c2ecf20Sopenharmony_ci		brelse(bh);
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci	search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci/* Drop the reference to each buffer in a path */
3778c2ecf20Sopenharmony_civoid pathrelse(struct treepath *search_path)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	int path_offset = search_path->path_length;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	RFALSE(path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
3828c2ecf20Sopenharmony_ci	       "PAP-5090: invalid path offset");
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	while (path_offset > ILLEGAL_PATH_ELEMENT_OFFSET)
3858c2ecf20Sopenharmony_ci		brelse(PATH_OFFSET_PBUFFER(search_path, path_offset--));
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic int has_valid_deh_location(struct buffer_head *bh, struct item_head *ih)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct reiserfs_de_head *deh;
3938c2ecf20Sopenharmony_ci	int i;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	deh = B_I_DEH(bh, ih);
3968c2ecf20Sopenharmony_ci	for (i = 0; i < ih_entry_count(ih); i++) {
3978c2ecf20Sopenharmony_ci		if (deh_location(&deh[i]) > ih_item_len(ih)) {
3988c2ecf20Sopenharmony_ci			reiserfs_warning(NULL, "reiserfs-5094",
3998c2ecf20Sopenharmony_ci					 "directory entry location seems wrong %h",
4008c2ecf20Sopenharmony_ci					 &deh[i]);
4018c2ecf20Sopenharmony_ci			return 0;
4028c2ecf20Sopenharmony_ci		}
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return 1;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic int is_leaf(char *buf, int blocksize, struct buffer_head *bh)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct block_head *blkh;
4118c2ecf20Sopenharmony_ci	struct item_head *ih;
4128c2ecf20Sopenharmony_ci	int used_space;
4138c2ecf20Sopenharmony_ci	int prev_location;
4148c2ecf20Sopenharmony_ci	int i;
4158c2ecf20Sopenharmony_ci	int nr;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	blkh = (struct block_head *)buf;
4188c2ecf20Sopenharmony_ci	if (blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) {
4198c2ecf20Sopenharmony_ci		reiserfs_warning(NULL, "reiserfs-5080",
4208c2ecf20Sopenharmony_ci				 "this should be caught earlier");
4218c2ecf20Sopenharmony_ci		return 0;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	nr = blkh_nr_item(blkh);
4258c2ecf20Sopenharmony_ci	if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) {
4268c2ecf20Sopenharmony_ci		/* item number is too big or too small */
4278c2ecf20Sopenharmony_ci		reiserfs_warning(NULL, "reiserfs-5081",
4288c2ecf20Sopenharmony_ci				 "nr_item seems wrong: %z", bh);
4298c2ecf20Sopenharmony_ci		return 0;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci	ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1;
4328c2ecf20Sopenharmony_ci	used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location(ih));
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* free space does not match to calculated amount of use space */
4358c2ecf20Sopenharmony_ci	if (used_space != blocksize - blkh_free_space(blkh)) {
4368c2ecf20Sopenharmony_ci		reiserfs_warning(NULL, "reiserfs-5082",
4378c2ecf20Sopenharmony_ci				 "free space seems wrong: %z", bh);
4388c2ecf20Sopenharmony_ci		return 0;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci	/*
4418c2ecf20Sopenharmony_ci	 * FIXME: it is_leaf will hit performance too much - we may have
4428c2ecf20Sopenharmony_ci	 * return 1 here
4438c2ecf20Sopenharmony_ci	 */
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/* check tables of item heads */
4468c2ecf20Sopenharmony_ci	ih = (struct item_head *)(buf + BLKH_SIZE);
4478c2ecf20Sopenharmony_ci	prev_location = blocksize;
4488c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++, ih++) {
4498c2ecf20Sopenharmony_ci		if (le_ih_k_type(ih) == TYPE_ANY) {
4508c2ecf20Sopenharmony_ci			reiserfs_warning(NULL, "reiserfs-5083",
4518c2ecf20Sopenharmony_ci					 "wrong item type for item %h",
4528c2ecf20Sopenharmony_ci					 ih);
4538c2ecf20Sopenharmony_ci			return 0;
4548c2ecf20Sopenharmony_ci		}
4558c2ecf20Sopenharmony_ci		if (ih_location(ih) >= blocksize
4568c2ecf20Sopenharmony_ci		    || ih_location(ih) < IH_SIZE * nr) {
4578c2ecf20Sopenharmony_ci			reiserfs_warning(NULL, "reiserfs-5084",
4588c2ecf20Sopenharmony_ci					 "item location seems wrong: %h",
4598c2ecf20Sopenharmony_ci					 ih);
4608c2ecf20Sopenharmony_ci			return 0;
4618c2ecf20Sopenharmony_ci		}
4628c2ecf20Sopenharmony_ci		if (ih_item_len(ih) < 1
4638c2ecf20Sopenharmony_ci		    || ih_item_len(ih) > MAX_ITEM_LEN(blocksize)) {
4648c2ecf20Sopenharmony_ci			reiserfs_warning(NULL, "reiserfs-5085",
4658c2ecf20Sopenharmony_ci					 "item length seems wrong: %h",
4668c2ecf20Sopenharmony_ci					 ih);
4678c2ecf20Sopenharmony_ci			return 0;
4688c2ecf20Sopenharmony_ci		}
4698c2ecf20Sopenharmony_ci		if (prev_location - ih_location(ih) != ih_item_len(ih)) {
4708c2ecf20Sopenharmony_ci			reiserfs_warning(NULL, "reiserfs-5086",
4718c2ecf20Sopenharmony_ci					 "item location seems wrong "
4728c2ecf20Sopenharmony_ci					 "(second one): %h", ih);
4738c2ecf20Sopenharmony_ci			return 0;
4748c2ecf20Sopenharmony_ci		}
4758c2ecf20Sopenharmony_ci		if (is_direntry_le_ih(ih)) {
4768c2ecf20Sopenharmony_ci			if (ih_item_len(ih) < (ih_entry_count(ih) * IH_SIZE)) {
4778c2ecf20Sopenharmony_ci				reiserfs_warning(NULL, "reiserfs-5093",
4788c2ecf20Sopenharmony_ci						 "item entry count seems wrong %h",
4798c2ecf20Sopenharmony_ci						 ih);
4808c2ecf20Sopenharmony_ci				return 0;
4818c2ecf20Sopenharmony_ci			}
4828c2ecf20Sopenharmony_ci			return has_valid_deh_location(bh, ih);
4838c2ecf20Sopenharmony_ci		}
4848c2ecf20Sopenharmony_ci		prev_location = ih_location(ih);
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* one may imagine many more checks */
4888c2ecf20Sopenharmony_ci	return 1;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci/* returns 1 if buf looks like an internal node, 0 otherwise */
4928c2ecf20Sopenharmony_cistatic int is_internal(char *buf, int blocksize, struct buffer_head *bh)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct block_head *blkh;
4958c2ecf20Sopenharmony_ci	int nr;
4968c2ecf20Sopenharmony_ci	int used_space;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	blkh = (struct block_head *)buf;
4998c2ecf20Sopenharmony_ci	nr = blkh_level(blkh);
5008c2ecf20Sopenharmony_ci	if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) {
5018c2ecf20Sopenharmony_ci		/* this level is not possible for internal nodes */
5028c2ecf20Sopenharmony_ci		reiserfs_warning(NULL, "reiserfs-5087",
5038c2ecf20Sopenharmony_ci				 "this should be caught earlier");
5048c2ecf20Sopenharmony_ci		return 0;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	nr = blkh_nr_item(blkh);
5088c2ecf20Sopenharmony_ci	/* for internal which is not root we might check min number of keys */
5098c2ecf20Sopenharmony_ci	if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) {
5108c2ecf20Sopenharmony_ci		reiserfs_warning(NULL, "reiserfs-5088",
5118c2ecf20Sopenharmony_ci				 "number of key seems wrong: %z", bh);
5128c2ecf20Sopenharmony_ci		return 0;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1);
5168c2ecf20Sopenharmony_ci	if (used_space != blocksize - blkh_free_space(blkh)) {
5178c2ecf20Sopenharmony_ci		reiserfs_warning(NULL, "reiserfs-5089",
5188c2ecf20Sopenharmony_ci				 "free space seems wrong: %z", bh);
5198c2ecf20Sopenharmony_ci		return 0;
5208c2ecf20Sopenharmony_ci	}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	/* one may imagine many more checks */
5238c2ecf20Sopenharmony_ci	return 1;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci/*
5278c2ecf20Sopenharmony_ci * make sure that bh contains formatted node of reiserfs tree of
5288c2ecf20Sopenharmony_ci * 'level'-th level
5298c2ecf20Sopenharmony_ci */
5308c2ecf20Sopenharmony_cistatic int is_tree_node(struct buffer_head *bh, int level)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	if (B_LEVEL(bh) != level) {
5338c2ecf20Sopenharmony_ci		reiserfs_warning(NULL, "reiserfs-5090", "node level %d does "
5348c2ecf20Sopenharmony_ci				 "not match to the expected one %d",
5358c2ecf20Sopenharmony_ci				 B_LEVEL(bh), level);
5368c2ecf20Sopenharmony_ci		return 0;
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci	if (level == DISK_LEAF_NODE_LEVEL)
5398c2ecf20Sopenharmony_ci		return is_leaf(bh->b_data, bh->b_size, bh);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	return is_internal(bh->b_data, bh->b_size, bh);
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci#define SEARCH_BY_KEY_READA 16
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci/*
5478c2ecf20Sopenharmony_ci * The function is NOT SCHEDULE-SAFE!
5488c2ecf20Sopenharmony_ci * It might unlock the write lock if we needed to wait for a block
5498c2ecf20Sopenharmony_ci * to be read. Note that in this case it won't recover the lock to avoid
5508c2ecf20Sopenharmony_ci * high contention resulting from too much lock requests, especially
5518c2ecf20Sopenharmony_ci * the caller (search_by_key) will perform other schedule-unsafe
5528c2ecf20Sopenharmony_ci * operations just after calling this function.
5538c2ecf20Sopenharmony_ci *
5548c2ecf20Sopenharmony_ci * @return depth of lock to be restored after read completes
5558c2ecf20Sopenharmony_ci */
5568c2ecf20Sopenharmony_cistatic int search_by_key_reada(struct super_block *s,
5578c2ecf20Sopenharmony_ci				struct buffer_head **bh,
5588c2ecf20Sopenharmony_ci				b_blocknr_t *b, int num)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	int i, j;
5618c2ecf20Sopenharmony_ci	int depth = -1;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
5648c2ecf20Sopenharmony_ci		bh[i] = sb_getblk(s, b[i]);
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci	/*
5678c2ecf20Sopenharmony_ci	 * We are going to read some blocks on which we
5688c2ecf20Sopenharmony_ci	 * have a reference. It's safe, though we might be
5698c2ecf20Sopenharmony_ci	 * reading blocks concurrently changed if we release
5708c2ecf20Sopenharmony_ci	 * the lock. But it's still fine because we check later
5718c2ecf20Sopenharmony_ci	 * if the tree changed
5728c2ecf20Sopenharmony_ci	 */
5738c2ecf20Sopenharmony_ci	for (j = 0; j < i; j++) {
5748c2ecf20Sopenharmony_ci		/*
5758c2ecf20Sopenharmony_ci		 * note, this needs attention if we are getting rid of the BKL
5768c2ecf20Sopenharmony_ci		 * you have to make sure the prepared bit isn't set on this
5778c2ecf20Sopenharmony_ci		 * buffer
5788c2ecf20Sopenharmony_ci		 */
5798c2ecf20Sopenharmony_ci		if (!buffer_uptodate(bh[j])) {
5808c2ecf20Sopenharmony_ci			if (depth == -1)
5818c2ecf20Sopenharmony_ci				depth = reiserfs_write_unlock_nested(s);
5828c2ecf20Sopenharmony_ci			ll_rw_block(REQ_OP_READ, REQ_RAHEAD, 1, bh + j);
5838c2ecf20Sopenharmony_ci		}
5848c2ecf20Sopenharmony_ci		brelse(bh[j]);
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci	return depth;
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci/*
5908c2ecf20Sopenharmony_ci * This function fills up the path from the root to the leaf as it
5918c2ecf20Sopenharmony_ci * descends the tree looking for the key.  It uses reiserfs_bread to
5928c2ecf20Sopenharmony_ci * try to find buffers in the cache given their block number.  If it
5938c2ecf20Sopenharmony_ci * does not find them in the cache it reads them from disk.  For each
5948c2ecf20Sopenharmony_ci * node search_by_key finds using reiserfs_bread it then uses
5958c2ecf20Sopenharmony_ci * bin_search to look through that node.  bin_search will find the
5968c2ecf20Sopenharmony_ci * position of the block_number of the next node if it is looking
5978c2ecf20Sopenharmony_ci * through an internal node.  If it is looking through a leaf node
5988c2ecf20Sopenharmony_ci * bin_search will find the position of the item which has key either
5998c2ecf20Sopenharmony_ci * equal to given key, or which is the maximal key less than the given
6008c2ecf20Sopenharmony_ci * key.  search_by_key returns a path that must be checked for the
6018c2ecf20Sopenharmony_ci * correctness of the top of the path but need not be checked for the
6028c2ecf20Sopenharmony_ci * correctness of the bottom of the path
6038c2ecf20Sopenharmony_ci */
6048c2ecf20Sopenharmony_ci/*
6058c2ecf20Sopenharmony_ci * search_by_key - search for key (and item) in stree
6068c2ecf20Sopenharmony_ci * @sb: superblock
6078c2ecf20Sopenharmony_ci * @key: pointer to key to search for
6088c2ecf20Sopenharmony_ci * @search_path: Allocated and initialized struct treepath; Returned filled
6098c2ecf20Sopenharmony_ci *		 on success.
6108c2ecf20Sopenharmony_ci * @stop_level: How far down the tree to search, Use DISK_LEAF_NODE_LEVEL to
6118c2ecf20Sopenharmony_ci *		stop at leaf level.
6128c2ecf20Sopenharmony_ci *
6138c2ecf20Sopenharmony_ci * The function is NOT SCHEDULE-SAFE!
6148c2ecf20Sopenharmony_ci */
6158c2ecf20Sopenharmony_ciint search_by_key(struct super_block *sb, const struct cpu_key *key,
6168c2ecf20Sopenharmony_ci		  struct treepath *search_path, int stop_level)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	b_blocknr_t block_number;
6198c2ecf20Sopenharmony_ci	int expected_level;
6208c2ecf20Sopenharmony_ci	struct buffer_head *bh;
6218c2ecf20Sopenharmony_ci	struct path_element *last_element;
6228c2ecf20Sopenharmony_ci	int node_level, retval;
6238c2ecf20Sopenharmony_ci	int fs_gen;
6248c2ecf20Sopenharmony_ci	struct buffer_head *reada_bh[SEARCH_BY_KEY_READA];
6258c2ecf20Sopenharmony_ci	b_blocknr_t reada_blocks[SEARCH_BY_KEY_READA];
6268c2ecf20Sopenharmony_ci	int reada_count = 0;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
6298c2ecf20Sopenharmony_ci	int repeat_counter = 0;
6308c2ecf20Sopenharmony_ci#endif
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	PROC_INFO_INC(sb, search_by_key);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	/*
6358c2ecf20Sopenharmony_ci	 * As we add each node to a path we increase its count.  This means
6368c2ecf20Sopenharmony_ci	 * that we must be careful to release all nodes in a path before we
6378c2ecf20Sopenharmony_ci	 * either discard the path struct or re-use the path struct, as we
6388c2ecf20Sopenharmony_ci	 * do here.
6398c2ecf20Sopenharmony_ci	 */
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	pathrelse(search_path);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/*
6448c2ecf20Sopenharmony_ci	 * With each iteration of this loop we search through the items in the
6458c2ecf20Sopenharmony_ci	 * current node, and calculate the next current node(next path element)
6468c2ecf20Sopenharmony_ci	 * for the next iteration of this loop..
6478c2ecf20Sopenharmony_ci	 */
6488c2ecf20Sopenharmony_ci	block_number = SB_ROOT_BLOCK(sb);
6498c2ecf20Sopenharmony_ci	expected_level = -1;
6508c2ecf20Sopenharmony_ci	while (1) {
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
6538c2ecf20Sopenharmony_ci		if (!(++repeat_counter % 50000))
6548c2ecf20Sopenharmony_ci			reiserfs_warning(sb, "PAP-5100",
6558c2ecf20Sopenharmony_ci					 "%s: there were %d iterations of "
6568c2ecf20Sopenharmony_ci					 "while loop looking for key %K",
6578c2ecf20Sopenharmony_ci					 current->comm, repeat_counter,
6588c2ecf20Sopenharmony_ci					 key);
6598c2ecf20Sopenharmony_ci#endif
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci		/* prep path to have another element added to it. */
6628c2ecf20Sopenharmony_ci		last_element =
6638c2ecf20Sopenharmony_ci		    PATH_OFFSET_PELEMENT(search_path,
6648c2ecf20Sopenharmony_ci					 ++search_path->path_length);
6658c2ecf20Sopenharmony_ci		fs_gen = get_generation(sb);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci		/*
6688c2ecf20Sopenharmony_ci		 * Read the next tree node, and set the last element
6698c2ecf20Sopenharmony_ci		 * in the path to have a pointer to it.
6708c2ecf20Sopenharmony_ci		 */
6718c2ecf20Sopenharmony_ci		if ((bh = last_element->pe_buffer =
6728c2ecf20Sopenharmony_ci		     sb_getblk(sb, block_number))) {
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci			/*
6758c2ecf20Sopenharmony_ci			 * We'll need to drop the lock if we encounter any
6768c2ecf20Sopenharmony_ci			 * buffers that need to be read. If all of them are
6778c2ecf20Sopenharmony_ci			 * already up to date, we don't need to drop the lock.
6788c2ecf20Sopenharmony_ci			 */
6798c2ecf20Sopenharmony_ci			int depth = -1;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci			if (!buffer_uptodate(bh) && reada_count > 1)
6828c2ecf20Sopenharmony_ci				depth = search_by_key_reada(sb, reada_bh,
6838c2ecf20Sopenharmony_ci						    reada_blocks, reada_count);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci			if (!buffer_uptodate(bh) && depth == -1)
6868c2ecf20Sopenharmony_ci				depth = reiserfs_write_unlock_nested(sb);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci			ll_rw_block(REQ_OP_READ, 0, 1, &bh);
6898c2ecf20Sopenharmony_ci			wait_on_buffer(bh);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci			if (depth != -1)
6928c2ecf20Sopenharmony_ci				reiserfs_write_lock_nested(sb, depth);
6938c2ecf20Sopenharmony_ci			if (!buffer_uptodate(bh))
6948c2ecf20Sopenharmony_ci				goto io_error;
6958c2ecf20Sopenharmony_ci		} else {
6968c2ecf20Sopenharmony_ciio_error:
6978c2ecf20Sopenharmony_ci			search_path->path_length--;
6988c2ecf20Sopenharmony_ci			pathrelse(search_path);
6998c2ecf20Sopenharmony_ci			return IO_ERROR;
7008c2ecf20Sopenharmony_ci		}
7018c2ecf20Sopenharmony_ci		reada_count = 0;
7028c2ecf20Sopenharmony_ci		if (expected_level == -1)
7038c2ecf20Sopenharmony_ci			expected_level = SB_TREE_HEIGHT(sb);
7048c2ecf20Sopenharmony_ci		expected_level--;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci		/*
7078c2ecf20Sopenharmony_ci		 * It is possible that schedule occurred. We must check
7088c2ecf20Sopenharmony_ci		 * whether the key to search is still in the tree rooted
7098c2ecf20Sopenharmony_ci		 * from the current buffer. If not then repeat search
7108c2ecf20Sopenharmony_ci		 * from the root.
7118c2ecf20Sopenharmony_ci		 */
7128c2ecf20Sopenharmony_ci		if (fs_changed(fs_gen, sb) &&
7138c2ecf20Sopenharmony_ci		    (!B_IS_IN_TREE(bh) ||
7148c2ecf20Sopenharmony_ci		     B_LEVEL(bh) != expected_level ||
7158c2ecf20Sopenharmony_ci		     !key_in_buffer(search_path, key, sb))) {
7168c2ecf20Sopenharmony_ci			PROC_INFO_INC(sb, search_by_key_fs_changed);
7178c2ecf20Sopenharmony_ci			PROC_INFO_INC(sb, search_by_key_restarted);
7188c2ecf20Sopenharmony_ci			PROC_INFO_INC(sb,
7198c2ecf20Sopenharmony_ci				      sbk_restarted[expected_level - 1]);
7208c2ecf20Sopenharmony_ci			pathrelse(search_path);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci			/*
7238c2ecf20Sopenharmony_ci			 * Get the root block number so that we can
7248c2ecf20Sopenharmony_ci			 * repeat the search starting from the root.
7258c2ecf20Sopenharmony_ci			 */
7268c2ecf20Sopenharmony_ci			block_number = SB_ROOT_BLOCK(sb);
7278c2ecf20Sopenharmony_ci			expected_level = -1;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci			/* repeat search from the root */
7308c2ecf20Sopenharmony_ci			continue;
7318c2ecf20Sopenharmony_ci		}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci		/*
7348c2ecf20Sopenharmony_ci		 * only check that the key is in the buffer if key is not
7358c2ecf20Sopenharmony_ci		 * equal to the MAX_KEY. Latter case is only possible in
7368c2ecf20Sopenharmony_ci		 * "finish_unfinished()" processing during mount.
7378c2ecf20Sopenharmony_ci		 */
7388c2ecf20Sopenharmony_ci		RFALSE(comp_keys(&MAX_KEY, key) &&
7398c2ecf20Sopenharmony_ci		       !key_in_buffer(search_path, key, sb),
7408c2ecf20Sopenharmony_ci		       "PAP-5130: key is not in the buffer");
7418c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
7428c2ecf20Sopenharmony_ci		if (REISERFS_SB(sb)->cur_tb) {
7438c2ecf20Sopenharmony_ci			print_cur_tb("5140");
7448c2ecf20Sopenharmony_ci			reiserfs_panic(sb, "PAP-5140",
7458c2ecf20Sopenharmony_ci				       "schedule occurred in do_balance!");
7468c2ecf20Sopenharmony_ci		}
7478c2ecf20Sopenharmony_ci#endif
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		/*
7508c2ecf20Sopenharmony_ci		 * make sure, that the node contents look like a node of
7518c2ecf20Sopenharmony_ci		 * certain level
7528c2ecf20Sopenharmony_ci		 */
7538c2ecf20Sopenharmony_ci		if (!is_tree_node(bh, expected_level)) {
7548c2ecf20Sopenharmony_ci			reiserfs_error(sb, "vs-5150",
7558c2ecf20Sopenharmony_ci				       "invalid format found in block %ld. "
7568c2ecf20Sopenharmony_ci				       "Fsck?", bh->b_blocknr);
7578c2ecf20Sopenharmony_ci			pathrelse(search_path);
7588c2ecf20Sopenharmony_ci			return IO_ERROR;
7598c2ecf20Sopenharmony_ci		}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci		/* ok, we have acquired next formatted node in the tree */
7628c2ecf20Sopenharmony_ci		node_level = B_LEVEL(bh);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci		PROC_INFO_BH_STAT(sb, bh, node_level - 1);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci		RFALSE(node_level < stop_level,
7678c2ecf20Sopenharmony_ci		       "vs-5152: tree level (%d) is less than stop level (%d)",
7688c2ecf20Sopenharmony_ci		       node_level, stop_level);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci		retval = bin_search(key, item_head(bh, 0),
7718c2ecf20Sopenharmony_ci				      B_NR_ITEMS(bh),
7728c2ecf20Sopenharmony_ci				      (node_level ==
7738c2ecf20Sopenharmony_ci				       DISK_LEAF_NODE_LEVEL) ? IH_SIZE :
7748c2ecf20Sopenharmony_ci				      KEY_SIZE,
7758c2ecf20Sopenharmony_ci				      &last_element->pe_position);
7768c2ecf20Sopenharmony_ci		if (node_level == stop_level) {
7778c2ecf20Sopenharmony_ci			return retval;
7788c2ecf20Sopenharmony_ci		}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci		/* we are not in the stop level */
7818c2ecf20Sopenharmony_ci		/*
7828c2ecf20Sopenharmony_ci		 * item has been found, so we choose the pointer which
7838c2ecf20Sopenharmony_ci		 * is to the right of the found one
7848c2ecf20Sopenharmony_ci		 */
7858c2ecf20Sopenharmony_ci		if (retval == ITEM_FOUND)
7868c2ecf20Sopenharmony_ci			last_element->pe_position++;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci		/*
7898c2ecf20Sopenharmony_ci		 * if item was not found we choose the position which is to
7908c2ecf20Sopenharmony_ci		 * the left of the found item. This requires no code,
7918c2ecf20Sopenharmony_ci		 * bin_search did it already.
7928c2ecf20Sopenharmony_ci		 */
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci		/*
7958c2ecf20Sopenharmony_ci		 * So we have chosen a position in the current node which is
7968c2ecf20Sopenharmony_ci		 * an internal node.  Now we calculate child block number by
7978c2ecf20Sopenharmony_ci		 * position in the node.
7988c2ecf20Sopenharmony_ci		 */
7998c2ecf20Sopenharmony_ci		block_number =
8008c2ecf20Sopenharmony_ci		    B_N_CHILD_NUM(bh, last_element->pe_position);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci		/*
8038c2ecf20Sopenharmony_ci		 * if we are going to read leaf nodes, try for read
8048c2ecf20Sopenharmony_ci		 * ahead as well
8058c2ecf20Sopenharmony_ci		 */
8068c2ecf20Sopenharmony_ci		if ((search_path->reada & PATH_READA) &&
8078c2ecf20Sopenharmony_ci		    node_level == DISK_LEAF_NODE_LEVEL + 1) {
8088c2ecf20Sopenharmony_ci			int pos = last_element->pe_position;
8098c2ecf20Sopenharmony_ci			int limit = B_NR_ITEMS(bh);
8108c2ecf20Sopenharmony_ci			struct reiserfs_key *le_key;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci			if (search_path->reada & PATH_READA_BACK)
8138c2ecf20Sopenharmony_ci				limit = 0;
8148c2ecf20Sopenharmony_ci			while (reada_count < SEARCH_BY_KEY_READA) {
8158c2ecf20Sopenharmony_ci				if (pos == limit)
8168c2ecf20Sopenharmony_ci					break;
8178c2ecf20Sopenharmony_ci				reada_blocks[reada_count++] =
8188c2ecf20Sopenharmony_ci				    B_N_CHILD_NUM(bh, pos);
8198c2ecf20Sopenharmony_ci				if (search_path->reada & PATH_READA_BACK)
8208c2ecf20Sopenharmony_ci					pos--;
8218c2ecf20Sopenharmony_ci				else
8228c2ecf20Sopenharmony_ci					pos++;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci				/*
8258c2ecf20Sopenharmony_ci				 * check to make sure we're in the same object
8268c2ecf20Sopenharmony_ci				 */
8278c2ecf20Sopenharmony_ci				le_key = internal_key(bh, pos);
8288c2ecf20Sopenharmony_ci				if (le32_to_cpu(le_key->k_objectid) !=
8298c2ecf20Sopenharmony_ci				    key->on_disk_key.k_objectid) {
8308c2ecf20Sopenharmony_ci					break;
8318c2ecf20Sopenharmony_ci				}
8328c2ecf20Sopenharmony_ci			}
8338c2ecf20Sopenharmony_ci		}
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci/*
8388c2ecf20Sopenharmony_ci * Form the path to an item and position in this item which contains
8398c2ecf20Sopenharmony_ci * file byte defined by key. If there is no such item
8408c2ecf20Sopenharmony_ci * corresponding to the key, we point the path to the item with
8418c2ecf20Sopenharmony_ci * maximal key less than key, and *pos_in_item is set to one
8428c2ecf20Sopenharmony_ci * past the last entry/byte in the item.  If searching for entry in a
8438c2ecf20Sopenharmony_ci * directory item, and it is not found, *pos_in_item is set to one
8448c2ecf20Sopenharmony_ci * entry more than the entry with maximal key which is less than the
8458c2ecf20Sopenharmony_ci * sought key.
8468c2ecf20Sopenharmony_ci *
8478c2ecf20Sopenharmony_ci * Note that if there is no entry in this same node which is one more,
8488c2ecf20Sopenharmony_ci * then we point to an imaginary entry.  for direct items, the
8498c2ecf20Sopenharmony_ci * position is in units of bytes, for indirect items the position is
8508c2ecf20Sopenharmony_ci * in units of blocknr entries, for directory items the position is in
8518c2ecf20Sopenharmony_ci * units of directory entries.
8528c2ecf20Sopenharmony_ci */
8538c2ecf20Sopenharmony_ci/* The function is NOT SCHEDULE-SAFE! */
8548c2ecf20Sopenharmony_ciint search_for_position_by_key(struct super_block *sb,
8558c2ecf20Sopenharmony_ci			       /* Key to search (cpu variable) */
8568c2ecf20Sopenharmony_ci			       const struct cpu_key *p_cpu_key,
8578c2ecf20Sopenharmony_ci			       /* Filled up by this function. */
8588c2ecf20Sopenharmony_ci			       struct treepath *search_path)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	struct item_head *p_le_ih;	/* pointer to on-disk structure */
8618c2ecf20Sopenharmony_ci	int blk_size;
8628c2ecf20Sopenharmony_ci	loff_t item_offset, offset;
8638c2ecf20Sopenharmony_ci	struct reiserfs_dir_entry de;
8648c2ecf20Sopenharmony_ci	int retval;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/* If searching for directory entry. */
8678c2ecf20Sopenharmony_ci	if (is_direntry_cpu_key(p_cpu_key))
8688c2ecf20Sopenharmony_ci		return search_by_entry_key(sb, p_cpu_key, search_path,
8698c2ecf20Sopenharmony_ci					   &de);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	/* If not searching for directory entry. */
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	/* If item is found. */
8748c2ecf20Sopenharmony_ci	retval = search_item(sb, p_cpu_key, search_path);
8758c2ecf20Sopenharmony_ci	if (retval == IO_ERROR)
8768c2ecf20Sopenharmony_ci		return retval;
8778c2ecf20Sopenharmony_ci	if (retval == ITEM_FOUND) {
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci		RFALSE(!ih_item_len
8808c2ecf20Sopenharmony_ci		       (item_head
8818c2ecf20Sopenharmony_ci			(PATH_PLAST_BUFFER(search_path),
8828c2ecf20Sopenharmony_ci			 PATH_LAST_POSITION(search_path))),
8838c2ecf20Sopenharmony_ci		       "PAP-5165: item length equals zero");
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		pos_in_item(search_path) = 0;
8868c2ecf20Sopenharmony_ci		return POSITION_FOUND;
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	RFALSE(!PATH_LAST_POSITION(search_path),
8908c2ecf20Sopenharmony_ci	       "PAP-5170: position equals zero");
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	/* Item is not found. Set path to the previous item. */
8938c2ecf20Sopenharmony_ci	p_le_ih =
8948c2ecf20Sopenharmony_ci	    item_head(PATH_PLAST_BUFFER(search_path),
8958c2ecf20Sopenharmony_ci			   --PATH_LAST_POSITION(search_path));
8968c2ecf20Sopenharmony_ci	blk_size = sb->s_blocksize;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (comp_short_keys(&p_le_ih->ih_key, p_cpu_key))
8998c2ecf20Sopenharmony_ci		return FILE_NOT_FOUND;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	/* FIXME: quite ugly this far */
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	item_offset = le_ih_k_offset(p_le_ih);
9048c2ecf20Sopenharmony_ci	offset = cpu_key_k_offset(p_cpu_key);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	/* Needed byte is contained in the item pointed to by the path. */
9078c2ecf20Sopenharmony_ci	if (item_offset <= offset &&
9088c2ecf20Sopenharmony_ci	    item_offset + op_bytes_number(p_le_ih, blk_size) > offset) {
9098c2ecf20Sopenharmony_ci		pos_in_item(search_path) = offset - item_offset;
9108c2ecf20Sopenharmony_ci		if (is_indirect_le_ih(p_le_ih)) {
9118c2ecf20Sopenharmony_ci			pos_in_item(search_path) /= blk_size;
9128c2ecf20Sopenharmony_ci		}
9138c2ecf20Sopenharmony_ci		return POSITION_FOUND;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	/*
9178c2ecf20Sopenharmony_ci	 * Needed byte is not contained in the item pointed to by the
9188c2ecf20Sopenharmony_ci	 * path. Set pos_in_item out of the item.
9198c2ecf20Sopenharmony_ci	 */
9208c2ecf20Sopenharmony_ci	if (is_indirect_le_ih(p_le_ih))
9218c2ecf20Sopenharmony_ci		pos_in_item(search_path) =
9228c2ecf20Sopenharmony_ci		    ih_item_len(p_le_ih) / UNFM_P_SIZE;
9238c2ecf20Sopenharmony_ci	else
9248c2ecf20Sopenharmony_ci		pos_in_item(search_path) = ih_item_len(p_le_ih);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	return POSITION_NOT_FOUND;
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci/* Compare given item and item pointed to by the path. */
9308c2ecf20Sopenharmony_ciint comp_items(const struct item_head *stored_ih, const struct treepath *path)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	struct buffer_head *bh = PATH_PLAST_BUFFER(path);
9338c2ecf20Sopenharmony_ci	struct item_head *ih;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	/* Last buffer at the path is not in the tree. */
9368c2ecf20Sopenharmony_ci	if (!B_IS_IN_TREE(bh))
9378c2ecf20Sopenharmony_ci		return 1;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	/* Last path position is invalid. */
9408c2ecf20Sopenharmony_ci	if (PATH_LAST_POSITION(path) >= B_NR_ITEMS(bh))
9418c2ecf20Sopenharmony_ci		return 1;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	/* we need only to know, whether it is the same item */
9448c2ecf20Sopenharmony_ci	ih = tp_item_head(path);
9458c2ecf20Sopenharmony_ci	return memcmp(stored_ih, ih, IH_SIZE);
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci/* prepare for delete or cut of direct item */
9498c2ecf20Sopenharmony_cistatic inline int prepare_for_direct_item(struct treepath *path,
9508c2ecf20Sopenharmony_ci					  struct item_head *le_ih,
9518c2ecf20Sopenharmony_ci					  struct inode *inode,
9528c2ecf20Sopenharmony_ci					  loff_t new_file_length, int *cut_size)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	loff_t round_len;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	if (new_file_length == max_reiserfs_offset(inode)) {
9578c2ecf20Sopenharmony_ci		/* item has to be deleted */
9588c2ecf20Sopenharmony_ci		*cut_size = -(IH_SIZE + ih_item_len(le_ih));
9598c2ecf20Sopenharmony_ci		return M_DELETE;
9608c2ecf20Sopenharmony_ci	}
9618c2ecf20Sopenharmony_ci	/* new file gets truncated */
9628c2ecf20Sopenharmony_ci	if (get_inode_item_key_version(inode) == KEY_FORMAT_3_6) {
9638c2ecf20Sopenharmony_ci		round_len = ROUND_UP(new_file_length);
9648c2ecf20Sopenharmony_ci		/* this was new_file_length < le_ih ... */
9658c2ecf20Sopenharmony_ci		if (round_len < le_ih_k_offset(le_ih)) {
9668c2ecf20Sopenharmony_ci			*cut_size = -(IH_SIZE + ih_item_len(le_ih));
9678c2ecf20Sopenharmony_ci			return M_DELETE;	/* Delete this item. */
9688c2ecf20Sopenharmony_ci		}
9698c2ecf20Sopenharmony_ci		/* Calculate first position and size for cutting from item. */
9708c2ecf20Sopenharmony_ci		pos_in_item(path) = round_len - (le_ih_k_offset(le_ih) - 1);
9718c2ecf20Sopenharmony_ci		*cut_size = -(ih_item_len(le_ih) - pos_in_item(path));
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci		return M_CUT;	/* Cut from this item. */
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	/* old file: items may have any length */
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	if (new_file_length < le_ih_k_offset(le_ih)) {
9798c2ecf20Sopenharmony_ci		*cut_size = -(IH_SIZE + ih_item_len(le_ih));
9808c2ecf20Sopenharmony_ci		return M_DELETE;	/* Delete this item. */
9818c2ecf20Sopenharmony_ci	}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	/* Calculate first position and size for cutting from item. */
9848c2ecf20Sopenharmony_ci	*cut_size = -(ih_item_len(le_ih) -
9858c2ecf20Sopenharmony_ci		      (pos_in_item(path) =
9868c2ecf20Sopenharmony_ci		       new_file_length + 1 - le_ih_k_offset(le_ih)));
9878c2ecf20Sopenharmony_ci	return M_CUT;		/* Cut from this item. */
9888c2ecf20Sopenharmony_ci}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_cistatic inline int prepare_for_direntry_item(struct treepath *path,
9918c2ecf20Sopenharmony_ci					    struct item_head *le_ih,
9928c2ecf20Sopenharmony_ci					    struct inode *inode,
9938c2ecf20Sopenharmony_ci					    loff_t new_file_length,
9948c2ecf20Sopenharmony_ci					    int *cut_size)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	if (le_ih_k_offset(le_ih) == DOT_OFFSET &&
9978c2ecf20Sopenharmony_ci	    new_file_length == max_reiserfs_offset(inode)) {
9988c2ecf20Sopenharmony_ci		RFALSE(ih_entry_count(le_ih) != 2,
9998c2ecf20Sopenharmony_ci		       "PAP-5220: incorrect empty directory item (%h)", le_ih);
10008c2ecf20Sopenharmony_ci		*cut_size = -(IH_SIZE + ih_item_len(le_ih));
10018c2ecf20Sopenharmony_ci		/* Delete the directory item containing "." and ".." entry. */
10028c2ecf20Sopenharmony_ci		return M_DELETE;
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (ih_entry_count(le_ih) == 1) {
10068c2ecf20Sopenharmony_ci		/*
10078c2ecf20Sopenharmony_ci		 * Delete the directory item such as there is one record only
10088c2ecf20Sopenharmony_ci		 * in this item
10098c2ecf20Sopenharmony_ci		 */
10108c2ecf20Sopenharmony_ci		*cut_size = -(IH_SIZE + ih_item_len(le_ih));
10118c2ecf20Sopenharmony_ci		return M_DELETE;
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	/* Cut one record from the directory item. */
10158c2ecf20Sopenharmony_ci	*cut_size =
10168c2ecf20Sopenharmony_ci	    -(DEH_SIZE +
10178c2ecf20Sopenharmony_ci	      entry_length(get_last_bh(path), le_ih, pos_in_item(path)));
10188c2ecf20Sopenharmony_ci	return M_CUT;
10198c2ecf20Sopenharmony_ci}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci#define JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD (2 * JOURNAL_PER_BALANCE_CNT + 1)
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci/*
10248c2ecf20Sopenharmony_ci * If the path points to a directory or direct item, calculate mode
10258c2ecf20Sopenharmony_ci * and the size cut, for balance.
10268c2ecf20Sopenharmony_ci * If the path points to an indirect item, remove some number of its
10278c2ecf20Sopenharmony_ci * unformatted nodes.
10288c2ecf20Sopenharmony_ci * In case of file truncate calculate whether this item must be
10298c2ecf20Sopenharmony_ci * deleted/truncated or last unformatted node of this item will be
10308c2ecf20Sopenharmony_ci * converted to a direct item.
10318c2ecf20Sopenharmony_ci * This function returns a determination of what balance mode the
10328c2ecf20Sopenharmony_ci * calling function should employ.
10338c2ecf20Sopenharmony_ci */
10348c2ecf20Sopenharmony_cistatic char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th,
10358c2ecf20Sopenharmony_ci				      struct inode *inode,
10368c2ecf20Sopenharmony_ci				      struct treepath *path,
10378c2ecf20Sopenharmony_ci				      const struct cpu_key *item_key,
10388c2ecf20Sopenharmony_ci				      /*
10398c2ecf20Sopenharmony_ci				       * Number of unformatted nodes
10408c2ecf20Sopenharmony_ci				       * which were removed from end
10418c2ecf20Sopenharmony_ci				       * of the file.
10428c2ecf20Sopenharmony_ci				       */
10438c2ecf20Sopenharmony_ci				      int *removed,
10448c2ecf20Sopenharmony_ci				      int *cut_size,
10458c2ecf20Sopenharmony_ci				      /* MAX_KEY_OFFSET in case of delete. */
10468c2ecf20Sopenharmony_ci				      unsigned long long new_file_length
10478c2ecf20Sopenharmony_ci    )
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
10508c2ecf20Sopenharmony_ci	struct item_head *p_le_ih = tp_item_head(path);
10518c2ecf20Sopenharmony_ci	struct buffer_head *bh = PATH_PLAST_BUFFER(path);
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	/* Stat_data item. */
10568c2ecf20Sopenharmony_ci	if (is_statdata_le_ih(p_le_ih)) {
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci		RFALSE(new_file_length != max_reiserfs_offset(inode),
10598c2ecf20Sopenharmony_ci		       "PAP-5210: mode must be M_DELETE");
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci		*cut_size = -(IH_SIZE + ih_item_len(p_le_ih));
10628c2ecf20Sopenharmony_ci		return M_DELETE;
10638c2ecf20Sopenharmony_ci	}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	/* Directory item. */
10668c2ecf20Sopenharmony_ci	if (is_direntry_le_ih(p_le_ih))
10678c2ecf20Sopenharmony_ci		return prepare_for_direntry_item(path, p_le_ih, inode,
10688c2ecf20Sopenharmony_ci						 new_file_length,
10698c2ecf20Sopenharmony_ci						 cut_size);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	/* Direct item. */
10728c2ecf20Sopenharmony_ci	if (is_direct_le_ih(p_le_ih))
10738c2ecf20Sopenharmony_ci		return prepare_for_direct_item(path, p_le_ih, inode,
10748c2ecf20Sopenharmony_ci					       new_file_length, cut_size);
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	/* Case of an indirect item. */
10778c2ecf20Sopenharmony_ci	{
10788c2ecf20Sopenharmony_ci	    int blk_size = sb->s_blocksize;
10798c2ecf20Sopenharmony_ci	    struct item_head s_ih;
10808c2ecf20Sopenharmony_ci	    int need_re_search;
10818c2ecf20Sopenharmony_ci	    int delete = 0;
10828c2ecf20Sopenharmony_ci	    int result = M_CUT;
10838c2ecf20Sopenharmony_ci	    int pos = 0;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	    if ( new_file_length == max_reiserfs_offset (inode) ) {
10868c2ecf20Sopenharmony_ci		/*
10878c2ecf20Sopenharmony_ci		 * prepare_for_delete_or_cut() is called by
10888c2ecf20Sopenharmony_ci		 * reiserfs_delete_item()
10898c2ecf20Sopenharmony_ci		 */
10908c2ecf20Sopenharmony_ci		new_file_length = 0;
10918c2ecf20Sopenharmony_ci		delete = 1;
10928c2ecf20Sopenharmony_ci	    }
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	    do {
10958c2ecf20Sopenharmony_ci		need_re_search = 0;
10968c2ecf20Sopenharmony_ci		*cut_size = 0;
10978c2ecf20Sopenharmony_ci		bh = PATH_PLAST_BUFFER(path);
10988c2ecf20Sopenharmony_ci		copy_item_head(&s_ih, tp_item_head(path));
10998c2ecf20Sopenharmony_ci		pos = I_UNFM_NUM(&s_ih);
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci		while (le_ih_k_offset (&s_ih) + (pos - 1) * blk_size > new_file_length) {
11028c2ecf20Sopenharmony_ci		    __le32 *unfm;
11038c2ecf20Sopenharmony_ci		    __u32 block;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci		    /*
11068c2ecf20Sopenharmony_ci		     * Each unformatted block deletion may involve
11078c2ecf20Sopenharmony_ci		     * one additional bitmap block into the transaction,
11088c2ecf20Sopenharmony_ci		     * thereby the initial journal space reservation
11098c2ecf20Sopenharmony_ci		     * might not be enough.
11108c2ecf20Sopenharmony_ci		     */
11118c2ecf20Sopenharmony_ci		    if (!delete && (*cut_size) != 0 &&
11128c2ecf20Sopenharmony_ci			reiserfs_transaction_free_space(th) < JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD)
11138c2ecf20Sopenharmony_ci			break;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci		    unfm = (__le32 *)ih_item_body(bh, &s_ih) + pos - 1;
11168c2ecf20Sopenharmony_ci		    block = get_block_num(unfm, 0);
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		    if (block != 0) {
11198c2ecf20Sopenharmony_ci			reiserfs_prepare_for_journal(sb, bh, 1);
11208c2ecf20Sopenharmony_ci			put_block_num(unfm, 0, 0);
11218c2ecf20Sopenharmony_ci			journal_mark_dirty(th, bh);
11228c2ecf20Sopenharmony_ci			reiserfs_free_block(th, inode, block, 1);
11238c2ecf20Sopenharmony_ci		    }
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci		    reiserfs_cond_resched(sb);
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci		    if (item_moved (&s_ih, path))  {
11288c2ecf20Sopenharmony_ci			need_re_search = 1;
11298c2ecf20Sopenharmony_ci			break;
11308c2ecf20Sopenharmony_ci		    }
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci		    pos --;
11338c2ecf20Sopenharmony_ci		    (*removed)++;
11348c2ecf20Sopenharmony_ci		    (*cut_size) -= UNFM_P_SIZE;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci		    if (pos == 0) {
11378c2ecf20Sopenharmony_ci			(*cut_size) -= IH_SIZE;
11388c2ecf20Sopenharmony_ci			result = M_DELETE;
11398c2ecf20Sopenharmony_ci			break;
11408c2ecf20Sopenharmony_ci		    }
11418c2ecf20Sopenharmony_ci		}
11428c2ecf20Sopenharmony_ci		/*
11438c2ecf20Sopenharmony_ci		 * a trick.  If the buffer has been logged, this will
11448c2ecf20Sopenharmony_ci		 * do nothing.  If we've broken the loop without logging
11458c2ecf20Sopenharmony_ci		 * it, it will restore the buffer
11468c2ecf20Sopenharmony_ci		 */
11478c2ecf20Sopenharmony_ci		reiserfs_restore_prepared_buffer(sb, bh);
11488c2ecf20Sopenharmony_ci	    } while (need_re_search &&
11498c2ecf20Sopenharmony_ci		     search_for_position_by_key(sb, item_key, path) == POSITION_FOUND);
11508c2ecf20Sopenharmony_ci	    pos_in_item(path) = pos * UNFM_P_SIZE;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	    if (*cut_size == 0) {
11538c2ecf20Sopenharmony_ci		/*
11548c2ecf20Sopenharmony_ci		 * Nothing was cut. maybe convert last unformatted node to the
11558c2ecf20Sopenharmony_ci		 * direct item?
11568c2ecf20Sopenharmony_ci		 */
11578c2ecf20Sopenharmony_ci		result = M_CONVERT;
11588c2ecf20Sopenharmony_ci	    }
11598c2ecf20Sopenharmony_ci	    return result;
11608c2ecf20Sopenharmony_ci	}
11618c2ecf20Sopenharmony_ci}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci/* Calculate number of bytes which will be deleted or cut during balance */
11648c2ecf20Sopenharmony_cistatic int calc_deleted_bytes_number(struct tree_balance *tb, char mode)
11658c2ecf20Sopenharmony_ci{
11668c2ecf20Sopenharmony_ci	int del_size;
11678c2ecf20Sopenharmony_ci	struct item_head *p_le_ih = tp_item_head(tb->tb_path);
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	if (is_statdata_le_ih(p_le_ih))
11708c2ecf20Sopenharmony_ci		return 0;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	del_size =
11738c2ecf20Sopenharmony_ci	    (mode ==
11748c2ecf20Sopenharmony_ci	     M_DELETE) ? ih_item_len(p_le_ih) : -tb->insert_size[0];
11758c2ecf20Sopenharmony_ci	if (is_direntry_le_ih(p_le_ih)) {
11768c2ecf20Sopenharmony_ci		/*
11778c2ecf20Sopenharmony_ci		 * return EMPTY_DIR_SIZE; We delete emty directories only.
11788c2ecf20Sopenharmony_ci		 * we can't use EMPTY_DIR_SIZE, as old format dirs have a
11798c2ecf20Sopenharmony_ci		 * different empty size.  ick. FIXME, is this right?
11808c2ecf20Sopenharmony_ci		 */
11818c2ecf20Sopenharmony_ci		return del_size;
11828c2ecf20Sopenharmony_ci	}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	if (is_indirect_le_ih(p_le_ih))
11858c2ecf20Sopenharmony_ci		del_size = (del_size / UNFM_P_SIZE) *
11868c2ecf20Sopenharmony_ci				(PATH_PLAST_BUFFER(tb->tb_path)->b_size);
11878c2ecf20Sopenharmony_ci	return del_size;
11888c2ecf20Sopenharmony_ci}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_cistatic void init_tb_struct(struct reiserfs_transaction_handle *th,
11918c2ecf20Sopenharmony_ci			   struct tree_balance *tb,
11928c2ecf20Sopenharmony_ci			   struct super_block *sb,
11938c2ecf20Sopenharmony_ci			   struct treepath *path, int size)
11948c2ecf20Sopenharmony_ci{
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	memset(tb, '\0', sizeof(struct tree_balance));
11998c2ecf20Sopenharmony_ci	tb->transaction_handle = th;
12008c2ecf20Sopenharmony_ci	tb->tb_sb = sb;
12018c2ecf20Sopenharmony_ci	tb->tb_path = path;
12028c2ecf20Sopenharmony_ci	PATH_OFFSET_PBUFFER(path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL;
12038c2ecf20Sopenharmony_ci	PATH_OFFSET_POSITION(path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0;
12048c2ecf20Sopenharmony_ci	tb->insert_size[0] = size;
12058c2ecf20Sopenharmony_ci}
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_civoid padd_item(char *item, int total_length, int length)
12088c2ecf20Sopenharmony_ci{
12098c2ecf20Sopenharmony_ci	int i;
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	for (i = total_length; i > length;)
12128c2ecf20Sopenharmony_ci		item[--i] = 0;
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG
12168c2ecf20Sopenharmony_cichar key2type(struct reiserfs_key *ih)
12178c2ecf20Sopenharmony_ci{
12188c2ecf20Sopenharmony_ci	if (is_direntry_le_key(2, ih))
12198c2ecf20Sopenharmony_ci		return 'd';
12208c2ecf20Sopenharmony_ci	if (is_direct_le_key(2, ih))
12218c2ecf20Sopenharmony_ci		return 'D';
12228c2ecf20Sopenharmony_ci	if (is_indirect_le_key(2, ih))
12238c2ecf20Sopenharmony_ci		return 'i';
12248c2ecf20Sopenharmony_ci	if (is_statdata_le_key(2, ih))
12258c2ecf20Sopenharmony_ci		return 's';
12268c2ecf20Sopenharmony_ci	return 'u';
12278c2ecf20Sopenharmony_ci}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_cichar head2type(struct item_head *ih)
12308c2ecf20Sopenharmony_ci{
12318c2ecf20Sopenharmony_ci	if (is_direntry_le_ih(ih))
12328c2ecf20Sopenharmony_ci		return 'd';
12338c2ecf20Sopenharmony_ci	if (is_direct_le_ih(ih))
12348c2ecf20Sopenharmony_ci		return 'D';
12358c2ecf20Sopenharmony_ci	if (is_indirect_le_ih(ih))
12368c2ecf20Sopenharmony_ci		return 'i';
12378c2ecf20Sopenharmony_ci	if (is_statdata_le_ih(ih))
12388c2ecf20Sopenharmony_ci		return 's';
12398c2ecf20Sopenharmony_ci	return 'u';
12408c2ecf20Sopenharmony_ci}
12418c2ecf20Sopenharmony_ci#endif
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci/*
12448c2ecf20Sopenharmony_ci * Delete object item.
12458c2ecf20Sopenharmony_ci * th       - active transaction handle
12468c2ecf20Sopenharmony_ci * path     - path to the deleted item
12478c2ecf20Sopenharmony_ci * item_key - key to search for the deleted item
12488c2ecf20Sopenharmony_ci * indode   - used for updating i_blocks and quotas
12498c2ecf20Sopenharmony_ci * un_bh    - NULL or unformatted node pointer
12508c2ecf20Sopenharmony_ci */
12518c2ecf20Sopenharmony_ciint reiserfs_delete_item(struct reiserfs_transaction_handle *th,
12528c2ecf20Sopenharmony_ci			 struct treepath *path, const struct cpu_key *item_key,
12538c2ecf20Sopenharmony_ci			 struct inode *inode, struct buffer_head *un_bh)
12548c2ecf20Sopenharmony_ci{
12558c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
12568c2ecf20Sopenharmony_ci	struct tree_balance s_del_balance;
12578c2ecf20Sopenharmony_ci	struct item_head s_ih;
12588c2ecf20Sopenharmony_ci	struct item_head *q_ih;
12598c2ecf20Sopenharmony_ci	int quota_cut_bytes;
12608c2ecf20Sopenharmony_ci	int ret_value, del_size, removed;
12618c2ecf20Sopenharmony_ci	int depth;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
12648c2ecf20Sopenharmony_ci	char mode;
12658c2ecf20Sopenharmony_ci	int iter = 0;
12668c2ecf20Sopenharmony_ci#endif
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	init_tb_struct(th, &s_del_balance, sb, path,
12718c2ecf20Sopenharmony_ci		       0 /*size is unknown */ );
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	while (1) {
12748c2ecf20Sopenharmony_ci		removed = 0;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
12778c2ecf20Sopenharmony_ci		iter++;
12788c2ecf20Sopenharmony_ci		mode =
12798c2ecf20Sopenharmony_ci#endif
12808c2ecf20Sopenharmony_ci		    prepare_for_delete_or_cut(th, inode, path,
12818c2ecf20Sopenharmony_ci					      item_key, &removed,
12828c2ecf20Sopenharmony_ci					      &del_size,
12838c2ecf20Sopenharmony_ci					      max_reiserfs_offset(inode));
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci		RFALSE(mode != M_DELETE, "PAP-5320: mode must be M_DELETE");
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci		copy_item_head(&s_ih, tp_item_head(path));
12888c2ecf20Sopenharmony_ci		s_del_balance.insert_size[0] = del_size;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, NULL);
12918c2ecf20Sopenharmony_ci		if (ret_value != REPEAT_SEARCH)
12928c2ecf20Sopenharmony_ci			break;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		PROC_INFO_INC(sb, delete_item_restarted);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci		/* file system changed, repeat search */
12978c2ecf20Sopenharmony_ci		ret_value =
12988c2ecf20Sopenharmony_ci		    search_for_position_by_key(sb, item_key, path);
12998c2ecf20Sopenharmony_ci		if (ret_value == IO_ERROR)
13008c2ecf20Sopenharmony_ci			break;
13018c2ecf20Sopenharmony_ci		if (ret_value == FILE_NOT_FOUND) {
13028c2ecf20Sopenharmony_ci			reiserfs_warning(sb, "vs-5340",
13038c2ecf20Sopenharmony_ci					 "no items of the file %K found",
13048c2ecf20Sopenharmony_ci					 item_key);
13058c2ecf20Sopenharmony_ci			break;
13068c2ecf20Sopenharmony_ci		}
13078c2ecf20Sopenharmony_ci	}			/* while (1) */
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	if (ret_value != CARRY_ON) {
13108c2ecf20Sopenharmony_ci		unfix_nodes(&s_del_balance);
13118c2ecf20Sopenharmony_ci		return 0;
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	/* reiserfs_delete_item returns item length when success */
13158c2ecf20Sopenharmony_ci	ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE);
13168c2ecf20Sopenharmony_ci	q_ih = tp_item_head(path);
13178c2ecf20Sopenharmony_ci	quota_cut_bytes = ih_item_len(q_ih);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	/*
13208c2ecf20Sopenharmony_ci	 * hack so the quota code doesn't have to guess if the file has a
13218c2ecf20Sopenharmony_ci	 * tail.  On tail insert, we allocate quota for 1 unformatted node.
13228c2ecf20Sopenharmony_ci	 * We test the offset because the tail might have been
13238c2ecf20Sopenharmony_ci	 * split into multiple items, and we only want to decrement for
13248c2ecf20Sopenharmony_ci	 * the unfm node once
13258c2ecf20Sopenharmony_ci	 */
13268c2ecf20Sopenharmony_ci	if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(q_ih)) {
13278c2ecf20Sopenharmony_ci		if ((le_ih_k_offset(q_ih) & (sb->s_blocksize - 1)) == 1) {
13288c2ecf20Sopenharmony_ci			quota_cut_bytes = sb->s_blocksize + UNFM_P_SIZE;
13298c2ecf20Sopenharmony_ci		} else {
13308c2ecf20Sopenharmony_ci			quota_cut_bytes = 0;
13318c2ecf20Sopenharmony_ci		}
13328c2ecf20Sopenharmony_ci	}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	if (un_bh) {
13358c2ecf20Sopenharmony_ci		int off;
13368c2ecf20Sopenharmony_ci		char *data;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci		/*
13398c2ecf20Sopenharmony_ci		 * We are in direct2indirect conversion, so move tail contents
13408c2ecf20Sopenharmony_ci		 * to the unformatted node
13418c2ecf20Sopenharmony_ci		 */
13428c2ecf20Sopenharmony_ci		/*
13438c2ecf20Sopenharmony_ci		 * note, we do the copy before preparing the buffer because we
13448c2ecf20Sopenharmony_ci		 * don't care about the contents of the unformatted node yet.
13458c2ecf20Sopenharmony_ci		 * the only thing we really care about is the direct item's
13468c2ecf20Sopenharmony_ci		 * data is in the unformatted node.
13478c2ecf20Sopenharmony_ci		 *
13488c2ecf20Sopenharmony_ci		 * Otherwise, we would have to call
13498c2ecf20Sopenharmony_ci		 * reiserfs_prepare_for_journal on the unformatted node,
13508c2ecf20Sopenharmony_ci		 * which might schedule, meaning we'd have to loop all the
13518c2ecf20Sopenharmony_ci		 * way back up to the start of the while loop.
13528c2ecf20Sopenharmony_ci		 *
13538c2ecf20Sopenharmony_ci		 * The unformatted node must be dirtied later on.  We can't be
13548c2ecf20Sopenharmony_ci		 * sure here if the entire tail has been deleted yet.
13558c2ecf20Sopenharmony_ci		 *
13568c2ecf20Sopenharmony_ci		 * un_bh is from the page cache (all unformatted nodes are
13578c2ecf20Sopenharmony_ci		 * from the page cache) and might be a highmem page.  So, we
13588c2ecf20Sopenharmony_ci		 * can't use un_bh->b_data.
13598c2ecf20Sopenharmony_ci		 * -clm
13608c2ecf20Sopenharmony_ci		 */
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci		data = kmap_atomic(un_bh->b_page);
13638c2ecf20Sopenharmony_ci		off = ((le_ih_k_offset(&s_ih) - 1) & (PAGE_SIZE - 1));
13648c2ecf20Sopenharmony_ci		memcpy(data + off,
13658c2ecf20Sopenharmony_ci		       ih_item_body(PATH_PLAST_BUFFER(path), &s_ih),
13668c2ecf20Sopenharmony_ci		       ret_value);
13678c2ecf20Sopenharmony_ci		kunmap_atomic(data);
13688c2ecf20Sopenharmony_ci	}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	/* Perform balancing after all resources have been collected at once. */
13718c2ecf20Sopenharmony_ci	do_balance(&s_del_balance, NULL, NULL, M_DELETE);
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG
13748c2ecf20Sopenharmony_ci	reiserfs_debug(sb, REISERFS_DEBUG_CODE,
13758c2ecf20Sopenharmony_ci		       "reiserquota delete_item(): freeing %u, id=%u type=%c",
13768c2ecf20Sopenharmony_ci		       quota_cut_bytes, inode->i_uid, head2type(&s_ih));
13778c2ecf20Sopenharmony_ci#endif
13788c2ecf20Sopenharmony_ci	depth = reiserfs_write_unlock_nested(inode->i_sb);
13798c2ecf20Sopenharmony_ci	dquot_free_space_nodirty(inode, quota_cut_bytes);
13808c2ecf20Sopenharmony_ci	reiserfs_write_lock_nested(inode->i_sb, depth);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	/* Return deleted body length */
13838c2ecf20Sopenharmony_ci	return ret_value;
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci/*
13878c2ecf20Sopenharmony_ci * Summary Of Mechanisms For Handling Collisions Between Processes:
13888c2ecf20Sopenharmony_ci *
13898c2ecf20Sopenharmony_ci *  deletion of the body of the object is performed by iput(), with the
13908c2ecf20Sopenharmony_ci *  result that if multiple processes are operating on a file, the
13918c2ecf20Sopenharmony_ci *  deletion of the body of the file is deferred until the last process
13928c2ecf20Sopenharmony_ci *  that has an open inode performs its iput().
13938c2ecf20Sopenharmony_ci *
13948c2ecf20Sopenharmony_ci *  writes and truncates are protected from collisions by use of
13958c2ecf20Sopenharmony_ci *  semaphores.
13968c2ecf20Sopenharmony_ci *
13978c2ecf20Sopenharmony_ci *  creates, linking, and mknod are protected from collisions with other
13988c2ecf20Sopenharmony_ci *  processes by making the reiserfs_add_entry() the last step in the
13998c2ecf20Sopenharmony_ci *  creation, and then rolling back all changes if there was a collision.
14008c2ecf20Sopenharmony_ci *  - Hans
14018c2ecf20Sopenharmony_ci*/
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci/* this deletes item which never gets split */
14048c2ecf20Sopenharmony_civoid reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
14058c2ecf20Sopenharmony_ci				struct inode *inode, struct reiserfs_key *key)
14068c2ecf20Sopenharmony_ci{
14078c2ecf20Sopenharmony_ci	struct super_block *sb = th->t_super;
14088c2ecf20Sopenharmony_ci	struct tree_balance tb;
14098c2ecf20Sopenharmony_ci	INITIALIZE_PATH(path);
14108c2ecf20Sopenharmony_ci	int item_len = 0;
14118c2ecf20Sopenharmony_ci	int tb_init = 0;
14128c2ecf20Sopenharmony_ci	struct cpu_key cpu_key;
14138c2ecf20Sopenharmony_ci	int retval;
14148c2ecf20Sopenharmony_ci	int quota_cut_bytes = 0;
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	le_key2cpu_key(&cpu_key, key);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	while (1) {
14218c2ecf20Sopenharmony_ci		retval = search_item(th->t_super, &cpu_key, &path);
14228c2ecf20Sopenharmony_ci		if (retval == IO_ERROR) {
14238c2ecf20Sopenharmony_ci			reiserfs_error(th->t_super, "vs-5350",
14248c2ecf20Sopenharmony_ci				       "i/o failure occurred trying "
14258c2ecf20Sopenharmony_ci				       "to delete %K", &cpu_key);
14268c2ecf20Sopenharmony_ci			break;
14278c2ecf20Sopenharmony_ci		}
14288c2ecf20Sopenharmony_ci		if (retval != ITEM_FOUND) {
14298c2ecf20Sopenharmony_ci			pathrelse(&path);
14308c2ecf20Sopenharmony_ci			/*
14318c2ecf20Sopenharmony_ci			 * No need for a warning, if there is just no free
14328c2ecf20Sopenharmony_ci			 * space to insert '..' item into the
14338c2ecf20Sopenharmony_ci			 * newly-created subdir
14348c2ecf20Sopenharmony_ci			 */
14358c2ecf20Sopenharmony_ci			if (!
14368c2ecf20Sopenharmony_ci			    ((unsigned long long)
14378c2ecf20Sopenharmony_ci			     GET_HASH_VALUE(le_key_k_offset
14388c2ecf20Sopenharmony_ci					    (le_key_version(key), key)) == 0
14398c2ecf20Sopenharmony_ci			     && (unsigned long long)
14408c2ecf20Sopenharmony_ci			     GET_GENERATION_NUMBER(le_key_k_offset
14418c2ecf20Sopenharmony_ci						   (le_key_version(key),
14428c2ecf20Sopenharmony_ci						    key)) == 1))
14438c2ecf20Sopenharmony_ci				reiserfs_warning(th->t_super, "vs-5355",
14448c2ecf20Sopenharmony_ci						 "%k not found", key);
14458c2ecf20Sopenharmony_ci			break;
14468c2ecf20Sopenharmony_ci		}
14478c2ecf20Sopenharmony_ci		if (!tb_init) {
14488c2ecf20Sopenharmony_ci			tb_init = 1;
14498c2ecf20Sopenharmony_ci			item_len = ih_item_len(tp_item_head(&path));
14508c2ecf20Sopenharmony_ci			init_tb_struct(th, &tb, th->t_super, &path,
14518c2ecf20Sopenharmony_ci				       -(IH_SIZE + item_len));
14528c2ecf20Sopenharmony_ci		}
14538c2ecf20Sopenharmony_ci		quota_cut_bytes = ih_item_len(tp_item_head(&path));
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci		retval = fix_nodes(M_DELETE, &tb, NULL, NULL);
14568c2ecf20Sopenharmony_ci		if (retval == REPEAT_SEARCH) {
14578c2ecf20Sopenharmony_ci			PROC_INFO_INC(th->t_super, delete_solid_item_restarted);
14588c2ecf20Sopenharmony_ci			continue;
14598c2ecf20Sopenharmony_ci		}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci		if (retval == CARRY_ON) {
14628c2ecf20Sopenharmony_ci			do_balance(&tb, NULL, NULL, M_DELETE);
14638c2ecf20Sopenharmony_ci			/*
14648c2ecf20Sopenharmony_ci			 * Should we count quota for item? (we don't
14658c2ecf20Sopenharmony_ci			 * count quotas for save-links)
14668c2ecf20Sopenharmony_ci			 */
14678c2ecf20Sopenharmony_ci			if (inode) {
14688c2ecf20Sopenharmony_ci				int depth;
14698c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG
14708c2ecf20Sopenharmony_ci				reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE,
14718c2ecf20Sopenharmony_ci					       "reiserquota delete_solid_item(): freeing %u id=%u type=%c",
14728c2ecf20Sopenharmony_ci					       quota_cut_bytes, inode->i_uid,
14738c2ecf20Sopenharmony_ci					       key2type(key));
14748c2ecf20Sopenharmony_ci#endif
14758c2ecf20Sopenharmony_ci				depth = reiserfs_write_unlock_nested(sb);
14768c2ecf20Sopenharmony_ci				dquot_free_space_nodirty(inode,
14778c2ecf20Sopenharmony_ci							 quota_cut_bytes);
14788c2ecf20Sopenharmony_ci				reiserfs_write_lock_nested(sb, depth);
14798c2ecf20Sopenharmony_ci			}
14808c2ecf20Sopenharmony_ci			break;
14818c2ecf20Sopenharmony_ci		}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci		/* IO_ERROR, NO_DISK_SPACE, etc */
14848c2ecf20Sopenharmony_ci		reiserfs_warning(th->t_super, "vs-5360",
14858c2ecf20Sopenharmony_ci				 "could not delete %K due to fix_nodes failure",
14868c2ecf20Sopenharmony_ci				 &cpu_key);
14878c2ecf20Sopenharmony_ci		unfix_nodes(&tb);
14888c2ecf20Sopenharmony_ci		break;
14898c2ecf20Sopenharmony_ci	}
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	reiserfs_check_path(&path);
14928c2ecf20Sopenharmony_ci}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ciint reiserfs_delete_object(struct reiserfs_transaction_handle *th,
14958c2ecf20Sopenharmony_ci			   struct inode *inode)
14968c2ecf20Sopenharmony_ci{
14978c2ecf20Sopenharmony_ci	int err;
14988c2ecf20Sopenharmony_ci	inode->i_size = 0;
14998c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	/* for directory this deletes item containing "." and ".." */
15028c2ecf20Sopenharmony_ci	err =
15038c2ecf20Sopenharmony_ci	    reiserfs_do_truncate(th, inode, NULL, 0 /*no timestamp updates */ );
15048c2ecf20Sopenharmony_ci	if (err)
15058c2ecf20Sopenharmony_ci		return err;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci#if defined( USE_INODE_GENERATION_COUNTER )
15088c2ecf20Sopenharmony_ci	if (!old_format_only(th->t_super)) {
15098c2ecf20Sopenharmony_ci		__le32 *inode_generation;
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci		inode_generation =
15128c2ecf20Sopenharmony_ci		    &REISERFS_SB(th->t_super)->s_rs->s_inode_generation;
15138c2ecf20Sopenharmony_ci		le32_add_cpu(inode_generation, 1);
15148c2ecf20Sopenharmony_ci	}
15158c2ecf20Sopenharmony_ci/* USE_INODE_GENERATION_COUNTER */
15168c2ecf20Sopenharmony_ci#endif
15178c2ecf20Sopenharmony_ci	reiserfs_delete_solid_item(th, inode, INODE_PKEY(inode));
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	return err;
15208c2ecf20Sopenharmony_ci}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_cistatic void unmap_buffers(struct page *page, loff_t pos)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	struct buffer_head *bh;
15258c2ecf20Sopenharmony_ci	struct buffer_head *head;
15268c2ecf20Sopenharmony_ci	struct buffer_head *next;
15278c2ecf20Sopenharmony_ci	unsigned long tail_index;
15288c2ecf20Sopenharmony_ci	unsigned long cur_index;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	if (page) {
15318c2ecf20Sopenharmony_ci		if (page_has_buffers(page)) {
15328c2ecf20Sopenharmony_ci			tail_index = pos & (PAGE_SIZE - 1);
15338c2ecf20Sopenharmony_ci			cur_index = 0;
15348c2ecf20Sopenharmony_ci			head = page_buffers(page);
15358c2ecf20Sopenharmony_ci			bh = head;
15368c2ecf20Sopenharmony_ci			do {
15378c2ecf20Sopenharmony_ci				next = bh->b_this_page;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci				/*
15408c2ecf20Sopenharmony_ci				 * we want to unmap the buffers that contain
15418c2ecf20Sopenharmony_ci				 * the tail, and all the buffers after it
15428c2ecf20Sopenharmony_ci				 * (since the tail must be at the end of the
15438c2ecf20Sopenharmony_ci				 * file).  We don't want to unmap file data
15448c2ecf20Sopenharmony_ci				 * before the tail, since it might be dirty
15458c2ecf20Sopenharmony_ci				 * and waiting to reach disk
15468c2ecf20Sopenharmony_ci				 */
15478c2ecf20Sopenharmony_ci				cur_index += bh->b_size;
15488c2ecf20Sopenharmony_ci				if (cur_index > tail_index) {
15498c2ecf20Sopenharmony_ci					reiserfs_unmap_buffer(bh);
15508c2ecf20Sopenharmony_ci				}
15518c2ecf20Sopenharmony_ci				bh = next;
15528c2ecf20Sopenharmony_ci			} while (bh != head);
15538c2ecf20Sopenharmony_ci		}
15548c2ecf20Sopenharmony_ci	}
15558c2ecf20Sopenharmony_ci}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_cistatic int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th,
15588c2ecf20Sopenharmony_ci				    struct inode *inode,
15598c2ecf20Sopenharmony_ci				    struct page *page,
15608c2ecf20Sopenharmony_ci				    struct treepath *path,
15618c2ecf20Sopenharmony_ci				    const struct cpu_key *item_key,
15628c2ecf20Sopenharmony_ci				    loff_t new_file_size, char *mode)
15638c2ecf20Sopenharmony_ci{
15648c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
15658c2ecf20Sopenharmony_ci	int block_size = sb->s_blocksize;
15668c2ecf20Sopenharmony_ci	int cut_bytes;
15678c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
15688c2ecf20Sopenharmony_ci	BUG_ON(new_file_size != inode->i_size);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	/*
15718c2ecf20Sopenharmony_ci	 * the page being sent in could be NULL if there was an i/o error
15728c2ecf20Sopenharmony_ci	 * reading in the last block.  The user will hit problems trying to
15738c2ecf20Sopenharmony_ci	 * read the file, but for now we just skip the indirect2direct
15748c2ecf20Sopenharmony_ci	 */
15758c2ecf20Sopenharmony_ci	if (atomic_read(&inode->i_count) > 1 ||
15768c2ecf20Sopenharmony_ci	    !tail_has_to_be_packed(inode) ||
15778c2ecf20Sopenharmony_ci	    !page || (REISERFS_I(inode)->i_flags & i_nopack_mask)) {
15788c2ecf20Sopenharmony_ci		/* leave tail in an unformatted node */
15798c2ecf20Sopenharmony_ci		*mode = M_SKIP_BALANCING;
15808c2ecf20Sopenharmony_ci		cut_bytes =
15818c2ecf20Sopenharmony_ci		    block_size - (new_file_size & (block_size - 1));
15828c2ecf20Sopenharmony_ci		pathrelse(path);
15838c2ecf20Sopenharmony_ci		return cut_bytes;
15848c2ecf20Sopenharmony_ci	}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	/* Perform the conversion to a direct_item. */
15878c2ecf20Sopenharmony_ci	return indirect2direct(th, inode, page, path, item_key,
15888c2ecf20Sopenharmony_ci			       new_file_size, mode);
15898c2ecf20Sopenharmony_ci}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci/*
15928c2ecf20Sopenharmony_ci * we did indirect_to_direct conversion. And we have inserted direct
15938c2ecf20Sopenharmony_ci * item successesfully, but there were no disk space to cut unfm
15948c2ecf20Sopenharmony_ci * pointer being converted. Therefore we have to delete inserted
15958c2ecf20Sopenharmony_ci * direct item(s)
15968c2ecf20Sopenharmony_ci */
15978c2ecf20Sopenharmony_cistatic void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th,
15988c2ecf20Sopenharmony_ci					 struct inode *inode, struct treepath *path)
15998c2ecf20Sopenharmony_ci{
16008c2ecf20Sopenharmony_ci	struct cpu_key tail_key;
16018c2ecf20Sopenharmony_ci	int tail_len;
16028c2ecf20Sopenharmony_ci	int removed;
16038c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	make_cpu_key(&tail_key, inode, inode->i_size + 1, TYPE_DIRECT, 4);
16068c2ecf20Sopenharmony_ci	tail_key.key_length = 4;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	tail_len =
16098c2ecf20Sopenharmony_ci	    (cpu_key_k_offset(&tail_key) & (inode->i_sb->s_blocksize - 1)) - 1;
16108c2ecf20Sopenharmony_ci	while (tail_len) {
16118c2ecf20Sopenharmony_ci		/* look for the last byte of the tail */
16128c2ecf20Sopenharmony_ci		if (search_for_position_by_key(inode->i_sb, &tail_key, path) ==
16138c2ecf20Sopenharmony_ci		    POSITION_NOT_FOUND)
16148c2ecf20Sopenharmony_ci			reiserfs_panic(inode->i_sb, "vs-5615",
16158c2ecf20Sopenharmony_ci				       "found invalid item");
16168c2ecf20Sopenharmony_ci		RFALSE(path->pos_in_item !=
16178c2ecf20Sopenharmony_ci		       ih_item_len(tp_item_head(path)) - 1,
16188c2ecf20Sopenharmony_ci		       "vs-5616: appended bytes found");
16198c2ecf20Sopenharmony_ci		PATH_LAST_POSITION(path)--;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci		removed =
16228c2ecf20Sopenharmony_ci		    reiserfs_delete_item(th, path, &tail_key, inode,
16238c2ecf20Sopenharmony_ci					 NULL /*unbh not needed */ );
16248c2ecf20Sopenharmony_ci		RFALSE(removed <= 0
16258c2ecf20Sopenharmony_ci		       || removed > tail_len,
16268c2ecf20Sopenharmony_ci		       "vs-5617: there was tail %d bytes, removed item length %d bytes",
16278c2ecf20Sopenharmony_ci		       tail_len, removed);
16288c2ecf20Sopenharmony_ci		tail_len -= removed;
16298c2ecf20Sopenharmony_ci		set_cpu_key_k_offset(&tail_key,
16308c2ecf20Sopenharmony_ci				     cpu_key_k_offset(&tail_key) - removed);
16318c2ecf20Sopenharmony_ci	}
16328c2ecf20Sopenharmony_ci	reiserfs_warning(inode->i_sb, "reiserfs-5091", "indirect_to_direct "
16338c2ecf20Sopenharmony_ci			 "conversion has been rolled back due to "
16348c2ecf20Sopenharmony_ci			 "lack of disk space");
16358c2ecf20Sopenharmony_ci	mark_inode_dirty(inode);
16368c2ecf20Sopenharmony_ci}
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci/* (Truncate or cut entry) or delete object item. Returns < 0 on failure */
16398c2ecf20Sopenharmony_ciint reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
16408c2ecf20Sopenharmony_ci			   struct treepath *path,
16418c2ecf20Sopenharmony_ci			   struct cpu_key *item_key,
16428c2ecf20Sopenharmony_ci			   struct inode *inode,
16438c2ecf20Sopenharmony_ci			   struct page *page, loff_t new_file_size)
16448c2ecf20Sopenharmony_ci{
16458c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
16468c2ecf20Sopenharmony_ci	/*
16478c2ecf20Sopenharmony_ci	 * Every function which is going to call do_balance must first
16488c2ecf20Sopenharmony_ci	 * create a tree_balance structure.  Then it must fill up this
16498c2ecf20Sopenharmony_ci	 * structure by using the init_tb_struct and fix_nodes functions.
16508c2ecf20Sopenharmony_ci	 * After that we can make tree balancing.
16518c2ecf20Sopenharmony_ci	 */
16528c2ecf20Sopenharmony_ci	struct tree_balance s_cut_balance;
16538c2ecf20Sopenharmony_ci	struct item_head *p_le_ih;
16548c2ecf20Sopenharmony_ci	int cut_size = 0;	/* Amount to be cut. */
16558c2ecf20Sopenharmony_ci	int ret_value = CARRY_ON;
16568c2ecf20Sopenharmony_ci	int removed = 0;	/* Number of the removed unformatted nodes. */
16578c2ecf20Sopenharmony_ci	int is_inode_locked = 0;
16588c2ecf20Sopenharmony_ci	char mode;		/* Mode of the balance. */
16598c2ecf20Sopenharmony_ci	int retval2 = -1;
16608c2ecf20Sopenharmony_ci	int quota_cut_bytes;
16618c2ecf20Sopenharmony_ci	loff_t tail_pos = 0;
16628c2ecf20Sopenharmony_ci	int depth;
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	init_tb_struct(th, &s_cut_balance, inode->i_sb, path,
16678c2ecf20Sopenharmony_ci		       cut_size);
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	/*
16708c2ecf20Sopenharmony_ci	 * Repeat this loop until we either cut the item without needing
16718c2ecf20Sopenharmony_ci	 * to balance, or we fix_nodes without schedule occurring
16728c2ecf20Sopenharmony_ci	 */
16738c2ecf20Sopenharmony_ci	while (1) {
16748c2ecf20Sopenharmony_ci		/*
16758c2ecf20Sopenharmony_ci		 * Determine the balance mode, position of the first byte to
16768c2ecf20Sopenharmony_ci		 * be cut, and size to be cut.  In case of the indirect item
16778c2ecf20Sopenharmony_ci		 * free unformatted nodes which are pointed to by the cut
16788c2ecf20Sopenharmony_ci		 * pointers.
16798c2ecf20Sopenharmony_ci		 */
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci		mode =
16828c2ecf20Sopenharmony_ci		    prepare_for_delete_or_cut(th, inode, path,
16838c2ecf20Sopenharmony_ci					      item_key, &removed,
16848c2ecf20Sopenharmony_ci					      &cut_size, new_file_size);
16858c2ecf20Sopenharmony_ci		if (mode == M_CONVERT) {
16868c2ecf20Sopenharmony_ci			/*
16878c2ecf20Sopenharmony_ci			 * convert last unformatted node to direct item or
16888c2ecf20Sopenharmony_ci			 * leave tail in the unformatted node
16898c2ecf20Sopenharmony_ci			 */
16908c2ecf20Sopenharmony_ci			RFALSE(ret_value != CARRY_ON,
16918c2ecf20Sopenharmony_ci			       "PAP-5570: can not convert twice");
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci			ret_value =
16948c2ecf20Sopenharmony_ci			    maybe_indirect_to_direct(th, inode, page,
16958c2ecf20Sopenharmony_ci						     path, item_key,
16968c2ecf20Sopenharmony_ci						     new_file_size, &mode);
16978c2ecf20Sopenharmony_ci			if (mode == M_SKIP_BALANCING)
16988c2ecf20Sopenharmony_ci				/* tail has been left in the unformatted node */
16998c2ecf20Sopenharmony_ci				return ret_value;
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci			is_inode_locked = 1;
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci			/*
17048c2ecf20Sopenharmony_ci			 * removing of last unformatted node will
17058c2ecf20Sopenharmony_ci			 * change value we have to return to truncate.
17068c2ecf20Sopenharmony_ci			 * Save it
17078c2ecf20Sopenharmony_ci			 */
17088c2ecf20Sopenharmony_ci			retval2 = ret_value;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci			/*
17118c2ecf20Sopenharmony_ci			 * So, we have performed the first part of the
17128c2ecf20Sopenharmony_ci			 * conversion:
17138c2ecf20Sopenharmony_ci			 * inserting the new direct item.  Now we are
17148c2ecf20Sopenharmony_ci			 * removing the last unformatted node pointer.
17158c2ecf20Sopenharmony_ci			 * Set key to search for it.
17168c2ecf20Sopenharmony_ci			 */
17178c2ecf20Sopenharmony_ci			set_cpu_key_k_type(item_key, TYPE_INDIRECT);
17188c2ecf20Sopenharmony_ci			item_key->key_length = 4;
17198c2ecf20Sopenharmony_ci			new_file_size -=
17208c2ecf20Sopenharmony_ci			    (new_file_size & (sb->s_blocksize - 1));
17218c2ecf20Sopenharmony_ci			tail_pos = new_file_size;
17228c2ecf20Sopenharmony_ci			set_cpu_key_k_offset(item_key, new_file_size + 1);
17238c2ecf20Sopenharmony_ci			if (search_for_position_by_key
17248c2ecf20Sopenharmony_ci			    (sb, item_key,
17258c2ecf20Sopenharmony_ci			     path) == POSITION_NOT_FOUND) {
17268c2ecf20Sopenharmony_ci				print_block(PATH_PLAST_BUFFER(path), 3,
17278c2ecf20Sopenharmony_ci					    PATH_LAST_POSITION(path) - 1,
17288c2ecf20Sopenharmony_ci					    PATH_LAST_POSITION(path) + 1);
17298c2ecf20Sopenharmony_ci				reiserfs_panic(sb, "PAP-5580", "item to "
17308c2ecf20Sopenharmony_ci					       "convert does not exist (%K)",
17318c2ecf20Sopenharmony_ci					       item_key);
17328c2ecf20Sopenharmony_ci			}
17338c2ecf20Sopenharmony_ci			continue;
17348c2ecf20Sopenharmony_ci		}
17358c2ecf20Sopenharmony_ci		if (cut_size == 0) {
17368c2ecf20Sopenharmony_ci			pathrelse(path);
17378c2ecf20Sopenharmony_ci			return 0;
17388c2ecf20Sopenharmony_ci		}
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci		s_cut_balance.insert_size[0] = cut_size;
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci		ret_value = fix_nodes(mode, &s_cut_balance, NULL, NULL);
17438c2ecf20Sopenharmony_ci		if (ret_value != REPEAT_SEARCH)
17448c2ecf20Sopenharmony_ci			break;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci		PROC_INFO_INC(sb, cut_from_item_restarted);
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci		ret_value =
17498c2ecf20Sopenharmony_ci		    search_for_position_by_key(sb, item_key, path);
17508c2ecf20Sopenharmony_ci		if (ret_value == POSITION_FOUND)
17518c2ecf20Sopenharmony_ci			continue;
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci		reiserfs_warning(sb, "PAP-5610", "item %K not found",
17548c2ecf20Sopenharmony_ci				 item_key);
17558c2ecf20Sopenharmony_ci		unfix_nodes(&s_cut_balance);
17568c2ecf20Sopenharmony_ci		return (ret_value == IO_ERROR) ? -EIO : -ENOENT;
17578c2ecf20Sopenharmony_ci	}			/* while */
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	/* check fix_nodes results (IO_ERROR or NO_DISK_SPACE) */
17608c2ecf20Sopenharmony_ci	if (ret_value != CARRY_ON) {
17618c2ecf20Sopenharmony_ci		if (is_inode_locked) {
17628c2ecf20Sopenharmony_ci			/*
17638c2ecf20Sopenharmony_ci			 * FIXME: this seems to be not needed: we are always
17648c2ecf20Sopenharmony_ci			 * able to cut item
17658c2ecf20Sopenharmony_ci			 */
17668c2ecf20Sopenharmony_ci			indirect_to_direct_roll_back(th, inode, path);
17678c2ecf20Sopenharmony_ci		}
17688c2ecf20Sopenharmony_ci		if (ret_value == NO_DISK_SPACE)
17698c2ecf20Sopenharmony_ci			reiserfs_warning(sb, "reiserfs-5092",
17708c2ecf20Sopenharmony_ci					 "NO_DISK_SPACE");
17718c2ecf20Sopenharmony_ci		unfix_nodes(&s_cut_balance);
17728c2ecf20Sopenharmony_ci		return -EIO;
17738c2ecf20Sopenharmony_ci	}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	/* go ahead and perform balancing */
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	RFALSE(mode == M_PASTE || mode == M_INSERT, "invalid mode");
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	/* Calculate number of bytes that need to be cut from the item. */
17808c2ecf20Sopenharmony_ci	quota_cut_bytes =
17818c2ecf20Sopenharmony_ci	    (mode ==
17828c2ecf20Sopenharmony_ci	     M_DELETE) ? ih_item_len(tp_item_head(path)) : -s_cut_balance.
17838c2ecf20Sopenharmony_ci	    insert_size[0];
17848c2ecf20Sopenharmony_ci	if (retval2 == -1)
17858c2ecf20Sopenharmony_ci		ret_value = calc_deleted_bytes_number(&s_cut_balance, mode);
17868c2ecf20Sopenharmony_ci	else
17878c2ecf20Sopenharmony_ci		ret_value = retval2;
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	/*
17908c2ecf20Sopenharmony_ci	 * For direct items, we only change the quota when deleting the last
17918c2ecf20Sopenharmony_ci	 * item.
17928c2ecf20Sopenharmony_ci	 */
17938c2ecf20Sopenharmony_ci	p_le_ih = tp_item_head(s_cut_balance.tb_path);
17948c2ecf20Sopenharmony_ci	if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(p_le_ih)) {
17958c2ecf20Sopenharmony_ci		if (mode == M_DELETE &&
17968c2ecf20Sopenharmony_ci		    (le_ih_k_offset(p_le_ih) & (sb->s_blocksize - 1)) ==
17978c2ecf20Sopenharmony_ci		    1) {
17988c2ecf20Sopenharmony_ci			/* FIXME: this is to keep 3.5 happy */
17998c2ecf20Sopenharmony_ci			REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
18008c2ecf20Sopenharmony_ci			quota_cut_bytes = sb->s_blocksize + UNFM_P_SIZE;
18018c2ecf20Sopenharmony_ci		} else {
18028c2ecf20Sopenharmony_ci			quota_cut_bytes = 0;
18038c2ecf20Sopenharmony_ci		}
18048c2ecf20Sopenharmony_ci	}
18058c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
18068c2ecf20Sopenharmony_ci	if (is_inode_locked) {
18078c2ecf20Sopenharmony_ci		struct item_head *le_ih =
18088c2ecf20Sopenharmony_ci		    tp_item_head(s_cut_balance.tb_path);
18098c2ecf20Sopenharmony_ci		/*
18108c2ecf20Sopenharmony_ci		 * we are going to complete indirect2direct conversion. Make
18118c2ecf20Sopenharmony_ci		 * sure, that we exactly remove last unformatted node pointer
18128c2ecf20Sopenharmony_ci		 * of the item
18138c2ecf20Sopenharmony_ci		 */
18148c2ecf20Sopenharmony_ci		if (!is_indirect_le_ih(le_ih))
18158c2ecf20Sopenharmony_ci			reiserfs_panic(sb, "vs-5652",
18168c2ecf20Sopenharmony_ci				       "item must be indirect %h", le_ih);
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci		if (mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE)
18198c2ecf20Sopenharmony_ci			reiserfs_panic(sb, "vs-5653", "completing "
18208c2ecf20Sopenharmony_ci				       "indirect2direct conversion indirect "
18218c2ecf20Sopenharmony_ci				       "item %h being deleted must be of "
18228c2ecf20Sopenharmony_ci				       "4 byte long", le_ih);
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci		if (mode == M_CUT
18258c2ecf20Sopenharmony_ci		    && s_cut_balance.insert_size[0] != -UNFM_P_SIZE) {
18268c2ecf20Sopenharmony_ci			reiserfs_panic(sb, "vs-5654", "can not complete "
18278c2ecf20Sopenharmony_ci				       "indirect2direct conversion of %h "
18288c2ecf20Sopenharmony_ci				       "(CUT, insert_size==%d)",
18298c2ecf20Sopenharmony_ci				       le_ih, s_cut_balance.insert_size[0]);
18308c2ecf20Sopenharmony_ci		}
18318c2ecf20Sopenharmony_ci		/*
18328c2ecf20Sopenharmony_ci		 * it would be useful to make sure, that right neighboring
18338c2ecf20Sopenharmony_ci		 * item is direct item of this file
18348c2ecf20Sopenharmony_ci		 */
18358c2ecf20Sopenharmony_ci	}
18368c2ecf20Sopenharmony_ci#endif
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	do_balance(&s_cut_balance, NULL, NULL, mode);
18398c2ecf20Sopenharmony_ci	if (is_inode_locked) {
18408c2ecf20Sopenharmony_ci		/*
18418c2ecf20Sopenharmony_ci		 * we've done an indirect->direct conversion.  when the
18428c2ecf20Sopenharmony_ci		 * data block was freed, it was removed from the list of
18438c2ecf20Sopenharmony_ci		 * blocks that must be flushed before the transaction
18448c2ecf20Sopenharmony_ci		 * commits, make sure to unmap and invalidate it
18458c2ecf20Sopenharmony_ci		 */
18468c2ecf20Sopenharmony_ci		unmap_buffers(page, tail_pos);
18478c2ecf20Sopenharmony_ci		REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
18488c2ecf20Sopenharmony_ci	}
18498c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG
18508c2ecf20Sopenharmony_ci	reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
18518c2ecf20Sopenharmony_ci		       "reiserquota cut_from_item(): freeing %u id=%u type=%c",
18528c2ecf20Sopenharmony_ci		       quota_cut_bytes, inode->i_uid, '?');
18538c2ecf20Sopenharmony_ci#endif
18548c2ecf20Sopenharmony_ci	depth = reiserfs_write_unlock_nested(sb);
18558c2ecf20Sopenharmony_ci	dquot_free_space_nodirty(inode, quota_cut_bytes);
18568c2ecf20Sopenharmony_ci	reiserfs_write_lock_nested(sb, depth);
18578c2ecf20Sopenharmony_ci	return ret_value;
18588c2ecf20Sopenharmony_ci}
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_cistatic void truncate_directory(struct reiserfs_transaction_handle *th,
18618c2ecf20Sopenharmony_ci			       struct inode *inode)
18628c2ecf20Sopenharmony_ci{
18638c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
18648c2ecf20Sopenharmony_ci	if (inode->i_nlink)
18658c2ecf20Sopenharmony_ci		reiserfs_error(inode->i_sb, "vs-5655", "link count != 0");
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	set_le_key_k_offset(KEY_FORMAT_3_5, INODE_PKEY(inode), DOT_OFFSET);
18688c2ecf20Sopenharmony_ci	set_le_key_k_type(KEY_FORMAT_3_5, INODE_PKEY(inode), TYPE_DIRENTRY);
18698c2ecf20Sopenharmony_ci	reiserfs_delete_solid_item(th, inode, INODE_PKEY(inode));
18708c2ecf20Sopenharmony_ci	reiserfs_update_sd(th, inode);
18718c2ecf20Sopenharmony_ci	set_le_key_k_offset(KEY_FORMAT_3_5, INODE_PKEY(inode), SD_OFFSET);
18728c2ecf20Sopenharmony_ci	set_le_key_k_type(KEY_FORMAT_3_5, INODE_PKEY(inode), TYPE_STAT_DATA);
18738c2ecf20Sopenharmony_ci}
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci/*
18768c2ecf20Sopenharmony_ci * Truncate file to the new size. Note, this must be called with a
18778c2ecf20Sopenharmony_ci * transaction already started
18788c2ecf20Sopenharmony_ci */
18798c2ecf20Sopenharmony_ciint reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
18808c2ecf20Sopenharmony_ci			 struct inode *inode,	/* ->i_size contains new size */
18818c2ecf20Sopenharmony_ci			 struct page *page,	/* up to date for last block */
18828c2ecf20Sopenharmony_ci			 /*
18838c2ecf20Sopenharmony_ci			  * when it is called by file_release to convert
18848c2ecf20Sopenharmony_ci			  * the tail - no timestamps should be updated
18858c2ecf20Sopenharmony_ci			  */
18868c2ecf20Sopenharmony_ci			 int update_timestamps
18878c2ecf20Sopenharmony_ci    )
18888c2ecf20Sopenharmony_ci{
18898c2ecf20Sopenharmony_ci	INITIALIZE_PATH(s_search_path);	/* Path to the current object item. */
18908c2ecf20Sopenharmony_ci	struct item_head *p_le_ih;	/* Pointer to an item header. */
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	/* Key to search for a previous file item. */
18938c2ecf20Sopenharmony_ci	struct cpu_key s_item_key;
18948c2ecf20Sopenharmony_ci	loff_t file_size,	/* Old file size. */
18958c2ecf20Sopenharmony_ci	 new_file_size;	/* New file size. */
18968c2ecf20Sopenharmony_ci	int deleted;		/* Number of deleted or truncated bytes. */
18978c2ecf20Sopenharmony_ci	int retval;
18988c2ecf20Sopenharmony_ci	int err = 0;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
19018c2ecf20Sopenharmony_ci	if (!
19028c2ecf20Sopenharmony_ci	    (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
19038c2ecf20Sopenharmony_ci	     || S_ISLNK(inode->i_mode)))
19048c2ecf20Sopenharmony_ci		return 0;
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	/* deletion of directory - no need to update timestamps */
19078c2ecf20Sopenharmony_ci	if (S_ISDIR(inode->i_mode)) {
19088c2ecf20Sopenharmony_ci		truncate_directory(th, inode);
19098c2ecf20Sopenharmony_ci		return 0;
19108c2ecf20Sopenharmony_ci	}
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	/* Get new file size. */
19138c2ecf20Sopenharmony_ci	new_file_size = inode->i_size;
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	/* FIXME: note, that key type is unimportant here */
19168c2ecf20Sopenharmony_ci	make_cpu_key(&s_item_key, inode, max_reiserfs_offset(inode),
19178c2ecf20Sopenharmony_ci		     TYPE_DIRECT, 3);
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	retval =
19208c2ecf20Sopenharmony_ci	    search_for_position_by_key(inode->i_sb, &s_item_key,
19218c2ecf20Sopenharmony_ci				       &s_search_path);
19228c2ecf20Sopenharmony_ci	if (retval == IO_ERROR) {
19238c2ecf20Sopenharmony_ci		reiserfs_error(inode->i_sb, "vs-5657",
19248c2ecf20Sopenharmony_ci			       "i/o failure occurred trying to truncate %K",
19258c2ecf20Sopenharmony_ci			       &s_item_key);
19268c2ecf20Sopenharmony_ci		err = -EIO;
19278c2ecf20Sopenharmony_ci		goto out;
19288c2ecf20Sopenharmony_ci	}
19298c2ecf20Sopenharmony_ci	if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) {
19308c2ecf20Sopenharmony_ci		reiserfs_error(inode->i_sb, "PAP-5660",
19318c2ecf20Sopenharmony_ci			       "wrong result %d of search for %K", retval,
19328c2ecf20Sopenharmony_ci			       &s_item_key);
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci		err = -EIO;
19358c2ecf20Sopenharmony_ci		goto out;
19368c2ecf20Sopenharmony_ci	}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	s_search_path.pos_in_item--;
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	/* Get real file size (total length of all file items) */
19418c2ecf20Sopenharmony_ci	p_le_ih = tp_item_head(&s_search_path);
19428c2ecf20Sopenharmony_ci	if (is_statdata_le_ih(p_le_ih))
19438c2ecf20Sopenharmony_ci		file_size = 0;
19448c2ecf20Sopenharmony_ci	else {
19458c2ecf20Sopenharmony_ci		loff_t offset = le_ih_k_offset(p_le_ih);
19468c2ecf20Sopenharmony_ci		int bytes =
19478c2ecf20Sopenharmony_ci		    op_bytes_number(p_le_ih, inode->i_sb->s_blocksize);
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci		/*
19508c2ecf20Sopenharmony_ci		 * this may mismatch with real file size: if last direct item
19518c2ecf20Sopenharmony_ci		 * had no padding zeros and last unformatted node had no free
19528c2ecf20Sopenharmony_ci		 * space, this file would have this file size
19538c2ecf20Sopenharmony_ci		 */
19548c2ecf20Sopenharmony_ci		file_size = offset + bytes - 1;
19558c2ecf20Sopenharmony_ci	}
19568c2ecf20Sopenharmony_ci	/*
19578c2ecf20Sopenharmony_ci	 * are we doing a full truncate or delete, if so
19588c2ecf20Sopenharmony_ci	 * kick in the reada code
19598c2ecf20Sopenharmony_ci	 */
19608c2ecf20Sopenharmony_ci	if (new_file_size == 0)
19618c2ecf20Sopenharmony_ci		s_search_path.reada = PATH_READA | PATH_READA_BACK;
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	if (file_size == 0 || file_size < new_file_size) {
19648c2ecf20Sopenharmony_ci		goto update_and_out;
19658c2ecf20Sopenharmony_ci	}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	/* Update key to search for the last file item. */
19688c2ecf20Sopenharmony_ci	set_cpu_key_k_offset(&s_item_key, file_size);
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	do {
19718c2ecf20Sopenharmony_ci		/* Cut or delete file item. */
19728c2ecf20Sopenharmony_ci		deleted =
19738c2ecf20Sopenharmony_ci		    reiserfs_cut_from_item(th, &s_search_path, &s_item_key,
19748c2ecf20Sopenharmony_ci					   inode, page, new_file_size);
19758c2ecf20Sopenharmony_ci		if (deleted < 0) {
19768c2ecf20Sopenharmony_ci			reiserfs_warning(inode->i_sb, "vs-5665",
19778c2ecf20Sopenharmony_ci					 "reiserfs_cut_from_item failed");
19788c2ecf20Sopenharmony_ci			reiserfs_check_path(&s_search_path);
19798c2ecf20Sopenharmony_ci			return 0;
19808c2ecf20Sopenharmony_ci		}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci		RFALSE(deleted > file_size,
19838c2ecf20Sopenharmony_ci		       "PAP-5670: reiserfs_cut_from_item: too many bytes deleted: deleted %d, file_size %lu, item_key %K",
19848c2ecf20Sopenharmony_ci		       deleted, file_size, &s_item_key);
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci		/* Change key to search the last file item. */
19878c2ecf20Sopenharmony_ci		file_size -= deleted;
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci		set_cpu_key_k_offset(&s_item_key, file_size);
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci		/*
19928c2ecf20Sopenharmony_ci		 * While there are bytes to truncate and previous
19938c2ecf20Sopenharmony_ci		 * file item is presented in the tree.
19948c2ecf20Sopenharmony_ci		 */
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci		/*
19978c2ecf20Sopenharmony_ci		 * This loop could take a really long time, and could log
19988c2ecf20Sopenharmony_ci		 * many more blocks than a transaction can hold.  So, we do
19998c2ecf20Sopenharmony_ci		 * a polite journal end here, and if the transaction needs
20008c2ecf20Sopenharmony_ci		 * ending, we make sure the file is consistent before ending
20018c2ecf20Sopenharmony_ci		 * the current trans and starting a new one
20028c2ecf20Sopenharmony_ci		 */
20038c2ecf20Sopenharmony_ci		if (journal_transaction_should_end(th, 0) ||
20048c2ecf20Sopenharmony_ci		    reiserfs_transaction_free_space(th) <= JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD) {
20058c2ecf20Sopenharmony_ci			pathrelse(&s_search_path);
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci			if (update_timestamps) {
20088c2ecf20Sopenharmony_ci				inode->i_mtime = current_time(inode);
20098c2ecf20Sopenharmony_ci				inode->i_ctime = current_time(inode);
20108c2ecf20Sopenharmony_ci			}
20118c2ecf20Sopenharmony_ci			reiserfs_update_sd(th, inode);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci			err = journal_end(th);
20148c2ecf20Sopenharmony_ci			if (err)
20158c2ecf20Sopenharmony_ci				goto out;
20168c2ecf20Sopenharmony_ci			err = journal_begin(th, inode->i_sb,
20178c2ecf20Sopenharmony_ci					    JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD + JOURNAL_PER_BALANCE_CNT * 4) ;
20188c2ecf20Sopenharmony_ci			if (err)
20198c2ecf20Sopenharmony_ci				goto out;
20208c2ecf20Sopenharmony_ci			reiserfs_update_inode_transaction(inode);
20218c2ecf20Sopenharmony_ci		}
20228c2ecf20Sopenharmony_ci	} while (file_size > ROUND_UP(new_file_size) &&
20238c2ecf20Sopenharmony_ci		 search_for_position_by_key(inode->i_sb, &s_item_key,
20248c2ecf20Sopenharmony_ci					    &s_search_path) == POSITION_FOUND);
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	RFALSE(file_size > ROUND_UP(new_file_size),
20278c2ecf20Sopenharmony_ci	       "PAP-5680: truncate did not finish: new_file_size %lld, current %lld, oid %d",
20288c2ecf20Sopenharmony_ci	       new_file_size, file_size, s_item_key.on_disk_key.k_objectid);
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ciupdate_and_out:
20318c2ecf20Sopenharmony_ci	if (update_timestamps) {
20328c2ecf20Sopenharmony_ci		/* this is truncate, not file closing */
20338c2ecf20Sopenharmony_ci		inode->i_mtime = current_time(inode);
20348c2ecf20Sopenharmony_ci		inode->i_ctime = current_time(inode);
20358c2ecf20Sopenharmony_ci	}
20368c2ecf20Sopenharmony_ci	reiserfs_update_sd(th, inode);
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ciout:
20398c2ecf20Sopenharmony_ci	pathrelse(&s_search_path);
20408c2ecf20Sopenharmony_ci	return err;
20418c2ecf20Sopenharmony_ci}
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
20448c2ecf20Sopenharmony_ci/* this makes sure, that we __append__, not overwrite or add holes */
20458c2ecf20Sopenharmony_cistatic void check_research_for_paste(struct treepath *path,
20468c2ecf20Sopenharmony_ci				     const struct cpu_key *key)
20478c2ecf20Sopenharmony_ci{
20488c2ecf20Sopenharmony_ci	struct item_head *found_ih = tp_item_head(path);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	if (is_direct_le_ih(found_ih)) {
20518c2ecf20Sopenharmony_ci		if (le_ih_k_offset(found_ih) +
20528c2ecf20Sopenharmony_ci		    op_bytes_number(found_ih,
20538c2ecf20Sopenharmony_ci				    get_last_bh(path)->b_size) !=
20548c2ecf20Sopenharmony_ci		    cpu_key_k_offset(key)
20558c2ecf20Sopenharmony_ci		    || op_bytes_number(found_ih,
20568c2ecf20Sopenharmony_ci				       get_last_bh(path)->b_size) !=
20578c2ecf20Sopenharmony_ci		    pos_in_item(path))
20588c2ecf20Sopenharmony_ci			reiserfs_panic(NULL, "PAP-5720", "found direct item "
20598c2ecf20Sopenharmony_ci				       "%h or position (%d) does not match "
20608c2ecf20Sopenharmony_ci				       "to key %K", found_ih,
20618c2ecf20Sopenharmony_ci				       pos_in_item(path), key);
20628c2ecf20Sopenharmony_ci	}
20638c2ecf20Sopenharmony_ci	if (is_indirect_le_ih(found_ih)) {
20648c2ecf20Sopenharmony_ci		if (le_ih_k_offset(found_ih) +
20658c2ecf20Sopenharmony_ci		    op_bytes_number(found_ih,
20668c2ecf20Sopenharmony_ci				    get_last_bh(path)->b_size) !=
20678c2ecf20Sopenharmony_ci		    cpu_key_k_offset(key)
20688c2ecf20Sopenharmony_ci		    || I_UNFM_NUM(found_ih) != pos_in_item(path)
20698c2ecf20Sopenharmony_ci		    || get_ih_free_space(found_ih) != 0)
20708c2ecf20Sopenharmony_ci			reiserfs_panic(NULL, "PAP-5730", "found indirect "
20718c2ecf20Sopenharmony_ci				       "item (%h) or position (%d) does not "
20728c2ecf20Sopenharmony_ci				       "match to key (%K)",
20738c2ecf20Sopenharmony_ci				       found_ih, pos_in_item(path), key);
20748c2ecf20Sopenharmony_ci	}
20758c2ecf20Sopenharmony_ci}
20768c2ecf20Sopenharmony_ci#endif				/* config reiserfs check */
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci/*
20798c2ecf20Sopenharmony_ci * Paste bytes to the existing item.
20808c2ecf20Sopenharmony_ci * Returns bytes number pasted into the item.
20818c2ecf20Sopenharmony_ci */
20828c2ecf20Sopenharmony_ciint reiserfs_paste_into_item(struct reiserfs_transaction_handle *th,
20838c2ecf20Sopenharmony_ci			     /* Path to the pasted item. */
20848c2ecf20Sopenharmony_ci			     struct treepath *search_path,
20858c2ecf20Sopenharmony_ci			     /* Key to search for the needed item. */
20868c2ecf20Sopenharmony_ci			     const struct cpu_key *key,
20878c2ecf20Sopenharmony_ci			     /* Inode item belongs to */
20888c2ecf20Sopenharmony_ci			     struct inode *inode,
20898c2ecf20Sopenharmony_ci			     /* Pointer to the bytes to paste. */
20908c2ecf20Sopenharmony_ci			     const char *body,
20918c2ecf20Sopenharmony_ci			     /* Size of pasted bytes. */
20928c2ecf20Sopenharmony_ci			     int pasted_size)
20938c2ecf20Sopenharmony_ci{
20948c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
20958c2ecf20Sopenharmony_ci	struct tree_balance s_paste_balance;
20968c2ecf20Sopenharmony_ci	int retval;
20978c2ecf20Sopenharmony_ci	int fs_gen;
20988c2ecf20Sopenharmony_ci	int depth;
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	fs_gen = get_generation(inode->i_sb);
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG
21058c2ecf20Sopenharmony_ci	reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
21068c2ecf20Sopenharmony_ci		       "reiserquota paste_into_item(): allocating %u id=%u type=%c",
21078c2ecf20Sopenharmony_ci		       pasted_size, inode->i_uid,
21088c2ecf20Sopenharmony_ci		       key2type(&key->on_disk_key));
21098c2ecf20Sopenharmony_ci#endif
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	depth = reiserfs_write_unlock_nested(sb);
21128c2ecf20Sopenharmony_ci	retval = dquot_alloc_space_nodirty(inode, pasted_size);
21138c2ecf20Sopenharmony_ci	reiserfs_write_lock_nested(sb, depth);
21148c2ecf20Sopenharmony_ci	if (retval) {
21158c2ecf20Sopenharmony_ci		pathrelse(search_path);
21168c2ecf20Sopenharmony_ci		return retval;
21178c2ecf20Sopenharmony_ci	}
21188c2ecf20Sopenharmony_ci	init_tb_struct(th, &s_paste_balance, th->t_super, search_path,
21198c2ecf20Sopenharmony_ci		       pasted_size);
21208c2ecf20Sopenharmony_ci#ifdef DISPLACE_NEW_PACKING_LOCALITIES
21218c2ecf20Sopenharmony_ci	s_paste_balance.key = key->on_disk_key;
21228c2ecf20Sopenharmony_ci#endif
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	/* DQUOT_* can schedule, must check before the fix_nodes */
21258c2ecf20Sopenharmony_ci	if (fs_changed(fs_gen, inode->i_sb)) {
21268c2ecf20Sopenharmony_ci		goto search_again;
21278c2ecf20Sopenharmony_ci	}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	while ((retval =
21308c2ecf20Sopenharmony_ci		fix_nodes(M_PASTE, &s_paste_balance, NULL,
21318c2ecf20Sopenharmony_ci			  body)) == REPEAT_SEARCH) {
21328c2ecf20Sopenharmony_cisearch_again:
21338c2ecf20Sopenharmony_ci		/* file system changed while we were in the fix_nodes */
21348c2ecf20Sopenharmony_ci		PROC_INFO_INC(th->t_super, paste_into_item_restarted);
21358c2ecf20Sopenharmony_ci		retval =
21368c2ecf20Sopenharmony_ci		    search_for_position_by_key(th->t_super, key,
21378c2ecf20Sopenharmony_ci					       search_path);
21388c2ecf20Sopenharmony_ci		if (retval == IO_ERROR) {
21398c2ecf20Sopenharmony_ci			retval = -EIO;
21408c2ecf20Sopenharmony_ci			goto error_out;
21418c2ecf20Sopenharmony_ci		}
21428c2ecf20Sopenharmony_ci		if (retval == POSITION_FOUND) {
21438c2ecf20Sopenharmony_ci			reiserfs_warning(inode->i_sb, "PAP-5710",
21448c2ecf20Sopenharmony_ci					 "entry or pasted byte (%K) exists",
21458c2ecf20Sopenharmony_ci					 key);
21468c2ecf20Sopenharmony_ci			retval = -EEXIST;
21478c2ecf20Sopenharmony_ci			goto error_out;
21488c2ecf20Sopenharmony_ci		}
21498c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
21508c2ecf20Sopenharmony_ci		check_research_for_paste(search_path, key);
21518c2ecf20Sopenharmony_ci#endif
21528c2ecf20Sopenharmony_ci	}
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	/*
21558c2ecf20Sopenharmony_ci	 * Perform balancing after all resources are collected by fix_nodes,
21568c2ecf20Sopenharmony_ci	 * and accessing them will not risk triggering schedule.
21578c2ecf20Sopenharmony_ci	 */
21588c2ecf20Sopenharmony_ci	if (retval == CARRY_ON) {
21598c2ecf20Sopenharmony_ci		do_balance(&s_paste_balance, NULL /*ih */ , body, M_PASTE);
21608c2ecf20Sopenharmony_ci		return 0;
21618c2ecf20Sopenharmony_ci	}
21628c2ecf20Sopenharmony_ci	retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
21638c2ecf20Sopenharmony_cierror_out:
21648c2ecf20Sopenharmony_ci	/* this also releases the path */
21658c2ecf20Sopenharmony_ci	unfix_nodes(&s_paste_balance);
21668c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG
21678c2ecf20Sopenharmony_ci	reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
21688c2ecf20Sopenharmony_ci		       "reiserquota paste_into_item(): freeing %u id=%u type=%c",
21698c2ecf20Sopenharmony_ci		       pasted_size, inode->i_uid,
21708c2ecf20Sopenharmony_ci		       key2type(&key->on_disk_key));
21718c2ecf20Sopenharmony_ci#endif
21728c2ecf20Sopenharmony_ci	depth = reiserfs_write_unlock_nested(sb);
21738c2ecf20Sopenharmony_ci	dquot_free_space_nodirty(inode, pasted_size);
21748c2ecf20Sopenharmony_ci	reiserfs_write_lock_nested(sb, depth);
21758c2ecf20Sopenharmony_ci	return retval;
21768c2ecf20Sopenharmony_ci}
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci/*
21798c2ecf20Sopenharmony_ci * Insert new item into the buffer at the path.
21808c2ecf20Sopenharmony_ci * th   - active transaction handle
21818c2ecf20Sopenharmony_ci * path - path to the inserted item
21828c2ecf20Sopenharmony_ci * ih   - pointer to the item header to insert
21838c2ecf20Sopenharmony_ci * body - pointer to the bytes to insert
21848c2ecf20Sopenharmony_ci */
21858c2ecf20Sopenharmony_ciint reiserfs_insert_item(struct reiserfs_transaction_handle *th,
21868c2ecf20Sopenharmony_ci			 struct treepath *path, const struct cpu_key *key,
21878c2ecf20Sopenharmony_ci			 struct item_head *ih, struct inode *inode,
21888c2ecf20Sopenharmony_ci			 const char *body)
21898c2ecf20Sopenharmony_ci{
21908c2ecf20Sopenharmony_ci	struct tree_balance s_ins_balance;
21918c2ecf20Sopenharmony_ci	int retval;
21928c2ecf20Sopenharmony_ci	int fs_gen = 0;
21938c2ecf20Sopenharmony_ci	int quota_bytes = 0;
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	BUG_ON(!th->t_trans_id);
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci	if (inode) {		/* Do we count quotas for item? */
21988c2ecf20Sopenharmony_ci		int depth;
21998c2ecf20Sopenharmony_ci		fs_gen = get_generation(inode->i_sb);
22008c2ecf20Sopenharmony_ci		quota_bytes = ih_item_len(ih);
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci		/*
22038c2ecf20Sopenharmony_ci		 * hack so the quota code doesn't have to guess
22048c2ecf20Sopenharmony_ci		 * if the file has a tail, links are always tails,
22058c2ecf20Sopenharmony_ci		 * so there's no guessing needed
22068c2ecf20Sopenharmony_ci		 */
22078c2ecf20Sopenharmony_ci		if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(ih))
22088c2ecf20Sopenharmony_ci			quota_bytes = inode->i_sb->s_blocksize + UNFM_P_SIZE;
22098c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG
22108c2ecf20Sopenharmony_ci		reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
22118c2ecf20Sopenharmony_ci			       "reiserquota insert_item(): allocating %u id=%u type=%c",
22128c2ecf20Sopenharmony_ci			       quota_bytes, inode->i_uid, head2type(ih));
22138c2ecf20Sopenharmony_ci#endif
22148c2ecf20Sopenharmony_ci		/*
22158c2ecf20Sopenharmony_ci		 * We can't dirty inode here. It would be immediately
22168c2ecf20Sopenharmony_ci		 * written but appropriate stat item isn't inserted yet...
22178c2ecf20Sopenharmony_ci		 */
22188c2ecf20Sopenharmony_ci		depth = reiserfs_write_unlock_nested(inode->i_sb);
22198c2ecf20Sopenharmony_ci		retval = dquot_alloc_space_nodirty(inode, quota_bytes);
22208c2ecf20Sopenharmony_ci		reiserfs_write_lock_nested(inode->i_sb, depth);
22218c2ecf20Sopenharmony_ci		if (retval) {
22228c2ecf20Sopenharmony_ci			pathrelse(path);
22238c2ecf20Sopenharmony_ci			return retval;
22248c2ecf20Sopenharmony_ci		}
22258c2ecf20Sopenharmony_ci	}
22268c2ecf20Sopenharmony_ci	init_tb_struct(th, &s_ins_balance, th->t_super, path,
22278c2ecf20Sopenharmony_ci		       IH_SIZE + ih_item_len(ih));
22288c2ecf20Sopenharmony_ci#ifdef DISPLACE_NEW_PACKING_LOCALITIES
22298c2ecf20Sopenharmony_ci	s_ins_balance.key = key->on_disk_key;
22308c2ecf20Sopenharmony_ci#endif
22318c2ecf20Sopenharmony_ci	/*
22328c2ecf20Sopenharmony_ci	 * DQUOT_* can schedule, must check to be sure calling
22338c2ecf20Sopenharmony_ci	 * fix_nodes is safe
22348c2ecf20Sopenharmony_ci	 */
22358c2ecf20Sopenharmony_ci	if (inode && fs_changed(fs_gen, inode->i_sb)) {
22368c2ecf20Sopenharmony_ci		goto search_again;
22378c2ecf20Sopenharmony_ci	}
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	while ((retval =
22408c2ecf20Sopenharmony_ci		fix_nodes(M_INSERT, &s_ins_balance, ih,
22418c2ecf20Sopenharmony_ci			  body)) == REPEAT_SEARCH) {
22428c2ecf20Sopenharmony_cisearch_again:
22438c2ecf20Sopenharmony_ci		/* file system changed while we were in the fix_nodes */
22448c2ecf20Sopenharmony_ci		PROC_INFO_INC(th->t_super, insert_item_restarted);
22458c2ecf20Sopenharmony_ci		retval = search_item(th->t_super, key, path);
22468c2ecf20Sopenharmony_ci		if (retval == IO_ERROR) {
22478c2ecf20Sopenharmony_ci			retval = -EIO;
22488c2ecf20Sopenharmony_ci			goto error_out;
22498c2ecf20Sopenharmony_ci		}
22508c2ecf20Sopenharmony_ci		if (retval == ITEM_FOUND) {
22518c2ecf20Sopenharmony_ci			reiserfs_warning(th->t_super, "PAP-5760",
22528c2ecf20Sopenharmony_ci					 "key %K already exists in the tree",
22538c2ecf20Sopenharmony_ci					 key);
22548c2ecf20Sopenharmony_ci			retval = -EEXIST;
22558c2ecf20Sopenharmony_ci			goto error_out;
22568c2ecf20Sopenharmony_ci		}
22578c2ecf20Sopenharmony_ci	}
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci	/* make balancing after all resources will be collected at a time */
22608c2ecf20Sopenharmony_ci	if (retval == CARRY_ON) {
22618c2ecf20Sopenharmony_ci		do_balance(&s_ins_balance, ih, body, M_INSERT);
22628c2ecf20Sopenharmony_ci		return 0;
22638c2ecf20Sopenharmony_ci	}
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci	retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
22668c2ecf20Sopenharmony_cierror_out:
22678c2ecf20Sopenharmony_ci	/* also releases the path */
22688c2ecf20Sopenharmony_ci	unfix_nodes(&s_ins_balance);
22698c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG
22708c2ecf20Sopenharmony_ci	if (inode)
22718c2ecf20Sopenharmony_ci		reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE,
22728c2ecf20Sopenharmony_ci		       "reiserquota insert_item(): freeing %u id=%u type=%c",
22738c2ecf20Sopenharmony_ci		       quota_bytes, inode->i_uid, head2type(ih));
22748c2ecf20Sopenharmony_ci#endif
22758c2ecf20Sopenharmony_ci	if (inode) {
22768c2ecf20Sopenharmony_ci		int depth = reiserfs_write_unlock_nested(inode->i_sb);
22778c2ecf20Sopenharmony_ci		dquot_free_space_nodirty(inode, quota_bytes);
22788c2ecf20Sopenharmony_ci		reiserfs_write_lock_nested(inode->i_sb, depth);
22798c2ecf20Sopenharmony_ci	}
22808c2ecf20Sopenharmony_ci	return retval;
22818c2ecf20Sopenharmony_ci}
2282