162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Copyright (C) International Business Machines Corp., 2000-2004
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/*
762306a36Sopenharmony_ci *	jfs_dtree.c: directory B+-tree manager
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * B+-tree with variable length key directory:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * each directory page is structured as an array of 32-byte
1262306a36Sopenharmony_ci * directory entry slots initialized as a freelist
1362306a36Sopenharmony_ci * to avoid search/compaction of free space at insertion.
1462306a36Sopenharmony_ci * when an entry is inserted, a number of slots are allocated
1562306a36Sopenharmony_ci * from the freelist as required to store variable length data
1662306a36Sopenharmony_ci * of the entry; when the entry is deleted, slots of the entry
1762306a36Sopenharmony_ci * are returned to freelist.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * leaf entry stores full name as key and file serial number
2062306a36Sopenharmony_ci * (aka inode number) as data.
2162306a36Sopenharmony_ci * internal/router entry stores sufffix compressed name
2262306a36Sopenharmony_ci * as key and simple extent descriptor as data.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * each directory page maintains a sorted entry index table
2562306a36Sopenharmony_ci * which stores the start slot index of sorted entries
2662306a36Sopenharmony_ci * to allow binary search on the table.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * directory starts as a root/leaf page in on-disk inode
2962306a36Sopenharmony_ci * inline data area.
3062306a36Sopenharmony_ci * when it becomes full, it starts a leaf of a external extent
3162306a36Sopenharmony_ci * of length of 1 block. each time the first leaf becomes full,
3262306a36Sopenharmony_ci * it is extended rather than split (its size is doubled),
3362306a36Sopenharmony_ci * until its length becoms 4 KBytes, from then the extent is split
3462306a36Sopenharmony_ci * with new 4 Kbyte extent when it becomes full
3562306a36Sopenharmony_ci * to reduce external fragmentation of small directories.
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * blah, blah, blah, for linear scan of directory in pieces by
3862306a36Sopenharmony_ci * readdir().
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci *	case-insensitive directory file system
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * names are stored in case-sensitive way in leaf entry.
4462306a36Sopenharmony_ci * but stored, searched and compared in case-insensitive (uppercase) order
4562306a36Sopenharmony_ci * (i.e., both search key and entry key are folded for search/compare):
4662306a36Sopenharmony_ci * (note that case-sensitive order is BROKEN in storage, e.g.,
4762306a36Sopenharmony_ci *  sensitive: Ad, aB, aC, aD -> insensitive: aB, aC, aD, Ad
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci *  entries which folds to the same key makes up a equivalent class
5062306a36Sopenharmony_ci *  whose members are stored as contiguous cluster (may cross page boundary)
5162306a36Sopenharmony_ci *  but whose order is arbitrary and acts as duplicate, e.g.,
5262306a36Sopenharmony_ci *  abc, Abc, aBc, abC)
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * once match is found at leaf, requires scan forward/backward
5562306a36Sopenharmony_ci * either for, in case-insensitive search, duplicate
5662306a36Sopenharmony_ci * or for, in case-sensitive search, for exact match
5762306a36Sopenharmony_ci *
5862306a36Sopenharmony_ci * router entry must be created/stored in case-insensitive way
5962306a36Sopenharmony_ci * in internal entry:
6062306a36Sopenharmony_ci * (right most key of left page and left most key of right page
6162306a36Sopenharmony_ci * are folded, and its suffix compression is propagated as router
6262306a36Sopenharmony_ci * key in parent)
6362306a36Sopenharmony_ci * (e.g., if split occurs <abc> and <aBd>, <ABD> trather than <aB>
6462306a36Sopenharmony_ci * should be made the router key for the split)
6562306a36Sopenharmony_ci *
6662306a36Sopenharmony_ci * case-insensitive search:
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci *	fold search key;
6962306a36Sopenharmony_ci *
7062306a36Sopenharmony_ci *	case-insensitive search of B-tree:
7162306a36Sopenharmony_ci *	for internal entry, router key is already folded;
7262306a36Sopenharmony_ci *	for leaf entry, fold the entry key before comparison.
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci *	if (leaf entry case-insensitive match found)
7562306a36Sopenharmony_ci *		if (next entry satisfies case-insensitive match)
7662306a36Sopenharmony_ci *			return EDUPLICATE;
7762306a36Sopenharmony_ci *		if (prev entry satisfies case-insensitive match)
7862306a36Sopenharmony_ci *			return EDUPLICATE;
7962306a36Sopenharmony_ci *		return match;
8062306a36Sopenharmony_ci *	else
8162306a36Sopenharmony_ci *		return no match;
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci *	serialization:
8462306a36Sopenharmony_ci * target directory inode lock is being held on entry/exit
8562306a36Sopenharmony_ci * of all main directory service routines.
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci *	log based recovery:
8862306a36Sopenharmony_ci */
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#include <linux/fs.h>
9162306a36Sopenharmony_ci#include <linux/quotaops.h>
9262306a36Sopenharmony_ci#include <linux/slab.h>
9362306a36Sopenharmony_ci#include "jfs_incore.h"
9462306a36Sopenharmony_ci#include "jfs_superblock.h"
9562306a36Sopenharmony_ci#include "jfs_filsys.h"
9662306a36Sopenharmony_ci#include "jfs_metapage.h"
9762306a36Sopenharmony_ci#include "jfs_dmap.h"
9862306a36Sopenharmony_ci#include "jfs_unicode.h"
9962306a36Sopenharmony_ci#include "jfs_debug.h"
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* dtree split parameter */
10262306a36Sopenharmony_cistruct dtsplit {
10362306a36Sopenharmony_ci	struct metapage *mp;
10462306a36Sopenharmony_ci	s16 index;
10562306a36Sopenharmony_ci	s16 nslot;
10662306a36Sopenharmony_ci	struct component_name *key;
10762306a36Sopenharmony_ci	ddata_t *data;
10862306a36Sopenharmony_ci	struct pxdlist *pxdlist;
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define DT_PAGE(IP, MP) BT_PAGE(IP, MP, dtpage_t, i_dtroot)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/* get page buffer for specified block address */
11462306a36Sopenharmony_ci#define DT_GETPAGE(IP, BN, MP, SIZE, P, RC)				\
11562306a36Sopenharmony_cido {									\
11662306a36Sopenharmony_ci	BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot);	\
11762306a36Sopenharmony_ci	if (!(RC)) {							\
11862306a36Sopenharmony_ci		if (((P)->header.nextindex >				\
11962306a36Sopenharmony_ci		     (((BN) == 0) ? DTROOTMAXSLOT : (P)->header.maxslot)) || \
12062306a36Sopenharmony_ci		    ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT))) {	\
12162306a36Sopenharmony_ci			BT_PUTPAGE(MP);					\
12262306a36Sopenharmony_ci			jfs_error((IP)->i_sb,				\
12362306a36Sopenharmony_ci				  "DT_GETPAGE: dtree page corrupt\n");	\
12462306a36Sopenharmony_ci			MP = NULL;					\
12562306a36Sopenharmony_ci			RC = -EIO;					\
12662306a36Sopenharmony_ci		}							\
12762306a36Sopenharmony_ci	}								\
12862306a36Sopenharmony_ci} while (0)
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* for consistency */
13162306a36Sopenharmony_ci#define DT_PUTPAGE(MP) BT_PUTPAGE(MP)
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci#define DT_GETSEARCH(IP, LEAF, BN, MP, P, INDEX) \
13462306a36Sopenharmony_ci	BT_GETSEARCH(IP, LEAF, BN, MP, dtpage_t, P, INDEX, i_dtroot)
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/*
13762306a36Sopenharmony_ci * forward references
13862306a36Sopenharmony_ci */
13962306a36Sopenharmony_cistatic int dtSplitUp(tid_t tid, struct inode *ip,
14062306a36Sopenharmony_ci		     struct dtsplit * split, struct btstack * btstack);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
14362306a36Sopenharmony_ci		       struct metapage ** rmpp, dtpage_t ** rpp, pxd_t * rxdp);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int dtExtendPage(tid_t tid, struct inode *ip,
14662306a36Sopenharmony_ci			struct dtsplit * split, struct btstack * btstack);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int dtSplitRoot(tid_t tid, struct inode *ip,
14962306a36Sopenharmony_ci		       struct dtsplit * split, struct metapage ** rmpp);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic int dtDeleteUp(tid_t tid, struct inode *ip, struct metapage * fmp,
15262306a36Sopenharmony_ci		      dtpage_t * fp, struct btstack * btstack);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int dtReadFirst(struct inode *ip, struct btstack * btstack);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic int dtReadNext(struct inode *ip,
15962306a36Sopenharmony_ci		      loff_t * offset, struct btstack * btstack);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int dtCompare(struct component_name * key, dtpage_t * p, int si);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int ciCompare(struct component_name * key, dtpage_t * p, int si,
16462306a36Sopenharmony_ci		     int flag);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic void dtGetKey(dtpage_t * p, int i, struct component_name * key,
16762306a36Sopenharmony_ci		     int flag);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
17062306a36Sopenharmony_ci			      int ri, struct component_name * key, int flag);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
17362306a36Sopenharmony_ci			  ddata_t * data, struct dt_lock **);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
17662306a36Sopenharmony_ci			struct dt_lock ** sdtlock, struct dt_lock ** ddtlock,
17762306a36Sopenharmony_ci			int do_index);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic void dtDeleteEntry(dtpage_t * p, int fi, struct dt_lock ** dtlock);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic void dtTruncateEntry(dtpage_t * p, int ti, struct dt_lock ** dtlock);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic void dtLinelockFreelist(dtpage_t * p, int m, struct dt_lock ** dtlock);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#define ciToUpper(c)	UniStrupr((c)->name)
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/*
18862306a36Sopenharmony_ci *	read_index_page()
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci *	Reads a page of a directory's index table.
19162306a36Sopenharmony_ci *	Having metadata mapped into the directory inode's address space
19262306a36Sopenharmony_ci *	presents a multitude of problems.  We avoid this by mapping to
19362306a36Sopenharmony_ci *	the absolute address space outside of the *_metapage routines
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_cistatic struct metapage *read_index_page(struct inode *inode, s64 blkno)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	int rc;
19862306a36Sopenharmony_ci	s64 xaddr;
19962306a36Sopenharmony_ci	int xflag;
20062306a36Sopenharmony_ci	s32 xlen;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	rc = xtLookup(inode, blkno, 1, &xflag, &xaddr, &xlen, 1);
20362306a36Sopenharmony_ci	if (rc || (xaddr == 0))
20462306a36Sopenharmony_ci		return NULL;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return read_metapage(inode, xaddr, PSIZE, 1);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci/*
21062306a36Sopenharmony_ci *	get_index_page()
21162306a36Sopenharmony_ci *
21262306a36Sopenharmony_ci *	Same as get_index_page(), but get's a new page without reading
21362306a36Sopenharmony_ci */
21462306a36Sopenharmony_cistatic struct metapage *get_index_page(struct inode *inode, s64 blkno)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	int rc;
21762306a36Sopenharmony_ci	s64 xaddr;
21862306a36Sopenharmony_ci	int xflag;
21962306a36Sopenharmony_ci	s32 xlen;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	rc = xtLookup(inode, blkno, 1, &xflag, &xaddr, &xlen, 1);
22262306a36Sopenharmony_ci	if (rc || (xaddr == 0))
22362306a36Sopenharmony_ci		return NULL;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return get_metapage(inode, xaddr, PSIZE, 1);
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/*
22962306a36Sopenharmony_ci *	find_index()
23062306a36Sopenharmony_ci *
23162306a36Sopenharmony_ci *	Returns dtree page containing directory table entry for specified
23262306a36Sopenharmony_ci *	index and pointer to its entry.
23362306a36Sopenharmony_ci *
23462306a36Sopenharmony_ci *	mp must be released by caller.
23562306a36Sopenharmony_ci */
23662306a36Sopenharmony_cistatic struct dir_table_slot *find_index(struct inode *ip, u32 index,
23762306a36Sopenharmony_ci					 struct metapage ** mp, s64 *lblock)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
24062306a36Sopenharmony_ci	s64 blkno;
24162306a36Sopenharmony_ci	s64 offset;
24262306a36Sopenharmony_ci	int page_offset;
24362306a36Sopenharmony_ci	struct dir_table_slot *slot;
24462306a36Sopenharmony_ci	static int maxWarnings = 10;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (index < 2) {
24762306a36Sopenharmony_ci		if (maxWarnings) {
24862306a36Sopenharmony_ci			jfs_warn("find_entry called with index = %d", index);
24962306a36Sopenharmony_ci			maxWarnings--;
25062306a36Sopenharmony_ci		}
25162306a36Sopenharmony_ci		return NULL;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (index >= jfs_ip->next_index) {
25562306a36Sopenharmony_ci		jfs_warn("find_entry called with index >= next_index");
25662306a36Sopenharmony_ci		return NULL;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (jfs_dirtable_inline(ip)) {
26062306a36Sopenharmony_ci		/*
26162306a36Sopenharmony_ci		 * Inline directory table
26262306a36Sopenharmony_ci		 */
26362306a36Sopenharmony_ci		*mp = NULL;
26462306a36Sopenharmony_ci		slot = &jfs_ip->i_dirtable[index - 2];
26562306a36Sopenharmony_ci	} else {
26662306a36Sopenharmony_ci		offset = (index - 2) * sizeof(struct dir_table_slot);
26762306a36Sopenharmony_ci		page_offset = offset & (PSIZE - 1);
26862306a36Sopenharmony_ci		blkno = ((offset + 1) >> L2PSIZE) <<
26962306a36Sopenharmony_ci		    JFS_SBI(ip->i_sb)->l2nbperpage;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci		if (*mp && (*lblock != blkno)) {
27262306a36Sopenharmony_ci			release_metapage(*mp);
27362306a36Sopenharmony_ci			*mp = NULL;
27462306a36Sopenharmony_ci		}
27562306a36Sopenharmony_ci		if (!(*mp)) {
27662306a36Sopenharmony_ci			*lblock = blkno;
27762306a36Sopenharmony_ci			*mp = read_index_page(ip, blkno);
27862306a36Sopenharmony_ci		}
27962306a36Sopenharmony_ci		if (!(*mp)) {
28062306a36Sopenharmony_ci			jfs_err("free_index: error reading directory table");
28162306a36Sopenharmony_ci			return NULL;
28262306a36Sopenharmony_ci		}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		slot =
28562306a36Sopenharmony_ci		    (struct dir_table_slot *) ((char *) (*mp)->data +
28662306a36Sopenharmony_ci					       page_offset);
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	return slot;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic inline void lock_index(tid_t tid, struct inode *ip, struct metapage * mp,
29262306a36Sopenharmony_ci			      u32 index)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct tlock *tlck;
29562306a36Sopenharmony_ci	struct linelock *llck;
29662306a36Sopenharmony_ci	struct lv *lv;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	tlck = txLock(tid, ip, mp, tlckDATA);
29962306a36Sopenharmony_ci	llck = (struct linelock *) tlck->lock;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (llck->index >= llck->maxcnt)
30262306a36Sopenharmony_ci		llck = txLinelock(llck);
30362306a36Sopenharmony_ci	lv = &llck->lv[llck->index];
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/*
30662306a36Sopenharmony_ci	 *	Linelock slot size is twice the size of directory table
30762306a36Sopenharmony_ci	 *	slot size.  512 entries per page.
30862306a36Sopenharmony_ci	 */
30962306a36Sopenharmony_ci	lv->offset = ((index - 2) & 511) >> 1;
31062306a36Sopenharmony_ci	lv->length = 1;
31162306a36Sopenharmony_ci	llck->index++;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/*
31562306a36Sopenharmony_ci *	add_index()
31662306a36Sopenharmony_ci *
31762306a36Sopenharmony_ci *	Adds an entry to the directory index table.  This is used to provide
31862306a36Sopenharmony_ci *	each directory entry with a persistent index in which to resume
31962306a36Sopenharmony_ci *	directory traversals
32062306a36Sopenharmony_ci */
32162306a36Sopenharmony_cistatic u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct super_block *sb = ip->i_sb;
32462306a36Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(sb);
32562306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
32662306a36Sopenharmony_ci	u64 blkno;
32762306a36Sopenharmony_ci	struct dir_table_slot *dirtab_slot;
32862306a36Sopenharmony_ci	u32 index;
32962306a36Sopenharmony_ci	struct linelock *llck;
33062306a36Sopenharmony_ci	struct lv *lv;
33162306a36Sopenharmony_ci	struct metapage *mp;
33262306a36Sopenharmony_ci	s64 offset;
33362306a36Sopenharmony_ci	uint page_offset;
33462306a36Sopenharmony_ci	struct tlock *tlck;
33562306a36Sopenharmony_ci	s64 xaddr;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	ASSERT(DO_INDEX(ip));
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (jfs_ip->next_index < 2) {
34062306a36Sopenharmony_ci		jfs_warn("add_index: next_index = %d.  Resetting!",
34162306a36Sopenharmony_ci			   jfs_ip->next_index);
34262306a36Sopenharmony_ci		jfs_ip->next_index = 2;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	index = jfs_ip->next_index++;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (index <= MAX_INLINE_DIRTABLE_ENTRY) {
34862306a36Sopenharmony_ci		/*
34962306a36Sopenharmony_ci		 * i_size reflects size of index table, or 8 bytes per entry.
35062306a36Sopenharmony_ci		 */
35162306a36Sopenharmony_ci		ip->i_size = (loff_t) (index - 1) << 3;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		/*
35462306a36Sopenharmony_ci		 * dir table fits inline within inode
35562306a36Sopenharmony_ci		 */
35662306a36Sopenharmony_ci		dirtab_slot = &jfs_ip->i_dirtable[index-2];
35762306a36Sopenharmony_ci		dirtab_slot->flag = DIR_INDEX_VALID;
35862306a36Sopenharmony_ci		dirtab_slot->slot = slot;
35962306a36Sopenharmony_ci		DTSaddress(dirtab_slot, bn);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		set_cflag(COMMIT_Dirtable, ip);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		return index;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci	if (index == (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
36662306a36Sopenharmony_ci		struct dir_table_slot temp_table[12];
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		/*
36962306a36Sopenharmony_ci		 * It's time to move the inline table to an external
37062306a36Sopenharmony_ci		 * page and begin to build the xtree
37162306a36Sopenharmony_ci		 */
37262306a36Sopenharmony_ci		if (dquot_alloc_block(ip, sbi->nbperpage))
37362306a36Sopenharmony_ci			goto clean_up;
37462306a36Sopenharmony_ci		if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr)) {
37562306a36Sopenharmony_ci			dquot_free_block(ip, sbi->nbperpage);
37662306a36Sopenharmony_ci			goto clean_up;
37762306a36Sopenharmony_ci		}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		/*
38062306a36Sopenharmony_ci		 * Save the table, we're going to overwrite it with the
38162306a36Sopenharmony_ci		 * xtree root
38262306a36Sopenharmony_ci		 */
38362306a36Sopenharmony_ci		memcpy(temp_table, &jfs_ip->i_dirtable, sizeof(temp_table));
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		/*
38662306a36Sopenharmony_ci		 * Initialize empty x-tree
38762306a36Sopenharmony_ci		 */
38862306a36Sopenharmony_ci		xtInitRoot(tid, ip);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		/*
39162306a36Sopenharmony_ci		 * Add the first block to the xtree
39262306a36Sopenharmony_ci		 */
39362306a36Sopenharmony_ci		if (xtInsert(tid, ip, 0, 0, sbi->nbperpage, &xaddr, 0)) {
39462306a36Sopenharmony_ci			/* This really shouldn't fail */
39562306a36Sopenharmony_ci			jfs_warn("add_index: xtInsert failed!");
39662306a36Sopenharmony_ci			memcpy(&jfs_ip->i_dirtable, temp_table,
39762306a36Sopenharmony_ci			       sizeof (temp_table));
39862306a36Sopenharmony_ci			dbFree(ip, xaddr, sbi->nbperpage);
39962306a36Sopenharmony_ci			dquot_free_block(ip, sbi->nbperpage);
40062306a36Sopenharmony_ci			goto clean_up;
40162306a36Sopenharmony_ci		}
40262306a36Sopenharmony_ci		ip->i_size = PSIZE;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		mp = get_index_page(ip, 0);
40562306a36Sopenharmony_ci		if (!mp) {
40662306a36Sopenharmony_ci			jfs_err("add_index: get_metapage failed!");
40762306a36Sopenharmony_ci			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
40862306a36Sopenharmony_ci			memcpy(&jfs_ip->i_dirtable, temp_table,
40962306a36Sopenharmony_ci			       sizeof (temp_table));
41062306a36Sopenharmony_ci			goto clean_up;
41162306a36Sopenharmony_ci		}
41262306a36Sopenharmony_ci		tlck = txLock(tid, ip, mp, tlckDATA);
41362306a36Sopenharmony_ci		llck = (struct linelock *) & tlck->lock;
41462306a36Sopenharmony_ci		ASSERT(llck->index == 0);
41562306a36Sopenharmony_ci		lv = &llck->lv[0];
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci		lv->offset = 0;
41862306a36Sopenharmony_ci		lv->length = 6;	/* tlckDATA slot size is 16 bytes */
41962306a36Sopenharmony_ci		llck->index++;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		memcpy(mp->data, temp_table, sizeof(temp_table));
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		mark_metapage_dirty(mp);
42462306a36Sopenharmony_ci		release_metapage(mp);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		/*
42762306a36Sopenharmony_ci		 * Logging is now directed by xtree tlocks
42862306a36Sopenharmony_ci		 */
42962306a36Sopenharmony_ci		clear_cflag(COMMIT_Dirtable, ip);
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	offset = (index - 2) * sizeof(struct dir_table_slot);
43362306a36Sopenharmony_ci	page_offset = offset & (PSIZE - 1);
43462306a36Sopenharmony_ci	blkno = ((offset + 1) >> L2PSIZE) << sbi->l2nbperpage;
43562306a36Sopenharmony_ci	if (page_offset == 0) {
43662306a36Sopenharmony_ci		/*
43762306a36Sopenharmony_ci		 * This will be the beginning of a new page
43862306a36Sopenharmony_ci		 */
43962306a36Sopenharmony_ci		xaddr = 0;
44062306a36Sopenharmony_ci		if (xtInsert(tid, ip, 0, blkno, sbi->nbperpage, &xaddr, 0)) {
44162306a36Sopenharmony_ci			jfs_warn("add_index: xtInsert failed!");
44262306a36Sopenharmony_ci			goto clean_up;
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci		ip->i_size += PSIZE;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		if ((mp = get_index_page(ip, blkno)))
44762306a36Sopenharmony_ci			memset(mp->data, 0, PSIZE);	/* Just looks better */
44862306a36Sopenharmony_ci		else
44962306a36Sopenharmony_ci			xtTruncate(tid, ip, offset, COMMIT_PWMAP);
45062306a36Sopenharmony_ci	} else
45162306a36Sopenharmony_ci		mp = read_index_page(ip, blkno);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (!mp) {
45462306a36Sopenharmony_ci		jfs_err("add_index: get/read_metapage failed!");
45562306a36Sopenharmony_ci		goto clean_up;
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	lock_index(tid, ip, mp, index);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	dirtab_slot =
46162306a36Sopenharmony_ci	    (struct dir_table_slot *) ((char *) mp->data + page_offset);
46262306a36Sopenharmony_ci	dirtab_slot->flag = DIR_INDEX_VALID;
46362306a36Sopenharmony_ci	dirtab_slot->slot = slot;
46462306a36Sopenharmony_ci	DTSaddress(dirtab_slot, bn);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	mark_metapage_dirty(mp);
46762306a36Sopenharmony_ci	release_metapage(mp);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	return index;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci      clean_up:
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	jfs_ip->next_index--;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return 0;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/*
47962306a36Sopenharmony_ci *	free_index()
48062306a36Sopenharmony_ci *
48162306a36Sopenharmony_ci *	Marks an entry to the directory index table as free.
48262306a36Sopenharmony_ci */
48362306a36Sopenharmony_cistatic void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct dir_table_slot *dirtab_slot;
48662306a36Sopenharmony_ci	s64 lblock;
48762306a36Sopenharmony_ci	struct metapage *mp = NULL;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	dirtab_slot = find_index(ip, index, &mp, &lblock);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (!dirtab_slot)
49262306a36Sopenharmony_ci		return;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	dirtab_slot->flag = DIR_INDEX_FREE;
49562306a36Sopenharmony_ci	dirtab_slot->slot = dirtab_slot->addr1 = 0;
49662306a36Sopenharmony_ci	dirtab_slot->addr2 = cpu_to_le32(next);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (mp) {
49962306a36Sopenharmony_ci		lock_index(tid, ip, mp, index);
50062306a36Sopenharmony_ci		mark_metapage_dirty(mp);
50162306a36Sopenharmony_ci		release_metapage(mp);
50262306a36Sopenharmony_ci	} else
50362306a36Sopenharmony_ci		set_cflag(COMMIT_Dirtable, ip);
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci/*
50762306a36Sopenharmony_ci *	modify_index()
50862306a36Sopenharmony_ci *
50962306a36Sopenharmony_ci *	Changes an entry in the directory index table
51062306a36Sopenharmony_ci */
51162306a36Sopenharmony_cistatic void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
51262306a36Sopenharmony_ci			 int slot, struct metapage ** mp, s64 *lblock)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	struct dir_table_slot *dirtab_slot;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	dirtab_slot = find_index(ip, index, mp, lblock);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (!dirtab_slot)
51962306a36Sopenharmony_ci		return;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	DTSaddress(dirtab_slot, bn);
52262306a36Sopenharmony_ci	dirtab_slot->slot = slot;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (*mp) {
52562306a36Sopenharmony_ci		lock_index(tid, ip, *mp, index);
52662306a36Sopenharmony_ci		mark_metapage_dirty(*mp);
52762306a36Sopenharmony_ci	} else
52862306a36Sopenharmony_ci		set_cflag(COMMIT_Dirtable, ip);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci/*
53262306a36Sopenharmony_ci *	read_index()
53362306a36Sopenharmony_ci *
53462306a36Sopenharmony_ci *	reads a directory table slot
53562306a36Sopenharmony_ci */
53662306a36Sopenharmony_cistatic int read_index(struct inode *ip, u32 index,
53762306a36Sopenharmony_ci		     struct dir_table_slot * dirtab_slot)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	s64 lblock;
54062306a36Sopenharmony_ci	struct metapage *mp = NULL;
54162306a36Sopenharmony_ci	struct dir_table_slot *slot;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	slot = find_index(ip, index, &mp, &lblock);
54462306a36Sopenharmony_ci	if (!slot) {
54562306a36Sopenharmony_ci		return -EIO;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	memcpy(dirtab_slot, slot, sizeof(struct dir_table_slot));
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (mp)
55162306a36Sopenharmony_ci		release_metapage(mp);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	return 0;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci/*
55762306a36Sopenharmony_ci *	dtSearch()
55862306a36Sopenharmony_ci *
55962306a36Sopenharmony_ci * function:
56062306a36Sopenharmony_ci *	Search for the entry with specified key
56162306a36Sopenharmony_ci *
56262306a36Sopenharmony_ci * parameter:
56362306a36Sopenharmony_ci *
56462306a36Sopenharmony_ci * return: 0 - search result on stack, leaf page pinned;
56562306a36Sopenharmony_ci *	   errno - I/O error
56662306a36Sopenharmony_ci */
56762306a36Sopenharmony_ciint dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
56862306a36Sopenharmony_ci	     struct btstack * btstack, int flag)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	int rc = 0;
57162306a36Sopenharmony_ci	int cmp = 1;		/* init for empty page */
57262306a36Sopenharmony_ci	s64 bn;
57362306a36Sopenharmony_ci	struct metapage *mp;
57462306a36Sopenharmony_ci	dtpage_t *p;
57562306a36Sopenharmony_ci	s8 *stbl;
57662306a36Sopenharmony_ci	int base, index, lim;
57762306a36Sopenharmony_ci	struct btframe *btsp;
57862306a36Sopenharmony_ci	pxd_t *pxd;
57962306a36Sopenharmony_ci	int psize = 288;	/* initial in-line directory */
58062306a36Sopenharmony_ci	ino_t inumber;
58162306a36Sopenharmony_ci	struct component_name ciKey;
58262306a36Sopenharmony_ci	struct super_block *sb = ip->i_sb;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	ciKey.name = kmalloc_array(JFS_NAME_MAX + 1, sizeof(wchar_t),
58562306a36Sopenharmony_ci				   GFP_NOFS);
58662306a36Sopenharmony_ci	if (!ciKey.name) {
58762306a36Sopenharmony_ci		rc = -ENOMEM;
58862306a36Sopenharmony_ci		goto dtSearch_Exit2;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	/* uppercase search key for c-i directory */
59362306a36Sopenharmony_ci	UniStrcpy(ciKey.name, key->name);
59462306a36Sopenharmony_ci	ciKey.namlen = key->namlen;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	/* only uppercase if case-insensitive support is on */
59762306a36Sopenharmony_ci	if ((JFS_SBI(sb)->mntflag & JFS_OS2) == JFS_OS2) {
59862306a36Sopenharmony_ci		ciToUpper(&ciKey);
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci	BT_CLR(btstack);	/* reset stack */
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* init level count for max pages to split */
60362306a36Sopenharmony_ci	btstack->nsplit = 1;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/*
60662306a36Sopenharmony_ci	 *	search down tree from root:
60762306a36Sopenharmony_ci	 *
60862306a36Sopenharmony_ci	 * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
60962306a36Sopenharmony_ci	 * internal page, child page Pi contains entry with k, Ki <= K < Kj.
61062306a36Sopenharmony_ci	 *
61162306a36Sopenharmony_ci	 * if entry with search key K is not found
61262306a36Sopenharmony_ci	 * internal page search find the entry with largest key Ki
61362306a36Sopenharmony_ci	 * less than K which point to the child page to search;
61462306a36Sopenharmony_ci	 * leaf page search find the entry with smallest key Kj
61562306a36Sopenharmony_ci	 * greater than K so that the returned index is the position of
61662306a36Sopenharmony_ci	 * the entry to be shifted right for insertion of new entry.
61762306a36Sopenharmony_ci	 * for empty tree, search key is greater than any key of the tree.
61862306a36Sopenharmony_ci	 *
61962306a36Sopenharmony_ci	 * by convention, root bn = 0.
62062306a36Sopenharmony_ci	 */
62162306a36Sopenharmony_ci	for (bn = 0;;) {
62262306a36Sopenharmony_ci		/* get/pin the page to search */
62362306a36Sopenharmony_ci		DT_GETPAGE(ip, bn, mp, psize, p, rc);
62462306a36Sopenharmony_ci		if (rc)
62562306a36Sopenharmony_ci			goto dtSearch_Exit1;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci		/* get sorted entry table of the page */
62862306a36Sopenharmony_ci		stbl = DT_GETSTBL(p);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		/*
63162306a36Sopenharmony_ci		 * binary search with search key K on the current page.
63262306a36Sopenharmony_ci		 */
63362306a36Sopenharmony_ci		for (base = 0, lim = p->header.nextindex; lim; lim >>= 1) {
63462306a36Sopenharmony_ci			index = base + (lim >> 1);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci			if (stbl[index] < 0) {
63762306a36Sopenharmony_ci				rc = -EIO;
63862306a36Sopenharmony_ci				goto out;
63962306a36Sopenharmony_ci			}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci			if (p->header.flag & BT_LEAF) {
64262306a36Sopenharmony_ci				/* uppercase leaf name to compare */
64362306a36Sopenharmony_ci				cmp =
64462306a36Sopenharmony_ci				    ciCompare(&ciKey, p, stbl[index],
64562306a36Sopenharmony_ci					      JFS_SBI(sb)->mntflag);
64662306a36Sopenharmony_ci			} else {
64762306a36Sopenharmony_ci				/* router key is in uppercase */
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci				cmp = dtCompare(&ciKey, p, stbl[index]);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci			}
65362306a36Sopenharmony_ci			if (cmp == 0) {
65462306a36Sopenharmony_ci				/*
65562306a36Sopenharmony_ci				 *	search hit
65662306a36Sopenharmony_ci				 */
65762306a36Sopenharmony_ci				/* search hit - leaf page:
65862306a36Sopenharmony_ci				 * return the entry found
65962306a36Sopenharmony_ci				 */
66062306a36Sopenharmony_ci				if (p->header.flag & BT_LEAF) {
66162306a36Sopenharmony_ci					inumber = le32_to_cpu(
66262306a36Sopenharmony_ci			((struct ldtentry *) & p->slot[stbl[index]])->inumber);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci					/*
66562306a36Sopenharmony_ci					 * search for JFS_LOOKUP
66662306a36Sopenharmony_ci					 */
66762306a36Sopenharmony_ci					if (flag == JFS_LOOKUP) {
66862306a36Sopenharmony_ci						*data = inumber;
66962306a36Sopenharmony_ci						rc = 0;
67062306a36Sopenharmony_ci						goto out;
67162306a36Sopenharmony_ci					}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci					/*
67462306a36Sopenharmony_ci					 * search for JFS_CREATE
67562306a36Sopenharmony_ci					 */
67662306a36Sopenharmony_ci					if (flag == JFS_CREATE) {
67762306a36Sopenharmony_ci						*data = inumber;
67862306a36Sopenharmony_ci						rc = -EEXIST;
67962306a36Sopenharmony_ci						goto out;
68062306a36Sopenharmony_ci					}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci					/*
68362306a36Sopenharmony_ci					 * search for JFS_REMOVE or JFS_RENAME
68462306a36Sopenharmony_ci					 */
68562306a36Sopenharmony_ci					if ((flag == JFS_REMOVE ||
68662306a36Sopenharmony_ci					     flag == JFS_RENAME) &&
68762306a36Sopenharmony_ci					    *data != inumber) {
68862306a36Sopenharmony_ci						rc = -ESTALE;
68962306a36Sopenharmony_ci						goto out;
69062306a36Sopenharmony_ci					}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci					/*
69362306a36Sopenharmony_ci					 * JFS_REMOVE|JFS_FINDDIR|JFS_RENAME
69462306a36Sopenharmony_ci					 */
69562306a36Sopenharmony_ci					/* save search result */
69662306a36Sopenharmony_ci					*data = inumber;
69762306a36Sopenharmony_ci					btsp = btstack->top;
69862306a36Sopenharmony_ci					btsp->bn = bn;
69962306a36Sopenharmony_ci					btsp->index = index;
70062306a36Sopenharmony_ci					btsp->mp = mp;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci					rc = 0;
70362306a36Sopenharmony_ci					goto dtSearch_Exit1;
70462306a36Sopenharmony_ci				}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci				/* search hit - internal page:
70762306a36Sopenharmony_ci				 * descend/search its child page
70862306a36Sopenharmony_ci				 */
70962306a36Sopenharmony_ci				goto getChild;
71062306a36Sopenharmony_ci			}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci			if (cmp > 0) {
71362306a36Sopenharmony_ci				base = index + 1;
71462306a36Sopenharmony_ci				--lim;
71562306a36Sopenharmony_ci			}
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		/*
71962306a36Sopenharmony_ci		 *	search miss
72062306a36Sopenharmony_ci		 *
72162306a36Sopenharmony_ci		 * base is the smallest index with key (Kj) greater than
72262306a36Sopenharmony_ci		 * search key (K) and may be zero or (maxindex + 1) index.
72362306a36Sopenharmony_ci		 */
72462306a36Sopenharmony_ci		/*
72562306a36Sopenharmony_ci		 * search miss - leaf page
72662306a36Sopenharmony_ci		 *
72762306a36Sopenharmony_ci		 * return location of entry (base) where new entry with
72862306a36Sopenharmony_ci		 * search key K is to be inserted.
72962306a36Sopenharmony_ci		 */
73062306a36Sopenharmony_ci		if (p->header.flag & BT_LEAF) {
73162306a36Sopenharmony_ci			/*
73262306a36Sopenharmony_ci			 * search for JFS_LOOKUP, JFS_REMOVE, or JFS_RENAME
73362306a36Sopenharmony_ci			 */
73462306a36Sopenharmony_ci			if (flag == JFS_LOOKUP || flag == JFS_REMOVE ||
73562306a36Sopenharmony_ci			    flag == JFS_RENAME) {
73662306a36Sopenharmony_ci				rc = -ENOENT;
73762306a36Sopenharmony_ci				goto out;
73862306a36Sopenharmony_ci			}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci			/*
74162306a36Sopenharmony_ci			 * search for JFS_CREATE|JFS_FINDDIR:
74262306a36Sopenharmony_ci			 *
74362306a36Sopenharmony_ci			 * save search result
74462306a36Sopenharmony_ci			 */
74562306a36Sopenharmony_ci			*data = 0;
74662306a36Sopenharmony_ci			btsp = btstack->top;
74762306a36Sopenharmony_ci			btsp->bn = bn;
74862306a36Sopenharmony_ci			btsp->index = base;
74962306a36Sopenharmony_ci			btsp->mp = mp;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci			rc = 0;
75262306a36Sopenharmony_ci			goto dtSearch_Exit1;
75362306a36Sopenharmony_ci		}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		/*
75662306a36Sopenharmony_ci		 * search miss - internal page
75762306a36Sopenharmony_ci		 *
75862306a36Sopenharmony_ci		 * if base is non-zero, decrement base by one to get the parent
75962306a36Sopenharmony_ci		 * entry of the child page to search.
76062306a36Sopenharmony_ci		 */
76162306a36Sopenharmony_ci		index = base ? base - 1 : base;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		/*
76462306a36Sopenharmony_ci		 * go down to child page
76562306a36Sopenharmony_ci		 */
76662306a36Sopenharmony_ci	      getChild:
76762306a36Sopenharmony_ci		/* update max. number of pages to split */
76862306a36Sopenharmony_ci		if (BT_STACK_FULL(btstack)) {
76962306a36Sopenharmony_ci			/* Something's corrupted, mark filesystem dirty so
77062306a36Sopenharmony_ci			 * chkdsk will fix it.
77162306a36Sopenharmony_ci			 */
77262306a36Sopenharmony_ci			jfs_error(sb, "stack overrun!\n");
77362306a36Sopenharmony_ci			BT_STACK_DUMP(btstack);
77462306a36Sopenharmony_ci			rc = -EIO;
77562306a36Sopenharmony_ci			goto out;
77662306a36Sopenharmony_ci		}
77762306a36Sopenharmony_ci		btstack->nsplit++;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci		/* push (bn, index) of the parent page/entry */
78062306a36Sopenharmony_ci		BT_PUSH(btstack, bn, index);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci		/* get the child page block number */
78362306a36Sopenharmony_ci		pxd = (pxd_t *) & p->slot[stbl[index]];
78462306a36Sopenharmony_ci		bn = addressPXD(pxd);
78562306a36Sopenharmony_ci		psize = lengthPXD(pxd) << JFS_SBI(ip->i_sb)->l2bsize;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci		/* unpin the parent page */
78862306a36Sopenharmony_ci		DT_PUTPAGE(mp);
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci      out:
79262306a36Sopenharmony_ci	DT_PUTPAGE(mp);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci      dtSearch_Exit1:
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	kfree(ciKey.name);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci      dtSearch_Exit2:
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	return rc;
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci/*
80562306a36Sopenharmony_ci *	dtInsert()
80662306a36Sopenharmony_ci *
80762306a36Sopenharmony_ci * function: insert an entry to directory tree
80862306a36Sopenharmony_ci *
80962306a36Sopenharmony_ci * parameter:
81062306a36Sopenharmony_ci *
81162306a36Sopenharmony_ci * return: 0 - success;
81262306a36Sopenharmony_ci *	   errno - failure;
81362306a36Sopenharmony_ci */
81462306a36Sopenharmony_ciint dtInsert(tid_t tid, struct inode *ip,
81562306a36Sopenharmony_ci	 struct component_name * name, ino_t * fsn, struct btstack * btstack)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	int rc = 0;
81862306a36Sopenharmony_ci	struct metapage *mp;	/* meta-page buffer */
81962306a36Sopenharmony_ci	dtpage_t *p;		/* base B+-tree index page */
82062306a36Sopenharmony_ci	s64 bn;
82162306a36Sopenharmony_ci	int index;
82262306a36Sopenharmony_ci	struct dtsplit split;	/* split information */
82362306a36Sopenharmony_ci	ddata_t data;
82462306a36Sopenharmony_ci	struct dt_lock *dtlck;
82562306a36Sopenharmony_ci	int n;
82662306a36Sopenharmony_ci	struct tlock *tlck;
82762306a36Sopenharmony_ci	struct lv *lv;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/*
83062306a36Sopenharmony_ci	 *	retrieve search result
83162306a36Sopenharmony_ci	 *
83262306a36Sopenharmony_ci	 * dtSearch() returns (leaf page pinned, index at which to insert).
83362306a36Sopenharmony_ci	 * n.b. dtSearch() may return index of (maxindex + 1) of
83462306a36Sopenharmony_ci	 * the full page.
83562306a36Sopenharmony_ci	 */
83662306a36Sopenharmony_ci	DT_GETSEARCH(ip, btstack->top, bn, mp, p, index);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	/*
83962306a36Sopenharmony_ci	 *	insert entry for new key
84062306a36Sopenharmony_ci	 */
84162306a36Sopenharmony_ci	if (DO_INDEX(ip)) {
84262306a36Sopenharmony_ci		if (JFS_IP(ip)->next_index == DIREND) {
84362306a36Sopenharmony_ci			DT_PUTPAGE(mp);
84462306a36Sopenharmony_ci			return -EMLINK;
84562306a36Sopenharmony_ci		}
84662306a36Sopenharmony_ci		n = NDTLEAF(name->namlen);
84762306a36Sopenharmony_ci		data.leaf.tid = tid;
84862306a36Sopenharmony_ci		data.leaf.ip = ip;
84962306a36Sopenharmony_ci	} else {
85062306a36Sopenharmony_ci		n = NDTLEAF_LEGACY(name->namlen);
85162306a36Sopenharmony_ci		data.leaf.ip = NULL;	/* signifies legacy directory format */
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci	data.leaf.ino = *fsn;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	/*
85662306a36Sopenharmony_ci	 *	leaf page does not have enough room for new entry:
85762306a36Sopenharmony_ci	 *
85862306a36Sopenharmony_ci	 *	extend/split the leaf page;
85962306a36Sopenharmony_ci	 *
86062306a36Sopenharmony_ci	 * dtSplitUp() will insert the entry and unpin the leaf page.
86162306a36Sopenharmony_ci	 */
86262306a36Sopenharmony_ci	if (n > p->header.freecnt) {
86362306a36Sopenharmony_ci		split.mp = mp;
86462306a36Sopenharmony_ci		split.index = index;
86562306a36Sopenharmony_ci		split.nslot = n;
86662306a36Sopenharmony_ci		split.key = name;
86762306a36Sopenharmony_ci		split.data = &data;
86862306a36Sopenharmony_ci		rc = dtSplitUp(tid, ip, &split, btstack);
86962306a36Sopenharmony_ci		return rc;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	/*
87362306a36Sopenharmony_ci	 *	leaf page does have enough room for new entry:
87462306a36Sopenharmony_ci	 *
87562306a36Sopenharmony_ci	 *	insert the new data entry into the leaf page;
87662306a36Sopenharmony_ci	 */
87762306a36Sopenharmony_ci	BT_MARK_DIRTY(mp, ip);
87862306a36Sopenharmony_ci	/*
87962306a36Sopenharmony_ci	 * acquire a transaction lock on the leaf page
88062306a36Sopenharmony_ci	 */
88162306a36Sopenharmony_ci	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
88262306a36Sopenharmony_ci	dtlck = (struct dt_lock *) & tlck->lock;
88362306a36Sopenharmony_ci	ASSERT(dtlck->index == 0);
88462306a36Sopenharmony_ci	lv = & dtlck->lv[0];
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* linelock header */
88762306a36Sopenharmony_ci	lv->offset = 0;
88862306a36Sopenharmony_ci	lv->length = 1;
88962306a36Sopenharmony_ci	dtlck->index++;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	dtInsertEntry(p, index, name, &data, &dtlck);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	/* linelock stbl of non-root leaf page */
89462306a36Sopenharmony_ci	if (!(p->header.flag & BT_ROOT)) {
89562306a36Sopenharmony_ci		if (dtlck->index >= dtlck->maxcnt)
89662306a36Sopenharmony_ci			dtlck = (struct dt_lock *) txLinelock(dtlck);
89762306a36Sopenharmony_ci		lv = & dtlck->lv[dtlck->index];
89862306a36Sopenharmony_ci		n = index >> L2DTSLOTSIZE;
89962306a36Sopenharmony_ci		lv->offset = p->header.stblindex + n;
90062306a36Sopenharmony_ci		lv->length =
90162306a36Sopenharmony_ci		    ((p->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1;
90262306a36Sopenharmony_ci		dtlck->index++;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	/* unpin the leaf page */
90662306a36Sopenharmony_ci	DT_PUTPAGE(mp);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	return 0;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci/*
91362306a36Sopenharmony_ci *	dtSplitUp()
91462306a36Sopenharmony_ci *
91562306a36Sopenharmony_ci * function: propagate insertion bottom up;
91662306a36Sopenharmony_ci *
91762306a36Sopenharmony_ci * parameter:
91862306a36Sopenharmony_ci *
91962306a36Sopenharmony_ci * return: 0 - success;
92062306a36Sopenharmony_ci *	   errno - failure;
92162306a36Sopenharmony_ci *	leaf page unpinned;
92262306a36Sopenharmony_ci */
92362306a36Sopenharmony_cistatic int dtSplitUp(tid_t tid,
92462306a36Sopenharmony_ci	  struct inode *ip, struct dtsplit * split, struct btstack * btstack)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
92762306a36Sopenharmony_ci	int rc = 0;
92862306a36Sopenharmony_ci	struct metapage *smp;
92962306a36Sopenharmony_ci	dtpage_t *sp;		/* split page */
93062306a36Sopenharmony_ci	struct metapage *rmp;
93162306a36Sopenharmony_ci	dtpage_t *rp;		/* new right page split from sp */
93262306a36Sopenharmony_ci	pxd_t rpxd;		/* new right page extent descriptor */
93362306a36Sopenharmony_ci	struct metapage *lmp;
93462306a36Sopenharmony_ci	dtpage_t *lp;		/* left child page */
93562306a36Sopenharmony_ci	int skip;		/* index of entry of insertion */
93662306a36Sopenharmony_ci	struct btframe *parent;	/* parent page entry on traverse stack */
93762306a36Sopenharmony_ci	s64 xaddr, nxaddr;
93862306a36Sopenharmony_ci	int xlen, xsize;
93962306a36Sopenharmony_ci	struct pxdlist pxdlist;
94062306a36Sopenharmony_ci	pxd_t *pxd;
94162306a36Sopenharmony_ci	struct component_name key = { 0, NULL };
94262306a36Sopenharmony_ci	ddata_t *data = split->data;
94362306a36Sopenharmony_ci	int n;
94462306a36Sopenharmony_ci	struct dt_lock *dtlck;
94562306a36Sopenharmony_ci	struct tlock *tlck;
94662306a36Sopenharmony_ci	struct lv *lv;
94762306a36Sopenharmony_ci	int quota_allocation = 0;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	/* get split page */
95062306a36Sopenharmony_ci	smp = split->mp;
95162306a36Sopenharmony_ci	sp = DT_PAGE(ip, smp);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	key.name = kmalloc_array(JFS_NAME_MAX + 2, sizeof(wchar_t), GFP_NOFS);
95462306a36Sopenharmony_ci	if (!key.name) {
95562306a36Sopenharmony_ci		DT_PUTPAGE(smp);
95662306a36Sopenharmony_ci		rc = -ENOMEM;
95762306a36Sopenharmony_ci		goto dtSplitUp_Exit;
95862306a36Sopenharmony_ci	}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	/*
96162306a36Sopenharmony_ci	 *	split leaf page
96262306a36Sopenharmony_ci	 *
96362306a36Sopenharmony_ci	 * The split routines insert the new entry, and
96462306a36Sopenharmony_ci	 * acquire txLock as appropriate.
96562306a36Sopenharmony_ci	 */
96662306a36Sopenharmony_ci	/*
96762306a36Sopenharmony_ci	 *	split root leaf page:
96862306a36Sopenharmony_ci	 */
96962306a36Sopenharmony_ci	if (sp->header.flag & BT_ROOT) {
97062306a36Sopenharmony_ci		/*
97162306a36Sopenharmony_ci		 * allocate a single extent child page
97262306a36Sopenharmony_ci		 */
97362306a36Sopenharmony_ci		xlen = 1;
97462306a36Sopenharmony_ci		n = sbi->bsize >> L2DTSLOTSIZE;
97562306a36Sopenharmony_ci		n -= (n + 31) >> L2DTSLOTSIZE;	/* stbl size */
97662306a36Sopenharmony_ci		n -= DTROOTMAXSLOT - sp->header.freecnt; /* header + entries */
97762306a36Sopenharmony_ci		if (n <= split->nslot)
97862306a36Sopenharmony_ci			xlen++;
97962306a36Sopenharmony_ci		if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr))) {
98062306a36Sopenharmony_ci			DT_PUTPAGE(smp);
98162306a36Sopenharmony_ci			goto freeKeyName;
98262306a36Sopenharmony_ci		}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci		pxdlist.maxnpxd = 1;
98562306a36Sopenharmony_ci		pxdlist.npxd = 0;
98662306a36Sopenharmony_ci		pxd = &pxdlist.pxd[0];
98762306a36Sopenharmony_ci		PXDaddress(pxd, xaddr);
98862306a36Sopenharmony_ci		PXDlength(pxd, xlen);
98962306a36Sopenharmony_ci		split->pxdlist = &pxdlist;
99062306a36Sopenharmony_ci		rc = dtSplitRoot(tid, ip, split, &rmp);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		if (rc)
99362306a36Sopenharmony_ci			dbFree(ip, xaddr, xlen);
99462306a36Sopenharmony_ci		else
99562306a36Sopenharmony_ci			DT_PUTPAGE(rmp);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci		DT_PUTPAGE(smp);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci		if (!DO_INDEX(ip))
100062306a36Sopenharmony_ci			ip->i_size = xlen << sbi->l2bsize;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci		goto freeKeyName;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/*
100662306a36Sopenharmony_ci	 *	extend first leaf page
100762306a36Sopenharmony_ci	 *
100862306a36Sopenharmony_ci	 * extend the 1st extent if less than buffer page size
100962306a36Sopenharmony_ci	 * (dtExtendPage() reurns leaf page unpinned)
101062306a36Sopenharmony_ci	 */
101162306a36Sopenharmony_ci	pxd = &sp->header.self;
101262306a36Sopenharmony_ci	xlen = lengthPXD(pxd);
101362306a36Sopenharmony_ci	xsize = xlen << sbi->l2bsize;
101462306a36Sopenharmony_ci	if (xsize < PSIZE) {
101562306a36Sopenharmony_ci		xaddr = addressPXD(pxd);
101662306a36Sopenharmony_ci		n = xsize >> L2DTSLOTSIZE;
101762306a36Sopenharmony_ci		n -= (n + 31) >> L2DTSLOTSIZE;	/* stbl size */
101862306a36Sopenharmony_ci		if ((n + sp->header.freecnt) <= split->nslot)
101962306a36Sopenharmony_ci			n = xlen + (xlen << 1);
102062306a36Sopenharmony_ci		else
102162306a36Sopenharmony_ci			n = xlen;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci		/* Allocate blocks to quota. */
102462306a36Sopenharmony_ci		rc = dquot_alloc_block(ip, n);
102562306a36Sopenharmony_ci		if (rc)
102662306a36Sopenharmony_ci			goto extendOut;
102762306a36Sopenharmony_ci		quota_allocation += n;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci		if ((rc = dbReAlloc(sbi->ipbmap, xaddr, (s64) xlen,
103062306a36Sopenharmony_ci				    (s64) n, &nxaddr)))
103162306a36Sopenharmony_ci			goto extendOut;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci		pxdlist.maxnpxd = 1;
103462306a36Sopenharmony_ci		pxdlist.npxd = 0;
103562306a36Sopenharmony_ci		pxd = &pxdlist.pxd[0];
103662306a36Sopenharmony_ci		PXDaddress(pxd, nxaddr);
103762306a36Sopenharmony_ci		PXDlength(pxd, xlen + n);
103862306a36Sopenharmony_ci		split->pxdlist = &pxdlist;
103962306a36Sopenharmony_ci		if ((rc = dtExtendPage(tid, ip, split, btstack))) {
104062306a36Sopenharmony_ci			nxaddr = addressPXD(pxd);
104162306a36Sopenharmony_ci			if (xaddr != nxaddr) {
104262306a36Sopenharmony_ci				/* free relocated extent */
104362306a36Sopenharmony_ci				xlen = lengthPXD(pxd);
104462306a36Sopenharmony_ci				dbFree(ip, nxaddr, (s64) xlen);
104562306a36Sopenharmony_ci			} else {
104662306a36Sopenharmony_ci				/* free extended delta */
104762306a36Sopenharmony_ci				xlen = lengthPXD(pxd) - n;
104862306a36Sopenharmony_ci				xaddr = addressPXD(pxd) + xlen;
104962306a36Sopenharmony_ci				dbFree(ip, xaddr, (s64) n);
105062306a36Sopenharmony_ci			}
105162306a36Sopenharmony_ci		} else if (!DO_INDEX(ip))
105262306a36Sopenharmony_ci			ip->i_size = lengthPXD(pxd) << sbi->l2bsize;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	      extendOut:
105662306a36Sopenharmony_ci		DT_PUTPAGE(smp);
105762306a36Sopenharmony_ci		goto freeKeyName;
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	/*
106162306a36Sopenharmony_ci	 *	split leaf page <sp> into <sp> and a new right page <rp>.
106262306a36Sopenharmony_ci	 *
106362306a36Sopenharmony_ci	 * return <rp> pinned and its extent descriptor <rpxd>
106462306a36Sopenharmony_ci	 */
106562306a36Sopenharmony_ci	/*
106662306a36Sopenharmony_ci	 * allocate new directory page extent and
106762306a36Sopenharmony_ci	 * new index page(s) to cover page split(s)
106862306a36Sopenharmony_ci	 *
106962306a36Sopenharmony_ci	 * allocation hint: ?
107062306a36Sopenharmony_ci	 */
107162306a36Sopenharmony_ci	n = btstack->nsplit;
107262306a36Sopenharmony_ci	pxdlist.maxnpxd = pxdlist.npxd = 0;
107362306a36Sopenharmony_ci	xlen = sbi->nbperpage;
107462306a36Sopenharmony_ci	for (pxd = pxdlist.pxd; n > 0; n--, pxd++) {
107562306a36Sopenharmony_ci		if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr)) == 0) {
107662306a36Sopenharmony_ci			PXDaddress(pxd, xaddr);
107762306a36Sopenharmony_ci			PXDlength(pxd, xlen);
107862306a36Sopenharmony_ci			pxdlist.maxnpxd++;
107962306a36Sopenharmony_ci			continue;
108062306a36Sopenharmony_ci		}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci		DT_PUTPAGE(smp);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci		/* undo allocation */
108562306a36Sopenharmony_ci		goto splitOut;
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	split->pxdlist = &pxdlist;
108962306a36Sopenharmony_ci	if ((rc = dtSplitPage(tid, ip, split, &rmp, &rp, &rpxd))) {
109062306a36Sopenharmony_ci		DT_PUTPAGE(smp);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		/* undo allocation */
109362306a36Sopenharmony_ci		goto splitOut;
109462306a36Sopenharmony_ci	}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	if (!DO_INDEX(ip))
109762306a36Sopenharmony_ci		ip->i_size += PSIZE;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	/*
110062306a36Sopenharmony_ci	 * propagate up the router entry for the leaf page just split
110162306a36Sopenharmony_ci	 *
110262306a36Sopenharmony_ci	 * insert a router entry for the new page into the parent page,
110362306a36Sopenharmony_ci	 * propagate the insert/split up the tree by walking back the stack
110462306a36Sopenharmony_ci	 * of (bn of parent page, index of child page entry in parent page)
110562306a36Sopenharmony_ci	 * that were traversed during the search for the page that split.
110662306a36Sopenharmony_ci	 *
110762306a36Sopenharmony_ci	 * the propagation of insert/split up the tree stops if the root
110862306a36Sopenharmony_ci	 * splits or the page inserted into doesn't have to split to hold
110962306a36Sopenharmony_ci	 * the new entry.
111062306a36Sopenharmony_ci	 *
111162306a36Sopenharmony_ci	 * the parent entry for the split page remains the same, and
111262306a36Sopenharmony_ci	 * a new entry is inserted at its right with the first key and
111362306a36Sopenharmony_ci	 * block number of the new right page.
111462306a36Sopenharmony_ci	 *
111562306a36Sopenharmony_ci	 * There are a maximum of 4 pages pinned at any time:
111662306a36Sopenharmony_ci	 * two children, left parent and right parent (when the parent splits).
111762306a36Sopenharmony_ci	 * keep the child pages pinned while working on the parent.
111862306a36Sopenharmony_ci	 * make sure that all pins are released at exit.
111962306a36Sopenharmony_ci	 */
112062306a36Sopenharmony_ci	while ((parent = BT_POP(btstack)) != NULL) {
112162306a36Sopenharmony_ci		/* parent page specified by stack frame <parent> */
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci		/* keep current child pages (<lp>, <rp>) pinned */
112462306a36Sopenharmony_ci		lmp = smp;
112562306a36Sopenharmony_ci		lp = sp;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci		/*
112862306a36Sopenharmony_ci		 * insert router entry in parent for new right child page <rp>
112962306a36Sopenharmony_ci		 */
113062306a36Sopenharmony_ci		/* get the parent page <sp> */
113162306a36Sopenharmony_ci		DT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc);
113262306a36Sopenharmony_ci		if (rc) {
113362306a36Sopenharmony_ci			DT_PUTPAGE(lmp);
113462306a36Sopenharmony_ci			DT_PUTPAGE(rmp);
113562306a36Sopenharmony_ci			goto splitOut;
113662306a36Sopenharmony_ci		}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci		/*
113962306a36Sopenharmony_ci		 * The new key entry goes ONE AFTER the index of parent entry,
114062306a36Sopenharmony_ci		 * because the split was to the right.
114162306a36Sopenharmony_ci		 */
114262306a36Sopenharmony_ci		skip = parent->index + 1;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci		/*
114562306a36Sopenharmony_ci		 * compute the key for the router entry
114662306a36Sopenharmony_ci		 *
114762306a36Sopenharmony_ci		 * key suffix compression:
114862306a36Sopenharmony_ci		 * for internal pages that have leaf pages as children,
114962306a36Sopenharmony_ci		 * retain only what's needed to distinguish between
115062306a36Sopenharmony_ci		 * the new entry and the entry on the page to its left.
115162306a36Sopenharmony_ci		 * If the keys compare equal, retain the entire key.
115262306a36Sopenharmony_ci		 *
115362306a36Sopenharmony_ci		 * note that compression is performed only at computing
115462306a36Sopenharmony_ci		 * router key at the lowest internal level.
115562306a36Sopenharmony_ci		 * further compression of the key between pairs of higher
115662306a36Sopenharmony_ci		 * level internal pages loses too much information and
115762306a36Sopenharmony_ci		 * the search may fail.
115862306a36Sopenharmony_ci		 * (e.g., two adjacent leaf pages of {a, ..., x} {xx, ...,}
115962306a36Sopenharmony_ci		 * results in two adjacent parent entries (a)(xx).
116062306a36Sopenharmony_ci		 * if split occurs between these two entries, and
116162306a36Sopenharmony_ci		 * if compression is applied, the router key of parent entry
116262306a36Sopenharmony_ci		 * of right page (x) will divert search for x into right
116362306a36Sopenharmony_ci		 * subtree and miss x in the left subtree.)
116462306a36Sopenharmony_ci		 *
116562306a36Sopenharmony_ci		 * the entire key must be retained for the next-to-leftmost
116662306a36Sopenharmony_ci		 * internal key at any level of the tree, or search may fail
116762306a36Sopenharmony_ci		 * (e.g., ?)
116862306a36Sopenharmony_ci		 */
116962306a36Sopenharmony_ci		switch (rp->header.flag & BT_TYPE) {
117062306a36Sopenharmony_ci		case BT_LEAF:
117162306a36Sopenharmony_ci			/*
117262306a36Sopenharmony_ci			 * compute the length of prefix for suffix compression
117362306a36Sopenharmony_ci			 * between last entry of left page and first entry
117462306a36Sopenharmony_ci			 * of right page
117562306a36Sopenharmony_ci			 */
117662306a36Sopenharmony_ci			if ((sp->header.flag & BT_ROOT && skip > 1) ||
117762306a36Sopenharmony_ci			    sp->header.prev != 0 || skip > 1) {
117862306a36Sopenharmony_ci				/* compute uppercase router prefix key */
117962306a36Sopenharmony_ci				rc = ciGetLeafPrefixKey(lp,
118062306a36Sopenharmony_ci							lp->header.nextindex-1,
118162306a36Sopenharmony_ci							rp, 0, &key,
118262306a36Sopenharmony_ci							sbi->mntflag);
118362306a36Sopenharmony_ci				if (rc) {
118462306a36Sopenharmony_ci					DT_PUTPAGE(lmp);
118562306a36Sopenharmony_ci					DT_PUTPAGE(rmp);
118662306a36Sopenharmony_ci					DT_PUTPAGE(smp);
118762306a36Sopenharmony_ci					goto splitOut;
118862306a36Sopenharmony_ci				}
118962306a36Sopenharmony_ci			} else {
119062306a36Sopenharmony_ci				/* next to leftmost entry of
119162306a36Sopenharmony_ci				   lowest internal level */
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci				/* compute uppercase router key */
119462306a36Sopenharmony_ci				dtGetKey(rp, 0, &key, sbi->mntflag);
119562306a36Sopenharmony_ci				key.name[key.namlen] = 0;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci				if ((sbi->mntflag & JFS_OS2) == JFS_OS2)
119862306a36Sopenharmony_ci					ciToUpper(&key);
119962306a36Sopenharmony_ci			}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci			n = NDTINTERNAL(key.namlen);
120262306a36Sopenharmony_ci			break;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci		case BT_INTERNAL:
120562306a36Sopenharmony_ci			dtGetKey(rp, 0, &key, sbi->mntflag);
120662306a36Sopenharmony_ci			n = NDTINTERNAL(key.namlen);
120762306a36Sopenharmony_ci			break;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci		default:
121062306a36Sopenharmony_ci			jfs_err("dtSplitUp(): UFO!");
121162306a36Sopenharmony_ci			break;
121262306a36Sopenharmony_ci		}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci		/* unpin left child page */
121562306a36Sopenharmony_ci		DT_PUTPAGE(lmp);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci		/*
121862306a36Sopenharmony_ci		 * compute the data for the router entry
121962306a36Sopenharmony_ci		 */
122062306a36Sopenharmony_ci		data->xd = rpxd;	/* child page xd */
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci		/*
122362306a36Sopenharmony_ci		 * parent page is full - split the parent page
122462306a36Sopenharmony_ci		 */
122562306a36Sopenharmony_ci		if (n > sp->header.freecnt) {
122662306a36Sopenharmony_ci			/* init for parent page split */
122762306a36Sopenharmony_ci			split->mp = smp;
122862306a36Sopenharmony_ci			split->index = skip;	/* index at insert */
122962306a36Sopenharmony_ci			split->nslot = n;
123062306a36Sopenharmony_ci			split->key = &key;
123162306a36Sopenharmony_ci			/* split->data = data; */
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci			/* unpin right child page */
123462306a36Sopenharmony_ci			DT_PUTPAGE(rmp);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci			/* The split routines insert the new entry,
123762306a36Sopenharmony_ci			 * acquire txLock as appropriate.
123862306a36Sopenharmony_ci			 * return <rp> pinned and its block number <rbn>.
123962306a36Sopenharmony_ci			 */
124062306a36Sopenharmony_ci			rc = (sp->header.flag & BT_ROOT) ?
124162306a36Sopenharmony_ci			    dtSplitRoot(tid, ip, split, &rmp) :
124262306a36Sopenharmony_ci			    dtSplitPage(tid, ip, split, &rmp, &rp, &rpxd);
124362306a36Sopenharmony_ci			if (rc) {
124462306a36Sopenharmony_ci				DT_PUTPAGE(smp);
124562306a36Sopenharmony_ci				goto splitOut;
124662306a36Sopenharmony_ci			}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci			/* smp and rmp are pinned */
124962306a36Sopenharmony_ci		}
125062306a36Sopenharmony_ci		/*
125162306a36Sopenharmony_ci		 * parent page is not full - insert router entry in parent page
125262306a36Sopenharmony_ci		 */
125362306a36Sopenharmony_ci		else {
125462306a36Sopenharmony_ci			BT_MARK_DIRTY(smp, ip);
125562306a36Sopenharmony_ci			/*
125662306a36Sopenharmony_ci			 * acquire a transaction lock on the parent page
125762306a36Sopenharmony_ci			 */
125862306a36Sopenharmony_ci			tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
125962306a36Sopenharmony_ci			dtlck = (struct dt_lock *) & tlck->lock;
126062306a36Sopenharmony_ci			ASSERT(dtlck->index == 0);
126162306a36Sopenharmony_ci			lv = & dtlck->lv[0];
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci			/* linelock header */
126462306a36Sopenharmony_ci			lv->offset = 0;
126562306a36Sopenharmony_ci			lv->length = 1;
126662306a36Sopenharmony_ci			dtlck->index++;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci			/* linelock stbl of non-root parent page */
126962306a36Sopenharmony_ci			if (!(sp->header.flag & BT_ROOT)) {
127062306a36Sopenharmony_ci				lv++;
127162306a36Sopenharmony_ci				n = skip >> L2DTSLOTSIZE;
127262306a36Sopenharmony_ci				lv->offset = sp->header.stblindex + n;
127362306a36Sopenharmony_ci				lv->length =
127462306a36Sopenharmony_ci				    ((sp->header.nextindex -
127562306a36Sopenharmony_ci				      1) >> L2DTSLOTSIZE) - n + 1;
127662306a36Sopenharmony_ci				dtlck->index++;
127762306a36Sopenharmony_ci			}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci			dtInsertEntry(sp, skip, &key, data, &dtlck);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci			/* exit propagate up */
128262306a36Sopenharmony_ci			break;
128362306a36Sopenharmony_ci		}
128462306a36Sopenharmony_ci	}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	/* unpin current split and its right page */
128762306a36Sopenharmony_ci	DT_PUTPAGE(smp);
128862306a36Sopenharmony_ci	DT_PUTPAGE(rmp);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/*
129162306a36Sopenharmony_ci	 * free remaining extents allocated for split
129262306a36Sopenharmony_ci	 */
129362306a36Sopenharmony_ci      splitOut:
129462306a36Sopenharmony_ci	n = pxdlist.npxd;
129562306a36Sopenharmony_ci	pxd = &pxdlist.pxd[n];
129662306a36Sopenharmony_ci	for (; n < pxdlist.maxnpxd; n++, pxd++)
129762306a36Sopenharmony_ci		dbFree(ip, addressPXD(pxd), (s64) lengthPXD(pxd));
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci      freeKeyName:
130062306a36Sopenharmony_ci	kfree(key.name);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	/* Rollback quota allocation */
130362306a36Sopenharmony_ci	if (rc && quota_allocation)
130462306a36Sopenharmony_ci		dquot_free_block(ip, quota_allocation);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci      dtSplitUp_Exit:
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	return rc;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci/*
131362306a36Sopenharmony_ci *	dtSplitPage()
131462306a36Sopenharmony_ci *
131562306a36Sopenharmony_ci * function: Split a non-root page of a btree.
131662306a36Sopenharmony_ci *
131762306a36Sopenharmony_ci * parameter:
131862306a36Sopenharmony_ci *
131962306a36Sopenharmony_ci * return: 0 - success;
132062306a36Sopenharmony_ci *	   errno - failure;
132162306a36Sopenharmony_ci *	return split and new page pinned;
132262306a36Sopenharmony_ci */
132362306a36Sopenharmony_cistatic int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
132462306a36Sopenharmony_ci	    struct metapage ** rmpp, dtpage_t ** rpp, pxd_t * rpxdp)
132562306a36Sopenharmony_ci{
132662306a36Sopenharmony_ci	int rc = 0;
132762306a36Sopenharmony_ci	struct metapage *smp;
132862306a36Sopenharmony_ci	dtpage_t *sp;
132962306a36Sopenharmony_ci	struct metapage *rmp;
133062306a36Sopenharmony_ci	dtpage_t *rp;		/* new right page allocated */
133162306a36Sopenharmony_ci	s64 rbn;		/* new right page block number */
133262306a36Sopenharmony_ci	struct metapage *mp;
133362306a36Sopenharmony_ci	dtpage_t *p;
133462306a36Sopenharmony_ci	s64 nextbn;
133562306a36Sopenharmony_ci	struct pxdlist *pxdlist;
133662306a36Sopenharmony_ci	pxd_t *pxd;
133762306a36Sopenharmony_ci	int skip, nextindex, half, left, nxt, off, si;
133862306a36Sopenharmony_ci	struct ldtentry *ldtentry;
133962306a36Sopenharmony_ci	struct idtentry *idtentry;
134062306a36Sopenharmony_ci	u8 *stbl;
134162306a36Sopenharmony_ci	struct dtslot *f;
134262306a36Sopenharmony_ci	int fsi, stblsize;
134362306a36Sopenharmony_ci	int n;
134462306a36Sopenharmony_ci	struct dt_lock *sdtlck, *rdtlck;
134562306a36Sopenharmony_ci	struct tlock *tlck;
134662306a36Sopenharmony_ci	struct dt_lock *dtlck;
134762306a36Sopenharmony_ci	struct lv *slv, *rlv, *lv;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	/* get split page */
135062306a36Sopenharmony_ci	smp = split->mp;
135162306a36Sopenharmony_ci	sp = DT_PAGE(ip, smp);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	/*
135462306a36Sopenharmony_ci	 * allocate the new right page for the split
135562306a36Sopenharmony_ci	 */
135662306a36Sopenharmony_ci	pxdlist = split->pxdlist;
135762306a36Sopenharmony_ci	pxd = &pxdlist->pxd[pxdlist->npxd];
135862306a36Sopenharmony_ci	pxdlist->npxd++;
135962306a36Sopenharmony_ci	rbn = addressPXD(pxd);
136062306a36Sopenharmony_ci	rmp = get_metapage(ip, rbn, PSIZE, 1);
136162306a36Sopenharmony_ci	if (rmp == NULL)
136262306a36Sopenharmony_ci		return -EIO;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	/* Allocate blocks to quota. */
136562306a36Sopenharmony_ci	rc = dquot_alloc_block(ip, lengthPXD(pxd));
136662306a36Sopenharmony_ci	if (rc) {
136762306a36Sopenharmony_ci		release_metapage(rmp);
136862306a36Sopenharmony_ci		return rc;
136962306a36Sopenharmony_ci	}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	jfs_info("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	BT_MARK_DIRTY(rmp, ip);
137462306a36Sopenharmony_ci	/*
137562306a36Sopenharmony_ci	 * acquire a transaction lock on the new right page
137662306a36Sopenharmony_ci	 */
137762306a36Sopenharmony_ci	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
137862306a36Sopenharmony_ci	rdtlck = (struct dt_lock *) & tlck->lock;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	rp = (dtpage_t *) rmp->data;
138162306a36Sopenharmony_ci	*rpp = rp;
138262306a36Sopenharmony_ci	rp->header.self = *pxd;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	BT_MARK_DIRTY(smp, ip);
138562306a36Sopenharmony_ci	/*
138662306a36Sopenharmony_ci	 * acquire a transaction lock on the split page
138762306a36Sopenharmony_ci	 *
138862306a36Sopenharmony_ci	 * action:
138962306a36Sopenharmony_ci	 */
139062306a36Sopenharmony_ci	tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
139162306a36Sopenharmony_ci	sdtlck = (struct dt_lock *) & tlck->lock;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	/* linelock header of split page */
139462306a36Sopenharmony_ci	ASSERT(sdtlck->index == 0);
139562306a36Sopenharmony_ci	slv = & sdtlck->lv[0];
139662306a36Sopenharmony_ci	slv->offset = 0;
139762306a36Sopenharmony_ci	slv->length = 1;
139862306a36Sopenharmony_ci	sdtlck->index++;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/*
140162306a36Sopenharmony_ci	 * initialize/update sibling pointers between sp and rp
140262306a36Sopenharmony_ci	 */
140362306a36Sopenharmony_ci	nextbn = le64_to_cpu(sp->header.next);
140462306a36Sopenharmony_ci	rp->header.next = cpu_to_le64(nextbn);
140562306a36Sopenharmony_ci	rp->header.prev = cpu_to_le64(addressPXD(&sp->header.self));
140662306a36Sopenharmony_ci	sp->header.next = cpu_to_le64(rbn);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	/*
140962306a36Sopenharmony_ci	 * initialize new right page
141062306a36Sopenharmony_ci	 */
141162306a36Sopenharmony_ci	rp->header.flag = sp->header.flag;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	/* compute sorted entry table at start of extent data area */
141462306a36Sopenharmony_ci	rp->header.nextindex = 0;
141562306a36Sopenharmony_ci	rp->header.stblindex = 1;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	n = PSIZE >> L2DTSLOTSIZE;
141862306a36Sopenharmony_ci	rp->header.maxslot = n;
141962306a36Sopenharmony_ci	stblsize = (n + 31) >> L2DTSLOTSIZE;	/* in unit of slot */
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	/* init freelist */
142262306a36Sopenharmony_ci	fsi = rp->header.stblindex + stblsize;
142362306a36Sopenharmony_ci	rp->header.freelist = fsi;
142462306a36Sopenharmony_ci	rp->header.freecnt = rp->header.maxslot - fsi;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	/*
142762306a36Sopenharmony_ci	 *	sequential append at tail: append without split
142862306a36Sopenharmony_ci	 *
142962306a36Sopenharmony_ci	 * If splitting the last page on a level because of appending
143062306a36Sopenharmony_ci	 * a entry to it (skip is maxentry), it's likely that the access is
143162306a36Sopenharmony_ci	 * sequential. Adding an empty page on the side of the level is less
143262306a36Sopenharmony_ci	 * work and can push the fill factor much higher than normal.
143362306a36Sopenharmony_ci	 * If we're wrong it's no big deal, we'll just do the split the right
143462306a36Sopenharmony_ci	 * way next time.
143562306a36Sopenharmony_ci	 * (It may look like it's equally easy to do a similar hack for
143662306a36Sopenharmony_ci	 * reverse sorted data, that is, split the tree left,
143762306a36Sopenharmony_ci	 * but it's not. Be my guest.)
143862306a36Sopenharmony_ci	 */
143962306a36Sopenharmony_ci	if (nextbn == 0 && split->index == sp->header.nextindex) {
144062306a36Sopenharmony_ci		/* linelock header + stbl (first slot) of new page */
144162306a36Sopenharmony_ci		rlv = & rdtlck->lv[rdtlck->index];
144262306a36Sopenharmony_ci		rlv->offset = 0;
144362306a36Sopenharmony_ci		rlv->length = 2;
144462306a36Sopenharmony_ci		rdtlck->index++;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci		/*
144762306a36Sopenharmony_ci		 * initialize freelist of new right page
144862306a36Sopenharmony_ci		 */
144962306a36Sopenharmony_ci		f = &rp->slot[fsi];
145062306a36Sopenharmony_ci		for (fsi++; fsi < rp->header.maxslot; f++, fsi++)
145162306a36Sopenharmony_ci			f->next = fsi;
145262306a36Sopenharmony_ci		f->next = -1;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci		/* insert entry at the first entry of the new right page */
145562306a36Sopenharmony_ci		dtInsertEntry(rp, 0, split->key, split->data, &rdtlck);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci		goto out;
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/*
146162306a36Sopenharmony_ci	 *	non-sequential insert (at possibly middle page)
146262306a36Sopenharmony_ci	 */
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	/*
146562306a36Sopenharmony_ci	 * update prev pointer of previous right sibling page;
146662306a36Sopenharmony_ci	 */
146762306a36Sopenharmony_ci	if (nextbn != 0) {
146862306a36Sopenharmony_ci		DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
146962306a36Sopenharmony_ci		if (rc) {
147062306a36Sopenharmony_ci			discard_metapage(rmp);
147162306a36Sopenharmony_ci			return rc;
147262306a36Sopenharmony_ci		}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		BT_MARK_DIRTY(mp, ip);
147562306a36Sopenharmony_ci		/*
147662306a36Sopenharmony_ci		 * acquire a transaction lock on the next page
147762306a36Sopenharmony_ci		 */
147862306a36Sopenharmony_ci		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
147962306a36Sopenharmony_ci		jfs_info("dtSplitPage: tlck = 0x%p, ip = 0x%p, mp=0x%p",
148062306a36Sopenharmony_ci			tlck, ip, mp);
148162306a36Sopenharmony_ci		dtlck = (struct dt_lock *) & tlck->lock;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci		/* linelock header of previous right sibling page */
148462306a36Sopenharmony_ci		lv = & dtlck->lv[dtlck->index];
148562306a36Sopenharmony_ci		lv->offset = 0;
148662306a36Sopenharmony_ci		lv->length = 1;
148762306a36Sopenharmony_ci		dtlck->index++;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		p->header.prev = cpu_to_le64(rbn);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci		DT_PUTPAGE(mp);
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	/*
149562306a36Sopenharmony_ci	 * split the data between the split and right pages.
149662306a36Sopenharmony_ci	 */
149762306a36Sopenharmony_ci	skip = split->index;
149862306a36Sopenharmony_ci	half = (PSIZE >> L2DTSLOTSIZE) >> 1;	/* swag */
149962306a36Sopenharmony_ci	left = 0;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	/*
150262306a36Sopenharmony_ci	 *	compute fill factor for split pages
150362306a36Sopenharmony_ci	 *
150462306a36Sopenharmony_ci	 * <nxt> traces the next entry to move to rp
150562306a36Sopenharmony_ci	 * <off> traces the next entry to stay in sp
150662306a36Sopenharmony_ci	 */
150762306a36Sopenharmony_ci	stbl = (u8 *) & sp->slot[sp->header.stblindex];
150862306a36Sopenharmony_ci	nextindex = sp->header.nextindex;
150962306a36Sopenharmony_ci	for (nxt = off = 0; nxt < nextindex; ++off) {
151062306a36Sopenharmony_ci		if (off == skip)
151162306a36Sopenharmony_ci			/* check for fill factor with new entry size */
151262306a36Sopenharmony_ci			n = split->nslot;
151362306a36Sopenharmony_ci		else {
151462306a36Sopenharmony_ci			si = stbl[nxt];
151562306a36Sopenharmony_ci			switch (sp->header.flag & BT_TYPE) {
151662306a36Sopenharmony_ci			case BT_LEAF:
151762306a36Sopenharmony_ci				ldtentry = (struct ldtentry *) & sp->slot[si];
151862306a36Sopenharmony_ci				if (DO_INDEX(ip))
151962306a36Sopenharmony_ci					n = NDTLEAF(ldtentry->namlen);
152062306a36Sopenharmony_ci				else
152162306a36Sopenharmony_ci					n = NDTLEAF_LEGACY(ldtentry->
152262306a36Sopenharmony_ci							   namlen);
152362306a36Sopenharmony_ci				break;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci			case BT_INTERNAL:
152662306a36Sopenharmony_ci				idtentry = (struct idtentry *) & sp->slot[si];
152762306a36Sopenharmony_ci				n = NDTINTERNAL(idtentry->namlen);
152862306a36Sopenharmony_ci				break;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci			default:
153162306a36Sopenharmony_ci				break;
153262306a36Sopenharmony_ci			}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci			++nxt;	/* advance to next entry to move in sp */
153562306a36Sopenharmony_ci		}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci		left += n;
153862306a36Sopenharmony_ci		if (left >= half)
153962306a36Sopenharmony_ci			break;
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	/* <nxt> poins to the 1st entry to move */
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	/*
154562306a36Sopenharmony_ci	 *	move entries to right page
154662306a36Sopenharmony_ci	 *
154762306a36Sopenharmony_ci	 * dtMoveEntry() initializes rp and reserves entry for insertion
154862306a36Sopenharmony_ci	 *
154962306a36Sopenharmony_ci	 * split page moved out entries are linelocked;
155062306a36Sopenharmony_ci	 * new/right page moved in entries are linelocked;
155162306a36Sopenharmony_ci	 */
155262306a36Sopenharmony_ci	/* linelock header + stbl of new right page */
155362306a36Sopenharmony_ci	rlv = & rdtlck->lv[rdtlck->index];
155462306a36Sopenharmony_ci	rlv->offset = 0;
155562306a36Sopenharmony_ci	rlv->length = 5;
155662306a36Sopenharmony_ci	rdtlck->index++;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	dtMoveEntry(sp, nxt, rp, &sdtlck, &rdtlck, DO_INDEX(ip));
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	sp->header.nextindex = nxt;
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	/*
156362306a36Sopenharmony_ci	 * finalize freelist of new right page
156462306a36Sopenharmony_ci	 */
156562306a36Sopenharmony_ci	fsi = rp->header.freelist;
156662306a36Sopenharmony_ci	f = &rp->slot[fsi];
156762306a36Sopenharmony_ci	for (fsi++; fsi < rp->header.maxslot; f++, fsi++)
156862306a36Sopenharmony_ci		f->next = fsi;
156962306a36Sopenharmony_ci	f->next = -1;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	/*
157262306a36Sopenharmony_ci	 * Update directory index table for entries now in right page
157362306a36Sopenharmony_ci	 */
157462306a36Sopenharmony_ci	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
157562306a36Sopenharmony_ci		s64 lblock;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci		mp = NULL;
157862306a36Sopenharmony_ci		stbl = DT_GETSTBL(rp);
157962306a36Sopenharmony_ci		for (n = 0; n < rp->header.nextindex; n++) {
158062306a36Sopenharmony_ci			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
158162306a36Sopenharmony_ci			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
158262306a36Sopenharmony_ci				     rbn, n, &mp, &lblock);
158362306a36Sopenharmony_ci		}
158462306a36Sopenharmony_ci		if (mp)
158562306a36Sopenharmony_ci			release_metapage(mp);
158662306a36Sopenharmony_ci	}
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	/*
158962306a36Sopenharmony_ci	 * the skipped index was on the left page,
159062306a36Sopenharmony_ci	 */
159162306a36Sopenharmony_ci	if (skip <= off) {
159262306a36Sopenharmony_ci		/* insert the new entry in the split page */
159362306a36Sopenharmony_ci		dtInsertEntry(sp, skip, split->key, split->data, &sdtlck);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci		/* linelock stbl of split page */
159662306a36Sopenharmony_ci		if (sdtlck->index >= sdtlck->maxcnt)
159762306a36Sopenharmony_ci			sdtlck = (struct dt_lock *) txLinelock(sdtlck);
159862306a36Sopenharmony_ci		slv = & sdtlck->lv[sdtlck->index];
159962306a36Sopenharmony_ci		n = skip >> L2DTSLOTSIZE;
160062306a36Sopenharmony_ci		slv->offset = sp->header.stblindex + n;
160162306a36Sopenharmony_ci		slv->length =
160262306a36Sopenharmony_ci		    ((sp->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1;
160362306a36Sopenharmony_ci		sdtlck->index++;
160462306a36Sopenharmony_ci	}
160562306a36Sopenharmony_ci	/*
160662306a36Sopenharmony_ci	 * the skipped index was on the right page,
160762306a36Sopenharmony_ci	 */
160862306a36Sopenharmony_ci	else {
160962306a36Sopenharmony_ci		/* adjust the skip index to reflect the new position */
161062306a36Sopenharmony_ci		skip -= nxt;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci		/* insert the new entry in the right page */
161362306a36Sopenharmony_ci		dtInsertEntry(rp, skip, split->key, split->data, &rdtlck);
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci      out:
161762306a36Sopenharmony_ci	*rmpp = rmp;
161862306a36Sopenharmony_ci	*rpxdp = *pxd;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	return rc;
162162306a36Sopenharmony_ci}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci/*
162562306a36Sopenharmony_ci *	dtExtendPage()
162662306a36Sopenharmony_ci *
162762306a36Sopenharmony_ci * function: extend 1st/only directory leaf page
162862306a36Sopenharmony_ci *
162962306a36Sopenharmony_ci * parameter:
163062306a36Sopenharmony_ci *
163162306a36Sopenharmony_ci * return: 0 - success;
163262306a36Sopenharmony_ci *	   errno - failure;
163362306a36Sopenharmony_ci *	return extended page pinned;
163462306a36Sopenharmony_ci */
163562306a36Sopenharmony_cistatic int dtExtendPage(tid_t tid,
163662306a36Sopenharmony_ci	     struct inode *ip, struct dtsplit * split, struct btstack * btstack)
163762306a36Sopenharmony_ci{
163862306a36Sopenharmony_ci	struct super_block *sb = ip->i_sb;
163962306a36Sopenharmony_ci	int rc;
164062306a36Sopenharmony_ci	struct metapage *smp, *pmp, *mp;
164162306a36Sopenharmony_ci	dtpage_t *sp, *pp;
164262306a36Sopenharmony_ci	struct pxdlist *pxdlist;
164362306a36Sopenharmony_ci	pxd_t *pxd, *tpxd;
164462306a36Sopenharmony_ci	int xlen, xsize;
164562306a36Sopenharmony_ci	int newstblindex, newstblsize;
164662306a36Sopenharmony_ci	int oldstblindex, oldstblsize;
164762306a36Sopenharmony_ci	int fsi, last;
164862306a36Sopenharmony_ci	struct dtslot *f;
164962306a36Sopenharmony_ci	struct btframe *parent;
165062306a36Sopenharmony_ci	int n;
165162306a36Sopenharmony_ci	struct dt_lock *dtlck;
165262306a36Sopenharmony_ci	s64 xaddr, txaddr;
165362306a36Sopenharmony_ci	struct tlock *tlck;
165462306a36Sopenharmony_ci	struct pxd_lock *pxdlock;
165562306a36Sopenharmony_ci	struct lv *lv;
165662306a36Sopenharmony_ci	uint type;
165762306a36Sopenharmony_ci	struct ldtentry *ldtentry;
165862306a36Sopenharmony_ci	u8 *stbl;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	/* get page to extend */
166162306a36Sopenharmony_ci	smp = split->mp;
166262306a36Sopenharmony_ci	sp = DT_PAGE(ip, smp);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	/* get parent/root page */
166562306a36Sopenharmony_ci	parent = BT_POP(btstack);
166662306a36Sopenharmony_ci	DT_GETPAGE(ip, parent->bn, pmp, PSIZE, pp, rc);
166762306a36Sopenharmony_ci	if (rc)
166862306a36Sopenharmony_ci		return (rc);
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	/*
167162306a36Sopenharmony_ci	 *	extend the extent
167262306a36Sopenharmony_ci	 */
167362306a36Sopenharmony_ci	pxdlist = split->pxdlist;
167462306a36Sopenharmony_ci	pxd = &pxdlist->pxd[pxdlist->npxd];
167562306a36Sopenharmony_ci	pxdlist->npxd++;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	xaddr = addressPXD(pxd);
167862306a36Sopenharmony_ci	tpxd = &sp->header.self;
167962306a36Sopenharmony_ci	txaddr = addressPXD(tpxd);
168062306a36Sopenharmony_ci	/* in-place extension */
168162306a36Sopenharmony_ci	if (xaddr == txaddr) {
168262306a36Sopenharmony_ci		type = tlckEXTEND;
168362306a36Sopenharmony_ci	}
168462306a36Sopenharmony_ci	/* relocation */
168562306a36Sopenharmony_ci	else {
168662306a36Sopenharmony_ci		type = tlckNEW;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci		/* save moved extent descriptor for later free */
168962306a36Sopenharmony_ci		tlck = txMaplock(tid, ip, tlckDTREE | tlckRELOCATE);
169062306a36Sopenharmony_ci		pxdlock = (struct pxd_lock *) & tlck->lock;
169162306a36Sopenharmony_ci		pxdlock->flag = mlckFREEPXD;
169262306a36Sopenharmony_ci		pxdlock->pxd = sp->header.self;
169362306a36Sopenharmony_ci		pxdlock->index = 1;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci		/*
169662306a36Sopenharmony_ci		 * Update directory index table to reflect new page address
169762306a36Sopenharmony_ci		 */
169862306a36Sopenharmony_ci		if (DO_INDEX(ip)) {
169962306a36Sopenharmony_ci			s64 lblock;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci			mp = NULL;
170262306a36Sopenharmony_ci			stbl = DT_GETSTBL(sp);
170362306a36Sopenharmony_ci			for (n = 0; n < sp->header.nextindex; n++) {
170462306a36Sopenharmony_ci				ldtentry =
170562306a36Sopenharmony_ci				    (struct ldtentry *) & sp->slot[stbl[n]];
170662306a36Sopenharmony_ci				modify_index(tid, ip,
170762306a36Sopenharmony_ci					     le32_to_cpu(ldtentry->index),
170862306a36Sopenharmony_ci					     xaddr, n, &mp, &lblock);
170962306a36Sopenharmony_ci			}
171062306a36Sopenharmony_ci			if (mp)
171162306a36Sopenharmony_ci				release_metapage(mp);
171262306a36Sopenharmony_ci		}
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	/*
171662306a36Sopenharmony_ci	 *	extend the page
171762306a36Sopenharmony_ci	 */
171862306a36Sopenharmony_ci	sp->header.self = *pxd;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	jfs_info("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p", ip, smp, sp);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	BT_MARK_DIRTY(smp, ip);
172362306a36Sopenharmony_ci	/*
172462306a36Sopenharmony_ci	 * acquire a transaction lock on the extended/leaf page
172562306a36Sopenharmony_ci	 */
172662306a36Sopenharmony_ci	tlck = txLock(tid, ip, smp, tlckDTREE | type);
172762306a36Sopenharmony_ci	dtlck = (struct dt_lock *) & tlck->lock;
172862306a36Sopenharmony_ci	lv = & dtlck->lv[0];
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	/* update buffer extent descriptor of extended page */
173162306a36Sopenharmony_ci	xlen = lengthPXD(pxd);
173262306a36Sopenharmony_ci	xsize = xlen << JFS_SBI(sb)->l2bsize;
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	/*
173562306a36Sopenharmony_ci	 * copy old stbl to new stbl at start of extended area
173662306a36Sopenharmony_ci	 */
173762306a36Sopenharmony_ci	oldstblindex = sp->header.stblindex;
173862306a36Sopenharmony_ci	oldstblsize = (sp->header.maxslot + 31) >> L2DTSLOTSIZE;
173962306a36Sopenharmony_ci	newstblindex = sp->header.maxslot;
174062306a36Sopenharmony_ci	n = xsize >> L2DTSLOTSIZE;
174162306a36Sopenharmony_ci	newstblsize = (n + 31) >> L2DTSLOTSIZE;
174262306a36Sopenharmony_ci	memcpy(&sp->slot[newstblindex], &sp->slot[oldstblindex],
174362306a36Sopenharmony_ci	       sp->header.nextindex);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	/*
174662306a36Sopenharmony_ci	 * in-line extension: linelock old area of extended page
174762306a36Sopenharmony_ci	 */
174862306a36Sopenharmony_ci	if (type == tlckEXTEND) {
174962306a36Sopenharmony_ci		/* linelock header */
175062306a36Sopenharmony_ci		lv->offset = 0;
175162306a36Sopenharmony_ci		lv->length = 1;
175262306a36Sopenharmony_ci		dtlck->index++;
175362306a36Sopenharmony_ci		lv++;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci		/* linelock new stbl of extended page */
175662306a36Sopenharmony_ci		lv->offset = newstblindex;
175762306a36Sopenharmony_ci		lv->length = newstblsize;
175862306a36Sopenharmony_ci	}
175962306a36Sopenharmony_ci	/*
176062306a36Sopenharmony_ci	 * relocation: linelock whole relocated area
176162306a36Sopenharmony_ci	 */
176262306a36Sopenharmony_ci	else {
176362306a36Sopenharmony_ci		lv->offset = 0;
176462306a36Sopenharmony_ci		lv->length = sp->header.maxslot + newstblsize;
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	dtlck->index++;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	sp->header.maxslot = n;
177062306a36Sopenharmony_ci	sp->header.stblindex = newstblindex;
177162306a36Sopenharmony_ci	/* sp->header.nextindex remains the same */
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	/*
177462306a36Sopenharmony_ci	 * add old stbl region at head of freelist
177562306a36Sopenharmony_ci	 */
177662306a36Sopenharmony_ci	fsi = oldstblindex;
177762306a36Sopenharmony_ci	f = &sp->slot[fsi];
177862306a36Sopenharmony_ci	last = sp->header.freelist;
177962306a36Sopenharmony_ci	for (n = 0; n < oldstblsize; n++, fsi++, f++) {
178062306a36Sopenharmony_ci		f->next = last;
178162306a36Sopenharmony_ci		last = fsi;
178262306a36Sopenharmony_ci	}
178362306a36Sopenharmony_ci	sp->header.freelist = last;
178462306a36Sopenharmony_ci	sp->header.freecnt += oldstblsize;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	/*
178762306a36Sopenharmony_ci	 * append free region of newly extended area at tail of freelist
178862306a36Sopenharmony_ci	 */
178962306a36Sopenharmony_ci	/* init free region of newly extended area */
179062306a36Sopenharmony_ci	fsi = n = newstblindex + newstblsize;
179162306a36Sopenharmony_ci	f = &sp->slot[fsi];
179262306a36Sopenharmony_ci	for (fsi++; fsi < sp->header.maxslot; f++, fsi++)
179362306a36Sopenharmony_ci		f->next = fsi;
179462306a36Sopenharmony_ci	f->next = -1;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	/* append new free region at tail of old freelist */
179762306a36Sopenharmony_ci	fsi = sp->header.freelist;
179862306a36Sopenharmony_ci	if (fsi == -1)
179962306a36Sopenharmony_ci		sp->header.freelist = n;
180062306a36Sopenharmony_ci	else {
180162306a36Sopenharmony_ci		do {
180262306a36Sopenharmony_ci			f = &sp->slot[fsi];
180362306a36Sopenharmony_ci			fsi = f->next;
180462306a36Sopenharmony_ci		} while (fsi != -1);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci		f->next = n;
180762306a36Sopenharmony_ci	}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	sp->header.freecnt += sp->header.maxslot - n;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	/*
181262306a36Sopenharmony_ci	 * insert the new entry
181362306a36Sopenharmony_ci	 */
181462306a36Sopenharmony_ci	dtInsertEntry(sp, split->index, split->key, split->data, &dtlck);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	BT_MARK_DIRTY(pmp, ip);
181762306a36Sopenharmony_ci	/*
181862306a36Sopenharmony_ci	 * linelock any freeslots residing in old extent
181962306a36Sopenharmony_ci	 */
182062306a36Sopenharmony_ci	if (type == tlckEXTEND) {
182162306a36Sopenharmony_ci		n = sp->header.maxslot >> 2;
182262306a36Sopenharmony_ci		if (sp->header.freelist < n)
182362306a36Sopenharmony_ci			dtLinelockFreelist(sp, n, &dtlck);
182462306a36Sopenharmony_ci	}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	/*
182762306a36Sopenharmony_ci	 *	update parent entry on the parent/root page
182862306a36Sopenharmony_ci	 */
182962306a36Sopenharmony_ci	/*
183062306a36Sopenharmony_ci	 * acquire a transaction lock on the parent/root page
183162306a36Sopenharmony_ci	 */
183262306a36Sopenharmony_ci	tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
183362306a36Sopenharmony_ci	dtlck = (struct dt_lock *) & tlck->lock;
183462306a36Sopenharmony_ci	lv = & dtlck->lv[dtlck->index];
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	/* linelock parent entry - 1st slot */
183762306a36Sopenharmony_ci	lv->offset = 1;
183862306a36Sopenharmony_ci	lv->length = 1;
183962306a36Sopenharmony_ci	dtlck->index++;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	/* update the parent pxd for page extension */
184262306a36Sopenharmony_ci	tpxd = (pxd_t *) & pp->slot[1];
184362306a36Sopenharmony_ci	*tpxd = *pxd;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	DT_PUTPAGE(pmp);
184662306a36Sopenharmony_ci	return 0;
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci/*
185162306a36Sopenharmony_ci *	dtSplitRoot()
185262306a36Sopenharmony_ci *
185362306a36Sopenharmony_ci * function:
185462306a36Sopenharmony_ci *	split the full root page into
185562306a36Sopenharmony_ci *	original/root/split page and new right page
185662306a36Sopenharmony_ci *	i.e., root remains fixed in tree anchor (inode) and
185762306a36Sopenharmony_ci *	the root is copied to a single new right child page
185862306a36Sopenharmony_ci *	since root page << non-root page, and
185962306a36Sopenharmony_ci *	the split root page contains a single entry for the
186062306a36Sopenharmony_ci *	new right child page.
186162306a36Sopenharmony_ci *
186262306a36Sopenharmony_ci * parameter:
186362306a36Sopenharmony_ci *
186462306a36Sopenharmony_ci * return: 0 - success;
186562306a36Sopenharmony_ci *	   errno - failure;
186662306a36Sopenharmony_ci *	return new page pinned;
186762306a36Sopenharmony_ci */
186862306a36Sopenharmony_cistatic int dtSplitRoot(tid_t tid,
186962306a36Sopenharmony_ci	    struct inode *ip, struct dtsplit * split, struct metapage ** rmpp)
187062306a36Sopenharmony_ci{
187162306a36Sopenharmony_ci	struct super_block *sb = ip->i_sb;
187262306a36Sopenharmony_ci	struct metapage *smp;
187362306a36Sopenharmony_ci	dtroot_t *sp;
187462306a36Sopenharmony_ci	struct metapage *rmp;
187562306a36Sopenharmony_ci	dtpage_t *rp;
187662306a36Sopenharmony_ci	s64 rbn;
187762306a36Sopenharmony_ci	int xlen;
187862306a36Sopenharmony_ci	int xsize;
187962306a36Sopenharmony_ci	struct dtslot *f;
188062306a36Sopenharmony_ci	s8 *stbl;
188162306a36Sopenharmony_ci	int fsi, stblsize, n;
188262306a36Sopenharmony_ci	struct idtentry *s;
188362306a36Sopenharmony_ci	pxd_t *ppxd;
188462306a36Sopenharmony_ci	struct pxdlist *pxdlist;
188562306a36Sopenharmony_ci	pxd_t *pxd;
188662306a36Sopenharmony_ci	struct dt_lock *dtlck;
188762306a36Sopenharmony_ci	struct tlock *tlck;
188862306a36Sopenharmony_ci	struct lv *lv;
188962306a36Sopenharmony_ci	int rc;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	/* get split root page */
189262306a36Sopenharmony_ci	smp = split->mp;
189362306a36Sopenharmony_ci	sp = &JFS_IP(ip)->i_dtroot;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	/*
189662306a36Sopenharmony_ci	 *	allocate/initialize a single (right) child page
189762306a36Sopenharmony_ci	 *
189862306a36Sopenharmony_ci	 * N.B. at first split, a one (or two) block to fit new entry
189962306a36Sopenharmony_ci	 * is allocated; at subsequent split, a full page is allocated;
190062306a36Sopenharmony_ci	 */
190162306a36Sopenharmony_ci	pxdlist = split->pxdlist;
190262306a36Sopenharmony_ci	pxd = &pxdlist->pxd[pxdlist->npxd];
190362306a36Sopenharmony_ci	pxdlist->npxd++;
190462306a36Sopenharmony_ci	rbn = addressPXD(pxd);
190562306a36Sopenharmony_ci	xlen = lengthPXD(pxd);
190662306a36Sopenharmony_ci	xsize = xlen << JFS_SBI(sb)->l2bsize;
190762306a36Sopenharmony_ci	rmp = get_metapage(ip, rbn, xsize, 1);
190862306a36Sopenharmony_ci	if (!rmp)
190962306a36Sopenharmony_ci		return -EIO;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	rp = rmp->data;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	/* Allocate blocks to quota. */
191462306a36Sopenharmony_ci	rc = dquot_alloc_block(ip, lengthPXD(pxd));
191562306a36Sopenharmony_ci	if (rc) {
191662306a36Sopenharmony_ci		release_metapage(rmp);
191762306a36Sopenharmony_ci		return rc;
191862306a36Sopenharmony_ci	}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	BT_MARK_DIRTY(rmp, ip);
192162306a36Sopenharmony_ci	/*
192262306a36Sopenharmony_ci	 * acquire a transaction lock on the new right page
192362306a36Sopenharmony_ci	 */
192462306a36Sopenharmony_ci	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
192562306a36Sopenharmony_ci	dtlck = (struct dt_lock *) & tlck->lock;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	rp->header.flag =
192862306a36Sopenharmony_ci	    (sp->header.flag & BT_LEAF) ? BT_LEAF : BT_INTERNAL;
192962306a36Sopenharmony_ci	rp->header.self = *pxd;
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	/* initialize sibling pointers */
193262306a36Sopenharmony_ci	rp->header.next = 0;
193362306a36Sopenharmony_ci	rp->header.prev = 0;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	/*
193662306a36Sopenharmony_ci	 *	move in-line root page into new right page extent
193762306a36Sopenharmony_ci	 */
193862306a36Sopenharmony_ci	/* linelock header + copied entries + new stbl (1st slot) in new page */
193962306a36Sopenharmony_ci	ASSERT(dtlck->index == 0);
194062306a36Sopenharmony_ci	lv = & dtlck->lv[0];
194162306a36Sopenharmony_ci	lv->offset = 0;
194262306a36Sopenharmony_ci	lv->length = 10;	/* 1 + 8 + 1 */
194362306a36Sopenharmony_ci	dtlck->index++;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	n = xsize >> L2DTSLOTSIZE;
194662306a36Sopenharmony_ci	rp->header.maxslot = n;
194762306a36Sopenharmony_ci	stblsize = (n + 31) >> L2DTSLOTSIZE;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	/* copy old stbl to new stbl at start of extended area */
195062306a36Sopenharmony_ci	rp->header.stblindex = DTROOTMAXSLOT;
195162306a36Sopenharmony_ci	stbl = (s8 *) & rp->slot[DTROOTMAXSLOT];
195262306a36Sopenharmony_ci	memcpy(stbl, sp->header.stbl, sp->header.nextindex);
195362306a36Sopenharmony_ci	rp->header.nextindex = sp->header.nextindex;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	/* copy old data area to start of new data area */
195662306a36Sopenharmony_ci	memcpy(&rp->slot[1], &sp->slot[1], IDATASIZE);
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	/*
195962306a36Sopenharmony_ci	 * append free region of newly extended area at tail of freelist
196062306a36Sopenharmony_ci	 */
196162306a36Sopenharmony_ci	/* init free region of newly extended area */
196262306a36Sopenharmony_ci	fsi = n = DTROOTMAXSLOT + stblsize;
196362306a36Sopenharmony_ci	f = &rp->slot[fsi];
196462306a36Sopenharmony_ci	for (fsi++; fsi < rp->header.maxslot; f++, fsi++)
196562306a36Sopenharmony_ci		f->next = fsi;
196662306a36Sopenharmony_ci	f->next = -1;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	/* append new free region at tail of old freelist */
196962306a36Sopenharmony_ci	fsi = sp->header.freelist;
197062306a36Sopenharmony_ci	if (fsi == -1)
197162306a36Sopenharmony_ci		rp->header.freelist = n;
197262306a36Sopenharmony_ci	else {
197362306a36Sopenharmony_ci		rp->header.freelist = fsi;
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci		do {
197662306a36Sopenharmony_ci			f = &rp->slot[fsi];
197762306a36Sopenharmony_ci			fsi = f->next;
197862306a36Sopenharmony_ci		} while (fsi >= 0);
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci		f->next = n;
198162306a36Sopenharmony_ci	}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	rp->header.freecnt = sp->header.freecnt + rp->header.maxslot - n;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	/*
198662306a36Sopenharmony_ci	 * Update directory index table for entries now in right page
198762306a36Sopenharmony_ci	 */
198862306a36Sopenharmony_ci	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
198962306a36Sopenharmony_ci		s64 lblock;
199062306a36Sopenharmony_ci		struct metapage *mp = NULL;
199162306a36Sopenharmony_ci		struct ldtentry *ldtentry;
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci		stbl = DT_GETSTBL(rp);
199462306a36Sopenharmony_ci		for (n = 0; n < rp->header.nextindex; n++) {
199562306a36Sopenharmony_ci			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
199662306a36Sopenharmony_ci			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
199762306a36Sopenharmony_ci				     rbn, n, &mp, &lblock);
199862306a36Sopenharmony_ci		}
199962306a36Sopenharmony_ci		if (mp)
200062306a36Sopenharmony_ci			release_metapage(mp);
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci	/*
200362306a36Sopenharmony_ci	 * insert the new entry into the new right/child page
200462306a36Sopenharmony_ci	 * (skip index in the new right page will not change)
200562306a36Sopenharmony_ci	 */
200662306a36Sopenharmony_ci	dtInsertEntry(rp, split->index, split->key, split->data, &dtlck);
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	/*
200962306a36Sopenharmony_ci	 *	reset parent/root page
201062306a36Sopenharmony_ci	 *
201162306a36Sopenharmony_ci	 * set the 1st entry offset to 0, which force the left-most key
201262306a36Sopenharmony_ci	 * at any level of the tree to be less than any search key.
201362306a36Sopenharmony_ci	 *
201462306a36Sopenharmony_ci	 * The btree comparison code guarantees that the left-most key on any
201562306a36Sopenharmony_ci	 * level of the tree is never used, so it doesn't need to be filled in.
201662306a36Sopenharmony_ci	 */
201762306a36Sopenharmony_ci	BT_MARK_DIRTY(smp, ip);
201862306a36Sopenharmony_ci	/*
201962306a36Sopenharmony_ci	 * acquire a transaction lock on the root page (in-memory inode)
202062306a36Sopenharmony_ci	 */
202162306a36Sopenharmony_ci	tlck = txLock(tid, ip, smp, tlckDTREE | tlckNEW | tlckBTROOT);
202262306a36Sopenharmony_ci	dtlck = (struct dt_lock *) & tlck->lock;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	/* linelock root */
202562306a36Sopenharmony_ci	ASSERT(dtlck->index == 0);
202662306a36Sopenharmony_ci	lv = & dtlck->lv[0];
202762306a36Sopenharmony_ci	lv->offset = 0;
202862306a36Sopenharmony_ci	lv->length = DTROOTMAXSLOT;
202962306a36Sopenharmony_ci	dtlck->index++;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	/* update page header of root */
203262306a36Sopenharmony_ci	if (sp->header.flag & BT_LEAF) {
203362306a36Sopenharmony_ci		sp->header.flag &= ~BT_LEAF;
203462306a36Sopenharmony_ci		sp->header.flag |= BT_INTERNAL;
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	/* init the first entry */
203862306a36Sopenharmony_ci	s = (struct idtentry *) & sp->slot[DTENTRYSTART];
203962306a36Sopenharmony_ci	ppxd = (pxd_t *) s;
204062306a36Sopenharmony_ci	*ppxd = *pxd;
204162306a36Sopenharmony_ci	s->next = -1;
204262306a36Sopenharmony_ci	s->namlen = 0;
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	stbl = sp->header.stbl;
204562306a36Sopenharmony_ci	stbl[0] = DTENTRYSTART;
204662306a36Sopenharmony_ci	sp->header.nextindex = 1;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	/* init freelist */
204962306a36Sopenharmony_ci	fsi = DTENTRYSTART + 1;
205062306a36Sopenharmony_ci	f = &sp->slot[fsi];
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	/* init free region of remaining area */
205362306a36Sopenharmony_ci	for (fsi++; fsi < DTROOTMAXSLOT; f++, fsi++)
205462306a36Sopenharmony_ci		f->next = fsi;
205562306a36Sopenharmony_ci	f->next = -1;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	sp->header.freelist = DTENTRYSTART + 1;
205862306a36Sopenharmony_ci	sp->header.freecnt = DTROOTMAXSLOT - (DTENTRYSTART + 1);
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	*rmpp = rmp;
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	return 0;
206362306a36Sopenharmony_ci}
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci/*
206762306a36Sopenharmony_ci *	dtDelete()
206862306a36Sopenharmony_ci *
206962306a36Sopenharmony_ci * function: delete the entry(s) referenced by a key.
207062306a36Sopenharmony_ci *
207162306a36Sopenharmony_ci * parameter:
207262306a36Sopenharmony_ci *
207362306a36Sopenharmony_ci * return:
207462306a36Sopenharmony_ci */
207562306a36Sopenharmony_ciint dtDelete(tid_t tid,
207662306a36Sopenharmony_ci	 struct inode *ip, struct component_name * key, ino_t * ino, int flag)
207762306a36Sopenharmony_ci{
207862306a36Sopenharmony_ci	int rc = 0;
207962306a36Sopenharmony_ci	s64 bn;
208062306a36Sopenharmony_ci	struct metapage *mp, *imp;
208162306a36Sopenharmony_ci	dtpage_t *p;
208262306a36Sopenharmony_ci	int index;
208362306a36Sopenharmony_ci	struct btstack btstack;
208462306a36Sopenharmony_ci	struct dt_lock *dtlck;
208562306a36Sopenharmony_ci	struct tlock *tlck;
208662306a36Sopenharmony_ci	struct lv *lv;
208762306a36Sopenharmony_ci	int i;
208862306a36Sopenharmony_ci	struct ldtentry *ldtentry;
208962306a36Sopenharmony_ci	u8 *stbl;
209062306a36Sopenharmony_ci	u32 table_index, next_index;
209162306a36Sopenharmony_ci	struct metapage *nmp;
209262306a36Sopenharmony_ci	dtpage_t *np;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	/*
209562306a36Sopenharmony_ci	 *	search for the entry to delete:
209662306a36Sopenharmony_ci	 *
209762306a36Sopenharmony_ci	 * dtSearch() returns (leaf page pinned, index at which to delete).
209862306a36Sopenharmony_ci	 */
209962306a36Sopenharmony_ci	if ((rc = dtSearch(ip, key, ino, &btstack, flag)))
210062306a36Sopenharmony_ci		return rc;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	/* retrieve search result */
210362306a36Sopenharmony_ci	DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	/*
210662306a36Sopenharmony_ci	 * We need to find put the index of the next entry into the
210762306a36Sopenharmony_ci	 * directory index table in order to resume a readdir from this
210862306a36Sopenharmony_ci	 * entry.
210962306a36Sopenharmony_ci	 */
211062306a36Sopenharmony_ci	if (DO_INDEX(ip)) {
211162306a36Sopenharmony_ci		stbl = DT_GETSTBL(p);
211262306a36Sopenharmony_ci		ldtentry = (struct ldtentry *) & p->slot[stbl[index]];
211362306a36Sopenharmony_ci		table_index = le32_to_cpu(ldtentry->index);
211462306a36Sopenharmony_ci		if (index == (p->header.nextindex - 1)) {
211562306a36Sopenharmony_ci			/*
211662306a36Sopenharmony_ci			 * Last entry in this leaf page
211762306a36Sopenharmony_ci			 */
211862306a36Sopenharmony_ci			if ((p->header.flag & BT_ROOT)
211962306a36Sopenharmony_ci			    || (p->header.next == 0))
212062306a36Sopenharmony_ci				next_index = -1;
212162306a36Sopenharmony_ci			else {
212262306a36Sopenharmony_ci				/* Read next leaf page */
212362306a36Sopenharmony_ci				DT_GETPAGE(ip, le64_to_cpu(p->header.next),
212462306a36Sopenharmony_ci					   nmp, PSIZE, np, rc);
212562306a36Sopenharmony_ci				if (rc)
212662306a36Sopenharmony_ci					next_index = -1;
212762306a36Sopenharmony_ci				else {
212862306a36Sopenharmony_ci					stbl = DT_GETSTBL(np);
212962306a36Sopenharmony_ci					ldtentry =
213062306a36Sopenharmony_ci					    (struct ldtentry *) & np->
213162306a36Sopenharmony_ci					    slot[stbl[0]];
213262306a36Sopenharmony_ci					next_index =
213362306a36Sopenharmony_ci					    le32_to_cpu(ldtentry->index);
213462306a36Sopenharmony_ci					DT_PUTPAGE(nmp);
213562306a36Sopenharmony_ci				}
213662306a36Sopenharmony_ci			}
213762306a36Sopenharmony_ci		} else {
213862306a36Sopenharmony_ci			ldtentry =
213962306a36Sopenharmony_ci			    (struct ldtentry *) & p->slot[stbl[index + 1]];
214062306a36Sopenharmony_ci			next_index = le32_to_cpu(ldtentry->index);
214162306a36Sopenharmony_ci		}
214262306a36Sopenharmony_ci		free_index(tid, ip, table_index, next_index);
214362306a36Sopenharmony_ci	}
214462306a36Sopenharmony_ci	/*
214562306a36Sopenharmony_ci	 * the leaf page becomes empty, delete the page
214662306a36Sopenharmony_ci	 */
214762306a36Sopenharmony_ci	if (p->header.nextindex == 1) {
214862306a36Sopenharmony_ci		/* delete empty page */
214962306a36Sopenharmony_ci		rc = dtDeleteUp(tid, ip, mp, p, &btstack);
215062306a36Sopenharmony_ci	}
215162306a36Sopenharmony_ci	/*
215262306a36Sopenharmony_ci	 * the leaf page has other entries remaining:
215362306a36Sopenharmony_ci	 *
215462306a36Sopenharmony_ci	 * delete the entry from the leaf page.
215562306a36Sopenharmony_ci	 */
215662306a36Sopenharmony_ci	else {
215762306a36Sopenharmony_ci		BT_MARK_DIRTY(mp, ip);
215862306a36Sopenharmony_ci		/*
215962306a36Sopenharmony_ci		 * acquire a transaction lock on the leaf page
216062306a36Sopenharmony_ci		 */
216162306a36Sopenharmony_ci		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
216262306a36Sopenharmony_ci		dtlck = (struct dt_lock *) & tlck->lock;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci		/*
216562306a36Sopenharmony_ci		 * Do not assume that dtlck->index will be zero.  During a
216662306a36Sopenharmony_ci		 * rename within a directory, this transaction may have
216762306a36Sopenharmony_ci		 * modified this page already when adding the new entry.
216862306a36Sopenharmony_ci		 */
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci		/* linelock header */
217162306a36Sopenharmony_ci		if (dtlck->index >= dtlck->maxcnt)
217262306a36Sopenharmony_ci			dtlck = (struct dt_lock *) txLinelock(dtlck);
217362306a36Sopenharmony_ci		lv = & dtlck->lv[dtlck->index];
217462306a36Sopenharmony_ci		lv->offset = 0;
217562306a36Sopenharmony_ci		lv->length = 1;
217662306a36Sopenharmony_ci		dtlck->index++;
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci		/* linelock stbl of non-root leaf page */
217962306a36Sopenharmony_ci		if (!(p->header.flag & BT_ROOT)) {
218062306a36Sopenharmony_ci			if (dtlck->index >= dtlck->maxcnt)
218162306a36Sopenharmony_ci				dtlck = (struct dt_lock *) txLinelock(dtlck);
218262306a36Sopenharmony_ci			lv = & dtlck->lv[dtlck->index];
218362306a36Sopenharmony_ci			i = index >> L2DTSLOTSIZE;
218462306a36Sopenharmony_ci			lv->offset = p->header.stblindex + i;
218562306a36Sopenharmony_ci			lv->length =
218662306a36Sopenharmony_ci			    ((p->header.nextindex - 1) >> L2DTSLOTSIZE) -
218762306a36Sopenharmony_ci			    i + 1;
218862306a36Sopenharmony_ci			dtlck->index++;
218962306a36Sopenharmony_ci		}
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci		/* free the leaf entry */
219262306a36Sopenharmony_ci		dtDeleteEntry(p, index, &dtlck);
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci		/*
219562306a36Sopenharmony_ci		 * Update directory index table for entries moved in stbl
219662306a36Sopenharmony_ci		 */
219762306a36Sopenharmony_ci		if (DO_INDEX(ip) && index < p->header.nextindex) {
219862306a36Sopenharmony_ci			s64 lblock;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci			imp = NULL;
220162306a36Sopenharmony_ci			stbl = DT_GETSTBL(p);
220262306a36Sopenharmony_ci			for (i = index; i < p->header.nextindex; i++) {
220362306a36Sopenharmony_ci				ldtentry =
220462306a36Sopenharmony_ci				    (struct ldtentry *) & p->slot[stbl[i]];
220562306a36Sopenharmony_ci				modify_index(tid, ip,
220662306a36Sopenharmony_ci					     le32_to_cpu(ldtentry->index),
220762306a36Sopenharmony_ci					     bn, i, &imp, &lblock);
220862306a36Sopenharmony_ci			}
220962306a36Sopenharmony_ci			if (imp)
221062306a36Sopenharmony_ci				release_metapage(imp);
221162306a36Sopenharmony_ci		}
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci		DT_PUTPAGE(mp);
221462306a36Sopenharmony_ci	}
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	return rc;
221762306a36Sopenharmony_ci}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci/*
222162306a36Sopenharmony_ci *	dtDeleteUp()
222262306a36Sopenharmony_ci *
222362306a36Sopenharmony_ci * function:
222462306a36Sopenharmony_ci *	free empty pages as propagating deletion up the tree
222562306a36Sopenharmony_ci *
222662306a36Sopenharmony_ci * parameter:
222762306a36Sopenharmony_ci *
222862306a36Sopenharmony_ci * return:
222962306a36Sopenharmony_ci */
223062306a36Sopenharmony_cistatic int dtDeleteUp(tid_t tid, struct inode *ip,
223162306a36Sopenharmony_ci	   struct metapage * fmp, dtpage_t * fp, struct btstack * btstack)
223262306a36Sopenharmony_ci{
223362306a36Sopenharmony_ci	int rc = 0;
223462306a36Sopenharmony_ci	struct metapage *mp;
223562306a36Sopenharmony_ci	dtpage_t *p;
223662306a36Sopenharmony_ci	int index, nextindex;
223762306a36Sopenharmony_ci	int xlen;
223862306a36Sopenharmony_ci	struct btframe *parent;
223962306a36Sopenharmony_ci	struct dt_lock *dtlck;
224062306a36Sopenharmony_ci	struct tlock *tlck;
224162306a36Sopenharmony_ci	struct lv *lv;
224262306a36Sopenharmony_ci	struct pxd_lock *pxdlock;
224362306a36Sopenharmony_ci	int i;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	/*
224662306a36Sopenharmony_ci	 *	keep the root leaf page which has become empty
224762306a36Sopenharmony_ci	 */
224862306a36Sopenharmony_ci	if (BT_IS_ROOT(fmp)) {
224962306a36Sopenharmony_ci		/*
225062306a36Sopenharmony_ci		 * reset the root
225162306a36Sopenharmony_ci		 *
225262306a36Sopenharmony_ci		 * dtInitRoot() acquires txlock on the root
225362306a36Sopenharmony_ci		 */
225462306a36Sopenharmony_ci		dtInitRoot(tid, ip, PARENT(ip));
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci		DT_PUTPAGE(fmp);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci		return 0;
225962306a36Sopenharmony_ci	}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	/*
226262306a36Sopenharmony_ci	 *	free the non-root leaf page
226362306a36Sopenharmony_ci	 */
226462306a36Sopenharmony_ci	/*
226562306a36Sopenharmony_ci	 * acquire a transaction lock on the page
226662306a36Sopenharmony_ci	 *
226762306a36Sopenharmony_ci	 * write FREEXTENT|NOREDOPAGE log record
226862306a36Sopenharmony_ci	 * N.B. linelock is overlaid as freed extent descriptor, and
226962306a36Sopenharmony_ci	 * the buffer page is freed;
227062306a36Sopenharmony_ci	 */
227162306a36Sopenharmony_ci	tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE);
227262306a36Sopenharmony_ci	pxdlock = (struct pxd_lock *) & tlck->lock;
227362306a36Sopenharmony_ci	pxdlock->flag = mlckFREEPXD;
227462306a36Sopenharmony_ci	pxdlock->pxd = fp->header.self;
227562306a36Sopenharmony_ci	pxdlock->index = 1;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	/* update sibling pointers */
227862306a36Sopenharmony_ci	if ((rc = dtRelink(tid, ip, fp))) {
227962306a36Sopenharmony_ci		BT_PUTPAGE(fmp);
228062306a36Sopenharmony_ci		return rc;
228162306a36Sopenharmony_ci	}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	xlen = lengthPXD(&fp->header.self);
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	/* Free quota allocation. */
228662306a36Sopenharmony_ci	dquot_free_block(ip, xlen);
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	/* free/invalidate its buffer page */
228962306a36Sopenharmony_ci	discard_metapage(fmp);
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	/*
229262306a36Sopenharmony_ci	 *	propagate page deletion up the directory tree
229362306a36Sopenharmony_ci	 *
229462306a36Sopenharmony_ci	 * If the delete from the parent page makes it empty,
229562306a36Sopenharmony_ci	 * continue all the way up the tree.
229662306a36Sopenharmony_ci	 * stop if the root page is reached (which is never deleted) or
229762306a36Sopenharmony_ci	 * if the entry deletion does not empty the page.
229862306a36Sopenharmony_ci	 */
229962306a36Sopenharmony_ci	while ((parent = BT_POP(btstack)) != NULL) {
230062306a36Sopenharmony_ci		/* pin the parent page <sp> */
230162306a36Sopenharmony_ci		DT_GETPAGE(ip, parent->bn, mp, PSIZE, p, rc);
230262306a36Sopenharmony_ci		if (rc)
230362306a36Sopenharmony_ci			return rc;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci		/*
230662306a36Sopenharmony_ci		 * free the extent of the child page deleted
230762306a36Sopenharmony_ci		 */
230862306a36Sopenharmony_ci		index = parent->index;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci		/*
231162306a36Sopenharmony_ci		 * delete the entry for the child page from parent
231262306a36Sopenharmony_ci		 */
231362306a36Sopenharmony_ci		nextindex = p->header.nextindex;
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci		/*
231662306a36Sopenharmony_ci		 * the parent has the single entry being deleted:
231762306a36Sopenharmony_ci		 *
231862306a36Sopenharmony_ci		 * free the parent page which has become empty.
231962306a36Sopenharmony_ci		 */
232062306a36Sopenharmony_ci		if (nextindex == 1) {
232162306a36Sopenharmony_ci			/*
232262306a36Sopenharmony_ci			 * keep the root internal page which has become empty
232362306a36Sopenharmony_ci			 */
232462306a36Sopenharmony_ci			if (p->header.flag & BT_ROOT) {
232562306a36Sopenharmony_ci				/*
232662306a36Sopenharmony_ci				 * reset the root
232762306a36Sopenharmony_ci				 *
232862306a36Sopenharmony_ci				 * dtInitRoot() acquires txlock on the root
232962306a36Sopenharmony_ci				 */
233062306a36Sopenharmony_ci				dtInitRoot(tid, ip, PARENT(ip));
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci				DT_PUTPAGE(mp);
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci				return 0;
233562306a36Sopenharmony_ci			}
233662306a36Sopenharmony_ci			/*
233762306a36Sopenharmony_ci			 * free the parent page
233862306a36Sopenharmony_ci			 */
233962306a36Sopenharmony_ci			else {
234062306a36Sopenharmony_ci				/*
234162306a36Sopenharmony_ci				 * acquire a transaction lock on the page
234262306a36Sopenharmony_ci				 *
234362306a36Sopenharmony_ci				 * write FREEXTENT|NOREDOPAGE log record
234462306a36Sopenharmony_ci				 */
234562306a36Sopenharmony_ci				tlck =
234662306a36Sopenharmony_ci				    txMaplock(tid, ip,
234762306a36Sopenharmony_ci					      tlckDTREE | tlckFREE);
234862306a36Sopenharmony_ci				pxdlock = (struct pxd_lock *) & tlck->lock;
234962306a36Sopenharmony_ci				pxdlock->flag = mlckFREEPXD;
235062306a36Sopenharmony_ci				pxdlock->pxd = p->header.self;
235162306a36Sopenharmony_ci				pxdlock->index = 1;
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci				/* update sibling pointers */
235462306a36Sopenharmony_ci				if ((rc = dtRelink(tid, ip, p))) {
235562306a36Sopenharmony_ci					DT_PUTPAGE(mp);
235662306a36Sopenharmony_ci					return rc;
235762306a36Sopenharmony_ci				}
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci				xlen = lengthPXD(&p->header.self);
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci				/* Free quota allocation */
236262306a36Sopenharmony_ci				dquot_free_block(ip, xlen);
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci				/* free/invalidate its buffer page */
236562306a36Sopenharmony_ci				discard_metapage(mp);
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci				/* propagate up */
236862306a36Sopenharmony_ci				continue;
236962306a36Sopenharmony_ci			}
237062306a36Sopenharmony_ci		}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci		/*
237362306a36Sopenharmony_ci		 * the parent has other entries remaining:
237462306a36Sopenharmony_ci		 *
237562306a36Sopenharmony_ci		 * delete the router entry from the parent page.
237662306a36Sopenharmony_ci		 */
237762306a36Sopenharmony_ci		BT_MARK_DIRTY(mp, ip);
237862306a36Sopenharmony_ci		/*
237962306a36Sopenharmony_ci		 * acquire a transaction lock on the page
238062306a36Sopenharmony_ci		 *
238162306a36Sopenharmony_ci		 * action: router entry deletion
238262306a36Sopenharmony_ci		 */
238362306a36Sopenharmony_ci		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
238462306a36Sopenharmony_ci		dtlck = (struct dt_lock *) & tlck->lock;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci		/* linelock header */
238762306a36Sopenharmony_ci		if (dtlck->index >= dtlck->maxcnt)
238862306a36Sopenharmony_ci			dtlck = (struct dt_lock *) txLinelock(dtlck);
238962306a36Sopenharmony_ci		lv = & dtlck->lv[dtlck->index];
239062306a36Sopenharmony_ci		lv->offset = 0;
239162306a36Sopenharmony_ci		lv->length = 1;
239262306a36Sopenharmony_ci		dtlck->index++;
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci		/* linelock stbl of non-root leaf page */
239562306a36Sopenharmony_ci		if (!(p->header.flag & BT_ROOT)) {
239662306a36Sopenharmony_ci			if (dtlck->index < dtlck->maxcnt)
239762306a36Sopenharmony_ci				lv++;
239862306a36Sopenharmony_ci			else {
239962306a36Sopenharmony_ci				dtlck = (struct dt_lock *) txLinelock(dtlck);
240062306a36Sopenharmony_ci				lv = & dtlck->lv[0];
240162306a36Sopenharmony_ci			}
240262306a36Sopenharmony_ci			i = index >> L2DTSLOTSIZE;
240362306a36Sopenharmony_ci			lv->offset = p->header.stblindex + i;
240462306a36Sopenharmony_ci			lv->length =
240562306a36Sopenharmony_ci			    ((p->header.nextindex - 1) >> L2DTSLOTSIZE) -
240662306a36Sopenharmony_ci			    i + 1;
240762306a36Sopenharmony_ci			dtlck->index++;
240862306a36Sopenharmony_ci		}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci		/* free the router entry */
241162306a36Sopenharmony_ci		dtDeleteEntry(p, index, &dtlck);
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci		/* reset key of new leftmost entry of level (for consistency) */
241462306a36Sopenharmony_ci		if (index == 0 &&
241562306a36Sopenharmony_ci		    ((p->header.flag & BT_ROOT) || p->header.prev == 0))
241662306a36Sopenharmony_ci			dtTruncateEntry(p, 0, &dtlck);
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci		/* unpin the parent page */
241962306a36Sopenharmony_ci		DT_PUTPAGE(mp);
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci		/* exit propagation up */
242262306a36Sopenharmony_ci		break;
242362306a36Sopenharmony_ci	}
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	if (!DO_INDEX(ip))
242662306a36Sopenharmony_ci		ip->i_size -= PSIZE;
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	return 0;
242962306a36Sopenharmony_ci}
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci/*
243262306a36Sopenharmony_ci *	dtRelink()
243362306a36Sopenharmony_ci *
243462306a36Sopenharmony_ci * function:
243562306a36Sopenharmony_ci *	link around a freed page.
243662306a36Sopenharmony_ci *
243762306a36Sopenharmony_ci * parameter:
243862306a36Sopenharmony_ci *	fp:	page to be freed
243962306a36Sopenharmony_ci *
244062306a36Sopenharmony_ci * return:
244162306a36Sopenharmony_ci */
244262306a36Sopenharmony_cistatic int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p)
244362306a36Sopenharmony_ci{
244462306a36Sopenharmony_ci	int rc;
244562306a36Sopenharmony_ci	struct metapage *mp;
244662306a36Sopenharmony_ci	s64 nextbn, prevbn;
244762306a36Sopenharmony_ci	struct tlock *tlck;
244862306a36Sopenharmony_ci	struct dt_lock *dtlck;
244962306a36Sopenharmony_ci	struct lv *lv;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	nextbn = le64_to_cpu(p->header.next);
245262306a36Sopenharmony_ci	prevbn = le64_to_cpu(p->header.prev);
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	/* update prev pointer of the next page */
245562306a36Sopenharmony_ci	if (nextbn != 0) {
245662306a36Sopenharmony_ci		DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
245762306a36Sopenharmony_ci		if (rc)
245862306a36Sopenharmony_ci			return rc;
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci		BT_MARK_DIRTY(mp, ip);
246162306a36Sopenharmony_ci		/*
246262306a36Sopenharmony_ci		 * acquire a transaction lock on the next page
246362306a36Sopenharmony_ci		 *
246462306a36Sopenharmony_ci		 * action: update prev pointer;
246562306a36Sopenharmony_ci		 */
246662306a36Sopenharmony_ci		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
246762306a36Sopenharmony_ci		jfs_info("dtRelink nextbn: tlck = 0x%p, ip = 0x%p, mp=0x%p",
246862306a36Sopenharmony_ci			tlck, ip, mp);
246962306a36Sopenharmony_ci		dtlck = (struct dt_lock *) & tlck->lock;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci		/* linelock header */
247262306a36Sopenharmony_ci		if (dtlck->index >= dtlck->maxcnt)
247362306a36Sopenharmony_ci			dtlck = (struct dt_lock *) txLinelock(dtlck);
247462306a36Sopenharmony_ci		lv = & dtlck->lv[dtlck->index];
247562306a36Sopenharmony_ci		lv->offset = 0;
247662306a36Sopenharmony_ci		lv->length = 1;
247762306a36Sopenharmony_ci		dtlck->index++;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci		p->header.prev = cpu_to_le64(prevbn);
248062306a36Sopenharmony_ci		DT_PUTPAGE(mp);
248162306a36Sopenharmony_ci	}
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	/* update next pointer of the previous page */
248462306a36Sopenharmony_ci	if (prevbn != 0) {
248562306a36Sopenharmony_ci		DT_GETPAGE(ip, prevbn, mp, PSIZE, p, rc);
248662306a36Sopenharmony_ci		if (rc)
248762306a36Sopenharmony_ci			return rc;
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci		BT_MARK_DIRTY(mp, ip);
249062306a36Sopenharmony_ci		/*
249162306a36Sopenharmony_ci		 * acquire a transaction lock on the prev page
249262306a36Sopenharmony_ci		 *
249362306a36Sopenharmony_ci		 * action: update next pointer;
249462306a36Sopenharmony_ci		 */
249562306a36Sopenharmony_ci		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
249662306a36Sopenharmony_ci		jfs_info("dtRelink prevbn: tlck = 0x%p, ip = 0x%p, mp=0x%p",
249762306a36Sopenharmony_ci			tlck, ip, mp);
249862306a36Sopenharmony_ci		dtlck = (struct dt_lock *) & tlck->lock;
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci		/* linelock header */
250162306a36Sopenharmony_ci		if (dtlck->index >= dtlck->maxcnt)
250262306a36Sopenharmony_ci			dtlck = (struct dt_lock *) txLinelock(dtlck);
250362306a36Sopenharmony_ci		lv = & dtlck->lv[dtlck->index];
250462306a36Sopenharmony_ci		lv->offset = 0;
250562306a36Sopenharmony_ci		lv->length = 1;
250662306a36Sopenharmony_ci		dtlck->index++;
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci		p->header.next = cpu_to_le64(nextbn);
250962306a36Sopenharmony_ci		DT_PUTPAGE(mp);
251062306a36Sopenharmony_ci	}
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	return 0;
251362306a36Sopenharmony_ci}
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci/*
251762306a36Sopenharmony_ci *	dtInitRoot()
251862306a36Sopenharmony_ci *
251962306a36Sopenharmony_ci * initialize directory root (inline in inode)
252062306a36Sopenharmony_ci */
252162306a36Sopenharmony_civoid dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
252262306a36Sopenharmony_ci{
252362306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
252462306a36Sopenharmony_ci	dtroot_t *p;
252562306a36Sopenharmony_ci	int fsi;
252662306a36Sopenharmony_ci	struct dtslot *f;
252762306a36Sopenharmony_ci	struct tlock *tlck;
252862306a36Sopenharmony_ci	struct dt_lock *dtlck;
252962306a36Sopenharmony_ci	struct lv *lv;
253062306a36Sopenharmony_ci	u16 xflag_save;
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	/*
253362306a36Sopenharmony_ci	 * If this was previously an non-empty directory, we need to remove
253462306a36Sopenharmony_ci	 * the old directory table.
253562306a36Sopenharmony_ci	 */
253662306a36Sopenharmony_ci	if (DO_INDEX(ip)) {
253762306a36Sopenharmony_ci		if (!jfs_dirtable_inline(ip)) {
253862306a36Sopenharmony_ci			struct tblock *tblk = tid_to_tblock(tid);
253962306a36Sopenharmony_ci			/*
254062306a36Sopenharmony_ci			 * We're playing games with the tid's xflag.  If
254162306a36Sopenharmony_ci			 * we're removing a regular file, the file's xtree
254262306a36Sopenharmony_ci			 * is committed with COMMIT_PMAP, but we always
254362306a36Sopenharmony_ci			 * commit the directories xtree with COMMIT_PWMAP.
254462306a36Sopenharmony_ci			 */
254562306a36Sopenharmony_ci			xflag_save = tblk->xflag;
254662306a36Sopenharmony_ci			tblk->xflag = 0;
254762306a36Sopenharmony_ci			/*
254862306a36Sopenharmony_ci			 * xtTruncate isn't guaranteed to fully truncate
254962306a36Sopenharmony_ci			 * the xtree.  The caller needs to check i_size
255062306a36Sopenharmony_ci			 * after committing the transaction to see if
255162306a36Sopenharmony_ci			 * additional truncation is needed.  The
255262306a36Sopenharmony_ci			 * COMMIT_Stale flag tells caller that we
255362306a36Sopenharmony_ci			 * initiated the truncation.
255462306a36Sopenharmony_ci			 */
255562306a36Sopenharmony_ci			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
255662306a36Sopenharmony_ci			set_cflag(COMMIT_Stale, ip);
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci			tblk->xflag = xflag_save;
255962306a36Sopenharmony_ci		} else
256062306a36Sopenharmony_ci			ip->i_size = 1;
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci		jfs_ip->next_index = 2;
256362306a36Sopenharmony_ci	} else
256462306a36Sopenharmony_ci		ip->i_size = IDATASIZE;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	/*
256762306a36Sopenharmony_ci	 * acquire a transaction lock on the root
256862306a36Sopenharmony_ci	 *
256962306a36Sopenharmony_ci	 * action: directory initialization;
257062306a36Sopenharmony_ci	 */
257162306a36Sopenharmony_ci	tlck = txLock(tid, ip, (struct metapage *) & jfs_ip->bxflag,
257262306a36Sopenharmony_ci		      tlckDTREE | tlckENTRY | tlckBTROOT);
257362306a36Sopenharmony_ci	dtlck = (struct dt_lock *) & tlck->lock;
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	/* linelock root */
257662306a36Sopenharmony_ci	ASSERT(dtlck->index == 0);
257762306a36Sopenharmony_ci	lv = & dtlck->lv[0];
257862306a36Sopenharmony_ci	lv->offset = 0;
257962306a36Sopenharmony_ci	lv->length = DTROOTMAXSLOT;
258062306a36Sopenharmony_ci	dtlck->index++;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	p = &jfs_ip->i_dtroot;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	p->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF;
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	p->header.nextindex = 0;
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	/* init freelist */
258962306a36Sopenharmony_ci	fsi = 1;
259062306a36Sopenharmony_ci	f = &p->slot[fsi];
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	/* init data area of root */
259362306a36Sopenharmony_ci	for (fsi++; fsi < DTROOTMAXSLOT; f++, fsi++)
259462306a36Sopenharmony_ci		f->next = fsi;
259562306a36Sopenharmony_ci	f->next = -1;
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	p->header.freelist = 1;
259862306a36Sopenharmony_ci	p->header.freecnt = 8;
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	/* init '..' entry */
260162306a36Sopenharmony_ci	p->header.idotdot = cpu_to_le32(idotdot);
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	return;
260462306a36Sopenharmony_ci}
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci/*
260762306a36Sopenharmony_ci *	add_missing_indices()
260862306a36Sopenharmony_ci *
260962306a36Sopenharmony_ci * function: Fix dtree page in which one or more entries has an invalid index.
261062306a36Sopenharmony_ci *	     fsck.jfs should really fix this, but it currently does not.
261162306a36Sopenharmony_ci *	     Called from jfs_readdir when bad index is detected.
261262306a36Sopenharmony_ci */
261362306a36Sopenharmony_cistatic void add_missing_indices(struct inode *inode, s64 bn)
261462306a36Sopenharmony_ci{
261562306a36Sopenharmony_ci	struct ldtentry *d;
261662306a36Sopenharmony_ci	struct dt_lock *dtlck;
261762306a36Sopenharmony_ci	int i;
261862306a36Sopenharmony_ci	uint index;
261962306a36Sopenharmony_ci	struct lv *lv;
262062306a36Sopenharmony_ci	struct metapage *mp;
262162306a36Sopenharmony_ci	dtpage_t *p;
262262306a36Sopenharmony_ci	int rc;
262362306a36Sopenharmony_ci	s8 *stbl;
262462306a36Sopenharmony_ci	tid_t tid;
262562306a36Sopenharmony_ci	struct tlock *tlck;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	tid = txBegin(inode->i_sb, 0);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	DT_GETPAGE(inode, bn, mp, PSIZE, p, rc);
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	if (rc) {
263262306a36Sopenharmony_ci		printk(KERN_ERR "DT_GETPAGE failed!\n");
263362306a36Sopenharmony_ci		goto end;
263462306a36Sopenharmony_ci	}
263562306a36Sopenharmony_ci	BT_MARK_DIRTY(mp, inode);
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	ASSERT(p->header.flag & BT_LEAF);
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	tlck = txLock(tid, inode, mp, tlckDTREE | tlckENTRY);
264062306a36Sopenharmony_ci	if (BT_IS_ROOT(mp))
264162306a36Sopenharmony_ci		tlck->type |= tlckBTROOT;
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	dtlck = (struct dt_lock *) &tlck->lock;
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci	stbl = DT_GETSTBL(p);
264662306a36Sopenharmony_ci	for (i = 0; i < p->header.nextindex; i++) {
264762306a36Sopenharmony_ci		d = (struct ldtentry *) &p->slot[stbl[i]];
264862306a36Sopenharmony_ci		index = le32_to_cpu(d->index);
264962306a36Sopenharmony_ci		if ((index < 2) || (index >= JFS_IP(inode)->next_index)) {
265062306a36Sopenharmony_ci			d->index = cpu_to_le32(add_index(tid, inode, bn, i));
265162306a36Sopenharmony_ci			if (dtlck->index >= dtlck->maxcnt)
265262306a36Sopenharmony_ci				dtlck = (struct dt_lock *) txLinelock(dtlck);
265362306a36Sopenharmony_ci			lv = &dtlck->lv[dtlck->index];
265462306a36Sopenharmony_ci			lv->offset = stbl[i];
265562306a36Sopenharmony_ci			lv->length = 1;
265662306a36Sopenharmony_ci			dtlck->index++;
265762306a36Sopenharmony_ci		}
265862306a36Sopenharmony_ci	}
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	DT_PUTPAGE(mp);
266162306a36Sopenharmony_ci	(void) txCommit(tid, 1, &inode, 0);
266262306a36Sopenharmony_ciend:
266362306a36Sopenharmony_ci	txEnd(tid);
266462306a36Sopenharmony_ci}
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci/*
266762306a36Sopenharmony_ci * Buffer to hold directory entry info while traversing a dtree page
266862306a36Sopenharmony_ci * before being fed to the filldir function
266962306a36Sopenharmony_ci */
267062306a36Sopenharmony_cistruct jfs_dirent {
267162306a36Sopenharmony_ci	loff_t position;
267262306a36Sopenharmony_ci	int ino;
267362306a36Sopenharmony_ci	u16 name_len;
267462306a36Sopenharmony_ci	char name[];
267562306a36Sopenharmony_ci};
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci/*
267862306a36Sopenharmony_ci * function to determine next variable-sized jfs_dirent in buffer
267962306a36Sopenharmony_ci */
268062306a36Sopenharmony_cistatic inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent)
268162306a36Sopenharmony_ci{
268262306a36Sopenharmony_ci	return (struct jfs_dirent *)
268362306a36Sopenharmony_ci		((char *)dirent +
268462306a36Sopenharmony_ci		 ((sizeof (struct jfs_dirent) + dirent->name_len + 1 +
268562306a36Sopenharmony_ci		   sizeof (loff_t) - 1) &
268662306a36Sopenharmony_ci		  ~(sizeof (loff_t) - 1)));
268762306a36Sopenharmony_ci}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci/*
269062306a36Sopenharmony_ci *	jfs_readdir()
269162306a36Sopenharmony_ci *
269262306a36Sopenharmony_ci * function: read directory entries sequentially
269362306a36Sopenharmony_ci *	from the specified entry offset
269462306a36Sopenharmony_ci *
269562306a36Sopenharmony_ci * parameter:
269662306a36Sopenharmony_ci *
269762306a36Sopenharmony_ci * return: offset = (pn, index) of start entry
269862306a36Sopenharmony_ci *	of next jfs_readdir()/dtRead()
269962306a36Sopenharmony_ci */
270062306a36Sopenharmony_ciint jfs_readdir(struct file *file, struct dir_context *ctx)
270162306a36Sopenharmony_ci{
270262306a36Sopenharmony_ci	struct inode *ip = file_inode(file);
270362306a36Sopenharmony_ci	struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
270462306a36Sopenharmony_ci	int rc = 0;
270562306a36Sopenharmony_ci	loff_t dtpos;	/* legacy OS/2 style position */
270662306a36Sopenharmony_ci	struct dtoffset {
270762306a36Sopenharmony_ci		s16 pn;
270862306a36Sopenharmony_ci		s16 index;
270962306a36Sopenharmony_ci		s32 unused;
271062306a36Sopenharmony_ci	} *dtoffset = (struct dtoffset *) &dtpos;
271162306a36Sopenharmony_ci	s64 bn;
271262306a36Sopenharmony_ci	struct metapage *mp;
271362306a36Sopenharmony_ci	dtpage_t *p;
271462306a36Sopenharmony_ci	int index;
271562306a36Sopenharmony_ci	s8 *stbl;
271662306a36Sopenharmony_ci	struct btstack btstack;
271762306a36Sopenharmony_ci	int i, next;
271862306a36Sopenharmony_ci	struct ldtentry *d;
271962306a36Sopenharmony_ci	struct dtslot *t;
272062306a36Sopenharmony_ci	int d_namleft, len, outlen;
272162306a36Sopenharmony_ci	unsigned long dirent_buf;
272262306a36Sopenharmony_ci	char *name_ptr;
272362306a36Sopenharmony_ci	u32 dir_index;
272462306a36Sopenharmony_ci	int do_index = 0;
272562306a36Sopenharmony_ci	uint loop_count = 0;
272662306a36Sopenharmony_ci	struct jfs_dirent *jfs_dirent;
272762306a36Sopenharmony_ci	int jfs_dirents;
272862306a36Sopenharmony_ci	int overflow, fix_page, page_fixed = 0;
272962306a36Sopenharmony_ci	static int unique_pos = 2;	/* If we can't fix broken index */
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	if (ctx->pos == DIREND)
273262306a36Sopenharmony_ci		return 0;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	if (DO_INDEX(ip)) {
273562306a36Sopenharmony_ci		/*
273662306a36Sopenharmony_ci		 * persistent index is stored in directory entries.
273762306a36Sopenharmony_ci		 * Special cases:	 0 = .
273862306a36Sopenharmony_ci		 *			 1 = ..
273962306a36Sopenharmony_ci		 *			-1 = End of directory
274062306a36Sopenharmony_ci		 */
274162306a36Sopenharmony_ci		do_index = 1;
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci		dir_index = (u32) ctx->pos;
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci		/*
274662306a36Sopenharmony_ci		 * NFSv4 reserves cookies 1 and 2 for . and .. so the value
274762306a36Sopenharmony_ci		 * we return to the vfs is one greater than the one we use
274862306a36Sopenharmony_ci		 * internally.
274962306a36Sopenharmony_ci		 */
275062306a36Sopenharmony_ci		if (dir_index)
275162306a36Sopenharmony_ci			dir_index--;
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci		if (dir_index > 1) {
275462306a36Sopenharmony_ci			struct dir_table_slot dirtab_slot;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci			if (dtEmpty(ip) ||
275762306a36Sopenharmony_ci			    (dir_index >= JFS_IP(ip)->next_index)) {
275862306a36Sopenharmony_ci				/* Stale position.  Directory has shrunk */
275962306a36Sopenharmony_ci				ctx->pos = DIREND;
276062306a36Sopenharmony_ci				return 0;
276162306a36Sopenharmony_ci			}
276262306a36Sopenharmony_ci		      repeat:
276362306a36Sopenharmony_ci			rc = read_index(ip, dir_index, &dirtab_slot);
276462306a36Sopenharmony_ci			if (rc) {
276562306a36Sopenharmony_ci				ctx->pos = DIREND;
276662306a36Sopenharmony_ci				return rc;
276762306a36Sopenharmony_ci			}
276862306a36Sopenharmony_ci			if (dirtab_slot.flag == DIR_INDEX_FREE) {
276962306a36Sopenharmony_ci				if (loop_count++ > JFS_IP(ip)->next_index) {
277062306a36Sopenharmony_ci					jfs_err("jfs_readdir detected infinite loop!");
277162306a36Sopenharmony_ci					ctx->pos = DIREND;
277262306a36Sopenharmony_ci					return 0;
277362306a36Sopenharmony_ci				}
277462306a36Sopenharmony_ci				dir_index = le32_to_cpu(dirtab_slot.addr2);
277562306a36Sopenharmony_ci				if (dir_index == -1) {
277662306a36Sopenharmony_ci					ctx->pos = DIREND;
277762306a36Sopenharmony_ci					return 0;
277862306a36Sopenharmony_ci				}
277962306a36Sopenharmony_ci				goto repeat;
278062306a36Sopenharmony_ci			}
278162306a36Sopenharmony_ci			bn = addressDTS(&dirtab_slot);
278262306a36Sopenharmony_ci			index = dirtab_slot.slot;
278362306a36Sopenharmony_ci			DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
278462306a36Sopenharmony_ci			if (rc) {
278562306a36Sopenharmony_ci				ctx->pos = DIREND;
278662306a36Sopenharmony_ci				return 0;
278762306a36Sopenharmony_ci			}
278862306a36Sopenharmony_ci			if (p->header.flag & BT_INTERNAL) {
278962306a36Sopenharmony_ci				jfs_err("jfs_readdir: bad index table");
279062306a36Sopenharmony_ci				DT_PUTPAGE(mp);
279162306a36Sopenharmony_ci				ctx->pos = DIREND;
279262306a36Sopenharmony_ci				return 0;
279362306a36Sopenharmony_ci			}
279462306a36Sopenharmony_ci		} else {
279562306a36Sopenharmony_ci			if (dir_index == 0) {
279662306a36Sopenharmony_ci				/*
279762306a36Sopenharmony_ci				 * self "."
279862306a36Sopenharmony_ci				 */
279962306a36Sopenharmony_ci				ctx->pos = 1;
280062306a36Sopenharmony_ci				if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
280162306a36Sopenharmony_ci					return 0;
280262306a36Sopenharmony_ci			}
280362306a36Sopenharmony_ci			/*
280462306a36Sopenharmony_ci			 * parent ".."
280562306a36Sopenharmony_ci			 */
280662306a36Sopenharmony_ci			ctx->pos = 2;
280762306a36Sopenharmony_ci			if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
280862306a36Sopenharmony_ci				return 0;
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci			/*
281162306a36Sopenharmony_ci			 * Find first entry of left-most leaf
281262306a36Sopenharmony_ci			 */
281362306a36Sopenharmony_ci			if (dtEmpty(ip)) {
281462306a36Sopenharmony_ci				ctx->pos = DIREND;
281562306a36Sopenharmony_ci				return 0;
281662306a36Sopenharmony_ci			}
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci			if ((rc = dtReadFirst(ip, &btstack)))
281962306a36Sopenharmony_ci				return rc;
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci			DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
282262306a36Sopenharmony_ci		}
282362306a36Sopenharmony_ci	} else {
282462306a36Sopenharmony_ci		/*
282562306a36Sopenharmony_ci		 * Legacy filesystem - OS/2 & Linux JFS < 0.3.6
282662306a36Sopenharmony_ci		 *
282762306a36Sopenharmony_ci		 * pn = 0; index = 1:	First entry "."
282862306a36Sopenharmony_ci		 * pn = 0; index = 2:	Second entry ".."
282962306a36Sopenharmony_ci		 * pn > 0:		Real entries, pn=1 -> leftmost page
283062306a36Sopenharmony_ci		 * pn = index = -1:	No more entries
283162306a36Sopenharmony_ci		 */
283262306a36Sopenharmony_ci		dtpos = ctx->pos;
283362306a36Sopenharmony_ci		if (dtpos < 2) {
283462306a36Sopenharmony_ci			/* build "." entry */
283562306a36Sopenharmony_ci			ctx->pos = 1;
283662306a36Sopenharmony_ci			if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
283762306a36Sopenharmony_ci				return 0;
283862306a36Sopenharmony_ci			dtoffset->index = 2;
283962306a36Sopenharmony_ci			ctx->pos = dtpos;
284062306a36Sopenharmony_ci		}
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci		if (dtoffset->pn == 0) {
284362306a36Sopenharmony_ci			if (dtoffset->index == 2) {
284462306a36Sopenharmony_ci				/* build ".." entry */
284562306a36Sopenharmony_ci				if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
284662306a36Sopenharmony_ci					return 0;
284762306a36Sopenharmony_ci			} else {
284862306a36Sopenharmony_ci				jfs_err("jfs_readdir called with invalid offset!");
284962306a36Sopenharmony_ci			}
285062306a36Sopenharmony_ci			dtoffset->pn = 1;
285162306a36Sopenharmony_ci			dtoffset->index = 0;
285262306a36Sopenharmony_ci			ctx->pos = dtpos;
285362306a36Sopenharmony_ci		}
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci		if (dtEmpty(ip)) {
285662306a36Sopenharmony_ci			ctx->pos = DIREND;
285762306a36Sopenharmony_ci			return 0;
285862306a36Sopenharmony_ci		}
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci		if ((rc = dtReadNext(ip, &ctx->pos, &btstack))) {
286162306a36Sopenharmony_ci			jfs_err("jfs_readdir: unexpected rc = %d from dtReadNext",
286262306a36Sopenharmony_ci				rc);
286362306a36Sopenharmony_ci			ctx->pos = DIREND;
286462306a36Sopenharmony_ci			return 0;
286562306a36Sopenharmony_ci		}
286662306a36Sopenharmony_ci		/* get start leaf page and index */
286762306a36Sopenharmony_ci		DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci		/* offset beyond directory eof ? */
287062306a36Sopenharmony_ci		if (bn < 0) {
287162306a36Sopenharmony_ci			ctx->pos = DIREND;
287262306a36Sopenharmony_ci			return 0;
287362306a36Sopenharmony_ci		}
287462306a36Sopenharmony_ci	}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci	dirent_buf = __get_free_page(GFP_KERNEL);
287762306a36Sopenharmony_ci	if (dirent_buf == 0) {
287862306a36Sopenharmony_ci		DT_PUTPAGE(mp);
287962306a36Sopenharmony_ci		jfs_warn("jfs_readdir: __get_free_page failed!");
288062306a36Sopenharmony_ci		ctx->pos = DIREND;
288162306a36Sopenharmony_ci		return -ENOMEM;
288262306a36Sopenharmony_ci	}
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	while (1) {
288562306a36Sopenharmony_ci		jfs_dirent = (struct jfs_dirent *) dirent_buf;
288662306a36Sopenharmony_ci		jfs_dirents = 0;
288762306a36Sopenharmony_ci		overflow = fix_page = 0;
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci		stbl = DT_GETSTBL(p);
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci		for (i = index; i < p->header.nextindex; i++) {
289262306a36Sopenharmony_ci			d = (struct ldtentry *) & p->slot[stbl[i]];
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci			if (((long) jfs_dirent + d->namlen + 1) >
289562306a36Sopenharmony_ci			    (dirent_buf + PAGE_SIZE)) {
289662306a36Sopenharmony_ci				/* DBCS codepages could overrun dirent_buf */
289762306a36Sopenharmony_ci				index = i;
289862306a36Sopenharmony_ci				overflow = 1;
289962306a36Sopenharmony_ci				break;
290062306a36Sopenharmony_ci			}
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci			d_namleft = d->namlen;
290362306a36Sopenharmony_ci			name_ptr = jfs_dirent->name;
290462306a36Sopenharmony_ci			jfs_dirent->ino = le32_to_cpu(d->inumber);
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci			if (do_index) {
290762306a36Sopenharmony_ci				len = min(d_namleft, DTLHDRDATALEN);
290862306a36Sopenharmony_ci				jfs_dirent->position = le32_to_cpu(d->index);
290962306a36Sopenharmony_ci				/*
291062306a36Sopenharmony_ci				 * d->index should always be valid, but it
291162306a36Sopenharmony_ci				 * isn't.  fsck.jfs doesn't create the
291262306a36Sopenharmony_ci				 * directory index for the lost+found
291362306a36Sopenharmony_ci				 * directory.  Rather than let it go,
291462306a36Sopenharmony_ci				 * we can try to fix it.
291562306a36Sopenharmony_ci				 */
291662306a36Sopenharmony_ci				if ((jfs_dirent->position < 2) ||
291762306a36Sopenharmony_ci				    (jfs_dirent->position >=
291862306a36Sopenharmony_ci				     JFS_IP(ip)->next_index)) {
291962306a36Sopenharmony_ci					if (!page_fixed && !isReadOnly(ip)) {
292062306a36Sopenharmony_ci						fix_page = 1;
292162306a36Sopenharmony_ci						/*
292262306a36Sopenharmony_ci						 * setting overflow and setting
292362306a36Sopenharmony_ci						 * index to i will cause the
292462306a36Sopenharmony_ci						 * same page to be processed
292562306a36Sopenharmony_ci						 * again starting here
292662306a36Sopenharmony_ci						 */
292762306a36Sopenharmony_ci						overflow = 1;
292862306a36Sopenharmony_ci						index = i;
292962306a36Sopenharmony_ci						break;
293062306a36Sopenharmony_ci					}
293162306a36Sopenharmony_ci					jfs_dirent->position = unique_pos++;
293262306a36Sopenharmony_ci				}
293362306a36Sopenharmony_ci				/*
293462306a36Sopenharmony_ci				 * We add 1 to the index because we may
293562306a36Sopenharmony_ci				 * use a value of 2 internally, and NFSv4
293662306a36Sopenharmony_ci				 * doesn't like that.
293762306a36Sopenharmony_ci				 */
293862306a36Sopenharmony_ci				jfs_dirent->position++;
293962306a36Sopenharmony_ci			} else {
294062306a36Sopenharmony_ci				jfs_dirent->position = dtpos;
294162306a36Sopenharmony_ci				len = min(d_namleft, DTLHDRDATALEN_LEGACY);
294262306a36Sopenharmony_ci			}
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci			/* copy the name of head/only segment */
294562306a36Sopenharmony_ci			outlen = jfs_strfromUCS_le(name_ptr, d->name, len,
294662306a36Sopenharmony_ci						   codepage);
294762306a36Sopenharmony_ci			jfs_dirent->name_len = outlen;
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci			/* copy name in the additional segment(s) */
295062306a36Sopenharmony_ci			next = d->next;
295162306a36Sopenharmony_ci			while (next >= 0) {
295262306a36Sopenharmony_ci				t = (struct dtslot *) & p->slot[next];
295362306a36Sopenharmony_ci				name_ptr += outlen;
295462306a36Sopenharmony_ci				d_namleft -= len;
295562306a36Sopenharmony_ci				/* Sanity Check */
295662306a36Sopenharmony_ci				if (d_namleft == 0) {
295762306a36Sopenharmony_ci					jfs_error(ip->i_sb,
295862306a36Sopenharmony_ci						  "JFS:Dtree error: ino = %ld, bn=%lld, index = %d\n",
295962306a36Sopenharmony_ci						  (long)ip->i_ino,
296062306a36Sopenharmony_ci						  (long long)bn,
296162306a36Sopenharmony_ci						  i);
296262306a36Sopenharmony_ci					goto skip_one;
296362306a36Sopenharmony_ci				}
296462306a36Sopenharmony_ci				len = min(d_namleft, DTSLOTDATALEN);
296562306a36Sopenharmony_ci				outlen = jfs_strfromUCS_le(name_ptr, t->name,
296662306a36Sopenharmony_ci							   len, codepage);
296762306a36Sopenharmony_ci				jfs_dirent->name_len += outlen;
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci				next = t->next;
297062306a36Sopenharmony_ci			}
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci			jfs_dirents++;
297362306a36Sopenharmony_ci			jfs_dirent = next_jfs_dirent(jfs_dirent);
297462306a36Sopenharmony_ciskip_one:
297562306a36Sopenharmony_ci			if (!do_index)
297662306a36Sopenharmony_ci				dtoffset->index++;
297762306a36Sopenharmony_ci		}
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci		if (!overflow) {
298062306a36Sopenharmony_ci			/* Point to next leaf page */
298162306a36Sopenharmony_ci			if (p->header.flag & BT_ROOT)
298262306a36Sopenharmony_ci				bn = 0;
298362306a36Sopenharmony_ci			else {
298462306a36Sopenharmony_ci				bn = le64_to_cpu(p->header.next);
298562306a36Sopenharmony_ci				index = 0;
298662306a36Sopenharmony_ci				/* update offset (pn:index) for new page */
298762306a36Sopenharmony_ci				if (!do_index) {
298862306a36Sopenharmony_ci					dtoffset->pn++;
298962306a36Sopenharmony_ci					dtoffset->index = 0;
299062306a36Sopenharmony_ci				}
299162306a36Sopenharmony_ci			}
299262306a36Sopenharmony_ci			page_fixed = 0;
299362306a36Sopenharmony_ci		}
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci		/* unpin previous leaf page */
299662306a36Sopenharmony_ci		DT_PUTPAGE(mp);
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci		jfs_dirent = (struct jfs_dirent *) dirent_buf;
299962306a36Sopenharmony_ci		while (jfs_dirents--) {
300062306a36Sopenharmony_ci			ctx->pos = jfs_dirent->position;
300162306a36Sopenharmony_ci			if (!dir_emit(ctx, jfs_dirent->name,
300262306a36Sopenharmony_ci				    jfs_dirent->name_len,
300362306a36Sopenharmony_ci				    jfs_dirent->ino, DT_UNKNOWN))
300462306a36Sopenharmony_ci				goto out;
300562306a36Sopenharmony_ci			jfs_dirent = next_jfs_dirent(jfs_dirent);
300662306a36Sopenharmony_ci		}
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci		if (fix_page) {
300962306a36Sopenharmony_ci			add_missing_indices(ip, bn);
301062306a36Sopenharmony_ci			page_fixed = 1;
301162306a36Sopenharmony_ci		}
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci		if (!overflow && (bn == 0)) {
301462306a36Sopenharmony_ci			ctx->pos = DIREND;
301562306a36Sopenharmony_ci			break;
301662306a36Sopenharmony_ci		}
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
301962306a36Sopenharmony_ci		if (rc) {
302062306a36Sopenharmony_ci			free_page(dirent_buf);
302162306a36Sopenharmony_ci			return rc;
302262306a36Sopenharmony_ci		}
302362306a36Sopenharmony_ci	}
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci      out:
302662306a36Sopenharmony_ci	free_page(dirent_buf);
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	return rc;
302962306a36Sopenharmony_ci}
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci/*
303362306a36Sopenharmony_ci *	dtReadFirst()
303462306a36Sopenharmony_ci *
303562306a36Sopenharmony_ci * function: get the leftmost page of the directory
303662306a36Sopenharmony_ci */
303762306a36Sopenharmony_cistatic int dtReadFirst(struct inode *ip, struct btstack * btstack)
303862306a36Sopenharmony_ci{
303962306a36Sopenharmony_ci	int rc = 0;
304062306a36Sopenharmony_ci	s64 bn;
304162306a36Sopenharmony_ci	int psize = 288;	/* initial in-line directory */
304262306a36Sopenharmony_ci	struct metapage *mp;
304362306a36Sopenharmony_ci	dtpage_t *p;
304462306a36Sopenharmony_ci	s8 *stbl;
304562306a36Sopenharmony_ci	struct btframe *btsp;
304662306a36Sopenharmony_ci	pxd_t *xd;
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	BT_CLR(btstack);	/* reset stack */
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	/*
305162306a36Sopenharmony_ci	 *	descend leftmost path of the tree
305262306a36Sopenharmony_ci	 *
305362306a36Sopenharmony_ci	 * by convention, root bn = 0.
305462306a36Sopenharmony_ci	 */
305562306a36Sopenharmony_ci	for (bn = 0;;) {
305662306a36Sopenharmony_ci		DT_GETPAGE(ip, bn, mp, psize, p, rc);
305762306a36Sopenharmony_ci		if (rc)
305862306a36Sopenharmony_ci			return rc;
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci		/*
306162306a36Sopenharmony_ci		 * leftmost leaf page
306262306a36Sopenharmony_ci		 */
306362306a36Sopenharmony_ci		if (p->header.flag & BT_LEAF) {
306462306a36Sopenharmony_ci			/* return leftmost entry */
306562306a36Sopenharmony_ci			btsp = btstack->top;
306662306a36Sopenharmony_ci			btsp->bn = bn;
306762306a36Sopenharmony_ci			btsp->index = 0;
306862306a36Sopenharmony_ci			btsp->mp = mp;
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci			return 0;
307162306a36Sopenharmony_ci		}
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci		/*
307462306a36Sopenharmony_ci		 * descend down to leftmost child page
307562306a36Sopenharmony_ci		 */
307662306a36Sopenharmony_ci		if (BT_STACK_FULL(btstack)) {
307762306a36Sopenharmony_ci			DT_PUTPAGE(mp);
307862306a36Sopenharmony_ci			jfs_error(ip->i_sb, "btstack overrun\n");
307962306a36Sopenharmony_ci			BT_STACK_DUMP(btstack);
308062306a36Sopenharmony_ci			return -EIO;
308162306a36Sopenharmony_ci		}
308262306a36Sopenharmony_ci		/* push (bn, index) of the parent page/entry */
308362306a36Sopenharmony_ci		BT_PUSH(btstack, bn, 0);
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci		/* get the leftmost entry */
308662306a36Sopenharmony_ci		stbl = DT_GETSTBL(p);
308762306a36Sopenharmony_ci		xd = (pxd_t *) & p->slot[stbl[0]];
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci		/* get the child page block address */
309062306a36Sopenharmony_ci		bn = addressPXD(xd);
309162306a36Sopenharmony_ci		psize = lengthPXD(xd) << JFS_SBI(ip->i_sb)->l2bsize;
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci		/* unpin the parent page */
309462306a36Sopenharmony_ci		DT_PUTPAGE(mp);
309562306a36Sopenharmony_ci	}
309662306a36Sopenharmony_ci}
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ci/*
310062306a36Sopenharmony_ci *	dtReadNext()
310162306a36Sopenharmony_ci *
310262306a36Sopenharmony_ci * function: get the page of the specified offset (pn:index)
310362306a36Sopenharmony_ci *
310462306a36Sopenharmony_ci * return: if (offset > eof), bn = -1;
310562306a36Sopenharmony_ci *
310662306a36Sopenharmony_ci * note: if index > nextindex of the target leaf page,
310762306a36Sopenharmony_ci * start with 1st entry of next leaf page;
310862306a36Sopenharmony_ci */
310962306a36Sopenharmony_cistatic int dtReadNext(struct inode *ip, loff_t * offset,
311062306a36Sopenharmony_ci		      struct btstack * btstack)
311162306a36Sopenharmony_ci{
311262306a36Sopenharmony_ci	int rc = 0;
311362306a36Sopenharmony_ci	struct dtoffset {
311462306a36Sopenharmony_ci		s16 pn;
311562306a36Sopenharmony_ci		s16 index;
311662306a36Sopenharmony_ci		s32 unused;
311762306a36Sopenharmony_ci	} *dtoffset = (struct dtoffset *) offset;
311862306a36Sopenharmony_ci	s64 bn;
311962306a36Sopenharmony_ci	struct metapage *mp;
312062306a36Sopenharmony_ci	dtpage_t *p;
312162306a36Sopenharmony_ci	int index;
312262306a36Sopenharmony_ci	int pn;
312362306a36Sopenharmony_ci	s8 *stbl;
312462306a36Sopenharmony_ci	struct btframe *btsp, *parent;
312562306a36Sopenharmony_ci	pxd_t *xd;
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ci	/*
312862306a36Sopenharmony_ci	 * get leftmost leaf page pinned
312962306a36Sopenharmony_ci	 */
313062306a36Sopenharmony_ci	if ((rc = dtReadFirst(ip, btstack)))
313162306a36Sopenharmony_ci		return rc;
313262306a36Sopenharmony_ci
313362306a36Sopenharmony_ci	/* get leaf page */
313462306a36Sopenharmony_ci	DT_GETSEARCH(ip, btstack->top, bn, mp, p, index);
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	/* get the start offset (pn:index) */
313762306a36Sopenharmony_ci	pn = dtoffset->pn - 1;	/* Now pn = 0 represents leftmost leaf */
313862306a36Sopenharmony_ci	index = dtoffset->index;
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci	/* start at leftmost page ? */
314162306a36Sopenharmony_ci	if (pn == 0) {
314262306a36Sopenharmony_ci		/* offset beyond eof ? */
314362306a36Sopenharmony_ci		if (index < p->header.nextindex)
314462306a36Sopenharmony_ci			goto out;
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci		if (p->header.flag & BT_ROOT) {
314762306a36Sopenharmony_ci			bn = -1;
314862306a36Sopenharmony_ci			goto out;
314962306a36Sopenharmony_ci		}
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci		/* start with 1st entry of next leaf page */
315262306a36Sopenharmony_ci		dtoffset->pn++;
315362306a36Sopenharmony_ci		dtoffset->index = index = 0;
315462306a36Sopenharmony_ci		goto a;
315562306a36Sopenharmony_ci	}
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	/* start at non-leftmost page: scan parent pages for large pn */
315862306a36Sopenharmony_ci	if (p->header.flag & BT_ROOT) {
315962306a36Sopenharmony_ci		bn = -1;
316062306a36Sopenharmony_ci		goto out;
316162306a36Sopenharmony_ci	}
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	/* start after next leaf page ? */
316462306a36Sopenharmony_ci	if (pn > 1)
316562306a36Sopenharmony_ci		goto b;
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci	/* get leaf page pn = 1 */
316862306a36Sopenharmony_ci      a:
316962306a36Sopenharmony_ci	bn = le64_to_cpu(p->header.next);
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci	/* unpin leaf page */
317262306a36Sopenharmony_ci	DT_PUTPAGE(mp);
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	/* offset beyond eof ? */
317562306a36Sopenharmony_ci	if (bn == 0) {
317662306a36Sopenharmony_ci		bn = -1;
317762306a36Sopenharmony_ci		goto out;
317862306a36Sopenharmony_ci	}
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ci	goto c;
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	/*
318362306a36Sopenharmony_ci	 * scan last internal page level to get target leaf page
318462306a36Sopenharmony_ci	 */
318562306a36Sopenharmony_ci      b:
318662306a36Sopenharmony_ci	/* unpin leftmost leaf page */
318762306a36Sopenharmony_ci	DT_PUTPAGE(mp);
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	/* get left most parent page */
319062306a36Sopenharmony_ci	btsp = btstack->top;
319162306a36Sopenharmony_ci	parent = btsp - 1;
319262306a36Sopenharmony_ci	bn = parent->bn;
319362306a36Sopenharmony_ci	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
319462306a36Sopenharmony_ci	if (rc)
319562306a36Sopenharmony_ci		return rc;
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci	/* scan parent pages at last internal page level */
319862306a36Sopenharmony_ci	while (pn >= p->header.nextindex) {
319962306a36Sopenharmony_ci		pn -= p->header.nextindex;
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci		/* get next parent page address */
320262306a36Sopenharmony_ci		bn = le64_to_cpu(p->header.next);
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci		/* unpin current parent page */
320562306a36Sopenharmony_ci		DT_PUTPAGE(mp);
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci		/* offset beyond eof ? */
320862306a36Sopenharmony_ci		if (bn == 0) {
320962306a36Sopenharmony_ci			bn = -1;
321062306a36Sopenharmony_ci			goto out;
321162306a36Sopenharmony_ci		}
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci		/* get next parent page */
321462306a36Sopenharmony_ci		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
321562306a36Sopenharmony_ci		if (rc)
321662306a36Sopenharmony_ci			return rc;
321762306a36Sopenharmony_ci
321862306a36Sopenharmony_ci		/* update parent page stack frame */
321962306a36Sopenharmony_ci		parent->bn = bn;
322062306a36Sopenharmony_ci	}
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	/* get leaf page address */
322362306a36Sopenharmony_ci	stbl = DT_GETSTBL(p);
322462306a36Sopenharmony_ci	xd = (pxd_t *) & p->slot[stbl[pn]];
322562306a36Sopenharmony_ci	bn = addressPXD(xd);
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci	/* unpin parent page */
322862306a36Sopenharmony_ci	DT_PUTPAGE(mp);
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	/*
323162306a36Sopenharmony_ci	 * get target leaf page
323262306a36Sopenharmony_ci	 */
323362306a36Sopenharmony_ci      c:
323462306a36Sopenharmony_ci	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
323562306a36Sopenharmony_ci	if (rc)
323662306a36Sopenharmony_ci		return rc;
323762306a36Sopenharmony_ci
323862306a36Sopenharmony_ci	/*
323962306a36Sopenharmony_ci	 * leaf page has been completed:
324062306a36Sopenharmony_ci	 * start with 1st entry of next leaf page
324162306a36Sopenharmony_ci	 */
324262306a36Sopenharmony_ci	if (index >= p->header.nextindex) {
324362306a36Sopenharmony_ci		bn = le64_to_cpu(p->header.next);
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_ci		/* unpin leaf page */
324662306a36Sopenharmony_ci		DT_PUTPAGE(mp);
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci		/* offset beyond eof ? */
324962306a36Sopenharmony_ci		if (bn == 0) {
325062306a36Sopenharmony_ci			bn = -1;
325162306a36Sopenharmony_ci			goto out;
325262306a36Sopenharmony_ci		}
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci		/* get next leaf page */
325562306a36Sopenharmony_ci		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
325662306a36Sopenharmony_ci		if (rc)
325762306a36Sopenharmony_ci			return rc;
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci		/* start with 1st entry of next leaf page */
326062306a36Sopenharmony_ci		dtoffset->pn++;
326162306a36Sopenharmony_ci		dtoffset->index = 0;
326262306a36Sopenharmony_ci	}
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ci      out:
326562306a36Sopenharmony_ci	/* return target leaf page pinned */
326662306a36Sopenharmony_ci	btsp = btstack->top;
326762306a36Sopenharmony_ci	btsp->bn = bn;
326862306a36Sopenharmony_ci	btsp->index = dtoffset->index;
326962306a36Sopenharmony_ci	btsp->mp = mp;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	return 0;
327262306a36Sopenharmony_ci}
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci/*
327662306a36Sopenharmony_ci *	dtCompare()
327762306a36Sopenharmony_ci *
327862306a36Sopenharmony_ci * function: compare search key with an internal entry
327962306a36Sopenharmony_ci *
328062306a36Sopenharmony_ci * return:
328162306a36Sopenharmony_ci *	< 0 if k is < record
328262306a36Sopenharmony_ci *	= 0 if k is = record
328362306a36Sopenharmony_ci *	> 0 if k is > record
328462306a36Sopenharmony_ci */
328562306a36Sopenharmony_cistatic int dtCompare(struct component_name * key,	/* search key */
328662306a36Sopenharmony_ci		     dtpage_t * p,	/* directory page */
328762306a36Sopenharmony_ci		     int si)
328862306a36Sopenharmony_ci{				/* entry slot index */
328962306a36Sopenharmony_ci	wchar_t *kname;
329062306a36Sopenharmony_ci	__le16 *name;
329162306a36Sopenharmony_ci	int klen, namlen, len, rc;
329262306a36Sopenharmony_ci	struct idtentry *ih;
329362306a36Sopenharmony_ci	struct dtslot *t;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	/*
329662306a36Sopenharmony_ci	 * force the left-most key on internal pages, at any level of
329762306a36Sopenharmony_ci	 * the tree, to be less than any search key.
329862306a36Sopenharmony_ci	 * this obviates having to update the leftmost key on an internal
329962306a36Sopenharmony_ci	 * page when the user inserts a new key in the tree smaller than
330062306a36Sopenharmony_ci	 * anything that has been stored.
330162306a36Sopenharmony_ci	 *
330262306a36Sopenharmony_ci	 * (? if/when dtSearch() narrows down to 1st entry (index = 0),
330362306a36Sopenharmony_ci	 * at any internal page at any level of the tree,
330462306a36Sopenharmony_ci	 * it descends to child of the entry anyway -
330562306a36Sopenharmony_ci	 * ? make the entry as min size dummy entry)
330662306a36Sopenharmony_ci	 *
330762306a36Sopenharmony_ci	 * if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & BT_LEAF))
330862306a36Sopenharmony_ci	 * return (1);
330962306a36Sopenharmony_ci	 */
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci	kname = key->name;
331262306a36Sopenharmony_ci	klen = key->namlen;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	ih = (struct idtentry *) & p->slot[si];
331562306a36Sopenharmony_ci	si = ih->next;
331662306a36Sopenharmony_ci	name = ih->name;
331762306a36Sopenharmony_ci	namlen = ih->namlen;
331862306a36Sopenharmony_ci	len = min(namlen, DTIHDRDATALEN);
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	/* compare with head/only segment */
332162306a36Sopenharmony_ci	len = min(klen, len);
332262306a36Sopenharmony_ci	if ((rc = UniStrncmp_le(kname, name, len)))
332362306a36Sopenharmony_ci		return rc;
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	klen -= len;
332662306a36Sopenharmony_ci	namlen -= len;
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_ci	/* compare with additional segment(s) */
332962306a36Sopenharmony_ci	kname += len;
333062306a36Sopenharmony_ci	while (klen > 0 && namlen > 0) {
333162306a36Sopenharmony_ci		/* compare with next name segment */
333262306a36Sopenharmony_ci		t = (struct dtslot *) & p->slot[si];
333362306a36Sopenharmony_ci		len = min(namlen, DTSLOTDATALEN);
333462306a36Sopenharmony_ci		len = min(klen, len);
333562306a36Sopenharmony_ci		name = t->name;
333662306a36Sopenharmony_ci		if ((rc = UniStrncmp_le(kname, name, len)))
333762306a36Sopenharmony_ci			return rc;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci		klen -= len;
334062306a36Sopenharmony_ci		namlen -= len;
334162306a36Sopenharmony_ci		kname += len;
334262306a36Sopenharmony_ci		si = t->next;
334362306a36Sopenharmony_ci	}
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_ci	return (klen - namlen);
334662306a36Sopenharmony_ci}
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci/*
335262306a36Sopenharmony_ci *	ciCompare()
335362306a36Sopenharmony_ci *
335462306a36Sopenharmony_ci * function: compare search key with an (leaf/internal) entry
335562306a36Sopenharmony_ci *
335662306a36Sopenharmony_ci * return:
335762306a36Sopenharmony_ci *	< 0 if k is < record
335862306a36Sopenharmony_ci *	= 0 if k is = record
335962306a36Sopenharmony_ci *	> 0 if k is > record
336062306a36Sopenharmony_ci */
336162306a36Sopenharmony_cistatic int ciCompare(struct component_name * key,	/* search key */
336262306a36Sopenharmony_ci		     dtpage_t * p,	/* directory page */
336362306a36Sopenharmony_ci		     int si,	/* entry slot index */
336462306a36Sopenharmony_ci		     int flag)
336562306a36Sopenharmony_ci{
336662306a36Sopenharmony_ci	wchar_t *kname, x;
336762306a36Sopenharmony_ci	__le16 *name;
336862306a36Sopenharmony_ci	int klen, namlen, len, rc;
336962306a36Sopenharmony_ci	struct ldtentry *lh;
337062306a36Sopenharmony_ci	struct idtentry *ih;
337162306a36Sopenharmony_ci	struct dtslot *t;
337262306a36Sopenharmony_ci	int i;
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci	/*
337562306a36Sopenharmony_ci	 * force the left-most key on internal pages, at any level of
337662306a36Sopenharmony_ci	 * the tree, to be less than any search key.
337762306a36Sopenharmony_ci	 * this obviates having to update the leftmost key on an internal
337862306a36Sopenharmony_ci	 * page when the user inserts a new key in the tree smaller than
337962306a36Sopenharmony_ci	 * anything that has been stored.
338062306a36Sopenharmony_ci	 *
338162306a36Sopenharmony_ci	 * (? if/when dtSearch() narrows down to 1st entry (index = 0),
338262306a36Sopenharmony_ci	 * at any internal page at any level of the tree,
338362306a36Sopenharmony_ci	 * it descends to child of the entry anyway -
338462306a36Sopenharmony_ci	 * ? make the entry as min size dummy entry)
338562306a36Sopenharmony_ci	 *
338662306a36Sopenharmony_ci	 * if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & BT_LEAF))
338762306a36Sopenharmony_ci	 * return (1);
338862306a36Sopenharmony_ci	 */
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci	kname = key->name;
339162306a36Sopenharmony_ci	klen = key->namlen;
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	/*
339462306a36Sopenharmony_ci	 * leaf page entry
339562306a36Sopenharmony_ci	 */
339662306a36Sopenharmony_ci	if (p->header.flag & BT_LEAF) {
339762306a36Sopenharmony_ci		lh = (struct ldtentry *) & p->slot[si];
339862306a36Sopenharmony_ci		si = lh->next;
339962306a36Sopenharmony_ci		name = lh->name;
340062306a36Sopenharmony_ci		namlen = lh->namlen;
340162306a36Sopenharmony_ci		if (flag & JFS_DIR_INDEX)
340262306a36Sopenharmony_ci			len = min(namlen, DTLHDRDATALEN);
340362306a36Sopenharmony_ci		else
340462306a36Sopenharmony_ci			len = min(namlen, DTLHDRDATALEN_LEGACY);
340562306a36Sopenharmony_ci	}
340662306a36Sopenharmony_ci	/*
340762306a36Sopenharmony_ci	 * internal page entry
340862306a36Sopenharmony_ci	 */
340962306a36Sopenharmony_ci	else {
341062306a36Sopenharmony_ci		ih = (struct idtentry *) & p->slot[si];
341162306a36Sopenharmony_ci		si = ih->next;
341262306a36Sopenharmony_ci		name = ih->name;
341362306a36Sopenharmony_ci		namlen = ih->namlen;
341462306a36Sopenharmony_ci		len = min(namlen, DTIHDRDATALEN);
341562306a36Sopenharmony_ci	}
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_ci	/* compare with head/only segment */
341862306a36Sopenharmony_ci	len = min(klen, len);
341962306a36Sopenharmony_ci	for (i = 0; i < len; i++, kname++, name++) {
342062306a36Sopenharmony_ci		/* only uppercase if case-insensitive support is on */
342162306a36Sopenharmony_ci		if ((flag & JFS_OS2) == JFS_OS2)
342262306a36Sopenharmony_ci			x = UniToupper(le16_to_cpu(*name));
342362306a36Sopenharmony_ci		else
342462306a36Sopenharmony_ci			x = le16_to_cpu(*name);
342562306a36Sopenharmony_ci		if ((rc = *kname - x))
342662306a36Sopenharmony_ci			return rc;
342762306a36Sopenharmony_ci	}
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	klen -= len;
343062306a36Sopenharmony_ci	namlen -= len;
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci	/* compare with additional segment(s) */
343362306a36Sopenharmony_ci	while (klen > 0 && namlen > 0) {
343462306a36Sopenharmony_ci		/* compare with next name segment */
343562306a36Sopenharmony_ci		t = (struct dtslot *) & p->slot[si];
343662306a36Sopenharmony_ci		len = min(namlen, DTSLOTDATALEN);
343762306a36Sopenharmony_ci		len = min(klen, len);
343862306a36Sopenharmony_ci		name = t->name;
343962306a36Sopenharmony_ci		for (i = 0; i < len; i++, kname++, name++) {
344062306a36Sopenharmony_ci			/* only uppercase if case-insensitive support is on */
344162306a36Sopenharmony_ci			if ((flag & JFS_OS2) == JFS_OS2)
344262306a36Sopenharmony_ci				x = UniToupper(le16_to_cpu(*name));
344362306a36Sopenharmony_ci			else
344462306a36Sopenharmony_ci				x = le16_to_cpu(*name);
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci			if ((rc = *kname - x))
344762306a36Sopenharmony_ci				return rc;
344862306a36Sopenharmony_ci		}
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci		klen -= len;
345162306a36Sopenharmony_ci		namlen -= len;
345262306a36Sopenharmony_ci		si = t->next;
345362306a36Sopenharmony_ci	}
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_ci	return (klen - namlen);
345662306a36Sopenharmony_ci}
345762306a36Sopenharmony_ci
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci/*
346062306a36Sopenharmony_ci *	ciGetLeafPrefixKey()
346162306a36Sopenharmony_ci *
346262306a36Sopenharmony_ci * function: compute prefix of suffix compression
346362306a36Sopenharmony_ci *	     from two adjacent leaf entries
346462306a36Sopenharmony_ci *	     across page boundary
346562306a36Sopenharmony_ci *
346662306a36Sopenharmony_ci * return: non-zero on error
346762306a36Sopenharmony_ci *
346862306a36Sopenharmony_ci */
346962306a36Sopenharmony_cistatic int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
347062306a36Sopenharmony_ci			       int ri, struct component_name * key, int flag)
347162306a36Sopenharmony_ci{
347262306a36Sopenharmony_ci	int klen, namlen;
347362306a36Sopenharmony_ci	wchar_t *pl, *pr, *kname;
347462306a36Sopenharmony_ci	struct component_name lkey;
347562306a36Sopenharmony_ci	struct component_name rkey;
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	lkey.name = kmalloc_array(JFS_NAME_MAX + 1, sizeof(wchar_t),
347862306a36Sopenharmony_ci					GFP_KERNEL);
347962306a36Sopenharmony_ci	if (lkey.name == NULL)
348062306a36Sopenharmony_ci		return -ENOMEM;
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ci	rkey.name = kmalloc_array(JFS_NAME_MAX + 1, sizeof(wchar_t),
348362306a36Sopenharmony_ci					GFP_KERNEL);
348462306a36Sopenharmony_ci	if (rkey.name == NULL) {
348562306a36Sopenharmony_ci		kfree(lkey.name);
348662306a36Sopenharmony_ci		return -ENOMEM;
348762306a36Sopenharmony_ci	}
348862306a36Sopenharmony_ci
348962306a36Sopenharmony_ci	/* get left and right key */
349062306a36Sopenharmony_ci	dtGetKey(lp, li, &lkey, flag);
349162306a36Sopenharmony_ci	lkey.name[lkey.namlen] = 0;
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci	if ((flag & JFS_OS2) == JFS_OS2)
349462306a36Sopenharmony_ci		ciToUpper(&lkey);
349562306a36Sopenharmony_ci
349662306a36Sopenharmony_ci	dtGetKey(rp, ri, &rkey, flag);
349762306a36Sopenharmony_ci	rkey.name[rkey.namlen] = 0;
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci	if ((flag & JFS_OS2) == JFS_OS2)
350162306a36Sopenharmony_ci		ciToUpper(&rkey);
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci	/* compute prefix */
350462306a36Sopenharmony_ci	klen = 0;
350562306a36Sopenharmony_ci	kname = key->name;
350662306a36Sopenharmony_ci	namlen = min(lkey.namlen, rkey.namlen);
350762306a36Sopenharmony_ci	for (pl = lkey.name, pr = rkey.name;
350862306a36Sopenharmony_ci	     namlen; pl++, pr++, namlen--, klen++, kname++) {
350962306a36Sopenharmony_ci		*kname = *pr;
351062306a36Sopenharmony_ci		if (*pl != *pr) {
351162306a36Sopenharmony_ci			key->namlen = klen + 1;
351262306a36Sopenharmony_ci			goto free_names;
351362306a36Sopenharmony_ci		}
351462306a36Sopenharmony_ci	}
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	/* l->namlen <= r->namlen since l <= r */
351762306a36Sopenharmony_ci	if (lkey.namlen < rkey.namlen) {
351862306a36Sopenharmony_ci		*kname = *pr;
351962306a36Sopenharmony_ci		key->namlen = klen + 1;
352062306a36Sopenharmony_ci	} else			/* l->namelen == r->namelen */
352162306a36Sopenharmony_ci		key->namlen = klen;
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_cifree_names:
352462306a36Sopenharmony_ci	kfree(lkey.name);
352562306a36Sopenharmony_ci	kfree(rkey.name);
352662306a36Sopenharmony_ci	return 0;
352762306a36Sopenharmony_ci}
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci/*
353262306a36Sopenharmony_ci *	dtGetKey()
353362306a36Sopenharmony_ci *
353462306a36Sopenharmony_ci * function: get key of the entry
353562306a36Sopenharmony_ci */
353662306a36Sopenharmony_cistatic void dtGetKey(dtpage_t * p, int i,	/* entry index */
353762306a36Sopenharmony_ci		     struct component_name * key, int flag)
353862306a36Sopenharmony_ci{
353962306a36Sopenharmony_ci	int si;
354062306a36Sopenharmony_ci	s8 *stbl;
354162306a36Sopenharmony_ci	struct ldtentry *lh;
354262306a36Sopenharmony_ci	struct idtentry *ih;
354362306a36Sopenharmony_ci	struct dtslot *t;
354462306a36Sopenharmony_ci	int namlen, len;
354562306a36Sopenharmony_ci	wchar_t *kname;
354662306a36Sopenharmony_ci	__le16 *name;
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci	/* get entry */
354962306a36Sopenharmony_ci	stbl = DT_GETSTBL(p);
355062306a36Sopenharmony_ci	si = stbl[i];
355162306a36Sopenharmony_ci	if (p->header.flag & BT_LEAF) {
355262306a36Sopenharmony_ci		lh = (struct ldtentry *) & p->slot[si];
355362306a36Sopenharmony_ci		si = lh->next;
355462306a36Sopenharmony_ci		namlen = lh->namlen;
355562306a36Sopenharmony_ci		name = lh->name;
355662306a36Sopenharmony_ci		if (flag & JFS_DIR_INDEX)
355762306a36Sopenharmony_ci			len = min(namlen, DTLHDRDATALEN);
355862306a36Sopenharmony_ci		else
355962306a36Sopenharmony_ci			len = min(namlen, DTLHDRDATALEN_LEGACY);
356062306a36Sopenharmony_ci	} else {
356162306a36Sopenharmony_ci		ih = (struct idtentry *) & p->slot[si];
356262306a36Sopenharmony_ci		si = ih->next;
356362306a36Sopenharmony_ci		namlen = ih->namlen;
356462306a36Sopenharmony_ci		name = ih->name;
356562306a36Sopenharmony_ci		len = min(namlen, DTIHDRDATALEN);
356662306a36Sopenharmony_ci	}
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci	key->namlen = namlen;
356962306a36Sopenharmony_ci	kname = key->name;
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci	/*
357262306a36Sopenharmony_ci	 * move head/only segment
357362306a36Sopenharmony_ci	 */
357462306a36Sopenharmony_ci	UniStrncpy_from_le(kname, name, len);
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci	/*
357762306a36Sopenharmony_ci	 * move additional segment(s)
357862306a36Sopenharmony_ci	 */
357962306a36Sopenharmony_ci	while (si >= 0) {
358062306a36Sopenharmony_ci		/* get next segment */
358162306a36Sopenharmony_ci		t = &p->slot[si];
358262306a36Sopenharmony_ci		kname += len;
358362306a36Sopenharmony_ci		namlen -= len;
358462306a36Sopenharmony_ci		len = min(namlen, DTSLOTDATALEN);
358562306a36Sopenharmony_ci		UniStrncpy_from_le(kname, t->name, len);
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci		si = t->next;
358862306a36Sopenharmony_ci	}
358962306a36Sopenharmony_ci}
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci
359262306a36Sopenharmony_ci/*
359362306a36Sopenharmony_ci *	dtInsertEntry()
359462306a36Sopenharmony_ci *
359562306a36Sopenharmony_ci * function: allocate free slot(s) and
359662306a36Sopenharmony_ci *	     write a leaf/internal entry
359762306a36Sopenharmony_ci *
359862306a36Sopenharmony_ci * return: entry slot index
359962306a36Sopenharmony_ci */
360062306a36Sopenharmony_cistatic void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
360162306a36Sopenharmony_ci			  ddata_t * data, struct dt_lock ** dtlock)
360262306a36Sopenharmony_ci{
360362306a36Sopenharmony_ci	struct dtslot *h, *t;
360462306a36Sopenharmony_ci	struct ldtentry *lh = NULL;
360562306a36Sopenharmony_ci	struct idtentry *ih = NULL;
360662306a36Sopenharmony_ci	int hsi, fsi, klen, len, nextindex;
360762306a36Sopenharmony_ci	wchar_t *kname;
360862306a36Sopenharmony_ci	__le16 *name;
360962306a36Sopenharmony_ci	s8 *stbl;
361062306a36Sopenharmony_ci	pxd_t *xd;
361162306a36Sopenharmony_ci	struct dt_lock *dtlck = *dtlock;
361262306a36Sopenharmony_ci	struct lv *lv;
361362306a36Sopenharmony_ci	int xsi, n;
361462306a36Sopenharmony_ci	s64 bn = 0;
361562306a36Sopenharmony_ci	struct metapage *mp = NULL;
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	klen = key->namlen;
361862306a36Sopenharmony_ci	kname = key->name;
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci	/* allocate a free slot */
362162306a36Sopenharmony_ci	hsi = fsi = p->header.freelist;
362262306a36Sopenharmony_ci	h = &p->slot[fsi];
362362306a36Sopenharmony_ci	p->header.freelist = h->next;
362462306a36Sopenharmony_ci	--p->header.freecnt;
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	/* open new linelock */
362762306a36Sopenharmony_ci	if (dtlck->index >= dtlck->maxcnt)
362862306a36Sopenharmony_ci		dtlck = (struct dt_lock *) txLinelock(dtlck);
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci	lv = & dtlck->lv[dtlck->index];
363162306a36Sopenharmony_ci	lv->offset = hsi;
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	/* write head/only segment */
363462306a36Sopenharmony_ci	if (p->header.flag & BT_LEAF) {
363562306a36Sopenharmony_ci		lh = (struct ldtentry *) h;
363662306a36Sopenharmony_ci		lh->next = h->next;
363762306a36Sopenharmony_ci		lh->inumber = cpu_to_le32(data->leaf.ino);
363862306a36Sopenharmony_ci		lh->namlen = klen;
363962306a36Sopenharmony_ci		name = lh->name;
364062306a36Sopenharmony_ci		if (data->leaf.ip) {
364162306a36Sopenharmony_ci			len = min(klen, DTLHDRDATALEN);
364262306a36Sopenharmony_ci			if (!(p->header.flag & BT_ROOT))
364362306a36Sopenharmony_ci				bn = addressPXD(&p->header.self);
364462306a36Sopenharmony_ci			lh->index = cpu_to_le32(add_index(data->leaf.tid,
364562306a36Sopenharmony_ci							  data->leaf.ip,
364662306a36Sopenharmony_ci							  bn, index));
364762306a36Sopenharmony_ci		} else
364862306a36Sopenharmony_ci			len = min(klen, DTLHDRDATALEN_LEGACY);
364962306a36Sopenharmony_ci	} else {
365062306a36Sopenharmony_ci		ih = (struct idtentry *) h;
365162306a36Sopenharmony_ci		ih->next = h->next;
365262306a36Sopenharmony_ci		xd = (pxd_t *) ih;
365362306a36Sopenharmony_ci		*xd = data->xd;
365462306a36Sopenharmony_ci		ih->namlen = klen;
365562306a36Sopenharmony_ci		name = ih->name;
365662306a36Sopenharmony_ci		len = min(klen, DTIHDRDATALEN);
365762306a36Sopenharmony_ci	}
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	UniStrncpy_to_le(name, kname, len);
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci	n = 1;
366262306a36Sopenharmony_ci	xsi = hsi;
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_ci	/* write additional segment(s) */
366562306a36Sopenharmony_ci	t = h;
366662306a36Sopenharmony_ci	klen -= len;
366762306a36Sopenharmony_ci	while (klen) {
366862306a36Sopenharmony_ci		/* get free slot */
366962306a36Sopenharmony_ci		fsi = p->header.freelist;
367062306a36Sopenharmony_ci		t = &p->slot[fsi];
367162306a36Sopenharmony_ci		p->header.freelist = t->next;
367262306a36Sopenharmony_ci		--p->header.freecnt;
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_ci		/* is next slot contiguous ? */
367562306a36Sopenharmony_ci		if (fsi != xsi + 1) {
367662306a36Sopenharmony_ci			/* close current linelock */
367762306a36Sopenharmony_ci			lv->length = n;
367862306a36Sopenharmony_ci			dtlck->index++;
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_ci			/* open new linelock */
368162306a36Sopenharmony_ci			if (dtlck->index < dtlck->maxcnt)
368262306a36Sopenharmony_ci				lv++;
368362306a36Sopenharmony_ci			else {
368462306a36Sopenharmony_ci				dtlck = (struct dt_lock *) txLinelock(dtlck);
368562306a36Sopenharmony_ci				lv = & dtlck->lv[0];
368662306a36Sopenharmony_ci			}
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci			lv->offset = fsi;
368962306a36Sopenharmony_ci			n = 0;
369062306a36Sopenharmony_ci		}
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci		kname += len;
369362306a36Sopenharmony_ci		len = min(klen, DTSLOTDATALEN);
369462306a36Sopenharmony_ci		UniStrncpy_to_le(t->name, kname, len);
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci		n++;
369762306a36Sopenharmony_ci		xsi = fsi;
369862306a36Sopenharmony_ci		klen -= len;
369962306a36Sopenharmony_ci	}
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	/* close current linelock */
370262306a36Sopenharmony_ci	lv->length = n;
370362306a36Sopenharmony_ci	dtlck->index++;
370462306a36Sopenharmony_ci
370562306a36Sopenharmony_ci	*dtlock = dtlck;
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_ci	/* terminate last/only segment */
370862306a36Sopenharmony_ci	if (h == t) {
370962306a36Sopenharmony_ci		/* single segment entry */
371062306a36Sopenharmony_ci		if (p->header.flag & BT_LEAF)
371162306a36Sopenharmony_ci			lh->next = -1;
371262306a36Sopenharmony_ci		else
371362306a36Sopenharmony_ci			ih->next = -1;
371462306a36Sopenharmony_ci	} else
371562306a36Sopenharmony_ci		/* multi-segment entry */
371662306a36Sopenharmony_ci		t->next = -1;
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_ci	/* if insert into middle, shift right succeeding entries in stbl */
371962306a36Sopenharmony_ci	stbl = DT_GETSTBL(p);
372062306a36Sopenharmony_ci	nextindex = p->header.nextindex;
372162306a36Sopenharmony_ci	if (index < nextindex) {
372262306a36Sopenharmony_ci		memmove(stbl + index + 1, stbl + index, nextindex - index);
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_ci		if ((p->header.flag & BT_LEAF) && data->leaf.ip) {
372562306a36Sopenharmony_ci			s64 lblock;
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_ci			/*
372862306a36Sopenharmony_ci			 * Need to update slot number for entries that moved
372962306a36Sopenharmony_ci			 * in the stbl
373062306a36Sopenharmony_ci			 */
373162306a36Sopenharmony_ci			mp = NULL;
373262306a36Sopenharmony_ci			for (n = index + 1; n <= nextindex; n++) {
373362306a36Sopenharmony_ci				lh = (struct ldtentry *) & (p->slot[stbl[n]]);
373462306a36Sopenharmony_ci				modify_index(data->leaf.tid, data->leaf.ip,
373562306a36Sopenharmony_ci					     le32_to_cpu(lh->index), bn, n,
373662306a36Sopenharmony_ci					     &mp, &lblock);
373762306a36Sopenharmony_ci			}
373862306a36Sopenharmony_ci			if (mp)
373962306a36Sopenharmony_ci				release_metapage(mp);
374062306a36Sopenharmony_ci		}
374162306a36Sopenharmony_ci	}
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci	stbl[index] = hsi;
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci	/* advance next available entry index of stbl */
374662306a36Sopenharmony_ci	++p->header.nextindex;
374762306a36Sopenharmony_ci}
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ci/*
375162306a36Sopenharmony_ci *	dtMoveEntry()
375262306a36Sopenharmony_ci *
375362306a36Sopenharmony_ci * function: move entries from split/left page to new/right page
375462306a36Sopenharmony_ci *
375562306a36Sopenharmony_ci *	nextindex of dst page and freelist/freecnt of both pages
375662306a36Sopenharmony_ci *	are updated.
375762306a36Sopenharmony_ci */
375862306a36Sopenharmony_cistatic void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
375962306a36Sopenharmony_ci			struct dt_lock ** sdtlock, struct dt_lock ** ddtlock,
376062306a36Sopenharmony_ci			int do_index)
376162306a36Sopenharmony_ci{
376262306a36Sopenharmony_ci	int ssi, next;		/* src slot index */
376362306a36Sopenharmony_ci	int di;			/* dst entry index */
376462306a36Sopenharmony_ci	int dsi;		/* dst slot index */
376562306a36Sopenharmony_ci	s8 *sstbl, *dstbl;	/* sorted entry table */
376662306a36Sopenharmony_ci	int snamlen, len;
376762306a36Sopenharmony_ci	struct ldtentry *slh, *dlh = NULL;
376862306a36Sopenharmony_ci	struct idtentry *sih, *dih = NULL;
376962306a36Sopenharmony_ci	struct dtslot *h, *s, *d;
377062306a36Sopenharmony_ci	struct dt_lock *sdtlck = *sdtlock, *ddtlck = *ddtlock;
377162306a36Sopenharmony_ci	struct lv *slv, *dlv;
377262306a36Sopenharmony_ci	int xssi, ns, nd;
377362306a36Sopenharmony_ci	int sfsi;
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_ci	sstbl = (s8 *) & sp->slot[sp->header.stblindex];
377662306a36Sopenharmony_ci	dstbl = (s8 *) & dp->slot[dp->header.stblindex];
377762306a36Sopenharmony_ci
377862306a36Sopenharmony_ci	dsi = dp->header.freelist;	/* first (whole page) free slot */
377962306a36Sopenharmony_ci	sfsi = sp->header.freelist;
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci	/* linelock destination entry slot */
378262306a36Sopenharmony_ci	dlv = & ddtlck->lv[ddtlck->index];
378362306a36Sopenharmony_ci	dlv->offset = dsi;
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci	/* linelock source entry slot */
378662306a36Sopenharmony_ci	slv = & sdtlck->lv[sdtlck->index];
378762306a36Sopenharmony_ci	slv->offset = sstbl[si];
378862306a36Sopenharmony_ci	xssi = slv->offset - 1;
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci	/*
379162306a36Sopenharmony_ci	 * move entries
379262306a36Sopenharmony_ci	 */
379362306a36Sopenharmony_ci	ns = nd = 0;
379462306a36Sopenharmony_ci	for (di = 0; si < sp->header.nextindex; si++, di++) {
379562306a36Sopenharmony_ci		ssi = sstbl[si];
379662306a36Sopenharmony_ci		dstbl[di] = dsi;
379762306a36Sopenharmony_ci
379862306a36Sopenharmony_ci		/* is next slot contiguous ? */
379962306a36Sopenharmony_ci		if (ssi != xssi + 1) {
380062306a36Sopenharmony_ci			/* close current linelock */
380162306a36Sopenharmony_ci			slv->length = ns;
380262306a36Sopenharmony_ci			sdtlck->index++;
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci			/* open new linelock */
380562306a36Sopenharmony_ci			if (sdtlck->index < sdtlck->maxcnt)
380662306a36Sopenharmony_ci				slv++;
380762306a36Sopenharmony_ci			else {
380862306a36Sopenharmony_ci				sdtlck = (struct dt_lock *) txLinelock(sdtlck);
380962306a36Sopenharmony_ci				slv = & sdtlck->lv[0];
381062306a36Sopenharmony_ci			}
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci			slv->offset = ssi;
381362306a36Sopenharmony_ci			ns = 0;
381462306a36Sopenharmony_ci		}
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci		/*
381762306a36Sopenharmony_ci		 * move head/only segment of an entry
381862306a36Sopenharmony_ci		 */
381962306a36Sopenharmony_ci		/* get dst slot */
382062306a36Sopenharmony_ci		h = d = &dp->slot[dsi];
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci		/* get src slot and move */
382362306a36Sopenharmony_ci		s = &sp->slot[ssi];
382462306a36Sopenharmony_ci		if (sp->header.flag & BT_LEAF) {
382562306a36Sopenharmony_ci			/* get source entry */
382662306a36Sopenharmony_ci			slh = (struct ldtentry *) s;
382762306a36Sopenharmony_ci			dlh = (struct ldtentry *) h;
382862306a36Sopenharmony_ci			snamlen = slh->namlen;
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_ci			if (do_index) {
383162306a36Sopenharmony_ci				len = min(snamlen, DTLHDRDATALEN);
383262306a36Sopenharmony_ci				dlh->index = slh->index; /* little-endian */
383362306a36Sopenharmony_ci			} else
383462306a36Sopenharmony_ci				len = min(snamlen, DTLHDRDATALEN_LEGACY);
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci			memcpy(dlh, slh, 6 + len * 2);
383762306a36Sopenharmony_ci
383862306a36Sopenharmony_ci			next = slh->next;
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci			/* update dst head/only segment next field */
384162306a36Sopenharmony_ci			dsi++;
384262306a36Sopenharmony_ci			dlh->next = dsi;
384362306a36Sopenharmony_ci		} else {
384462306a36Sopenharmony_ci			sih = (struct idtentry *) s;
384562306a36Sopenharmony_ci			snamlen = sih->namlen;
384662306a36Sopenharmony_ci
384762306a36Sopenharmony_ci			len = min(snamlen, DTIHDRDATALEN);
384862306a36Sopenharmony_ci			dih = (struct idtentry *) h;
384962306a36Sopenharmony_ci			memcpy(dih, sih, 10 + len * 2);
385062306a36Sopenharmony_ci			next = sih->next;
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_ci			dsi++;
385362306a36Sopenharmony_ci			dih->next = dsi;
385462306a36Sopenharmony_ci		}
385562306a36Sopenharmony_ci
385662306a36Sopenharmony_ci		/* free src head/only segment */
385762306a36Sopenharmony_ci		s->next = sfsi;
385862306a36Sopenharmony_ci		s->cnt = 1;
385962306a36Sopenharmony_ci		sfsi = ssi;
386062306a36Sopenharmony_ci
386162306a36Sopenharmony_ci		ns++;
386262306a36Sopenharmony_ci		nd++;
386362306a36Sopenharmony_ci		xssi = ssi;
386462306a36Sopenharmony_ci
386562306a36Sopenharmony_ci		/*
386662306a36Sopenharmony_ci		 * move additional segment(s) of the entry
386762306a36Sopenharmony_ci		 */
386862306a36Sopenharmony_ci		snamlen -= len;
386962306a36Sopenharmony_ci		while ((ssi = next) >= 0) {
387062306a36Sopenharmony_ci			/* is next slot contiguous ? */
387162306a36Sopenharmony_ci			if (ssi != xssi + 1) {
387262306a36Sopenharmony_ci				/* close current linelock */
387362306a36Sopenharmony_ci				slv->length = ns;
387462306a36Sopenharmony_ci				sdtlck->index++;
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci				/* open new linelock */
387762306a36Sopenharmony_ci				if (sdtlck->index < sdtlck->maxcnt)
387862306a36Sopenharmony_ci					slv++;
387962306a36Sopenharmony_ci				else {
388062306a36Sopenharmony_ci					sdtlck =
388162306a36Sopenharmony_ci					    (struct dt_lock *)
388262306a36Sopenharmony_ci					    txLinelock(sdtlck);
388362306a36Sopenharmony_ci					slv = & sdtlck->lv[0];
388462306a36Sopenharmony_ci				}
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci				slv->offset = ssi;
388762306a36Sopenharmony_ci				ns = 0;
388862306a36Sopenharmony_ci			}
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_ci			/* get next source segment */
389162306a36Sopenharmony_ci			s = &sp->slot[ssi];
389262306a36Sopenharmony_ci
389362306a36Sopenharmony_ci			/* get next destination free slot */
389462306a36Sopenharmony_ci			d++;
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_ci			len = min(snamlen, DTSLOTDATALEN);
389762306a36Sopenharmony_ci			UniStrncpy_le(d->name, s->name, len);
389862306a36Sopenharmony_ci
389962306a36Sopenharmony_ci			ns++;
390062306a36Sopenharmony_ci			nd++;
390162306a36Sopenharmony_ci			xssi = ssi;
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci			dsi++;
390462306a36Sopenharmony_ci			d->next = dsi;
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci			/* free source segment */
390762306a36Sopenharmony_ci			next = s->next;
390862306a36Sopenharmony_ci			s->next = sfsi;
390962306a36Sopenharmony_ci			s->cnt = 1;
391062306a36Sopenharmony_ci			sfsi = ssi;
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci			snamlen -= len;
391362306a36Sopenharmony_ci		}		/* end while */
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_ci		/* terminate dst last/only segment */
391662306a36Sopenharmony_ci		if (h == d) {
391762306a36Sopenharmony_ci			/* single segment entry */
391862306a36Sopenharmony_ci			if (dp->header.flag & BT_LEAF)
391962306a36Sopenharmony_ci				dlh->next = -1;
392062306a36Sopenharmony_ci			else
392162306a36Sopenharmony_ci				dih->next = -1;
392262306a36Sopenharmony_ci		} else
392362306a36Sopenharmony_ci			/* multi-segment entry */
392462306a36Sopenharmony_ci			d->next = -1;
392562306a36Sopenharmony_ci	}			/* end for */
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_ci	/* close current linelock */
392862306a36Sopenharmony_ci	slv->length = ns;
392962306a36Sopenharmony_ci	sdtlck->index++;
393062306a36Sopenharmony_ci	*sdtlock = sdtlck;
393162306a36Sopenharmony_ci
393262306a36Sopenharmony_ci	dlv->length = nd;
393362306a36Sopenharmony_ci	ddtlck->index++;
393462306a36Sopenharmony_ci	*ddtlock = ddtlck;
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	/* update source header */
393762306a36Sopenharmony_ci	sp->header.freelist = sfsi;
393862306a36Sopenharmony_ci	sp->header.freecnt += nd;
393962306a36Sopenharmony_ci
394062306a36Sopenharmony_ci	/* update destination header */
394162306a36Sopenharmony_ci	dp->header.nextindex = di;
394262306a36Sopenharmony_ci
394362306a36Sopenharmony_ci	dp->header.freelist = dsi;
394462306a36Sopenharmony_ci	dp->header.freecnt -= nd;
394562306a36Sopenharmony_ci}
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci
394862306a36Sopenharmony_ci/*
394962306a36Sopenharmony_ci *	dtDeleteEntry()
395062306a36Sopenharmony_ci *
395162306a36Sopenharmony_ci * function: free a (leaf/internal) entry
395262306a36Sopenharmony_ci *
395362306a36Sopenharmony_ci * log freelist header, stbl, and each segment slot of entry
395462306a36Sopenharmony_ci * (even though last/only segment next field is modified,
395562306a36Sopenharmony_ci * physical image logging requires all segment slots of
395662306a36Sopenharmony_ci * the entry logged to avoid applying previous updates
395762306a36Sopenharmony_ci * to the same slots)
395862306a36Sopenharmony_ci */
395962306a36Sopenharmony_cistatic void dtDeleteEntry(dtpage_t * p, int fi, struct dt_lock ** dtlock)
396062306a36Sopenharmony_ci{
396162306a36Sopenharmony_ci	int fsi;		/* free entry slot index */
396262306a36Sopenharmony_ci	s8 *stbl;
396362306a36Sopenharmony_ci	struct dtslot *t;
396462306a36Sopenharmony_ci	int si, freecnt;
396562306a36Sopenharmony_ci	struct dt_lock *dtlck = *dtlock;
396662306a36Sopenharmony_ci	struct lv *lv;
396762306a36Sopenharmony_ci	int xsi, n;
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_ci	/* get free entry slot index */
397062306a36Sopenharmony_ci	stbl = DT_GETSTBL(p);
397162306a36Sopenharmony_ci	fsi = stbl[fi];
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci	/* open new linelock */
397462306a36Sopenharmony_ci	if (dtlck->index >= dtlck->maxcnt)
397562306a36Sopenharmony_ci		dtlck = (struct dt_lock *) txLinelock(dtlck);
397662306a36Sopenharmony_ci	lv = & dtlck->lv[dtlck->index];
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci	lv->offset = fsi;
397962306a36Sopenharmony_ci
398062306a36Sopenharmony_ci	/* get the head/only segment */
398162306a36Sopenharmony_ci	t = &p->slot[fsi];
398262306a36Sopenharmony_ci	if (p->header.flag & BT_LEAF)
398362306a36Sopenharmony_ci		si = ((struct ldtentry *) t)->next;
398462306a36Sopenharmony_ci	else
398562306a36Sopenharmony_ci		si = ((struct idtentry *) t)->next;
398662306a36Sopenharmony_ci	t->next = si;
398762306a36Sopenharmony_ci	t->cnt = 1;
398862306a36Sopenharmony_ci
398962306a36Sopenharmony_ci	n = freecnt = 1;
399062306a36Sopenharmony_ci	xsi = fsi;
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci	/* find the last/only segment */
399362306a36Sopenharmony_ci	while (si >= 0) {
399462306a36Sopenharmony_ci		/* is next slot contiguous ? */
399562306a36Sopenharmony_ci		if (si != xsi + 1) {
399662306a36Sopenharmony_ci			/* close current linelock */
399762306a36Sopenharmony_ci			lv->length = n;
399862306a36Sopenharmony_ci			dtlck->index++;
399962306a36Sopenharmony_ci
400062306a36Sopenharmony_ci			/* open new linelock */
400162306a36Sopenharmony_ci			if (dtlck->index < dtlck->maxcnt)
400262306a36Sopenharmony_ci				lv++;
400362306a36Sopenharmony_ci			else {
400462306a36Sopenharmony_ci				dtlck = (struct dt_lock *) txLinelock(dtlck);
400562306a36Sopenharmony_ci				lv = & dtlck->lv[0];
400662306a36Sopenharmony_ci			}
400762306a36Sopenharmony_ci
400862306a36Sopenharmony_ci			lv->offset = si;
400962306a36Sopenharmony_ci			n = 0;
401062306a36Sopenharmony_ci		}
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_ci		n++;
401362306a36Sopenharmony_ci		xsi = si;
401462306a36Sopenharmony_ci		freecnt++;
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_ci		t = &p->slot[si];
401762306a36Sopenharmony_ci		t->cnt = 1;
401862306a36Sopenharmony_ci		si = t->next;
401962306a36Sopenharmony_ci	}
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_ci	/* close current linelock */
402262306a36Sopenharmony_ci	lv->length = n;
402362306a36Sopenharmony_ci	dtlck->index++;
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_ci	*dtlock = dtlck;
402662306a36Sopenharmony_ci
402762306a36Sopenharmony_ci	/* update freelist */
402862306a36Sopenharmony_ci	t->next = p->header.freelist;
402962306a36Sopenharmony_ci	p->header.freelist = fsi;
403062306a36Sopenharmony_ci	p->header.freecnt += freecnt;
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci	/* if delete from middle,
403362306a36Sopenharmony_ci	 * shift left the succedding entries in the stbl
403462306a36Sopenharmony_ci	 */
403562306a36Sopenharmony_ci	si = p->header.nextindex;
403662306a36Sopenharmony_ci	if (fi < si - 1)
403762306a36Sopenharmony_ci		memmove(&stbl[fi], &stbl[fi + 1], si - fi - 1);
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci	p->header.nextindex--;
404062306a36Sopenharmony_ci}
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci/*
404462306a36Sopenharmony_ci *	dtTruncateEntry()
404562306a36Sopenharmony_ci *
404662306a36Sopenharmony_ci * function: truncate a (leaf/internal) entry
404762306a36Sopenharmony_ci *
404862306a36Sopenharmony_ci * log freelist header, stbl, and each segment slot of entry
404962306a36Sopenharmony_ci * (even though last/only segment next field is modified,
405062306a36Sopenharmony_ci * physical image logging requires all segment slots of
405162306a36Sopenharmony_ci * the entry logged to avoid applying previous updates
405262306a36Sopenharmony_ci * to the same slots)
405362306a36Sopenharmony_ci */
405462306a36Sopenharmony_cistatic void dtTruncateEntry(dtpage_t * p, int ti, struct dt_lock ** dtlock)
405562306a36Sopenharmony_ci{
405662306a36Sopenharmony_ci	int tsi;		/* truncate entry slot index */
405762306a36Sopenharmony_ci	s8 *stbl;
405862306a36Sopenharmony_ci	struct dtslot *t;
405962306a36Sopenharmony_ci	int si, freecnt;
406062306a36Sopenharmony_ci	struct dt_lock *dtlck = *dtlock;
406162306a36Sopenharmony_ci	struct lv *lv;
406262306a36Sopenharmony_ci	int fsi, xsi, n;
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_ci	/* get free entry slot index */
406562306a36Sopenharmony_ci	stbl = DT_GETSTBL(p);
406662306a36Sopenharmony_ci	tsi = stbl[ti];
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_ci	/* open new linelock */
406962306a36Sopenharmony_ci	if (dtlck->index >= dtlck->maxcnt)
407062306a36Sopenharmony_ci		dtlck = (struct dt_lock *) txLinelock(dtlck);
407162306a36Sopenharmony_ci	lv = & dtlck->lv[dtlck->index];
407262306a36Sopenharmony_ci
407362306a36Sopenharmony_ci	lv->offset = tsi;
407462306a36Sopenharmony_ci
407562306a36Sopenharmony_ci	/* get the head/only segment */
407662306a36Sopenharmony_ci	t = &p->slot[tsi];
407762306a36Sopenharmony_ci	ASSERT(p->header.flag & BT_INTERNAL);
407862306a36Sopenharmony_ci	((struct idtentry *) t)->namlen = 0;
407962306a36Sopenharmony_ci	si = ((struct idtentry *) t)->next;
408062306a36Sopenharmony_ci	((struct idtentry *) t)->next = -1;
408162306a36Sopenharmony_ci
408262306a36Sopenharmony_ci	n = 1;
408362306a36Sopenharmony_ci	freecnt = 0;
408462306a36Sopenharmony_ci	fsi = si;
408562306a36Sopenharmony_ci	xsi = tsi;
408662306a36Sopenharmony_ci
408762306a36Sopenharmony_ci	/* find the last/only segment */
408862306a36Sopenharmony_ci	while (si >= 0) {
408962306a36Sopenharmony_ci		/* is next slot contiguous ? */
409062306a36Sopenharmony_ci		if (si != xsi + 1) {
409162306a36Sopenharmony_ci			/* close current linelock */
409262306a36Sopenharmony_ci			lv->length = n;
409362306a36Sopenharmony_ci			dtlck->index++;
409462306a36Sopenharmony_ci
409562306a36Sopenharmony_ci			/* open new linelock */
409662306a36Sopenharmony_ci			if (dtlck->index < dtlck->maxcnt)
409762306a36Sopenharmony_ci				lv++;
409862306a36Sopenharmony_ci			else {
409962306a36Sopenharmony_ci				dtlck = (struct dt_lock *) txLinelock(dtlck);
410062306a36Sopenharmony_ci				lv = & dtlck->lv[0];
410162306a36Sopenharmony_ci			}
410262306a36Sopenharmony_ci
410362306a36Sopenharmony_ci			lv->offset = si;
410462306a36Sopenharmony_ci			n = 0;
410562306a36Sopenharmony_ci		}
410662306a36Sopenharmony_ci
410762306a36Sopenharmony_ci		n++;
410862306a36Sopenharmony_ci		xsi = si;
410962306a36Sopenharmony_ci		freecnt++;
411062306a36Sopenharmony_ci
411162306a36Sopenharmony_ci		t = &p->slot[si];
411262306a36Sopenharmony_ci		t->cnt = 1;
411362306a36Sopenharmony_ci		si = t->next;
411462306a36Sopenharmony_ci	}
411562306a36Sopenharmony_ci
411662306a36Sopenharmony_ci	/* close current linelock */
411762306a36Sopenharmony_ci	lv->length = n;
411862306a36Sopenharmony_ci	dtlck->index++;
411962306a36Sopenharmony_ci
412062306a36Sopenharmony_ci	*dtlock = dtlck;
412162306a36Sopenharmony_ci
412262306a36Sopenharmony_ci	/* update freelist */
412362306a36Sopenharmony_ci	if (freecnt == 0)
412462306a36Sopenharmony_ci		return;
412562306a36Sopenharmony_ci	t->next = p->header.freelist;
412662306a36Sopenharmony_ci	p->header.freelist = fsi;
412762306a36Sopenharmony_ci	p->header.freecnt += freecnt;
412862306a36Sopenharmony_ci}
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_ci
413162306a36Sopenharmony_ci/*
413262306a36Sopenharmony_ci *	dtLinelockFreelist()
413362306a36Sopenharmony_ci */
413462306a36Sopenharmony_cistatic void dtLinelockFreelist(dtpage_t * p,	/* directory page */
413562306a36Sopenharmony_ci			       int m,	/* max slot index */
413662306a36Sopenharmony_ci			       struct dt_lock ** dtlock)
413762306a36Sopenharmony_ci{
413862306a36Sopenharmony_ci	int fsi;		/* free entry slot index */
413962306a36Sopenharmony_ci	struct dtslot *t;
414062306a36Sopenharmony_ci	int si;
414162306a36Sopenharmony_ci	struct dt_lock *dtlck = *dtlock;
414262306a36Sopenharmony_ci	struct lv *lv;
414362306a36Sopenharmony_ci	int xsi, n;
414462306a36Sopenharmony_ci
414562306a36Sopenharmony_ci	/* get free entry slot index */
414662306a36Sopenharmony_ci	fsi = p->header.freelist;
414762306a36Sopenharmony_ci
414862306a36Sopenharmony_ci	/* open new linelock */
414962306a36Sopenharmony_ci	if (dtlck->index >= dtlck->maxcnt)
415062306a36Sopenharmony_ci		dtlck = (struct dt_lock *) txLinelock(dtlck);
415162306a36Sopenharmony_ci	lv = & dtlck->lv[dtlck->index];
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_ci	lv->offset = fsi;
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_ci	n = 1;
415662306a36Sopenharmony_ci	xsi = fsi;
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_ci	t = &p->slot[fsi];
415962306a36Sopenharmony_ci	si = t->next;
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci	/* find the last/only segment */
416262306a36Sopenharmony_ci	while (si < m && si >= 0) {
416362306a36Sopenharmony_ci		/* is next slot contiguous ? */
416462306a36Sopenharmony_ci		if (si != xsi + 1) {
416562306a36Sopenharmony_ci			/* close current linelock */
416662306a36Sopenharmony_ci			lv->length = n;
416762306a36Sopenharmony_ci			dtlck->index++;
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci			/* open new linelock */
417062306a36Sopenharmony_ci			if (dtlck->index < dtlck->maxcnt)
417162306a36Sopenharmony_ci				lv++;
417262306a36Sopenharmony_ci			else {
417362306a36Sopenharmony_ci				dtlck = (struct dt_lock *) txLinelock(dtlck);
417462306a36Sopenharmony_ci				lv = & dtlck->lv[0];
417562306a36Sopenharmony_ci			}
417662306a36Sopenharmony_ci
417762306a36Sopenharmony_ci			lv->offset = si;
417862306a36Sopenharmony_ci			n = 0;
417962306a36Sopenharmony_ci		}
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci		n++;
418262306a36Sopenharmony_ci		xsi = si;
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_ci		t = &p->slot[si];
418562306a36Sopenharmony_ci		si = t->next;
418662306a36Sopenharmony_ci	}
418762306a36Sopenharmony_ci
418862306a36Sopenharmony_ci	/* close current linelock */
418962306a36Sopenharmony_ci	lv->length = n;
419062306a36Sopenharmony_ci	dtlck->index++;
419162306a36Sopenharmony_ci
419262306a36Sopenharmony_ci	*dtlock = dtlck;
419362306a36Sopenharmony_ci}
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci
419662306a36Sopenharmony_ci/*
419762306a36Sopenharmony_ci * NAME: dtModify
419862306a36Sopenharmony_ci *
419962306a36Sopenharmony_ci * FUNCTION: Modify the inode number part of a directory entry
420062306a36Sopenharmony_ci *
420162306a36Sopenharmony_ci * PARAMETERS:
420262306a36Sopenharmony_ci *	tid	- Transaction id
420362306a36Sopenharmony_ci *	ip	- Inode of parent directory
420462306a36Sopenharmony_ci *	key	- Name of entry to be modified
420562306a36Sopenharmony_ci *	orig_ino	- Original inode number expected in entry
420662306a36Sopenharmony_ci *	new_ino	- New inode number to put into entry
420762306a36Sopenharmony_ci *	flag	- JFS_RENAME
420862306a36Sopenharmony_ci *
420962306a36Sopenharmony_ci * RETURNS:
421062306a36Sopenharmony_ci *	-ESTALE	- If entry found does not match orig_ino passed in
421162306a36Sopenharmony_ci *	-ENOENT	- If no entry can be found to match key
421262306a36Sopenharmony_ci *	0	- If successfully modified entry
421362306a36Sopenharmony_ci */
421462306a36Sopenharmony_ciint dtModify(tid_t tid, struct inode *ip,
421562306a36Sopenharmony_ci	 struct component_name * key, ino_t * orig_ino, ino_t new_ino, int flag)
421662306a36Sopenharmony_ci{
421762306a36Sopenharmony_ci	int rc;
421862306a36Sopenharmony_ci	s64 bn;
421962306a36Sopenharmony_ci	struct metapage *mp;
422062306a36Sopenharmony_ci	dtpage_t *p;
422162306a36Sopenharmony_ci	int index;
422262306a36Sopenharmony_ci	struct btstack btstack;
422362306a36Sopenharmony_ci	struct tlock *tlck;
422462306a36Sopenharmony_ci	struct dt_lock *dtlck;
422562306a36Sopenharmony_ci	struct lv *lv;
422662306a36Sopenharmony_ci	s8 *stbl;
422762306a36Sopenharmony_ci	int entry_si;		/* entry slot index */
422862306a36Sopenharmony_ci	struct ldtentry *entry;
422962306a36Sopenharmony_ci
423062306a36Sopenharmony_ci	/*
423162306a36Sopenharmony_ci	 *	search for the entry to modify:
423262306a36Sopenharmony_ci	 *
423362306a36Sopenharmony_ci	 * dtSearch() returns (leaf page pinned, index at which to modify).
423462306a36Sopenharmony_ci	 */
423562306a36Sopenharmony_ci	if ((rc = dtSearch(ip, key, orig_ino, &btstack, flag)))
423662306a36Sopenharmony_ci		return rc;
423762306a36Sopenharmony_ci
423862306a36Sopenharmony_ci	/* retrieve search result */
423962306a36Sopenharmony_ci	DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
424062306a36Sopenharmony_ci
424162306a36Sopenharmony_ci	BT_MARK_DIRTY(mp, ip);
424262306a36Sopenharmony_ci	/*
424362306a36Sopenharmony_ci	 * acquire a transaction lock on the leaf page of named entry
424462306a36Sopenharmony_ci	 */
424562306a36Sopenharmony_ci	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
424662306a36Sopenharmony_ci	dtlck = (struct dt_lock *) & tlck->lock;
424762306a36Sopenharmony_ci
424862306a36Sopenharmony_ci	/* get slot index of the entry */
424962306a36Sopenharmony_ci	stbl = DT_GETSTBL(p);
425062306a36Sopenharmony_ci	entry_si = stbl[index];
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_ci	/* linelock entry */
425362306a36Sopenharmony_ci	ASSERT(dtlck->index == 0);
425462306a36Sopenharmony_ci	lv = & dtlck->lv[0];
425562306a36Sopenharmony_ci	lv->offset = entry_si;
425662306a36Sopenharmony_ci	lv->length = 1;
425762306a36Sopenharmony_ci	dtlck->index++;
425862306a36Sopenharmony_ci
425962306a36Sopenharmony_ci	/* get the head/only segment */
426062306a36Sopenharmony_ci	entry = (struct ldtentry *) & p->slot[entry_si];
426162306a36Sopenharmony_ci
426262306a36Sopenharmony_ci	/* substitute the inode number of the entry */
426362306a36Sopenharmony_ci	entry->inumber = cpu_to_le32(new_ino);
426462306a36Sopenharmony_ci
426562306a36Sopenharmony_ci	/* unpin the leaf page */
426662306a36Sopenharmony_ci	DT_PUTPAGE(mp);
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_ci	return 0;
426962306a36Sopenharmony_ci}
4270