18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
48c2ecf20Sopenharmony_ci * All Rights Reserved.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include "xfs.h"
78c2ecf20Sopenharmony_ci#include "xfs_fs.h"
88c2ecf20Sopenharmony_ci#include "xfs_shared.h"
98c2ecf20Sopenharmony_ci#include "xfs_format.h"
108c2ecf20Sopenharmony_ci#include "xfs_log_format.h"
118c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h"
128c2ecf20Sopenharmony_ci#include "xfs_mount.h"
138c2ecf20Sopenharmony_ci#include "xfs_inode.h"
148c2ecf20Sopenharmony_ci#include "xfs_trans.h"
158c2ecf20Sopenharmony_ci#include "xfs_dir2.h"
168c2ecf20Sopenharmony_ci#include "xfs_dir2_priv.h"
178c2ecf20Sopenharmony_ci#include "xfs_trace.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Prototypes for internal functions.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_cistatic void xfs_dir2_sf_addname_easy(xfs_da_args_t *args,
238c2ecf20Sopenharmony_ci				     xfs_dir2_sf_entry_t *sfep,
248c2ecf20Sopenharmony_ci				     xfs_dir2_data_aoff_t offset,
258c2ecf20Sopenharmony_ci				     int new_isize);
268c2ecf20Sopenharmony_cistatic void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange,
278c2ecf20Sopenharmony_ci				     int new_isize);
288c2ecf20Sopenharmony_cistatic int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange,
298c2ecf20Sopenharmony_ci				    xfs_dir2_sf_entry_t **sfepp,
308c2ecf20Sopenharmony_ci				    xfs_dir2_data_aoff_t *offsetp);
318c2ecf20Sopenharmony_ci#ifdef DEBUG
328c2ecf20Sopenharmony_cistatic void xfs_dir2_sf_check(xfs_da_args_t *args);
338c2ecf20Sopenharmony_ci#else
348c2ecf20Sopenharmony_ci#define	xfs_dir2_sf_check(args)
358c2ecf20Sopenharmony_ci#endif /* DEBUG */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic void xfs_dir2_sf_toino4(xfs_da_args_t *args);
388c2ecf20Sopenharmony_cistatic void xfs_dir2_sf_toino8(xfs_da_args_t *args);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ciint
418c2ecf20Sopenharmony_cixfs_dir2_sf_entsize(
428c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
438c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr	*hdr,
448c2ecf20Sopenharmony_ci	int			len)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	int			count = len;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	count += sizeof(struct xfs_dir2_sf_entry);	/* namelen + offset */
498c2ecf20Sopenharmony_ci	count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	if (xfs_sb_version_hasftype(&mp->m_sb))
528c2ecf20Sopenharmony_ci		count += sizeof(uint8_t);
538c2ecf20Sopenharmony_ci	return count;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistruct xfs_dir2_sf_entry *
578c2ecf20Sopenharmony_cixfs_dir2_sf_nextentry(
588c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
598c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr	*hdr,
608c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_entry *sfep)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	return (void *)sfep + xfs_dir2_sf_entsize(mp, hdr, sfep->namelen);
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/*
668c2ecf20Sopenharmony_ci * In short-form directory entries the inode numbers are stored at variable
678c2ecf20Sopenharmony_ci * offset behind the entry name. If the entry stores a filetype value, then it
688c2ecf20Sopenharmony_ci * sits between the name and the inode number.  The actual inode numbers can
698c2ecf20Sopenharmony_ci * come in two formats as well, either 4 bytes or 8 bytes wide.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_cixfs_ino_t
728c2ecf20Sopenharmony_cixfs_dir2_sf_get_ino(
738c2ecf20Sopenharmony_ci	struct xfs_mount		*mp,
748c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr		*hdr,
758c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_entry	*sfep)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	uint8_t				*from = sfep->name + sfep->namelen;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (xfs_sb_version_hasftype(&mp->m_sb))
808c2ecf20Sopenharmony_ci		from++;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (!hdr->i8count)
838c2ecf20Sopenharmony_ci		return get_unaligned_be32(from);
848c2ecf20Sopenharmony_ci	return get_unaligned_be64(from) & XFS_MAXINUMBER;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_civoid
888c2ecf20Sopenharmony_cixfs_dir2_sf_put_ino(
898c2ecf20Sopenharmony_ci	struct xfs_mount		*mp,
908c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr		*hdr,
918c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_entry	*sfep,
928c2ecf20Sopenharmony_ci	xfs_ino_t			ino)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	uint8_t				*to = sfep->name + sfep->namelen;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	ASSERT(ino <= XFS_MAXINUMBER);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (xfs_sb_version_hasftype(&mp->m_sb))
998c2ecf20Sopenharmony_ci		to++;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (hdr->i8count)
1028c2ecf20Sopenharmony_ci		put_unaligned_be64(ino, to);
1038c2ecf20Sopenharmony_ci	else
1048c2ecf20Sopenharmony_ci		put_unaligned_be32(ino, to);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cixfs_ino_t
1088c2ecf20Sopenharmony_cixfs_dir2_sf_get_parent_ino(
1098c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr	*hdr)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	if (!hdr->i8count)
1128c2ecf20Sopenharmony_ci		return get_unaligned_be32(hdr->parent);
1138c2ecf20Sopenharmony_ci	return get_unaligned_be64(hdr->parent) & XFS_MAXINUMBER;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_civoid
1178c2ecf20Sopenharmony_cixfs_dir2_sf_put_parent_ino(
1188c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr		*hdr,
1198c2ecf20Sopenharmony_ci	xfs_ino_t			ino)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	ASSERT(ino <= XFS_MAXINUMBER);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (hdr->i8count)
1248c2ecf20Sopenharmony_ci		put_unaligned_be64(ino, hdr->parent);
1258c2ecf20Sopenharmony_ci	else
1268c2ecf20Sopenharmony_ci		put_unaligned_be32(ino, hdr->parent);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/*
1308c2ecf20Sopenharmony_ci * The file type field is stored at the end of the name for filetype enabled
1318c2ecf20Sopenharmony_ci * shortform directories, or not at all otherwise.
1328c2ecf20Sopenharmony_ci */
1338c2ecf20Sopenharmony_ciuint8_t
1348c2ecf20Sopenharmony_cixfs_dir2_sf_get_ftype(
1358c2ecf20Sopenharmony_ci	struct xfs_mount		*mp,
1368c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_entry	*sfep)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	if (xfs_sb_version_hasftype(&mp->m_sb)) {
1398c2ecf20Sopenharmony_ci		uint8_t			ftype = sfep->name[sfep->namelen];
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		if (ftype < XFS_DIR3_FT_MAX)
1428c2ecf20Sopenharmony_ci			return ftype;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	return XFS_DIR3_FT_UNKNOWN;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_civoid
1498c2ecf20Sopenharmony_cixfs_dir2_sf_put_ftype(
1508c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
1518c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_entry *sfep,
1528c2ecf20Sopenharmony_ci	uint8_t			ftype)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	ASSERT(ftype < XFS_DIR3_FT_MAX);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (xfs_sb_version_hasftype(&mp->m_sb))
1578c2ecf20Sopenharmony_ci		sfep->name[sfep->namelen] = ftype;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/*
1618c2ecf20Sopenharmony_ci * Given a block directory (dp/block), calculate its size as a shortform (sf)
1628c2ecf20Sopenharmony_ci * directory and a header for the sf directory, if it will fit it the
1638c2ecf20Sopenharmony_ci * space currently present in the inode.  If it won't fit, the output
1648c2ecf20Sopenharmony_ci * size is too big (but not accurate).
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_ciint						/* size for sf form */
1678c2ecf20Sopenharmony_cixfs_dir2_block_sfsize(
1688c2ecf20Sopenharmony_ci	xfs_inode_t		*dp,		/* incore inode pointer */
1698c2ecf20Sopenharmony_ci	xfs_dir2_data_hdr_t	*hdr,		/* block directory data */
1708c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfhp)		/* output: header for sf form */
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	xfs_dir2_dataptr_t	addr;		/* data entry address */
1738c2ecf20Sopenharmony_ci	xfs_dir2_leaf_entry_t	*blp;		/* leaf area of the block */
1748c2ecf20Sopenharmony_ci	xfs_dir2_block_tail_t	*btp;		/* tail area of the block */
1758c2ecf20Sopenharmony_ci	int			count;		/* shortform entry count */
1768c2ecf20Sopenharmony_ci	xfs_dir2_data_entry_t	*dep;		/* data entry in the block */
1778c2ecf20Sopenharmony_ci	int			i;		/* block entry index */
1788c2ecf20Sopenharmony_ci	int			i8count;	/* count of big-inode entries */
1798c2ecf20Sopenharmony_ci	int			isdot;		/* entry is "." */
1808c2ecf20Sopenharmony_ci	int			isdotdot;	/* entry is ".." */
1818c2ecf20Sopenharmony_ci	xfs_mount_t		*mp;		/* mount structure pointer */
1828c2ecf20Sopenharmony_ci	int			namelen;	/* total name bytes */
1838c2ecf20Sopenharmony_ci	xfs_ino_t		parent = 0;	/* parent inode number */
1848c2ecf20Sopenharmony_ci	int			size=0;		/* total computed size */
1858c2ecf20Sopenharmony_ci	int			has_ftype;
1868c2ecf20Sopenharmony_ci	struct xfs_da_geometry	*geo;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	mp = dp->i_mount;
1898c2ecf20Sopenharmony_ci	geo = mp->m_dir_geo;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/*
1928c2ecf20Sopenharmony_ci	 * if there is a filetype field, add the extra byte to the namelen
1938c2ecf20Sopenharmony_ci	 * for each entry that we see.
1948c2ecf20Sopenharmony_ci	 */
1958c2ecf20Sopenharmony_ci	has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	count = i8count = namelen = 0;
1988c2ecf20Sopenharmony_ci	btp = xfs_dir2_block_tail_p(geo, hdr);
1998c2ecf20Sopenharmony_ci	blp = xfs_dir2_block_leaf_p(btp);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/*
2028c2ecf20Sopenharmony_ci	 * Iterate over the block's data entries by using the leaf pointers.
2038c2ecf20Sopenharmony_ci	 */
2048c2ecf20Sopenharmony_ci	for (i = 0; i < be32_to_cpu(btp->count); i++) {
2058c2ecf20Sopenharmony_ci		if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR)
2068c2ecf20Sopenharmony_ci			continue;
2078c2ecf20Sopenharmony_ci		/*
2088c2ecf20Sopenharmony_ci		 * Calculate the pointer to the entry at hand.
2098c2ecf20Sopenharmony_ci		 */
2108c2ecf20Sopenharmony_ci		dep = (xfs_dir2_data_entry_t *)((char *)hdr +
2118c2ecf20Sopenharmony_ci				xfs_dir2_dataptr_to_off(geo, addr));
2128c2ecf20Sopenharmony_ci		/*
2138c2ecf20Sopenharmony_ci		 * Detect . and .., so we can special-case them.
2148c2ecf20Sopenharmony_ci		 * . is not included in sf directories.
2158c2ecf20Sopenharmony_ci		 * .. is included by just the parent inode number.
2168c2ecf20Sopenharmony_ci		 */
2178c2ecf20Sopenharmony_ci		isdot = dep->namelen == 1 && dep->name[0] == '.';
2188c2ecf20Sopenharmony_ci		isdotdot =
2198c2ecf20Sopenharmony_ci			dep->namelen == 2 &&
2208c2ecf20Sopenharmony_ci			dep->name[0] == '.' && dep->name[1] == '.';
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		if (!isdot)
2238c2ecf20Sopenharmony_ci			i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		/* take into account the file type field */
2268c2ecf20Sopenharmony_ci		if (!isdot && !isdotdot) {
2278c2ecf20Sopenharmony_ci			count++;
2288c2ecf20Sopenharmony_ci			namelen += dep->namelen + has_ftype;
2298c2ecf20Sopenharmony_ci		} else if (isdotdot)
2308c2ecf20Sopenharmony_ci			parent = be64_to_cpu(dep->inumber);
2318c2ecf20Sopenharmony_ci		/*
2328c2ecf20Sopenharmony_ci		 * Calculate the new size, see if we should give up yet.
2338c2ecf20Sopenharmony_ci		 */
2348c2ecf20Sopenharmony_ci		size = xfs_dir2_sf_hdr_size(i8count) +	/* header */
2358c2ecf20Sopenharmony_ci		       count * 3 * sizeof(u8) +		/* namelen + offset */
2368c2ecf20Sopenharmony_ci		       namelen +			/* name */
2378c2ecf20Sopenharmony_ci		       (i8count ?			/* inumber */
2388c2ecf20Sopenharmony_ci				count * XFS_INO64_SIZE :
2398c2ecf20Sopenharmony_ci				count * XFS_INO32_SIZE);
2408c2ecf20Sopenharmony_ci		if (size > XFS_IFORK_DSIZE(dp))
2418c2ecf20Sopenharmony_ci			return size;		/* size value is a failure */
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	/*
2448c2ecf20Sopenharmony_ci	 * Create the output header, if it worked.
2458c2ecf20Sopenharmony_ci	 */
2468c2ecf20Sopenharmony_ci	sfhp->count = count;
2478c2ecf20Sopenharmony_ci	sfhp->i8count = i8count;
2488c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_parent_ino(sfhp, parent);
2498c2ecf20Sopenharmony_ci	return size;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci/*
2538c2ecf20Sopenharmony_ci * Convert a block format directory to shortform.
2548c2ecf20Sopenharmony_ci * Caller has already checked that it will fit, and built us a header.
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_ciint						/* error */
2578c2ecf20Sopenharmony_cixfs_dir2_block_to_sf(
2588c2ecf20Sopenharmony_ci	struct xfs_da_args	*args,		/* operation arguments */
2598c2ecf20Sopenharmony_ci	struct xfs_buf		*bp,
2608c2ecf20Sopenharmony_ci	int			size,		/* shortform directory size */
2618c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr	*sfhp)		/* shortform directory hdr */
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
2648c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
2658c2ecf20Sopenharmony_ci	int			error;		/* error return value */
2668c2ecf20Sopenharmony_ci	int			logflags;	/* inode logging flags */
2678c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_entry *sfep;		/* shortform entry */
2688c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr	*sfp;		/* shortform directory header */
2698c2ecf20Sopenharmony_ci	unsigned int		offset = args->geo->data_entry_offset;
2708c2ecf20Sopenharmony_ci	unsigned int		end;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	trace_xfs_dir2_block_to_sf(args);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/*
2758c2ecf20Sopenharmony_ci	 * Allocate a temporary destination buffer the size of the inode to
2768c2ecf20Sopenharmony_ci	 * format the data into.  Once we have formatted the data, we can free
2778c2ecf20Sopenharmony_ci	 * the block and copy the formatted data into the inode literal area.
2788c2ecf20Sopenharmony_ci	 */
2798c2ecf20Sopenharmony_ci	sfp = kmem_alloc(mp->m_sb.sb_inodesize, 0);
2808c2ecf20Sopenharmony_ci	memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	/*
2838c2ecf20Sopenharmony_ci	 * Loop over the active and unused entries.  Stop when we reach the
2848c2ecf20Sopenharmony_ci	 * leaf/tail portion of the block.
2858c2ecf20Sopenharmony_ci	 */
2868c2ecf20Sopenharmony_ci	end = xfs_dir3_data_end_offset(args->geo, bp->b_addr);
2878c2ecf20Sopenharmony_ci	sfep = xfs_dir2_sf_firstentry(sfp);
2888c2ecf20Sopenharmony_ci	while (offset < end) {
2898c2ecf20Sopenharmony_ci		struct xfs_dir2_data_unused	*dup = bp->b_addr + offset;
2908c2ecf20Sopenharmony_ci		struct xfs_dir2_data_entry	*dep = bp->b_addr + offset;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		/*
2938c2ecf20Sopenharmony_ci		 * If it's unused, just skip over it.
2948c2ecf20Sopenharmony_ci		 */
2958c2ecf20Sopenharmony_ci		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
2968c2ecf20Sopenharmony_ci			offset += be16_to_cpu(dup->length);
2978c2ecf20Sopenharmony_ci			continue;
2988c2ecf20Sopenharmony_ci		}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		/*
3018c2ecf20Sopenharmony_ci		 * Skip .
3028c2ecf20Sopenharmony_ci		 */
3038c2ecf20Sopenharmony_ci		if (dep->namelen == 1 && dep->name[0] == '.')
3048c2ecf20Sopenharmony_ci			ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
3058c2ecf20Sopenharmony_ci		/*
3068c2ecf20Sopenharmony_ci		 * Skip .., but make sure the inode number is right.
3078c2ecf20Sopenharmony_ci		 */
3088c2ecf20Sopenharmony_ci		else if (dep->namelen == 2 &&
3098c2ecf20Sopenharmony_ci			 dep->name[0] == '.' && dep->name[1] == '.')
3108c2ecf20Sopenharmony_ci			ASSERT(be64_to_cpu(dep->inumber) ==
3118c2ecf20Sopenharmony_ci			       xfs_dir2_sf_get_parent_ino(sfp));
3128c2ecf20Sopenharmony_ci		/*
3138c2ecf20Sopenharmony_ci		 * Normal entry, copy it into shortform.
3148c2ecf20Sopenharmony_ci		 */
3158c2ecf20Sopenharmony_ci		else {
3168c2ecf20Sopenharmony_ci			sfep->namelen = dep->namelen;
3178c2ecf20Sopenharmony_ci			xfs_dir2_sf_put_offset(sfep, offset);
3188c2ecf20Sopenharmony_ci			memcpy(sfep->name, dep->name, dep->namelen);
3198c2ecf20Sopenharmony_ci			xfs_dir2_sf_put_ino(mp, sfp, sfep,
3208c2ecf20Sopenharmony_ci					      be64_to_cpu(dep->inumber));
3218c2ecf20Sopenharmony_ci			xfs_dir2_sf_put_ftype(mp, sfep,
3228c2ecf20Sopenharmony_ci					xfs_dir2_data_get_ftype(mp, dep));
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci			sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
3258c2ecf20Sopenharmony_ci		}
3268c2ecf20Sopenharmony_ci		offset += xfs_dir2_data_entsize(mp, dep->namelen);
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci	ASSERT((char *)sfep - (char *)sfp == size);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* now we are done with the block, we can shrink the inode */
3318c2ecf20Sopenharmony_ci	logflags = XFS_ILOG_CORE;
3328c2ecf20Sopenharmony_ci	error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp);
3338c2ecf20Sopenharmony_ci	if (error) {
3348c2ecf20Sopenharmony_ci		ASSERT(error != -ENOSPC);
3358c2ecf20Sopenharmony_ci		goto out;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	/*
3398c2ecf20Sopenharmony_ci	 * The buffer is now unconditionally gone, whether
3408c2ecf20Sopenharmony_ci	 * xfs_dir2_shrink_inode worked or not.
3418c2ecf20Sopenharmony_ci	 *
3428c2ecf20Sopenharmony_ci	 * Convert the inode to local format and copy the data in.
3438c2ecf20Sopenharmony_ci	 */
3448c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_bytes == 0);
3458c2ecf20Sopenharmony_ci	xfs_init_local_fork(dp, XFS_DATA_FORK, sfp, size);
3468c2ecf20Sopenharmony_ci	dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
3478c2ecf20Sopenharmony_ci	dp->i_d.di_size = size;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	logflags |= XFS_ILOG_DDATA;
3508c2ecf20Sopenharmony_ci	xfs_dir2_sf_check(args);
3518c2ecf20Sopenharmony_ciout:
3528c2ecf20Sopenharmony_ci	xfs_trans_log_inode(args->trans, dp, logflags);
3538c2ecf20Sopenharmony_ci	kmem_free(sfp);
3548c2ecf20Sopenharmony_ci	return error;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci/*
3588c2ecf20Sopenharmony_ci * Add a name to a shortform directory.
3598c2ecf20Sopenharmony_ci * There are two algorithms, "easy" and "hard" which we decide on
3608c2ecf20Sopenharmony_ci * before changing anything.
3618c2ecf20Sopenharmony_ci * Convert to block form if necessary, if the new entry won't fit.
3628c2ecf20Sopenharmony_ci */
3638c2ecf20Sopenharmony_ciint						/* error */
3648c2ecf20Sopenharmony_cixfs_dir2_sf_addname(
3658c2ecf20Sopenharmony_ci	xfs_da_args_t		*args)		/* operation arguments */
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	xfs_inode_t		*dp;		/* incore directory inode */
3688c2ecf20Sopenharmony_ci	int			error;		/* error return value */
3698c2ecf20Sopenharmony_ci	int			incr_isize;	/* total change in size */
3708c2ecf20Sopenharmony_ci	int			new_isize;	/* di_size after adding name */
3718c2ecf20Sopenharmony_ci	int			objchange;	/* changing to 8-byte inodes */
3728c2ecf20Sopenharmony_ci	xfs_dir2_data_aoff_t	offset = 0;	/* offset for new entry */
3738c2ecf20Sopenharmony_ci	int			pick;		/* which algorithm to use */
3748c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
3758c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep = NULL;	/* shortform entry */
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	trace_xfs_dir2_sf_addname(args);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT);
3808c2ecf20Sopenharmony_ci	dp = args->dp;
3818c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
3828c2ecf20Sopenharmony_ci	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
3838c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
3848c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_u1.if_data != NULL);
3858c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
3868c2ecf20Sopenharmony_ci	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
3878c2ecf20Sopenharmony_ci	/*
3888c2ecf20Sopenharmony_ci	 * Compute entry (and change in) size.
3898c2ecf20Sopenharmony_ci	 */
3908c2ecf20Sopenharmony_ci	incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
3918c2ecf20Sopenharmony_ci	objchange = 0;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/*
3948c2ecf20Sopenharmony_ci	 * Do we have to change to 8 byte inodes?
3958c2ecf20Sopenharmony_ci	 */
3968c2ecf20Sopenharmony_ci	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
3978c2ecf20Sopenharmony_ci		/*
3988c2ecf20Sopenharmony_ci		 * Yes, adjust the inode size.  old count + (parent + new)
3998c2ecf20Sopenharmony_ci		 */
4008c2ecf20Sopenharmony_ci		incr_isize += (sfp->count + 2) * XFS_INO64_DIFF;
4018c2ecf20Sopenharmony_ci		objchange = 1;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	new_isize = (int)dp->i_d.di_size + incr_isize;
4058c2ecf20Sopenharmony_ci	/*
4068c2ecf20Sopenharmony_ci	 * Won't fit as shortform any more (due to size),
4078c2ecf20Sopenharmony_ci	 * or the pick routine says it won't (due to offset values).
4088c2ecf20Sopenharmony_ci	 */
4098c2ecf20Sopenharmony_ci	if (new_isize > XFS_IFORK_DSIZE(dp) ||
4108c2ecf20Sopenharmony_ci	    (pick =
4118c2ecf20Sopenharmony_ci	     xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) {
4128c2ecf20Sopenharmony_ci		/*
4138c2ecf20Sopenharmony_ci		 * Just checking or no space reservation, it doesn't fit.
4148c2ecf20Sopenharmony_ci		 */
4158c2ecf20Sopenharmony_ci		if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
4168c2ecf20Sopenharmony_ci			return -ENOSPC;
4178c2ecf20Sopenharmony_ci		/*
4188c2ecf20Sopenharmony_ci		 * Convert to block form then add the name.
4198c2ecf20Sopenharmony_ci		 */
4208c2ecf20Sopenharmony_ci		error = xfs_dir2_sf_to_block(args);
4218c2ecf20Sopenharmony_ci		if (error)
4228c2ecf20Sopenharmony_ci			return error;
4238c2ecf20Sopenharmony_ci		return xfs_dir2_block_addname(args);
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci	/*
4268c2ecf20Sopenharmony_ci	 * Just checking, it fits.
4278c2ecf20Sopenharmony_ci	 */
4288c2ecf20Sopenharmony_ci	if (args->op_flags & XFS_DA_OP_JUSTCHECK)
4298c2ecf20Sopenharmony_ci		return 0;
4308c2ecf20Sopenharmony_ci	/*
4318c2ecf20Sopenharmony_ci	 * Do it the easy way - just add it at the end.
4328c2ecf20Sopenharmony_ci	 */
4338c2ecf20Sopenharmony_ci	if (pick == 1)
4348c2ecf20Sopenharmony_ci		xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize);
4358c2ecf20Sopenharmony_ci	/*
4368c2ecf20Sopenharmony_ci	 * Do it the hard way - look for a place to insert the new entry.
4378c2ecf20Sopenharmony_ci	 * Convert to 8 byte inode numbers first if necessary.
4388c2ecf20Sopenharmony_ci	 */
4398c2ecf20Sopenharmony_ci	else {
4408c2ecf20Sopenharmony_ci		ASSERT(pick == 2);
4418c2ecf20Sopenharmony_ci		if (objchange)
4428c2ecf20Sopenharmony_ci			xfs_dir2_sf_toino8(args);
4438c2ecf20Sopenharmony_ci		xfs_dir2_sf_addname_hard(args, objchange, new_isize);
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
4468c2ecf20Sopenharmony_ci	return 0;
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci/*
4508c2ecf20Sopenharmony_ci * Add the new entry the "easy" way.
4518c2ecf20Sopenharmony_ci * This is copying the old directory and adding the new entry at the end.
4528c2ecf20Sopenharmony_ci * Since it's sorted by "offset" we need room after the last offset
4538c2ecf20Sopenharmony_ci * that's already there, and then room to convert to a block directory.
4548c2ecf20Sopenharmony_ci * This is already checked by the pick routine.
4558c2ecf20Sopenharmony_ci */
4568c2ecf20Sopenharmony_cistatic void
4578c2ecf20Sopenharmony_cixfs_dir2_sf_addname_easy(
4588c2ecf20Sopenharmony_ci	xfs_da_args_t		*args,		/* operation arguments */
4598c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep,		/* pointer to new entry */
4608c2ecf20Sopenharmony_ci	xfs_dir2_data_aoff_t	offset,		/* offset to use for new ent */
4618c2ecf20Sopenharmony_ci	int			new_isize)	/* new directory size */
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
4648c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
4658c2ecf20Sopenharmony_ci	int			byteoff;	/* byte offset in sf dir */
4668c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
4698c2ecf20Sopenharmony_ci	byteoff = (int)((char *)sfep - (char *)sfp);
4708c2ecf20Sopenharmony_ci	/*
4718c2ecf20Sopenharmony_ci	 * Grow the in-inode space.
4728c2ecf20Sopenharmony_ci	 */
4738c2ecf20Sopenharmony_ci	xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->namelen),
4748c2ecf20Sopenharmony_ci			  XFS_DATA_FORK);
4758c2ecf20Sopenharmony_ci	/*
4768c2ecf20Sopenharmony_ci	 * Need to set up again due to realloc of the inode data.
4778c2ecf20Sopenharmony_ci	 */
4788c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
4798c2ecf20Sopenharmony_ci	sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff);
4808c2ecf20Sopenharmony_ci	/*
4818c2ecf20Sopenharmony_ci	 * Fill in the new entry.
4828c2ecf20Sopenharmony_ci	 */
4838c2ecf20Sopenharmony_ci	sfep->namelen = args->namelen;
4848c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_offset(sfep, offset);
4858c2ecf20Sopenharmony_ci	memcpy(sfep->name, args->name, sfep->namelen);
4868c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
4878c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/*
4908c2ecf20Sopenharmony_ci	 * Update the header and inode.
4918c2ecf20Sopenharmony_ci	 */
4928c2ecf20Sopenharmony_ci	sfp->count++;
4938c2ecf20Sopenharmony_ci	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM)
4948c2ecf20Sopenharmony_ci		sfp->i8count++;
4958c2ecf20Sopenharmony_ci	dp->i_d.di_size = new_isize;
4968c2ecf20Sopenharmony_ci	xfs_dir2_sf_check(args);
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci/*
5008c2ecf20Sopenharmony_ci * Add the new entry the "hard" way.
5018c2ecf20Sopenharmony_ci * The caller has already converted to 8 byte inode numbers if necessary,
5028c2ecf20Sopenharmony_ci * in which case we need to leave the i8count at 1.
5038c2ecf20Sopenharmony_ci * Find a hole that the new entry will fit into, and copy
5048c2ecf20Sopenharmony_ci * the first part of the entries, the new entry, and the last part of
5058c2ecf20Sopenharmony_ci * the entries.
5068c2ecf20Sopenharmony_ci */
5078c2ecf20Sopenharmony_ci/* ARGSUSED */
5088c2ecf20Sopenharmony_cistatic void
5098c2ecf20Sopenharmony_cixfs_dir2_sf_addname_hard(
5108c2ecf20Sopenharmony_ci	xfs_da_args_t		*args,		/* operation arguments */
5118c2ecf20Sopenharmony_ci	int			objchange,	/* changing inode number size */
5128c2ecf20Sopenharmony_ci	int			new_isize)	/* new directory size */
5138c2ecf20Sopenharmony_ci{
5148c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
5158c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
5168c2ecf20Sopenharmony_ci	int			add_datasize;	/* data size need for new ent */
5178c2ecf20Sopenharmony_ci	char			*buf;		/* buffer for old */
5188c2ecf20Sopenharmony_ci	int			eof;		/* reached end of old dir */
5198c2ecf20Sopenharmony_ci	int			nbytes;		/* temp for byte copies */
5208c2ecf20Sopenharmony_ci	xfs_dir2_data_aoff_t	new_offset;	/* next offset value */
5218c2ecf20Sopenharmony_ci	xfs_dir2_data_aoff_t	offset;		/* current offset value */
5228c2ecf20Sopenharmony_ci	int			old_isize;	/* previous di_size */
5238c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*oldsfep;	/* entry in original dir */
5248c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*oldsfp;	/* original shortform dir */
5258c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep;		/* entry in new dir */
5268c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* new shortform dir */
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	/*
5298c2ecf20Sopenharmony_ci	 * Copy the old directory to the stack buffer.
5308c2ecf20Sopenharmony_ci	 */
5318c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
5328c2ecf20Sopenharmony_ci	old_isize = (int)dp->i_d.di_size;
5338c2ecf20Sopenharmony_ci	buf = kmem_alloc(old_isize, 0);
5348c2ecf20Sopenharmony_ci	oldsfp = (xfs_dir2_sf_hdr_t *)buf;
5358c2ecf20Sopenharmony_ci	memcpy(oldsfp, sfp, old_isize);
5368c2ecf20Sopenharmony_ci	/*
5378c2ecf20Sopenharmony_ci	 * Loop over the old directory finding the place we're going
5388c2ecf20Sopenharmony_ci	 * to insert the new entry.
5398c2ecf20Sopenharmony_ci	 * If it's going to end up at the end then oldsfep will point there.
5408c2ecf20Sopenharmony_ci	 */
5418c2ecf20Sopenharmony_ci	for (offset = args->geo->data_first_offset,
5428c2ecf20Sopenharmony_ci	      oldsfep = xfs_dir2_sf_firstentry(oldsfp),
5438c2ecf20Sopenharmony_ci	      add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
5448c2ecf20Sopenharmony_ci	      eof = (char *)oldsfep == &buf[old_isize];
5458c2ecf20Sopenharmony_ci	     !eof;
5468c2ecf20Sopenharmony_ci	     offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
5478c2ecf20Sopenharmony_ci	      oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep),
5488c2ecf20Sopenharmony_ci	      eof = (char *)oldsfep == &buf[old_isize]) {
5498c2ecf20Sopenharmony_ci		new_offset = xfs_dir2_sf_get_offset(oldsfep);
5508c2ecf20Sopenharmony_ci		if (offset + add_datasize <= new_offset)
5518c2ecf20Sopenharmony_ci			break;
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci	/*
5548c2ecf20Sopenharmony_ci	 * Get rid of the old directory, then allocate space for
5558c2ecf20Sopenharmony_ci	 * the new one.  We do this so xfs_idata_realloc won't copy
5568c2ecf20Sopenharmony_ci	 * the data.
5578c2ecf20Sopenharmony_ci	 */
5588c2ecf20Sopenharmony_ci	xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK);
5598c2ecf20Sopenharmony_ci	xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK);
5608c2ecf20Sopenharmony_ci	/*
5618c2ecf20Sopenharmony_ci	 * Reset the pointer since the buffer was reallocated.
5628c2ecf20Sopenharmony_ci	 */
5638c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
5648c2ecf20Sopenharmony_ci	/*
5658c2ecf20Sopenharmony_ci	 * Copy the first part of the directory, including the header.
5668c2ecf20Sopenharmony_ci	 */
5678c2ecf20Sopenharmony_ci	nbytes = (int)((char *)oldsfep - (char *)oldsfp);
5688c2ecf20Sopenharmony_ci	memcpy(sfp, oldsfp, nbytes);
5698c2ecf20Sopenharmony_ci	sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
5708c2ecf20Sopenharmony_ci	/*
5718c2ecf20Sopenharmony_ci	 * Fill in the new entry, and update the header counts.
5728c2ecf20Sopenharmony_ci	 */
5738c2ecf20Sopenharmony_ci	sfep->namelen = args->namelen;
5748c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_offset(sfep, offset);
5758c2ecf20Sopenharmony_ci	memcpy(sfep->name, args->name, sfep->namelen);
5768c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
5778c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
5788c2ecf20Sopenharmony_ci	sfp->count++;
5798c2ecf20Sopenharmony_ci	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
5808c2ecf20Sopenharmony_ci		sfp->i8count++;
5818c2ecf20Sopenharmony_ci	/*
5828c2ecf20Sopenharmony_ci	 * If there's more left to copy, do that.
5838c2ecf20Sopenharmony_ci	 */
5848c2ecf20Sopenharmony_ci	if (!eof) {
5858c2ecf20Sopenharmony_ci		sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
5868c2ecf20Sopenharmony_ci		memcpy(sfep, oldsfep, old_isize - nbytes);
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci	kmem_free(buf);
5898c2ecf20Sopenharmony_ci	dp->i_d.di_size = new_isize;
5908c2ecf20Sopenharmony_ci	xfs_dir2_sf_check(args);
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci/*
5948c2ecf20Sopenharmony_ci * Decide if the new entry will fit at all.
5958c2ecf20Sopenharmony_ci * If it will fit, pick between adding the new entry to the end (easy)
5968c2ecf20Sopenharmony_ci * or somewhere else (hard).
5978c2ecf20Sopenharmony_ci * Return 0 (won't fit), 1 (easy), 2 (hard).
5988c2ecf20Sopenharmony_ci */
5998c2ecf20Sopenharmony_ci/*ARGSUSED*/
6008c2ecf20Sopenharmony_cistatic int					/* pick result */
6018c2ecf20Sopenharmony_cixfs_dir2_sf_addname_pick(
6028c2ecf20Sopenharmony_ci	xfs_da_args_t		*args,		/* operation arguments */
6038c2ecf20Sopenharmony_ci	int			objchange,	/* inode # size changes */
6048c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	**sfepp,	/* out(1): new entry ptr */
6058c2ecf20Sopenharmony_ci	xfs_dir2_data_aoff_t	*offsetp)	/* out(1): new offset */
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
6088c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
6098c2ecf20Sopenharmony_ci	int			holefit;	/* found hole it will fit in */
6108c2ecf20Sopenharmony_ci	int			i;		/* entry number */
6118c2ecf20Sopenharmony_ci	xfs_dir2_data_aoff_t	offset;		/* data block offset */
6128c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep;		/* shortform entry */
6138c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
6148c2ecf20Sopenharmony_ci	int			size;		/* entry's data size */
6158c2ecf20Sopenharmony_ci	int			used;		/* data bytes used */
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
6188c2ecf20Sopenharmony_ci	size = xfs_dir2_data_entsize(mp, args->namelen);
6198c2ecf20Sopenharmony_ci	offset = args->geo->data_first_offset;
6208c2ecf20Sopenharmony_ci	sfep = xfs_dir2_sf_firstentry(sfp);
6218c2ecf20Sopenharmony_ci	holefit = 0;
6228c2ecf20Sopenharmony_ci	/*
6238c2ecf20Sopenharmony_ci	 * Loop over sf entries.
6248c2ecf20Sopenharmony_ci	 * Keep track of data offset and whether we've seen a place
6258c2ecf20Sopenharmony_ci	 * to insert the new entry.
6268c2ecf20Sopenharmony_ci	 */
6278c2ecf20Sopenharmony_ci	for (i = 0; i < sfp->count; i++) {
6288c2ecf20Sopenharmony_ci		if (!holefit)
6298c2ecf20Sopenharmony_ci			holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
6308c2ecf20Sopenharmony_ci		offset = xfs_dir2_sf_get_offset(sfep) +
6318c2ecf20Sopenharmony_ci			 xfs_dir2_data_entsize(mp, sfep->namelen);
6328c2ecf20Sopenharmony_ci		sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci	/*
6358c2ecf20Sopenharmony_ci	 * Calculate data bytes used excluding the new entry, if this
6368c2ecf20Sopenharmony_ci	 * was a data block (block form directory).
6378c2ecf20Sopenharmony_ci	 */
6388c2ecf20Sopenharmony_ci	used = offset +
6398c2ecf20Sopenharmony_ci	       (sfp->count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
6408c2ecf20Sopenharmony_ci	       (uint)sizeof(xfs_dir2_block_tail_t);
6418c2ecf20Sopenharmony_ci	/*
6428c2ecf20Sopenharmony_ci	 * If it won't fit in a block form then we can't insert it,
6438c2ecf20Sopenharmony_ci	 * we'll go back, convert to block, then try the insert and convert
6448c2ecf20Sopenharmony_ci	 * to leaf.
6458c2ecf20Sopenharmony_ci	 */
6468c2ecf20Sopenharmony_ci	if (used + (holefit ? 0 : size) > args->geo->blksize)
6478c2ecf20Sopenharmony_ci		return 0;
6488c2ecf20Sopenharmony_ci	/*
6498c2ecf20Sopenharmony_ci	 * If changing the inode number size, do it the hard way.
6508c2ecf20Sopenharmony_ci	 */
6518c2ecf20Sopenharmony_ci	if (objchange)
6528c2ecf20Sopenharmony_ci		return 2;
6538c2ecf20Sopenharmony_ci	/*
6548c2ecf20Sopenharmony_ci	 * If it won't fit at the end then do it the hard way (use the hole).
6558c2ecf20Sopenharmony_ci	 */
6568c2ecf20Sopenharmony_ci	if (used + size > args->geo->blksize)
6578c2ecf20Sopenharmony_ci		return 2;
6588c2ecf20Sopenharmony_ci	/*
6598c2ecf20Sopenharmony_ci	 * Do it the easy way.
6608c2ecf20Sopenharmony_ci	 */
6618c2ecf20Sopenharmony_ci	*sfepp = sfep;
6628c2ecf20Sopenharmony_ci	*offsetp = offset;
6638c2ecf20Sopenharmony_ci	return 1;
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci#ifdef DEBUG
6678c2ecf20Sopenharmony_ci/*
6688c2ecf20Sopenharmony_ci * Check consistency of shortform directory, assert if bad.
6698c2ecf20Sopenharmony_ci */
6708c2ecf20Sopenharmony_cistatic void
6718c2ecf20Sopenharmony_cixfs_dir2_sf_check(
6728c2ecf20Sopenharmony_ci	xfs_da_args_t		*args)		/* operation arguments */
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
6758c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
6768c2ecf20Sopenharmony_ci	int			i;		/* entry number */
6778c2ecf20Sopenharmony_ci	int			i8count;	/* number of big inode#s */
6788c2ecf20Sopenharmony_ci	xfs_ino_t		ino;		/* entry inode number */
6798c2ecf20Sopenharmony_ci	int			offset;		/* data offset */
6808c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep;		/* shortform dir entry */
6818c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
6848c2ecf20Sopenharmony_ci	offset = args->geo->data_first_offset;
6858c2ecf20Sopenharmony_ci	ino = xfs_dir2_sf_get_parent_ino(sfp);
6868c2ecf20Sopenharmony_ci	i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
6898c2ecf20Sopenharmony_ci	     i < sfp->count;
6908c2ecf20Sopenharmony_ci	     i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
6918c2ecf20Sopenharmony_ci		ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
6928c2ecf20Sopenharmony_ci		ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
6938c2ecf20Sopenharmony_ci		i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
6948c2ecf20Sopenharmony_ci		offset =
6958c2ecf20Sopenharmony_ci			xfs_dir2_sf_get_offset(sfep) +
6968c2ecf20Sopenharmony_ci			xfs_dir2_data_entsize(mp, sfep->namelen);
6978c2ecf20Sopenharmony_ci		ASSERT(xfs_dir2_sf_get_ftype(mp, sfep) < XFS_DIR3_FT_MAX);
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci	ASSERT(i8count == sfp->i8count);
7008c2ecf20Sopenharmony_ci	ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
7018c2ecf20Sopenharmony_ci	ASSERT(offset +
7028c2ecf20Sopenharmony_ci	       (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
7038c2ecf20Sopenharmony_ci	       (uint)sizeof(xfs_dir2_block_tail_t) <= args->geo->blksize);
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci#endif	/* DEBUG */
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci/* Verify the consistency of an inline directory. */
7088c2ecf20Sopenharmony_cixfs_failaddr_t
7098c2ecf20Sopenharmony_cixfs_dir2_sf_verify(
7108c2ecf20Sopenharmony_ci	struct xfs_inode		*ip)
7118c2ecf20Sopenharmony_ci{
7128c2ecf20Sopenharmony_ci	struct xfs_mount		*mp = ip->i_mount;
7138c2ecf20Sopenharmony_ci	struct xfs_ifork		*ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
7148c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr		*sfp;
7158c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_entry	*sfep;
7168c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_entry	*next_sfep;
7178c2ecf20Sopenharmony_ci	char				*endp;
7188c2ecf20Sopenharmony_ci	xfs_ino_t			ino;
7198c2ecf20Sopenharmony_ci	int				i;
7208c2ecf20Sopenharmony_ci	int				i8count;
7218c2ecf20Sopenharmony_ci	int				offset;
7228c2ecf20Sopenharmony_ci	int64_t				size;
7238c2ecf20Sopenharmony_ci	int				error;
7248c2ecf20Sopenharmony_ci	uint8_t				filetype;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
7298c2ecf20Sopenharmony_ci	size = ifp->if_bytes;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	/*
7328c2ecf20Sopenharmony_ci	 * Give up if the directory is way too short.
7338c2ecf20Sopenharmony_ci	 */
7348c2ecf20Sopenharmony_ci	if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) ||
7358c2ecf20Sopenharmony_ci	    size < xfs_dir2_sf_hdr_size(sfp->i8count))
7368c2ecf20Sopenharmony_ci		return __this_address;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	endp = (char *)sfp + size;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	/* Check .. entry */
7418c2ecf20Sopenharmony_ci	ino = xfs_dir2_sf_get_parent_ino(sfp);
7428c2ecf20Sopenharmony_ci	i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
7438c2ecf20Sopenharmony_ci	error = xfs_dir_ino_validate(mp, ino);
7448c2ecf20Sopenharmony_ci	if (error)
7458c2ecf20Sopenharmony_ci		return __this_address;
7468c2ecf20Sopenharmony_ci	offset = mp->m_dir_geo->data_first_offset;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* Check all reported entries */
7498c2ecf20Sopenharmony_ci	sfep = xfs_dir2_sf_firstentry(sfp);
7508c2ecf20Sopenharmony_ci	for (i = 0; i < sfp->count; i++) {
7518c2ecf20Sopenharmony_ci		/*
7528c2ecf20Sopenharmony_ci		 * struct xfs_dir2_sf_entry has a variable length.
7538c2ecf20Sopenharmony_ci		 * Check the fixed-offset parts of the structure are
7548c2ecf20Sopenharmony_ci		 * within the data buffer.
7558c2ecf20Sopenharmony_ci		 */
7568c2ecf20Sopenharmony_ci		if (((char *)sfep + sizeof(*sfep)) >= endp)
7578c2ecf20Sopenharmony_ci			return __this_address;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci		/* Don't allow names with known bad length. */
7608c2ecf20Sopenharmony_ci		if (sfep->namelen == 0)
7618c2ecf20Sopenharmony_ci			return __this_address;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci		/*
7648c2ecf20Sopenharmony_ci		 * Check that the variable-length part of the structure is
7658c2ecf20Sopenharmony_ci		 * within the data buffer.  The next entry starts after the
7668c2ecf20Sopenharmony_ci		 * name component, so nextentry is an acceptable test.
7678c2ecf20Sopenharmony_ci		 */
7688c2ecf20Sopenharmony_ci		next_sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
7698c2ecf20Sopenharmony_ci		if (endp < (char *)next_sfep)
7708c2ecf20Sopenharmony_ci			return __this_address;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci		/* Check that the offsets always increase. */
7738c2ecf20Sopenharmony_ci		if (xfs_dir2_sf_get_offset(sfep) < offset)
7748c2ecf20Sopenharmony_ci			return __this_address;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci		/* Check the inode number. */
7778c2ecf20Sopenharmony_ci		ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
7788c2ecf20Sopenharmony_ci		i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
7798c2ecf20Sopenharmony_ci		error = xfs_dir_ino_validate(mp, ino);
7808c2ecf20Sopenharmony_ci		if (error)
7818c2ecf20Sopenharmony_ci			return __this_address;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci		/* Check the file type. */
7848c2ecf20Sopenharmony_ci		filetype = xfs_dir2_sf_get_ftype(mp, sfep);
7858c2ecf20Sopenharmony_ci		if (filetype >= XFS_DIR3_FT_MAX)
7868c2ecf20Sopenharmony_ci			return __this_address;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci		offset = xfs_dir2_sf_get_offset(sfep) +
7898c2ecf20Sopenharmony_ci				xfs_dir2_data_entsize(mp, sfep->namelen);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		sfep = next_sfep;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci	if (i8count != sfp->i8count)
7948c2ecf20Sopenharmony_ci		return __this_address;
7958c2ecf20Sopenharmony_ci	if ((void *)sfep != (void *)endp)
7968c2ecf20Sopenharmony_ci		return __this_address;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	/* Make sure this whole thing ought to be in local format. */
7998c2ecf20Sopenharmony_ci	if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
8008c2ecf20Sopenharmony_ci	    (uint)sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize)
8018c2ecf20Sopenharmony_ci		return __this_address;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	return NULL;
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci/*
8078c2ecf20Sopenharmony_ci * Create a new (shortform) directory.
8088c2ecf20Sopenharmony_ci */
8098c2ecf20Sopenharmony_ciint					/* error, always 0 */
8108c2ecf20Sopenharmony_cixfs_dir2_sf_create(
8118c2ecf20Sopenharmony_ci	xfs_da_args_t	*args,		/* operation arguments */
8128c2ecf20Sopenharmony_ci	xfs_ino_t	pino)		/* parent inode number */
8138c2ecf20Sopenharmony_ci{
8148c2ecf20Sopenharmony_ci	xfs_inode_t	*dp;		/* incore directory inode */
8158c2ecf20Sopenharmony_ci	int		i8count;	/* parent inode is an 8-byte number */
8168c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t *sfp;		/* shortform structure */
8178c2ecf20Sopenharmony_ci	int		size;		/* directory size */
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	trace_xfs_dir2_sf_create(args);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	dp = args->dp;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	ASSERT(dp != NULL);
8248c2ecf20Sopenharmony_ci	ASSERT(dp->i_d.di_size == 0);
8258c2ecf20Sopenharmony_ci	/*
8268c2ecf20Sopenharmony_ci	 * If it's currently a zero-length extent file,
8278c2ecf20Sopenharmony_ci	 * convert it to local format.
8288c2ecf20Sopenharmony_ci	 */
8298c2ecf20Sopenharmony_ci	if (dp->i_df.if_format == XFS_DINODE_FMT_EXTENTS) {
8308c2ecf20Sopenharmony_ci		dp->i_df.if_flags &= ~XFS_IFEXTENTS;	/* just in case */
8318c2ecf20Sopenharmony_ci		dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
8328c2ecf20Sopenharmony_ci		xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
8338c2ecf20Sopenharmony_ci		dp->i_df.if_flags |= XFS_IFINLINE;
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
8368c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_bytes == 0);
8378c2ecf20Sopenharmony_ci	i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
8388c2ecf20Sopenharmony_ci	size = xfs_dir2_sf_hdr_size(i8count);
8398c2ecf20Sopenharmony_ci	/*
8408c2ecf20Sopenharmony_ci	 * Make a buffer for the data.
8418c2ecf20Sopenharmony_ci	 */
8428c2ecf20Sopenharmony_ci	xfs_idata_realloc(dp, size, XFS_DATA_FORK);
8438c2ecf20Sopenharmony_ci	/*
8448c2ecf20Sopenharmony_ci	 * Fill in the header,
8458c2ecf20Sopenharmony_ci	 */
8468c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
8478c2ecf20Sopenharmony_ci	sfp->i8count = i8count;
8488c2ecf20Sopenharmony_ci	/*
8498c2ecf20Sopenharmony_ci	 * Now can put in the inode number, since i8count is set.
8508c2ecf20Sopenharmony_ci	 */
8518c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_parent_ino(sfp, pino);
8528c2ecf20Sopenharmony_ci	sfp->count = 0;
8538c2ecf20Sopenharmony_ci	dp->i_d.di_size = size;
8548c2ecf20Sopenharmony_ci	xfs_dir2_sf_check(args);
8558c2ecf20Sopenharmony_ci	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
8568c2ecf20Sopenharmony_ci	return 0;
8578c2ecf20Sopenharmony_ci}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci/*
8608c2ecf20Sopenharmony_ci * Lookup an entry in a shortform directory.
8618c2ecf20Sopenharmony_ci * Returns EEXIST if found, ENOENT if not found.
8628c2ecf20Sopenharmony_ci */
8638c2ecf20Sopenharmony_ciint						/* error */
8648c2ecf20Sopenharmony_cixfs_dir2_sf_lookup(
8658c2ecf20Sopenharmony_ci	xfs_da_args_t		*args)		/* operation arguments */
8668c2ecf20Sopenharmony_ci{
8678c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
8688c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
8698c2ecf20Sopenharmony_ci	int			i;		/* entry index */
8708c2ecf20Sopenharmony_ci	int			error;
8718c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */
8728c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
8738c2ecf20Sopenharmony_ci	enum xfs_dacmp		cmp;		/* comparison result */
8748c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*ci_sfep;	/* case-insens. entry */
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	trace_xfs_dir2_sf_lookup(args);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	xfs_dir2_sf_check(args);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
8818c2ecf20Sopenharmony_ci	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
8828c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
8838c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_u1.if_data != NULL);
8848c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
8858c2ecf20Sopenharmony_ci	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
8868c2ecf20Sopenharmony_ci	/*
8878c2ecf20Sopenharmony_ci	 * Special case for .
8888c2ecf20Sopenharmony_ci	 */
8898c2ecf20Sopenharmony_ci	if (args->namelen == 1 && args->name[0] == '.') {
8908c2ecf20Sopenharmony_ci		args->inumber = dp->i_ino;
8918c2ecf20Sopenharmony_ci		args->cmpresult = XFS_CMP_EXACT;
8928c2ecf20Sopenharmony_ci		args->filetype = XFS_DIR3_FT_DIR;
8938c2ecf20Sopenharmony_ci		return -EEXIST;
8948c2ecf20Sopenharmony_ci	}
8958c2ecf20Sopenharmony_ci	/*
8968c2ecf20Sopenharmony_ci	 * Special case for ..
8978c2ecf20Sopenharmony_ci	 */
8988c2ecf20Sopenharmony_ci	if (args->namelen == 2 &&
8998c2ecf20Sopenharmony_ci	    args->name[0] == '.' && args->name[1] == '.') {
9008c2ecf20Sopenharmony_ci		args->inumber = xfs_dir2_sf_get_parent_ino(sfp);
9018c2ecf20Sopenharmony_ci		args->cmpresult = XFS_CMP_EXACT;
9028c2ecf20Sopenharmony_ci		args->filetype = XFS_DIR3_FT_DIR;
9038c2ecf20Sopenharmony_ci		return -EEXIST;
9048c2ecf20Sopenharmony_ci	}
9058c2ecf20Sopenharmony_ci	/*
9068c2ecf20Sopenharmony_ci	 * Loop over all the entries trying to match ours.
9078c2ecf20Sopenharmony_ci	 */
9088c2ecf20Sopenharmony_ci	ci_sfep = NULL;
9098c2ecf20Sopenharmony_ci	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
9108c2ecf20Sopenharmony_ci	     i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
9118c2ecf20Sopenharmony_ci		/*
9128c2ecf20Sopenharmony_ci		 * Compare name and if it's an exact match, return the inode
9138c2ecf20Sopenharmony_ci		 * number. If it's the first case-insensitive match, store the
9148c2ecf20Sopenharmony_ci		 * inode number and continue looking for an exact match.
9158c2ecf20Sopenharmony_ci		 */
9168c2ecf20Sopenharmony_ci		cmp = xfs_dir2_compname(args, sfep->name, sfep->namelen);
9178c2ecf20Sopenharmony_ci		if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
9188c2ecf20Sopenharmony_ci			args->cmpresult = cmp;
9198c2ecf20Sopenharmony_ci			args->inumber = xfs_dir2_sf_get_ino(mp, sfp, sfep);
9208c2ecf20Sopenharmony_ci			args->filetype = xfs_dir2_sf_get_ftype(mp, sfep);
9218c2ecf20Sopenharmony_ci			if (cmp == XFS_CMP_EXACT)
9228c2ecf20Sopenharmony_ci				return -EEXIST;
9238c2ecf20Sopenharmony_ci			ci_sfep = sfep;
9248c2ecf20Sopenharmony_ci		}
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci	ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
9278c2ecf20Sopenharmony_ci	/*
9288c2ecf20Sopenharmony_ci	 * Here, we can only be doing a lookup (not a rename or replace).
9298c2ecf20Sopenharmony_ci	 * If a case-insensitive match was not found, return -ENOENT.
9308c2ecf20Sopenharmony_ci	 */
9318c2ecf20Sopenharmony_ci	if (!ci_sfep)
9328c2ecf20Sopenharmony_ci		return -ENOENT;
9338c2ecf20Sopenharmony_ci	/* otherwise process the CI match as required by the caller */
9348c2ecf20Sopenharmony_ci	error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen);
9358c2ecf20Sopenharmony_ci	return error;
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci/*
9398c2ecf20Sopenharmony_ci * Remove an entry from a shortform directory.
9408c2ecf20Sopenharmony_ci */
9418c2ecf20Sopenharmony_ciint						/* error */
9428c2ecf20Sopenharmony_cixfs_dir2_sf_removename(
9438c2ecf20Sopenharmony_ci	xfs_da_args_t		*args)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
9468c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
9478c2ecf20Sopenharmony_ci	int			byteoff;	/* offset of removed entry */
9488c2ecf20Sopenharmony_ci	int			entsize;	/* this entry's size */
9498c2ecf20Sopenharmony_ci	int			i;		/* shortform entry index */
9508c2ecf20Sopenharmony_ci	int			newsize;	/* new inode size */
9518c2ecf20Sopenharmony_ci	int			oldsize;	/* old inode size */
9528c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */
9538c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	trace_xfs_dir2_sf_removename(args);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
9588c2ecf20Sopenharmony_ci	oldsize = (int)dp->i_d.di_size;
9598c2ecf20Sopenharmony_ci	ASSERT(oldsize >= offsetof(struct xfs_dir2_sf_hdr, parent));
9608c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_bytes == oldsize);
9618c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_u1.if_data != NULL);
9628c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
9638c2ecf20Sopenharmony_ci	ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count));
9648c2ecf20Sopenharmony_ci	/*
9658c2ecf20Sopenharmony_ci	 * Loop over the old directory entries.
9668c2ecf20Sopenharmony_ci	 * Find the one we're deleting.
9678c2ecf20Sopenharmony_ci	 */
9688c2ecf20Sopenharmony_ci	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
9698c2ecf20Sopenharmony_ci	     i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
9708c2ecf20Sopenharmony_ci		if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
9718c2ecf20Sopenharmony_ci								XFS_CMP_EXACT) {
9728c2ecf20Sopenharmony_ci			ASSERT(xfs_dir2_sf_get_ino(mp, sfp, sfep) ==
9738c2ecf20Sopenharmony_ci			       args->inumber);
9748c2ecf20Sopenharmony_ci			break;
9758c2ecf20Sopenharmony_ci		}
9768c2ecf20Sopenharmony_ci	}
9778c2ecf20Sopenharmony_ci	/*
9788c2ecf20Sopenharmony_ci	 * Didn't find it.
9798c2ecf20Sopenharmony_ci	 */
9808c2ecf20Sopenharmony_ci	if (i == sfp->count)
9818c2ecf20Sopenharmony_ci		return -ENOENT;
9828c2ecf20Sopenharmony_ci	/*
9838c2ecf20Sopenharmony_ci	 * Calculate sizes.
9848c2ecf20Sopenharmony_ci	 */
9858c2ecf20Sopenharmony_ci	byteoff = (int)((char *)sfep - (char *)sfp);
9868c2ecf20Sopenharmony_ci	entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
9878c2ecf20Sopenharmony_ci	newsize = oldsize - entsize;
9888c2ecf20Sopenharmony_ci	/*
9898c2ecf20Sopenharmony_ci	 * Copy the part if any after the removed entry, sliding it down.
9908c2ecf20Sopenharmony_ci	 */
9918c2ecf20Sopenharmony_ci	if (byteoff + entsize < oldsize)
9928c2ecf20Sopenharmony_ci		memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
9938c2ecf20Sopenharmony_ci			oldsize - (byteoff + entsize));
9948c2ecf20Sopenharmony_ci	/*
9958c2ecf20Sopenharmony_ci	 * Fix up the header and file size.
9968c2ecf20Sopenharmony_ci	 */
9978c2ecf20Sopenharmony_ci	sfp->count--;
9988c2ecf20Sopenharmony_ci	dp->i_d.di_size = newsize;
9998c2ecf20Sopenharmony_ci	/*
10008c2ecf20Sopenharmony_ci	 * Reallocate, making it smaller.
10018c2ecf20Sopenharmony_ci	 */
10028c2ecf20Sopenharmony_ci	xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK);
10038c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
10048c2ecf20Sopenharmony_ci	/*
10058c2ecf20Sopenharmony_ci	 * Are we changing inode number size?
10068c2ecf20Sopenharmony_ci	 */
10078c2ecf20Sopenharmony_ci	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
10088c2ecf20Sopenharmony_ci		if (sfp->i8count == 1)
10098c2ecf20Sopenharmony_ci			xfs_dir2_sf_toino4(args);
10108c2ecf20Sopenharmony_ci		else
10118c2ecf20Sopenharmony_ci			sfp->i8count--;
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci	xfs_dir2_sf_check(args);
10148c2ecf20Sopenharmony_ci	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
10158c2ecf20Sopenharmony_ci	return 0;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci/*
10198c2ecf20Sopenharmony_ci * Check whether the sf dir replace operation need more blocks.
10208c2ecf20Sopenharmony_ci */
10218c2ecf20Sopenharmony_cistatic bool
10228c2ecf20Sopenharmony_cixfs_dir2_sf_replace_needblock(
10238c2ecf20Sopenharmony_ci	struct xfs_inode	*dp,
10248c2ecf20Sopenharmony_ci	xfs_ino_t		inum)
10258c2ecf20Sopenharmony_ci{
10268c2ecf20Sopenharmony_ci	int			newsize;
10278c2ecf20Sopenharmony_ci	struct xfs_dir2_sf_hdr	*sfp;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	if (dp->i_df.if_format != XFS_DINODE_FMT_LOCAL)
10308c2ecf20Sopenharmony_ci		return false;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data;
10338c2ecf20Sopenharmony_ci	newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	return inum > XFS_DIR2_MAX_SHORT_INUM &&
10368c2ecf20Sopenharmony_ci	       sfp->i8count == 0 && newsize > XFS_IFORK_DSIZE(dp);
10378c2ecf20Sopenharmony_ci}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci/*
10408c2ecf20Sopenharmony_ci * Replace the inode number of an entry in a shortform directory.
10418c2ecf20Sopenharmony_ci */
10428c2ecf20Sopenharmony_ciint						/* error */
10438c2ecf20Sopenharmony_cixfs_dir2_sf_replace(
10448c2ecf20Sopenharmony_ci	xfs_da_args_t		*args)		/* operation arguments */
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
10478c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
10488c2ecf20Sopenharmony_ci	int			i;		/* entry index */
10498c2ecf20Sopenharmony_ci	xfs_ino_t		ino=0;		/* entry old inode number */
10508c2ecf20Sopenharmony_ci	int			i8elevated;	/* sf_toino8 set i8count=1 */
10518c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */
10528c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	trace_xfs_dir2_sf_replace(args);
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
10578c2ecf20Sopenharmony_ci	ASSERT(dp->i_d.di_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
10588c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
10598c2ecf20Sopenharmony_ci	ASSERT(dp->i_df.if_u1.if_data != NULL);
10608c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
10618c2ecf20Sopenharmony_ci	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	/*
10648c2ecf20Sopenharmony_ci	 * New inode number is large, and need to convert to 8-byte inodes.
10658c2ecf20Sopenharmony_ci	 */
10668c2ecf20Sopenharmony_ci	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
10678c2ecf20Sopenharmony_ci		int	error;			/* error return value */
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci		/*
10708c2ecf20Sopenharmony_ci		 * Won't fit as shortform, convert to block then do replace.
10718c2ecf20Sopenharmony_ci		 */
10728c2ecf20Sopenharmony_ci		if (xfs_dir2_sf_replace_needblock(dp, args->inumber)) {
10738c2ecf20Sopenharmony_ci			error = xfs_dir2_sf_to_block(args);
10748c2ecf20Sopenharmony_ci			if (error)
10758c2ecf20Sopenharmony_ci				return error;
10768c2ecf20Sopenharmony_ci			return xfs_dir2_block_replace(args);
10778c2ecf20Sopenharmony_ci		}
10788c2ecf20Sopenharmony_ci		/*
10798c2ecf20Sopenharmony_ci		 * Still fits, convert to 8-byte now.
10808c2ecf20Sopenharmony_ci		 */
10818c2ecf20Sopenharmony_ci		xfs_dir2_sf_toino8(args);
10828c2ecf20Sopenharmony_ci		i8elevated = 1;
10838c2ecf20Sopenharmony_ci		sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
10848c2ecf20Sopenharmony_ci	} else
10858c2ecf20Sopenharmony_ci		i8elevated = 0;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	ASSERT(args->namelen != 1 || args->name[0] != '.');
10888c2ecf20Sopenharmony_ci	/*
10898c2ecf20Sopenharmony_ci	 * Replace ..'s entry.
10908c2ecf20Sopenharmony_ci	 */
10918c2ecf20Sopenharmony_ci	if (args->namelen == 2 &&
10928c2ecf20Sopenharmony_ci	    args->name[0] == '.' && args->name[1] == '.') {
10938c2ecf20Sopenharmony_ci		ino = xfs_dir2_sf_get_parent_ino(sfp);
10948c2ecf20Sopenharmony_ci		ASSERT(args->inumber != ino);
10958c2ecf20Sopenharmony_ci		xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
10968c2ecf20Sopenharmony_ci	}
10978c2ecf20Sopenharmony_ci	/*
10988c2ecf20Sopenharmony_ci	 * Normal entry, look for the name.
10998c2ecf20Sopenharmony_ci	 */
11008c2ecf20Sopenharmony_ci	else {
11018c2ecf20Sopenharmony_ci		for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
11028c2ecf20Sopenharmony_ci		     i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
11038c2ecf20Sopenharmony_ci			if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
11048c2ecf20Sopenharmony_ci								XFS_CMP_EXACT) {
11058c2ecf20Sopenharmony_ci				ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
11068c2ecf20Sopenharmony_ci				ASSERT(args->inumber != ino);
11078c2ecf20Sopenharmony_ci				xfs_dir2_sf_put_ino(mp, sfp, sfep,
11088c2ecf20Sopenharmony_ci						args->inumber);
11098c2ecf20Sopenharmony_ci				xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
11108c2ecf20Sopenharmony_ci				break;
11118c2ecf20Sopenharmony_ci			}
11128c2ecf20Sopenharmony_ci		}
11138c2ecf20Sopenharmony_ci		/*
11148c2ecf20Sopenharmony_ci		 * Didn't find it.
11158c2ecf20Sopenharmony_ci		 */
11168c2ecf20Sopenharmony_ci		if (i == sfp->count) {
11178c2ecf20Sopenharmony_ci			ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
11188c2ecf20Sopenharmony_ci			if (i8elevated)
11198c2ecf20Sopenharmony_ci				xfs_dir2_sf_toino4(args);
11208c2ecf20Sopenharmony_ci			return -ENOENT;
11218c2ecf20Sopenharmony_ci		}
11228c2ecf20Sopenharmony_ci	}
11238c2ecf20Sopenharmony_ci	/*
11248c2ecf20Sopenharmony_ci	 * See if the old number was large, the new number is small.
11258c2ecf20Sopenharmony_ci	 */
11268c2ecf20Sopenharmony_ci	if (ino > XFS_DIR2_MAX_SHORT_INUM &&
11278c2ecf20Sopenharmony_ci	    args->inumber <= XFS_DIR2_MAX_SHORT_INUM) {
11288c2ecf20Sopenharmony_ci		/*
11298c2ecf20Sopenharmony_ci		 * And the old count was one, so need to convert to small.
11308c2ecf20Sopenharmony_ci		 */
11318c2ecf20Sopenharmony_ci		if (sfp->i8count == 1)
11328c2ecf20Sopenharmony_ci			xfs_dir2_sf_toino4(args);
11338c2ecf20Sopenharmony_ci		else
11348c2ecf20Sopenharmony_ci			sfp->i8count--;
11358c2ecf20Sopenharmony_ci	}
11368c2ecf20Sopenharmony_ci	/*
11378c2ecf20Sopenharmony_ci	 * See if the old number was small, the new number is large.
11388c2ecf20Sopenharmony_ci	 */
11398c2ecf20Sopenharmony_ci	if (ino <= XFS_DIR2_MAX_SHORT_INUM &&
11408c2ecf20Sopenharmony_ci	    args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
11418c2ecf20Sopenharmony_ci		/*
11428c2ecf20Sopenharmony_ci		 * add to the i8count unless we just converted to 8-byte
11438c2ecf20Sopenharmony_ci		 * inodes (which does an implied i8count = 1)
11448c2ecf20Sopenharmony_ci		 */
11458c2ecf20Sopenharmony_ci		ASSERT(sfp->i8count != 0);
11468c2ecf20Sopenharmony_ci		if (!i8elevated)
11478c2ecf20Sopenharmony_ci			sfp->i8count++;
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci	xfs_dir2_sf_check(args);
11508c2ecf20Sopenharmony_ci	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
11518c2ecf20Sopenharmony_ci	return 0;
11528c2ecf20Sopenharmony_ci}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci/*
11558c2ecf20Sopenharmony_ci * Convert from 8-byte inode numbers to 4-byte inode numbers.
11568c2ecf20Sopenharmony_ci * The last 8-byte inode number is gone, but the count is still 1.
11578c2ecf20Sopenharmony_ci */
11588c2ecf20Sopenharmony_cistatic void
11598c2ecf20Sopenharmony_cixfs_dir2_sf_toino4(
11608c2ecf20Sopenharmony_ci	xfs_da_args_t		*args)		/* operation arguments */
11618c2ecf20Sopenharmony_ci{
11628c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
11638c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
11648c2ecf20Sopenharmony_ci	char			*buf;		/* old dir's buffer */
11658c2ecf20Sopenharmony_ci	int			i;		/* entry index */
11668c2ecf20Sopenharmony_ci	int			newsize;	/* new inode size */
11678c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*oldsfep;	/* old sf entry */
11688c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*oldsfp;	/* old sf directory */
11698c2ecf20Sopenharmony_ci	int			oldsize;	/* old inode size */
11708c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep;		/* new sf entry */
11718c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* new sf directory */
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	trace_xfs_dir2_sf_toino4(args);
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	/*
11768c2ecf20Sopenharmony_ci	 * Copy the old directory to the buffer.
11778c2ecf20Sopenharmony_ci	 * Then nuke it from the inode, and add the new buffer to the inode.
11788c2ecf20Sopenharmony_ci	 * Don't want xfs_idata_realloc copying the data here.
11798c2ecf20Sopenharmony_ci	 */
11808c2ecf20Sopenharmony_ci	oldsize = dp->i_df.if_bytes;
11818c2ecf20Sopenharmony_ci	buf = kmem_alloc(oldsize, 0);
11828c2ecf20Sopenharmony_ci	oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
11838c2ecf20Sopenharmony_ci	ASSERT(oldsfp->i8count == 1);
11848c2ecf20Sopenharmony_ci	memcpy(buf, oldsfp, oldsize);
11858c2ecf20Sopenharmony_ci	/*
11868c2ecf20Sopenharmony_ci	 * Compute the new inode size.
11878c2ecf20Sopenharmony_ci	 */
11888c2ecf20Sopenharmony_ci	newsize = oldsize - (oldsfp->count + 1) * XFS_INO64_DIFF;
11898c2ecf20Sopenharmony_ci	xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
11908c2ecf20Sopenharmony_ci	xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
11918c2ecf20Sopenharmony_ci	/*
11928c2ecf20Sopenharmony_ci	 * Reset our pointers, the data has moved.
11938c2ecf20Sopenharmony_ci	 */
11948c2ecf20Sopenharmony_ci	oldsfp = (xfs_dir2_sf_hdr_t *)buf;
11958c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
11968c2ecf20Sopenharmony_ci	/*
11978c2ecf20Sopenharmony_ci	 * Fill in the new header.
11988c2ecf20Sopenharmony_ci	 */
11998c2ecf20Sopenharmony_ci	sfp->count = oldsfp->count;
12008c2ecf20Sopenharmony_ci	sfp->i8count = 0;
12018c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
12028c2ecf20Sopenharmony_ci	/*
12038c2ecf20Sopenharmony_ci	 * Copy the entries field by field.
12048c2ecf20Sopenharmony_ci	 */
12058c2ecf20Sopenharmony_ci	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
12068c2ecf20Sopenharmony_ci		    oldsfep = xfs_dir2_sf_firstentry(oldsfp);
12078c2ecf20Sopenharmony_ci	     i < sfp->count;
12088c2ecf20Sopenharmony_ci	     i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
12098c2ecf20Sopenharmony_ci		  oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
12108c2ecf20Sopenharmony_ci		sfep->namelen = oldsfep->namelen;
12118c2ecf20Sopenharmony_ci		memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
12128c2ecf20Sopenharmony_ci		memcpy(sfep->name, oldsfep->name, sfep->namelen);
12138c2ecf20Sopenharmony_ci		xfs_dir2_sf_put_ino(mp, sfp, sfep,
12148c2ecf20Sopenharmony_ci				xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
12158c2ecf20Sopenharmony_ci		xfs_dir2_sf_put_ftype(mp, sfep,
12168c2ecf20Sopenharmony_ci				xfs_dir2_sf_get_ftype(mp, oldsfep));
12178c2ecf20Sopenharmony_ci	}
12188c2ecf20Sopenharmony_ci	/*
12198c2ecf20Sopenharmony_ci	 * Clean up the inode.
12208c2ecf20Sopenharmony_ci	 */
12218c2ecf20Sopenharmony_ci	kmem_free(buf);
12228c2ecf20Sopenharmony_ci	dp->i_d.di_size = newsize;
12238c2ecf20Sopenharmony_ci	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
12248c2ecf20Sopenharmony_ci}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci/*
12278c2ecf20Sopenharmony_ci * Convert existing entries from 4-byte inode numbers to 8-byte inode numbers.
12288c2ecf20Sopenharmony_ci * The new entry w/ an 8-byte inode number is not there yet; we leave with
12298c2ecf20Sopenharmony_ci * i8count set to 1, but no corresponding 8-byte entry.
12308c2ecf20Sopenharmony_ci */
12318c2ecf20Sopenharmony_cistatic void
12328c2ecf20Sopenharmony_cixfs_dir2_sf_toino8(
12338c2ecf20Sopenharmony_ci	xfs_da_args_t		*args)		/* operation arguments */
12348c2ecf20Sopenharmony_ci{
12358c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
12368c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
12378c2ecf20Sopenharmony_ci	char			*buf;		/* old dir's buffer */
12388c2ecf20Sopenharmony_ci	int			i;		/* entry index */
12398c2ecf20Sopenharmony_ci	int			newsize;	/* new inode size */
12408c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*oldsfep;	/* old sf entry */
12418c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*oldsfp;	/* old sf directory */
12428c2ecf20Sopenharmony_ci	int			oldsize;	/* old inode size */
12438c2ecf20Sopenharmony_ci	xfs_dir2_sf_entry_t	*sfep;		/* new sf entry */
12448c2ecf20Sopenharmony_ci	xfs_dir2_sf_hdr_t	*sfp;		/* new sf directory */
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	trace_xfs_dir2_sf_toino8(args);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	/*
12498c2ecf20Sopenharmony_ci	 * Copy the old directory to the buffer.
12508c2ecf20Sopenharmony_ci	 * Then nuke it from the inode, and add the new buffer to the inode.
12518c2ecf20Sopenharmony_ci	 * Don't want xfs_idata_realloc copying the data here.
12528c2ecf20Sopenharmony_ci	 */
12538c2ecf20Sopenharmony_ci	oldsize = dp->i_df.if_bytes;
12548c2ecf20Sopenharmony_ci	buf = kmem_alloc(oldsize, 0);
12558c2ecf20Sopenharmony_ci	oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
12568c2ecf20Sopenharmony_ci	ASSERT(oldsfp->i8count == 0);
12578c2ecf20Sopenharmony_ci	memcpy(buf, oldsfp, oldsize);
12588c2ecf20Sopenharmony_ci	/*
12598c2ecf20Sopenharmony_ci	 * Compute the new inode size (nb: entry count + 1 for parent)
12608c2ecf20Sopenharmony_ci	 */
12618c2ecf20Sopenharmony_ci	newsize = oldsize + (oldsfp->count + 1) * XFS_INO64_DIFF;
12628c2ecf20Sopenharmony_ci	xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
12638c2ecf20Sopenharmony_ci	xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
12648c2ecf20Sopenharmony_ci	/*
12658c2ecf20Sopenharmony_ci	 * Reset our pointers, the data has moved.
12668c2ecf20Sopenharmony_ci	 */
12678c2ecf20Sopenharmony_ci	oldsfp = (xfs_dir2_sf_hdr_t *)buf;
12688c2ecf20Sopenharmony_ci	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
12698c2ecf20Sopenharmony_ci	/*
12708c2ecf20Sopenharmony_ci	 * Fill in the new header.
12718c2ecf20Sopenharmony_ci	 */
12728c2ecf20Sopenharmony_ci	sfp->count = oldsfp->count;
12738c2ecf20Sopenharmony_ci	sfp->i8count = 1;
12748c2ecf20Sopenharmony_ci	xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
12758c2ecf20Sopenharmony_ci	/*
12768c2ecf20Sopenharmony_ci	 * Copy the entries field by field.
12778c2ecf20Sopenharmony_ci	 */
12788c2ecf20Sopenharmony_ci	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
12798c2ecf20Sopenharmony_ci		    oldsfep = xfs_dir2_sf_firstentry(oldsfp);
12808c2ecf20Sopenharmony_ci	     i < sfp->count;
12818c2ecf20Sopenharmony_ci	     i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
12828c2ecf20Sopenharmony_ci		  oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
12838c2ecf20Sopenharmony_ci		sfep->namelen = oldsfep->namelen;
12848c2ecf20Sopenharmony_ci		memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
12858c2ecf20Sopenharmony_ci		memcpy(sfep->name, oldsfep->name, sfep->namelen);
12868c2ecf20Sopenharmony_ci		xfs_dir2_sf_put_ino(mp, sfp, sfep,
12878c2ecf20Sopenharmony_ci				xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
12888c2ecf20Sopenharmony_ci		xfs_dir2_sf_put_ftype(mp, sfep,
12898c2ecf20Sopenharmony_ci				xfs_dir2_sf_get_ftype(mp, oldsfep));
12908c2ecf20Sopenharmony_ci	}
12918c2ecf20Sopenharmony_ci	/*
12928c2ecf20Sopenharmony_ci	 * Clean up the inode.
12938c2ecf20Sopenharmony_ci	 */
12948c2ecf20Sopenharmony_ci	kmem_free(buf);
12958c2ecf20Sopenharmony_ci	dp->i_d.di_size = newsize;
12968c2ecf20Sopenharmony_ci	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
12978c2ecf20Sopenharmony_ci}
1298