Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
   1/*
   2 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
   3 * All Rights Reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it would be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write the Free Software Foundation,
  16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17 */
  18#include "xfs.h"
  19#include "xfs_fs.h"
  20#include "xfs_format.h"
  21#include "xfs_log_format.h"
  22#include "xfs_trans_resv.h"
  23#include "xfs_sb.h"
  24#include "xfs_ag.h"
  25#include "xfs_mount.h"
  26#include "xfs_da_format.h"
  27#include "xfs_da_btree.h"
  28#include "xfs_inode.h"
  29#include "xfs_trans.h"
  30#include "xfs_inode_item.h"
  31#include "xfs_error.h"
  32#include "xfs_dir2.h"
  33#include "xfs_dir2_priv.h"
  34#include "xfs_trace.h"
  35#include "xfs_dinode.h"
  36
  37/*
  38 * Prototypes for internal functions.
  39 */
  40static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args,
  41				     xfs_dir2_sf_entry_t *sfep,
  42				     xfs_dir2_data_aoff_t offset,
  43				     int new_isize);
  44static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange,
  45				     int new_isize);
  46static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange,
  47				    xfs_dir2_sf_entry_t **sfepp,
  48				    xfs_dir2_data_aoff_t *offsetp);
  49#ifdef DEBUG
  50static void xfs_dir2_sf_check(xfs_da_args_t *args);
  51#else
  52#define	xfs_dir2_sf_check(args)
  53#endif /* DEBUG */
  54#if XFS_BIG_INUMS
  55static void xfs_dir2_sf_toino4(xfs_da_args_t *args);
  56static void xfs_dir2_sf_toino8(xfs_da_args_t *args);
  57#endif /* XFS_BIG_INUMS */
  58
  59/*
  60 * Given a block directory (dp/block), calculate its size as a shortform (sf)
  61 * directory and a header for the sf directory, if it will fit it the
  62 * space currently present in the inode.  If it won't fit, the output
  63 * size is too big (but not accurate).
  64 */
  65int						/* size for sf form */
  66xfs_dir2_block_sfsize(
  67	xfs_inode_t		*dp,		/* incore inode pointer */
  68	xfs_dir2_data_hdr_t	*hdr,		/* block directory data */
  69	xfs_dir2_sf_hdr_t	*sfhp)		/* output: header for sf form */
  70{
  71	xfs_dir2_dataptr_t	addr;		/* data entry address */
  72	xfs_dir2_leaf_entry_t	*blp;		/* leaf area of the block */
  73	xfs_dir2_block_tail_t	*btp;		/* tail area of the block */
  74	int			count;		/* shortform entry count */
  75	xfs_dir2_data_entry_t	*dep;		/* data entry in the block */
  76	int			i;		/* block entry index */
  77	int			i8count;	/* count of big-inode entries */
  78	int			isdot;		/* entry is "." */
  79	int			isdotdot;	/* entry is ".." */
  80	xfs_mount_t		*mp;		/* mount structure pointer */
  81	int			namelen;	/* total name bytes */
  82	xfs_ino_t		parent = 0;	/* parent inode number */
  83	int			size=0;		/* total computed size */
  84	int			has_ftype;
  85
  86	mp = dp->i_mount;
  87
  88	/*
  89	 * if there is a filetype field, add the extra byte to the namelen
  90	 * for each entry that we see.
  91	 */
  92	has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0;
  93
  94	count = i8count = namelen = 0;
  95	btp = xfs_dir2_block_tail_p(mp, hdr);
  96	blp = xfs_dir2_block_leaf_p(btp);
  97
  98	/*
  99	 * Iterate over the block's data entries by using the leaf pointers.
 100	 */
 101	for (i = 0; i < be32_to_cpu(btp->count); i++) {
 102		if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR)
 103			continue;
 104		/*
 105		 * Calculate the pointer to the entry at hand.
 106		 */
 107		dep = (xfs_dir2_data_entry_t *)
 108		      ((char *)hdr + xfs_dir2_dataptr_to_off(mp, addr));
 109		/*
 110		 * Detect . and .., so we can special-case them.
 111		 * . is not included in sf directories.
 112		 * .. is included by just the parent inode number.
 113		 */
 114		isdot = dep->namelen == 1 && dep->name[0] == '.';
 115		isdotdot =
 116			dep->namelen == 2 &&
 117			dep->name[0] == '.' && dep->name[1] == '.';
 118#if XFS_BIG_INUMS
 119		if (!isdot)
 120			i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
 121#endif
 122		/* take into account the file type field */
 123		if (!isdot && !isdotdot) {
 124			count++;
 125			namelen += dep->namelen + has_ftype;
 126		} else if (isdotdot)
 127			parent = be64_to_cpu(dep->inumber);
 128		/*
 129		 * Calculate the new size, see if we should give up yet.
 130		 */
 131		size = xfs_dir2_sf_hdr_size(i8count) +		/* header */
 132		       count +					/* namelen */
 133		       count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */
 134		       namelen +				/* name */
 135		       (i8count ?				/* inumber */
 136				(uint)sizeof(xfs_dir2_ino8_t) * count :
 137				(uint)sizeof(xfs_dir2_ino4_t) * count);
 138		if (size > XFS_IFORK_DSIZE(dp))
 139			return size;		/* size value is a failure */
 140	}
 141	/*
 142	 * Create the output header, if it worked.
 143	 */
 144	sfhp->count = count;
 145	sfhp->i8count = i8count;
 146	dp->d_ops->sf_put_parent_ino(sfhp, parent);
 147	return size;
 148}
 149
 150/*
 151 * Convert a block format directory to shortform.
 152 * Caller has already checked that it will fit, and built us a header.
 153 */
 154int						/* error */
 155xfs_dir2_block_to_sf(
 156	xfs_da_args_t		*args,		/* operation arguments */
 157	struct xfs_buf		*bp,
 158	int			size,		/* shortform directory size */
 159	xfs_dir2_sf_hdr_t	*sfhp)		/* shortform directory hdr */
 160{
 161	xfs_dir2_data_hdr_t	*hdr;		/* block header */
 162	xfs_dir2_block_tail_t	*btp;		/* block tail pointer */
 163	xfs_dir2_data_entry_t	*dep;		/* data entry pointer */
 164	xfs_inode_t		*dp;		/* incore directory inode */
 165	xfs_dir2_data_unused_t	*dup;		/* unused data pointer */
 166	char			*endptr;	/* end of data entries */
 167	int			error;		/* error return value */
 168	int			logflags;	/* inode logging flags */
 169	xfs_mount_t		*mp;		/* filesystem mount point */
 170	char			*ptr;		/* current data pointer */
 171	xfs_dir2_sf_entry_t	*sfep;		/* shortform entry */
 172	xfs_dir2_sf_hdr_t	*sfp;		/* shortform directory header */
 173	xfs_dir2_sf_hdr_t	*dst;		/* temporary data buffer */
 174
 175	trace_xfs_dir2_block_to_sf(args);
 176
 177	dp = args->dp;
 178	mp = dp->i_mount;
 179
 180	/*
 181	 * allocate a temporary destination buffer the size of the inode
 182	 * to format the data into. Once we have formatted the data, we
 183	 * can free the block and copy the formatted data into the inode literal
 184	 * area.
 185	 */
 186	dst = kmem_alloc(mp->m_sb.sb_inodesize, KM_SLEEP);
 187	hdr = bp->b_addr;
 188
 189	/*
 190	 * Copy the header into the newly allocate local space.
 191	 */
 192	sfp = (xfs_dir2_sf_hdr_t *)dst;
 193	memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
 194
 195	/*
 196	 * Set up to loop over the block's entries.
 197	 */
 198	btp = xfs_dir2_block_tail_p(mp, hdr);
 199	ptr = (char *)dp->d_ops->data_entry_p(hdr);
 200	endptr = (char *)xfs_dir2_block_leaf_p(btp);
 201	sfep = xfs_dir2_sf_firstentry(sfp);
 202	/*
 203	 * Loop over the active and unused entries.
 204	 * Stop when we reach the leaf/tail portion of the block.
 205	 */
 206	while (ptr < endptr) {
 207		/*
 208		 * If it's unused, just skip over it.
 209		 */
 210		dup = (xfs_dir2_data_unused_t *)ptr;
 211		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
 212			ptr += be16_to_cpu(dup->length);
 213			continue;
 214		}
 215		dep = (xfs_dir2_data_entry_t *)ptr;
 216		/*
 217		 * Skip .
 218		 */
 219		if (dep->namelen == 1 && dep->name[0] == '.')
 220			ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
 221		/*
 222		 * Skip .., but make sure the inode number is right.
 223		 */
 224		else if (dep->namelen == 2 &&
 225			 dep->name[0] == '.' && dep->name[1] == '.')
 226			ASSERT(be64_to_cpu(dep->inumber) ==
 227			       dp->d_ops->sf_get_parent_ino(sfp));
 228		/*
 229		 * Normal entry, copy it into shortform.
 230		 */
 231		else {
 232			sfep->namelen = dep->namelen;
 233			xfs_dir2_sf_put_offset(sfep,
 234				(xfs_dir2_data_aoff_t)
 235				((char *)dep - (char *)hdr));
 236			memcpy(sfep->name, dep->name, dep->namelen);
 237			dp->d_ops->sf_put_ino(sfp, sfep,
 238					      be64_to_cpu(dep->inumber));
 239			dp->d_ops->sf_put_ftype(sfep,
 240					dp->d_ops->data_get_ftype(dep));
 241
 242			sfep = dp->d_ops->sf_nextentry(sfp, sfep);
 243		}
 244		ptr += dp->d_ops->data_entsize(dep->namelen);
 245	}
 246	ASSERT((char *)sfep - (char *)sfp == size);
 247
 248	/* now we are done with the block, we can shrink the inode */
 249	logflags = XFS_ILOG_CORE;
 250	error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp);
 251	if (error) {
 252		ASSERT(error != ENOSPC);
 253		goto out;
 254	}
 255
 256	/*
 257	 * The buffer is now unconditionally gone, whether
 258	 * xfs_dir2_shrink_inode worked or not.
 259	 *
 260	 * Convert the inode to local format and copy the data in.
 261	 */
 262	dp->i_df.if_flags &= ~XFS_IFEXTENTS;
 263	dp->i_df.if_flags |= XFS_IFINLINE;
 264	dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
 265	ASSERT(dp->i_df.if_bytes == 0);
 266	xfs_idata_realloc(dp, size, XFS_DATA_FORK);
 267
 268	logflags |= XFS_ILOG_DDATA;
 269	memcpy(dp->i_df.if_u1.if_data, dst, size);
 270	dp->i_d.di_size = size;
 271	xfs_dir2_sf_check(args);
 272out:
 273	xfs_trans_log_inode(args->trans, dp, logflags);
 274	kmem_free(dst);
 275	return error;
 276}
 277
 278/*
 279 * Add a name to a shortform directory.
 280 * There are two algorithms, "easy" and "hard" which we decide on
 281 * before changing anything.
 282 * Convert to block form if necessary, if the new entry won't fit.
 283 */
 284int						/* error */
 285xfs_dir2_sf_addname(
 286	xfs_da_args_t		*args)		/* operation arguments */
 287{
 288	int			add_entsize;	/* size of the new entry */
 289	xfs_inode_t		*dp;		/* incore directory inode */
 290	int			error;		/* error return value */
 291	int			incr_isize;	/* total change in size */
 292	int			new_isize;	/* di_size after adding name */
 293	int			objchange;	/* changing to 8-byte inodes */
 294	xfs_dir2_data_aoff_t	offset = 0;	/* offset for new entry */
 295	int			old_isize;	/* di_size before adding name */
 296	int			pick;		/* which algorithm to use */
 297	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
 298	xfs_dir2_sf_entry_t	*sfep = NULL;	/* shortform entry */
 299
 300	trace_xfs_dir2_sf_addname(args);
 301
 302	ASSERT(xfs_dir2_sf_lookup(args) == ENOENT);
 303	dp = args->dp;
 304	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
 305	/*
 306	 * Make sure the shortform value has some of its header.
 307	 */
 308	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
 309		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
 310		return XFS_ERROR(EIO);
 311	}
 312	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
 313	ASSERT(dp->i_df.if_u1.if_data != NULL);
 314	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 315	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
 316	/*
 317	 * Compute entry (and change in) size.
 318	 */
 319	add_entsize = dp->d_ops->sf_entsize(sfp, args->namelen);
 320	incr_isize = add_entsize;
 321	objchange = 0;
 322#if XFS_BIG_INUMS
 323	/*
 324	 * Do we have to change to 8 byte inodes?
 325	 */
 326	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
 327		/*
 328		 * Yes, adjust the entry size and the total size.
 329		 */
 330		add_entsize +=
 331			(uint)sizeof(xfs_dir2_ino8_t) -
 332			(uint)sizeof(xfs_dir2_ino4_t);
 333		incr_isize +=
 334			(sfp->count + 2) *
 335			((uint)sizeof(xfs_dir2_ino8_t) -
 336			 (uint)sizeof(xfs_dir2_ino4_t));
 337		objchange = 1;
 338	}
 339#endif
 340	old_isize = (int)dp->i_d.di_size;
 341	new_isize = old_isize + incr_isize;
 342	/*
 343	 * Won't fit as shortform any more (due to size),
 344	 * or the pick routine says it won't (due to offset values).
 345	 */
 346	if (new_isize > XFS_IFORK_DSIZE(dp) ||
 347	    (pick =
 348	     xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) {
 349		/*
 350		 * Just checking or no space reservation, it doesn't fit.
 351		 */
 352		if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
 353			return XFS_ERROR(ENOSPC);
 354		/*
 355		 * Convert to block form then add the name.
 356		 */
 357		error = xfs_dir2_sf_to_block(args);
 358		if (error)
 359			return error;
 360		return xfs_dir2_block_addname(args);
 361	}
 362	/*
 363	 * Just checking, it fits.
 364	 */
 365	if (args->op_flags & XFS_DA_OP_JUSTCHECK)
 366		return 0;
 367	/*
 368	 * Do it the easy way - just add it at the end.
 369	 */
 370	if (pick == 1)
 371		xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize);
 372	/*
 373	 * Do it the hard way - look for a place to insert the new entry.
 374	 * Convert to 8 byte inode numbers first if necessary.
 375	 */
 376	else {
 377		ASSERT(pick == 2);
 378#if XFS_BIG_INUMS
 379		if (objchange)
 380			xfs_dir2_sf_toino8(args);
 381#endif
 382		xfs_dir2_sf_addname_hard(args, objchange, new_isize);
 383	}
 384	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
 385	return 0;
 386}
 387
 388/*
 389 * Add the new entry the "easy" way.
 390 * This is copying the old directory and adding the new entry at the end.
 391 * Since it's sorted by "offset" we need room after the last offset
 392 * that's already there, and then room to convert to a block directory.
 393 * This is already checked by the pick routine.
 394 */
 395static void
 396xfs_dir2_sf_addname_easy(
 397	xfs_da_args_t		*args,		/* operation arguments */
 398	xfs_dir2_sf_entry_t	*sfep,		/* pointer to new entry */
 399	xfs_dir2_data_aoff_t	offset,		/* offset to use for new ent */
 400	int			new_isize)	/* new directory size */
 401{
 402	int			byteoff;	/* byte offset in sf dir */
 403	xfs_inode_t		*dp;		/* incore directory inode */
 404	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
 405
 406	dp = args->dp;
 407
 408	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 409	byteoff = (int)((char *)sfep - (char *)sfp);
 410	/*
 411	 * Grow the in-inode space.
 412	 */
 413	xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen),
 414			  XFS_DATA_FORK);
 415	/*
 416	 * Need to set up again due to realloc of the inode data.
 417	 */
 418	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 419	sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff);
 420	/*
 421	 * Fill in the new entry.
 422	 */
 423	sfep->namelen = args->namelen;
 424	xfs_dir2_sf_put_offset(sfep, offset);
 425	memcpy(sfep->name, args->name, sfep->namelen);
 426	dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
 427	dp->d_ops->sf_put_ftype(sfep, args->filetype);
 428
 429	/*
 430	 * Update the header and inode.
 431	 */
 432	sfp->count++;
 433#if XFS_BIG_INUMS
 434	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM)
 435		sfp->i8count++;
 436#endif
 437	dp->i_d.di_size = new_isize;
 438	xfs_dir2_sf_check(args);
 439}
 440
 441/*
 442 * Add the new entry the "hard" way.
 443 * The caller has already converted to 8 byte inode numbers if necessary,
 444 * in which case we need to leave the i8count at 1.
 445 * Find a hole that the new entry will fit into, and copy
 446 * the first part of the entries, the new entry, and the last part of
 447 * the entries.
 448 */
 449/* ARGSUSED */
 450static void
 451xfs_dir2_sf_addname_hard(
 452	xfs_da_args_t		*args,		/* operation arguments */
 453	int			objchange,	/* changing inode number size */
 454	int			new_isize)	/* new directory size */
 455{
 456	int			add_datasize;	/* data size need for new ent */
 457	char			*buf;		/* buffer for old */
 458	xfs_inode_t		*dp;		/* incore directory inode */
 459	int			eof;		/* reached end of old dir */
 460	int			nbytes;		/* temp for byte copies */
 461	xfs_dir2_data_aoff_t	new_offset;	/* next offset value */
 462	xfs_dir2_data_aoff_t	offset;		/* current offset value */
 463	int			old_isize;	/* previous di_size */
 464	xfs_dir2_sf_entry_t	*oldsfep;	/* entry in original dir */
 465	xfs_dir2_sf_hdr_t	*oldsfp;	/* original shortform dir */
 466	xfs_dir2_sf_entry_t	*sfep;		/* entry in new dir */
 467	xfs_dir2_sf_hdr_t	*sfp;		/* new shortform dir */
 468	struct xfs_mount	*mp;
 469
 470	/*
 471	 * Copy the old directory to the stack buffer.
 472	 */
 473	dp = args->dp;
 474	mp = dp->i_mount;
 475
 476	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 477	old_isize = (int)dp->i_d.di_size;
 478	buf = kmem_alloc(old_isize, KM_SLEEP);
 479	oldsfp = (xfs_dir2_sf_hdr_t *)buf;
 480	memcpy(oldsfp, sfp, old_isize);
 481	/*
 482	 * Loop over the old directory finding the place we're going
 483	 * to insert the new entry.
 484	 * If it's going to end up at the end then oldsfep will point there.
 485	 */
 486	for (offset = dp->d_ops->data_first_offset,
 487	      oldsfep = xfs_dir2_sf_firstentry(oldsfp),
 488	      add_datasize = dp->d_ops->data_entsize(args->namelen),
 489	      eof = (char *)oldsfep == &buf[old_isize];
 490	     !eof;
 491	     offset = new_offset + dp->d_ops->data_entsize(oldsfep->namelen),
 492	      oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep),
 493	      eof = (char *)oldsfep == &buf[old_isize]) {
 494		new_offset = xfs_dir2_sf_get_offset(oldsfep);
 495		if (offset + add_datasize <= new_offset)
 496			break;
 497	}
 498	/*
 499	 * Get rid of the old directory, then allocate space for
 500	 * the new one.  We do this so xfs_idata_realloc won't copy
 501	 * the data.
 502	 */
 503	xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK);
 504	xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK);
 505	/*
 506	 * Reset the pointer since the buffer was reallocated.
 507	 */
 508	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 509	/*
 510	 * Copy the first part of the directory, including the header.
 511	 */
 512	nbytes = (int)((char *)oldsfep - (char *)oldsfp);
 513	memcpy(sfp, oldsfp, nbytes);
 514	sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
 515	/*
 516	 * Fill in the new entry, and update the header counts.
 517	 */
 518	sfep->namelen = args->namelen;
 519	xfs_dir2_sf_put_offset(sfep, offset);
 520	memcpy(sfep->name, args->name, sfep->namelen);
 521	dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
 522	dp->d_ops->sf_put_ftype(sfep, args->filetype);
 523	sfp->count++;
 524#if XFS_BIG_INUMS
 525	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
 526		sfp->i8count++;
 527#endif
 528	/*
 529	 * If there's more left to copy, do that.
 530	 */
 531	if (!eof) {
 532		sfep = dp->d_ops->sf_nextentry(sfp, sfep);
 533		memcpy(sfep, oldsfep, old_isize - nbytes);
 534	}
 535	kmem_free(buf);
 536	dp->i_d.di_size = new_isize;
 537	xfs_dir2_sf_check(args);
 538}
 539
 540/*
 541 * Decide if the new entry will fit at all.
 542 * If it will fit, pick between adding the new entry to the end (easy)
 543 * or somewhere else (hard).
 544 * Return 0 (won't fit), 1 (easy), 2 (hard).
 545 */
 546/*ARGSUSED*/
 547static int					/* pick result */
 548xfs_dir2_sf_addname_pick(
 549	xfs_da_args_t		*args,		/* operation arguments */
 550	int			objchange,	/* inode # size changes */
 551	xfs_dir2_sf_entry_t	**sfepp,	/* out(1): new entry ptr */
 552	xfs_dir2_data_aoff_t	*offsetp)	/* out(1): new offset */
 553{
 554	xfs_inode_t		*dp;		/* incore directory inode */
 555	int			holefit;	/* found hole it will fit in */
 556	int			i;		/* entry number */
 557	xfs_mount_t		*mp;		/* filesystem mount point */
 558	xfs_dir2_data_aoff_t	offset;		/* data block offset */
 559	xfs_dir2_sf_entry_t	*sfep;		/* shortform entry */
 560	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
 561	int			size;		/* entry's data size */
 562	int			used;		/* data bytes used */
 563
 564	dp = args->dp;
 565	mp = dp->i_mount;
 566
 567	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 568	size = dp->d_ops->data_entsize(args->namelen);
 569	offset = dp->d_ops->data_first_offset;
 570	sfep = xfs_dir2_sf_firstentry(sfp);
 571	holefit = 0;
 572	/*
 573	 * Loop over sf entries.
 574	 * Keep track of data offset and whether we've seen a place
 575	 * to insert the new entry.
 576	 */
 577	for (i = 0; i < sfp->count; i++) {
 578		if (!holefit)
 579			holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
 580		offset = xfs_dir2_sf_get_offset(sfep) +
 581			 dp->d_ops->data_entsize(sfep->namelen);
 582		sfep = dp->d_ops->sf_nextentry(sfp, sfep);
 583	}
 584	/*
 585	 * Calculate data bytes used excluding the new entry, if this
 586	 * was a data block (block form directory).
 587	 */
 588	used = offset +
 589	       (sfp->count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
 590	       (uint)sizeof(xfs_dir2_block_tail_t);
 591	/*
 592	 * If it won't fit in a block form then we can't insert it,
 593	 * we'll go back, convert to block, then try the insert and convert
 594	 * to leaf.
 595	 */
 596	if (used + (holefit ? 0 : size) > mp->m_dirblksize)
 597		return 0;
 598	/*
 599	 * If changing the inode number size, do it the hard way.
 600	 */
 601#if XFS_BIG_INUMS
 602	if (objchange) {
 603		return 2;
 604	}
 605#else
 606	ASSERT(objchange == 0);
 607#endif
 608	/*
 609	 * If it won't fit at the end then do it the hard way (use the hole).
 610	 */
 611	if (used + size > mp->m_dirblksize)
 612		return 2;
 613	/*
 614	 * Do it the easy way.
 615	 */
 616	*sfepp = sfep;
 617	*offsetp = offset;
 618	return 1;
 619}
 620
 621#ifdef DEBUG
 622/*
 623 * Check consistency of shortform directory, assert if bad.
 624 */
 625static void
 626xfs_dir2_sf_check(
 627	xfs_da_args_t		*args)		/* operation arguments */
 628{
 629	xfs_inode_t		*dp;		/* incore directory inode */
 630	int			i;		/* entry number */
 631	int			i8count;	/* number of big inode#s */
 632	xfs_ino_t		ino;		/* entry inode number */
 633	int			offset;		/* data offset */
 634	xfs_dir2_sf_entry_t	*sfep;		/* shortform dir entry */
 635	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
 636	struct xfs_mount	*mp;
 637
 638	dp = args->dp;
 639	mp = dp->i_mount;
 640
 641	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 642	offset = dp->d_ops->data_first_offset;
 643	ino = dp->d_ops->sf_get_parent_ino(sfp);
 644	i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
 645
 646	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
 647	     i < sfp->count;
 648	     i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
 649		ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
 650		ino = dp->d_ops->sf_get_ino(sfp, sfep);
 651		i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
 652		offset =
 653			xfs_dir2_sf_get_offset(sfep) +
 654			dp->d_ops->data_entsize(sfep->namelen);
 655		ASSERT(dp->d_ops->sf_get_ftype(sfep) < XFS_DIR3_FT_MAX);
 656	}
 657	ASSERT(i8count == sfp->i8count);
 658	ASSERT(XFS_BIG_INUMS || i8count == 0);
 659	ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
 660	ASSERT(offset +
 661	       (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
 662	       (uint)sizeof(xfs_dir2_block_tail_t) <= mp->m_dirblksize);
 663}
 664#endif	/* DEBUG */
 665
 666/*
 667 * Create a new (shortform) directory.
 668 */
 669int					/* error, always 0 */
 670xfs_dir2_sf_create(
 671	xfs_da_args_t	*args,		/* operation arguments */
 672	xfs_ino_t	pino)		/* parent inode number */
 673{
 674	xfs_inode_t	*dp;		/* incore directory inode */
 675	int		i8count;	/* parent inode is an 8-byte number */
 676	xfs_dir2_sf_hdr_t *sfp;		/* shortform structure */
 677	int		size;		/* directory size */
 678
 679	trace_xfs_dir2_sf_create(args);
 680
 681	dp = args->dp;
 682
 683	ASSERT(dp != NULL);
 684	ASSERT(dp->i_d.di_size == 0);
 685	/*
 686	 * If it's currently a zero-length extent file,
 687	 * convert it to local format.
 688	 */
 689	if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) {
 690		dp->i_df.if_flags &= ~XFS_IFEXTENTS;	/* just in case */
 691		dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
 692		xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
 693		dp->i_df.if_flags |= XFS_IFINLINE;
 694	}
 695	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
 696	ASSERT(dp->i_df.if_bytes == 0);
 697	i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
 698	size = xfs_dir2_sf_hdr_size(i8count);
 699	/*
 700	 * Make a buffer for the data.
 701	 */
 702	xfs_idata_realloc(dp, size, XFS_DATA_FORK);
 703	/*
 704	 * Fill in the header,
 705	 */
 706	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 707	sfp->i8count = i8count;
 708	/*
 709	 * Now can put in the inode number, since i8count is set.
 710	 */
 711	dp->d_ops->sf_put_parent_ino(sfp, pino);
 712	sfp->count = 0;
 713	dp->i_d.di_size = size;
 714	xfs_dir2_sf_check(args);
 715	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
 716	return 0;
 717}
 718
 719/*
 720 * Lookup an entry in a shortform directory.
 721 * Returns EEXIST if found, ENOENT if not found.
 722 */
 723int						/* error */
 724xfs_dir2_sf_lookup(
 725	xfs_da_args_t		*args)		/* operation arguments */
 726{
 727	xfs_inode_t		*dp;		/* incore directory inode */
 728	int			i;		/* entry index */
 729	int			error;
 730	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */
 731	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
 732	enum xfs_dacmp		cmp;		/* comparison result */
 733	xfs_dir2_sf_entry_t	*ci_sfep;	/* case-insens. entry */
 734
 735	trace_xfs_dir2_sf_lookup(args);
 736
 737	xfs_dir2_sf_check(args);
 738	dp = args->dp;
 739
 740	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
 741	/*
 742	 * Bail out if the directory is way too short.
 743	 */
 744	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
 745		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
 746		return XFS_ERROR(EIO);
 747	}
 748	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
 749	ASSERT(dp->i_df.if_u1.if_data != NULL);
 750	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 751	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
 752	/*
 753	 * Special case for .
 754	 */
 755	if (args->namelen == 1 && args->name[0] == '.') {
 756		args->inumber = dp->i_ino;
 757		args->cmpresult = XFS_CMP_EXACT;
 758		args->filetype = XFS_DIR3_FT_DIR;
 759		return XFS_ERROR(EEXIST);
 760	}
 761	/*
 762	 * Special case for ..
 763	 */
 764	if (args->namelen == 2 &&
 765	    args->name[0] == '.' && args->name[1] == '.') {
 766		args->inumber = dp->d_ops->sf_get_parent_ino(sfp);
 767		args->cmpresult = XFS_CMP_EXACT;
 768		args->filetype = XFS_DIR3_FT_DIR;
 769		return XFS_ERROR(EEXIST);
 770	}
 771	/*
 772	 * Loop over all the entries trying to match ours.
 773	 */
 774	ci_sfep = NULL;
 775	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
 776	     i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
 777		/*
 778		 * Compare name and if it's an exact match, return the inode
 779		 * number. If it's the first case-insensitive match, store the
 780		 * inode number and continue looking for an exact match.
 781		 */
 782		cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name,
 783								sfep->namelen);
 784		if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
 785			args->cmpresult = cmp;
 786			args->inumber = dp->d_ops->sf_get_ino(sfp, sfep);
 787			args->filetype = dp->d_ops->sf_get_ftype(sfep);
 788			if (cmp == XFS_CMP_EXACT)
 789				return XFS_ERROR(EEXIST);
 790			ci_sfep = sfep;
 791		}
 792	}
 793	ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
 794	/*
 795	 * Here, we can only be doing a lookup (not a rename or replace).
 796	 * If a case-insensitive match was not found, return ENOENT.
 797	 */
 798	if (!ci_sfep)
 799		return XFS_ERROR(ENOENT);
 800	/* otherwise process the CI match as required by the caller */
 801	error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen);
 802	return XFS_ERROR(error);
 803}
 804
 805/*
 806 * Remove an entry from a shortform directory.
 807 */
 808int						/* error */
 809xfs_dir2_sf_removename(
 810	xfs_da_args_t		*args)
 811{
 812	int			byteoff;	/* offset of removed entry */
 813	xfs_inode_t		*dp;		/* incore directory inode */
 814	int			entsize;	/* this entry's size */
 815	int			i;		/* shortform entry index */
 816	int			newsize;	/* new inode size */
 817	int			oldsize;	/* old inode size */
 818	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */
 819	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
 820
 821	trace_xfs_dir2_sf_removename(args);
 822
 823	dp = args->dp;
 824
 825	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
 826	oldsize = (int)dp->i_d.di_size;
 827	/*
 828	 * Bail out if the directory is way too short.
 829	 */
 830	if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) {
 831		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
 832		return XFS_ERROR(EIO);
 833	}
 834	ASSERT(dp->i_df.if_bytes == oldsize);
 835	ASSERT(dp->i_df.if_u1.if_data != NULL);
 836	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 837	ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count));
 838	/*
 839	 * Loop over the old directory entries.
 840	 * Find the one we're deleting.
 841	 */
 842	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
 843	     i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
 844		if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
 845								XFS_CMP_EXACT) {
 846			ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) ==
 847			       args->inumber);
 848			break;
 849		}
 850	}
 851	/*
 852	 * Didn't find it.
 853	 */
 854	if (i == sfp->count)
 855		return XFS_ERROR(ENOENT);
 856	/*
 857	 * Calculate sizes.
 858	 */
 859	byteoff = (int)((char *)sfep - (char *)sfp);
 860	entsize = dp->d_ops->sf_entsize(sfp, args->namelen);
 861	newsize = oldsize - entsize;
 862	/*
 863	 * Copy the part if any after the removed entry, sliding it down.
 864	 */
 865	if (byteoff + entsize < oldsize)
 866		memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
 867			oldsize - (byteoff + entsize));
 868	/*
 869	 * Fix up the header and file size.
 870	 */
 871	sfp->count--;
 872	dp->i_d.di_size = newsize;
 873	/*
 874	 * Reallocate, making it smaller.
 875	 */
 876	xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK);
 877	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 878#if XFS_BIG_INUMS
 879	/*
 880	 * Are we changing inode number size?
 881	 */
 882	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
 883		if (sfp->i8count == 1)
 884			xfs_dir2_sf_toino4(args);
 885		else
 886			sfp->i8count--;
 887	}
 888#endif
 889	xfs_dir2_sf_check(args);
 890	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
 891	return 0;
 892}
 893
 894/*
 895 * Replace the inode number of an entry in a shortform directory.
 896 */
 897int						/* error */
 898xfs_dir2_sf_replace(
 899	xfs_da_args_t		*args)		/* operation arguments */
 900{
 901	xfs_inode_t		*dp;		/* incore directory inode */
 902	int			i;		/* entry index */
 903#if XFS_BIG_INUMS || defined(DEBUG)
 904	xfs_ino_t		ino=0;		/* entry old inode number */
 905#endif
 906#if XFS_BIG_INUMS
 907	int			i8elevated;	/* sf_toino8 set i8count=1 */
 908#endif
 909	xfs_dir2_sf_entry_t	*sfep;		/* shortform directory entry */
 910	xfs_dir2_sf_hdr_t	*sfp;		/* shortform structure */
 911
 912	trace_xfs_dir2_sf_replace(args);
 913
 914	dp = args->dp;
 915
 916	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
 917	/*
 918	 * Bail out if the shortform directory is way too small.
 919	 */
 920	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
 921		ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
 922		return XFS_ERROR(EIO);
 923	}
 924	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
 925	ASSERT(dp->i_df.if_u1.if_data != NULL);
 926	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 927	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
 928#if XFS_BIG_INUMS
 929	/*
 930	 * New inode number is large, and need to convert to 8-byte inodes.
 931	 */
 932	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
 933		int	error;			/* error return value */
 934		int	newsize;		/* new inode size */
 935
 936		newsize =
 937			dp->i_df.if_bytes +
 938			(sfp->count + 1) *
 939			((uint)sizeof(xfs_dir2_ino8_t) -
 940			 (uint)sizeof(xfs_dir2_ino4_t));
 941		/*
 942		 * Won't fit as shortform, convert to block then do replace.
 943		 */
 944		if (newsize > XFS_IFORK_DSIZE(dp)) {
 945			error = xfs_dir2_sf_to_block(args);
 946			if (error) {
 947				return error;
 948			}
 949			return xfs_dir2_block_replace(args);
 950		}
 951		/*
 952		 * Still fits, convert to 8-byte now.
 953		 */
 954		xfs_dir2_sf_toino8(args);
 955		i8elevated = 1;
 956		sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 957	} else
 958		i8elevated = 0;
 959#endif
 960	ASSERT(args->namelen != 1 || args->name[0] != '.');
 961	/*
 962	 * Replace ..'s entry.
 963	 */
 964	if (args->namelen == 2 &&
 965	    args->name[0] == '.' && args->name[1] == '.') {
 966#if XFS_BIG_INUMS || defined(DEBUG)
 967		ino = dp->d_ops->sf_get_parent_ino(sfp);
 968		ASSERT(args->inumber != ino);
 969#endif
 970		dp->d_ops->sf_put_parent_ino(sfp, args->inumber);
 971	}
 972	/*
 973	 * Normal entry, look for the name.
 974	 */
 975	else {
 976		for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
 977		     i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) {
 978			if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
 979								XFS_CMP_EXACT) {
 980#if XFS_BIG_INUMS || defined(DEBUG)
 981				ino = dp->d_ops->sf_get_ino(sfp, sfep);
 982				ASSERT(args->inumber != ino);
 983#endif
 984				dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
 985				dp->d_ops->sf_put_ftype(sfep, args->filetype);
 986				break;
 987			}
 988		}
 989		/*
 990		 * Didn't find it.
 991		 */
 992		if (i == sfp->count) {
 993			ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
 994#if XFS_BIG_INUMS
 995			if (i8elevated)
 996				xfs_dir2_sf_toino4(args);
 997#endif
 998			return XFS_ERROR(ENOENT);
 999		}
1000	}
1001#if XFS_BIG_INUMS
1002	/*
1003	 * See if the old number was large, the new number is small.
1004	 */
1005	if (ino > XFS_DIR2_MAX_SHORT_INUM &&
1006	    args->inumber <= XFS_DIR2_MAX_SHORT_INUM) {
1007		/*
1008		 * And the old count was one, so need to convert to small.
1009		 */
1010		if (sfp->i8count == 1)
1011			xfs_dir2_sf_toino4(args);
1012		else
1013			sfp->i8count--;
1014	}
1015	/*
1016	 * See if the old number was small, the new number is large.
1017	 */
1018	if (ino <= XFS_DIR2_MAX_SHORT_INUM &&
1019	    args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
1020		/*
1021		 * add to the i8count unless we just converted to 8-byte
1022		 * inodes (which does an implied i8count = 1)
1023		 */
1024		ASSERT(sfp->i8count != 0);
1025		if (!i8elevated)
1026			sfp->i8count++;
1027	}
1028#endif
1029	xfs_dir2_sf_check(args);
1030	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
1031	return 0;
1032}
1033
1034#if XFS_BIG_INUMS
1035/*
1036 * Convert from 8-byte inode numbers to 4-byte inode numbers.
1037 * The last 8-byte inode number is gone, but the count is still 1.
1038 */
1039static void
1040xfs_dir2_sf_toino4(
1041	xfs_da_args_t		*args)		/* operation arguments */
1042{
1043	char			*buf;		/* old dir's buffer */
1044	xfs_inode_t		*dp;		/* incore directory inode */
1045	int			i;		/* entry index */
1046	int			newsize;	/* new inode size */
1047	xfs_dir2_sf_entry_t	*oldsfep;	/* old sf entry */
1048	xfs_dir2_sf_hdr_t	*oldsfp;	/* old sf directory */
1049	int			oldsize;	/* old inode size */
1050	xfs_dir2_sf_entry_t	*sfep;		/* new sf entry */
1051	xfs_dir2_sf_hdr_t	*sfp;		/* new sf directory */
1052	struct xfs_mount	*mp;
1053
1054	trace_xfs_dir2_sf_toino4(args);
1055
1056	dp = args->dp;
1057	mp = dp->i_mount;
1058
1059	/*
1060	 * Copy the old directory to the buffer.
1061	 * Then nuke it from the inode, and add the new buffer to the inode.
1062	 * Don't want xfs_idata_realloc copying the data here.
1063	 */
1064	oldsize = dp->i_df.if_bytes;
1065	buf = kmem_alloc(oldsize, KM_SLEEP);
1066	oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1067	ASSERT(oldsfp->i8count == 1);
1068	memcpy(buf, oldsfp, oldsize);
1069	/*
1070	 * Compute the new inode size.
1071	 */
1072	newsize =
1073		oldsize -
1074		(oldsfp->count + 1) *
1075		((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t));
1076	xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1077	xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1078	/*
1079	 * Reset our pointers, the data has moved.
1080	 */
1081	oldsfp = (xfs_dir2_sf_hdr_t *)buf;
1082	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1083	/*
1084	 * Fill in the new header.
1085	 */
1086	sfp->count = oldsfp->count;
1087	sfp->i8count = 0;
1088	dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp));
1089	/*
1090	 * Copy the entries field by field.
1091	 */
1092	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1093		    oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1094	     i < sfp->count;
1095	     i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep),
1096		  oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) {
1097		sfep->namelen = oldsfep->namelen;
1098		sfep->offset = oldsfep->offset;
1099		memcpy(sfep->name, oldsfep->name, sfep->namelen);
1100		dp->d_ops->sf_put_ino(sfp, sfep,
1101				      dp->d_ops->sf_get_ino(oldsfp, oldsfep));
1102		dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep));
1103	}
1104	/*
1105	 * Clean up the inode.
1106	 */
1107	kmem_free(buf);
1108	dp->i_d.di_size = newsize;
1109	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1110}
1111
1112/*
1113 * Convert from 4-byte inode numbers to 8-byte inode numbers.
1114 * The new 8-byte inode number is not there yet, we leave with the
1115 * count 1 but no corresponding entry.
1116 */
1117static void
1118xfs_dir2_sf_toino8(
1119	xfs_da_args_t		*args)		/* operation arguments */
1120{
1121	char			*buf;		/* old dir's buffer */
1122	xfs_inode_t		*dp;		/* incore directory inode */
1123	int			i;		/* entry index */
1124	int			newsize;	/* new inode size */
1125	xfs_dir2_sf_entry_t	*oldsfep;	/* old sf entry */
1126	xfs_dir2_sf_hdr_t	*oldsfp;	/* old sf directory */
1127	int			oldsize;	/* old inode size */
1128	xfs_dir2_sf_entry_t	*sfep;		/* new sf entry */
1129	xfs_dir2_sf_hdr_t	*sfp;		/* new sf directory */
1130	struct xfs_mount	*mp;
1131
1132	trace_xfs_dir2_sf_toino8(args);
1133
1134	dp = args->dp;
1135	mp = dp->i_mount;
1136
1137	/*
1138	 * Copy the old directory to the buffer.
1139	 * Then nuke it from the inode, and add the new buffer to the inode.
1140	 * Don't want xfs_idata_realloc copying the data here.
1141	 */
1142	oldsize = dp->i_df.if_bytes;
1143	buf = kmem_alloc(oldsize, KM_SLEEP);
1144	oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1145	ASSERT(oldsfp->i8count == 0);
1146	memcpy(buf, oldsfp, oldsize);
1147	/*
1148	 * Compute the new inode size.
1149	 */
1150	newsize =
1151		oldsize +
1152		(oldsfp->count + 1) *
1153		((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t));
1154	xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1155	xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1156	/*
1157	 * Reset our pointers, the data has moved.
1158	 */
1159	oldsfp = (xfs_dir2_sf_hdr_t *)buf;
1160	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1161	/*
1162	 * Fill in the new header.
1163	 */
1164	sfp->count = oldsfp->count;
1165	sfp->i8count = 1;
1166	dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp));
1167	/*
1168	 * Copy the entries field by field.
1169	 */
1170	for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1171		    oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1172	     i < sfp->count;
1173	     i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep),
1174		  oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) {
1175		sfep->namelen = oldsfep->namelen;
1176		sfep->offset = oldsfep->offset;
1177		memcpy(sfep->name, oldsfep->name, sfep->namelen);
1178		dp->d_ops->sf_put_ino(sfp, sfep,
1179				      dp->d_ops->sf_get_ino(oldsfp, oldsfep));
1180		dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep));
1181	}
1182	/*
1183	 * Clean up the inode.
1184	 */
1185	kmem_free(buf);
1186	dp->i_d.di_size = newsize;
1187	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1188}
1189#endif	/* XFS_BIG_INUMS */