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