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