1 /*
2  * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32 
33 #include "xfs.h"
34 
35 #include "xfs_macros.h"
36 #include "xfs_types.h"
37 #include "xfs_inum.h"
38 #include "xfs_log.h"
39 #include "xfs_trans.h"
40 #include "xfs_sb.h"
41 #include "xfs_dir.h"
42 #include "xfs_dir2.h"
43 #include "xfs_dmapi.h"
44 #include "xfs_mount.h"
45 #include "xfs_alloc_btree.h"
46 #include "xfs_bmap_btree.h"
47 #include "xfs_ialloc_btree.h"
48 #include "xfs_alloc.h"
49 #include "xfs_btree.h"
50 #include "xfs_attr_sf.h"
51 #include "xfs_dir_sf.h"
52 #include "xfs_dir2_sf.h"
53 #include "xfs_dinode.h"
54 #include "xfs_inode.h"
55 #include "xfs_bmap.h"
56 #include "xfs_da_btree.h"
57 #include "xfs_dir_leaf.h"
58 #include "xfs_error.h"
59 
60 /*
61  * xfs_dir.c
62  *
63  * Provide the external interfaces to manage directories.
64  */
65 
66 /*========================================================================
67  * Function prototypes for the kernel.
68  *========================================================================*/
69 
70 /*
71  * Functions for the dirops interfaces.
72  */
73 static void	xfs_dir_mount(struct xfs_mount *mp);
74 
75 static int	xfs_dir_isempty(struct xfs_inode *dp);
76 
77 static int	xfs_dir_init(struct xfs_trans *trans,
78 			     struct xfs_inode *dir,
79 			     struct xfs_inode *parent_dir);
80 
81 static int	xfs_dir_createname(struct xfs_trans *trans,
82 				   struct xfs_inode *dp,
83 				   char *name_string,
84 				   int name_len,
85 				   xfs_ino_t inode_number,
86 				   xfs_fsblock_t *firstblock,
87 				   xfs_bmap_free_t *flist,
88 				   xfs_extlen_t total);
89 
90 static int	xfs_dir_lookup(struct xfs_trans *tp,
91 			       struct xfs_inode *dp,
92 			       char *name_string,
93 			       int name_length,
94 			       xfs_ino_t *inode_number);
95 
96 static int	xfs_dir_removename(struct xfs_trans *trans,
97 				   struct xfs_inode *dp,
98 				   char *name_string,
99 				   int name_length,
100 				   xfs_ino_t ino,
101 				   xfs_fsblock_t *firstblock,
102 				   xfs_bmap_free_t *flist,
103 				   xfs_extlen_t total);
104 
105 static int	xfs_dir_getdents(struct xfs_trans *tp,
106 				 struct xfs_inode *dp,
107 				 struct uio *uiop,
108 				 int *eofp);
109 
110 static int	xfs_dir_replace(struct xfs_trans *tp,
111 				struct xfs_inode *dp,
112 				char *name_string,
113 				int name_length,
114 				xfs_ino_t inode_number,
115 				xfs_fsblock_t *firstblock,
116 				xfs_bmap_free_t *flist,
117 				xfs_extlen_t total);
118 
119 static int	xfs_dir_canenter(struct xfs_trans *tp,
120 				 struct xfs_inode *dp,
121 				 char *name_string,
122 				 int name_length);
123 
124 static int	xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp,
125 						  xfs_dinode_t *dip);
126 
127 xfs_dirops_t xfsv1_dirops = {
128 	.xd_mount			= xfs_dir_mount,
129 	.xd_isempty			= xfs_dir_isempty,
130 	.xd_init			= xfs_dir_init,
131 	.xd_createname			= xfs_dir_createname,
132 	.xd_lookup			= xfs_dir_lookup,
133 	.xd_removename			= xfs_dir_removename,
134 	.xd_getdents			= xfs_dir_getdents,
135 	.xd_replace			= xfs_dir_replace,
136 	.xd_canenter			= xfs_dir_canenter,
137 	.xd_shortform_validate_ondisk	= xfs_dir_shortform_validate_ondisk,
138 	.xd_shortform_to_single		= xfs_dir_shortform_to_leaf,
139 };
140 
141 /*
142  * Internal routines when dirsize == XFS_LBSIZE(mp).
143  */
144 STATIC int xfs_dir_leaf_lookup(xfs_da_args_t *args);
145 STATIC int xfs_dir_leaf_removename(xfs_da_args_t *args, int *number_entries,
146 						 int *total_namebytes);
147 STATIC int xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp,
148 					     uio_t *uio, int *eofp,
149 					     xfs_dirent_t *dbp,
150 					     xfs_dir_put_t put);
151 STATIC int xfs_dir_leaf_replace(xfs_da_args_t *args);
152 
153 /*
154  * Internal routines when dirsize > XFS_LBSIZE(mp).
155  */
156 STATIC int xfs_dir_node_addname(xfs_da_args_t *args);
157 STATIC int xfs_dir_node_lookup(xfs_da_args_t *args);
158 STATIC int xfs_dir_node_removename(xfs_da_args_t *args);
159 STATIC int xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp,
160 					     uio_t *uio, int *eofp,
161 					     xfs_dirent_t *dbp,
162 					     xfs_dir_put_t put);
163 STATIC int xfs_dir_node_replace(xfs_da_args_t *args);
164 
165 #if defined(XFS_DIR_TRACE)
166 ktrace_t *xfs_dir_trace_buf;
167 #endif
168 
169 
170 /*========================================================================
171  * Overall external interface routines.
172  *========================================================================*/
173 
174 xfs_dahash_t	xfs_dir_hash_dot, xfs_dir_hash_dotdot;
175 
176 /*
177  * One-time startup routine called from xfs_init().
178  */
179 void
xfs_dir_startup(void)180 xfs_dir_startup(void)
181 {
182 	xfs_dir_hash_dot = xfs_da_hashname(".", 1);
183 	xfs_dir_hash_dotdot = xfs_da_hashname("..", 2);
184 }
185 
186 /*
187  * Initialize directory-related fields in the mount structure.
188  */
189 static void
xfs_dir_mount(xfs_mount_t * mp)190 xfs_dir_mount(xfs_mount_t *mp)
191 {
192 	uint shortcount, leafcount, count;
193 
194 	mp->m_dirversion = 1;
195 	shortcount = (mp->m_attroffset - (uint)sizeof(xfs_dir_sf_hdr_t)) /
196 		     (uint)sizeof(xfs_dir_sf_entry_t);
197 	leafcount = (XFS_LBSIZE(mp) - (uint)sizeof(xfs_dir_leaf_hdr_t)) /
198 		    ((uint)sizeof(xfs_dir_leaf_entry_t) +
199 		     (uint)sizeof(xfs_dir_leaf_name_t));
200 	count = shortcount > leafcount ? shortcount : leafcount;
201 	mp->m_dircook_elog = xfs_da_log2_roundup(count + 1);
202 	ASSERT(mp->m_dircook_elog <= mp->m_sb.sb_blocklog);
203 	mp->m_dir_node_ents = mp->m_attr_node_ents =
204 		(XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) /
205 		(uint)sizeof(xfs_da_node_entry_t);
206 	mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100;
207 	mp->m_dirblksize = mp->m_sb.sb_blocksize;
208 	mp->m_dirblkfsbs = 1;
209 }
210 
211 /*
212  * Return 1 if directory contains only "." and "..".
213  */
214 static int
xfs_dir_isempty(xfs_inode_t * dp)215 xfs_dir_isempty(xfs_inode_t *dp)
216 {
217 	xfs_dir_sf_hdr_t *hdr;
218 
219 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
220 	if (dp->i_d.di_size == 0)
221 		return(1);
222 	if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
223 		return(0);
224 	hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data;
225 	return(hdr->count == 0);
226 }
227 
228 /*
229  * Initialize a directory with its "." and ".." entries.
230  */
231 static int
xfs_dir_init(xfs_trans_t * trans,xfs_inode_t * dir,xfs_inode_t * parent_dir)232 xfs_dir_init(xfs_trans_t *trans, xfs_inode_t *dir, xfs_inode_t *parent_dir)
233 {
234 	xfs_da_args_t args;
235 	int error;
236 
237 	memset((char *)&args, 0, sizeof(args));
238 	args.dp = dir;
239 	args.trans = trans;
240 
241 	ASSERT((dir->i_d.di_mode & S_IFMT) == S_IFDIR);
242 	if ((error = xfs_dir_ino_validate(trans->t_mountp, parent_dir->i_ino)))
243 		return error;
244 
245 	return(xfs_dir_shortform_create(&args, parent_dir->i_ino));
246 }
247 
248 /*
249  * Generic handler routine to add a name to a directory.
250  * Transitions directory from shortform to Btree as necessary.
251  */
252 static int							/* error */
xfs_dir_createname(xfs_trans_t * trans,xfs_inode_t * dp,char * name,int namelen,xfs_ino_t inum,xfs_fsblock_t * firstblock,xfs_bmap_free_t * flist,xfs_extlen_t total)253 xfs_dir_createname(xfs_trans_t *trans, xfs_inode_t *dp, char *name,
254 		   int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock,
255 		   xfs_bmap_free_t *flist, xfs_extlen_t total)
256 {
257 	xfs_da_args_t args;
258 	int retval, newsize, done;
259 
260 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
261 
262 	if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum)))
263 		return (retval);
264 
265 	XFS_STATS_INC(xs_dir_create);
266 	/*
267 	 * Fill in the arg structure for this request.
268 	 */
269 	args.name = name;
270 	args.namelen = namelen;
271 	args.hashval = xfs_da_hashname(name, namelen);
272 	args.inumber = inum;
273 	args.dp = dp;
274 	args.firstblock = firstblock;
275 	args.flist = flist;
276 	args.total = total;
277 	args.whichfork = XFS_DATA_FORK;
278 	args.trans = trans;
279 	args.justcheck = 0;
280 	args.addname = args.oknoent = 1;
281 
282 	/*
283 	 * Decide on what work routines to call based on the inode size.
284 	 */
285 	done = 0;
286 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
287 		newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen);
288 		if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) {
289 			retval = xfs_dir_shortform_addname(&args);
290 			done = 1;
291 		} else {
292 			if (total == 0)
293 				return XFS_ERROR(ENOSPC);
294 			retval = xfs_dir_shortform_to_leaf(&args);
295 			done = retval != 0;
296 		}
297 	}
298 	if (!done && xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
299 		retval = xfs_dir_leaf_addname(&args);
300 		done = retval != ENOSPC;
301 		if (!done) {
302 			if (total == 0)
303 				return XFS_ERROR(ENOSPC);
304 			retval = xfs_dir_leaf_to_node(&args);
305 			done = retval != 0;
306 		}
307 	}
308 	if (!done) {
309 		retval = xfs_dir_node_addname(&args);
310 	}
311 	return(retval);
312 }
313 
314 /*
315  * Generic handler routine to check if a name can be added to a directory,
316  * without adding any blocks to the directory.
317  */
318 static int							/* error */
xfs_dir_canenter(xfs_trans_t * trans,xfs_inode_t * dp,char * name,int namelen)319 xfs_dir_canenter(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen)
320 {
321 	xfs_da_args_t args;
322 	int retval, newsize;
323 
324 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
325 	/*
326 	 * Fill in the arg structure for this request.
327 	 */
328 	args.name = name;
329 	args.namelen = namelen;
330 	args.hashval = xfs_da_hashname(name, namelen);
331 	args.inumber = 0;
332 	args.dp = dp;
333 	args.firstblock = NULL;
334 	args.flist = NULL;
335 	args.total = 0;
336 	args.whichfork = XFS_DATA_FORK;
337 	args.trans = trans;
338 	args.justcheck = args.addname = args.oknoent = 1;
339 
340 	/*
341 	 * Decide on what work routines to call based on the inode size.
342 	 */
343 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
344 		newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen);
345 		if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp))
346 			retval = 0;
347 		else
348 			retval = XFS_ERROR(ENOSPC);
349 	} else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
350 		retval = xfs_dir_leaf_addname(&args);
351 	} else {
352 		retval = xfs_dir_node_addname(&args);
353 	}
354 	return(retval);
355 }
356 
357 /*
358  * Generic handler routine to remove a name from a directory.
359  * Transitions directory from Btree to shortform as necessary.
360  */
361 static int							/* error */
xfs_dir_removename(xfs_trans_t * trans,xfs_inode_t * dp,char * name,int namelen,xfs_ino_t ino,xfs_fsblock_t * firstblock,xfs_bmap_free_t * flist,xfs_extlen_t total)362 xfs_dir_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name,
363 		   int namelen, xfs_ino_t ino, xfs_fsblock_t *firstblock,
364 		   xfs_bmap_free_t *flist, xfs_extlen_t total)
365 {
366 	xfs_da_args_t args;
367 	int count, totallen, newsize, retval;
368 
369 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
370 	XFS_STATS_INC(xs_dir_remove);
371 	/*
372 	 * Fill in the arg structure for this request.
373 	 */
374 	args.name = name;
375 	args.namelen = namelen;
376 	args.hashval = xfs_da_hashname(name, namelen);
377 	args.inumber = ino;
378 	args.dp = dp;
379 	args.firstblock = firstblock;
380 	args.flist = flist;
381 	args.total = total;
382 	args.whichfork = XFS_DATA_FORK;
383 	args.trans = trans;
384 	args.justcheck = args.addname = args.oknoent = 0;
385 
386 	/*
387 	 * Decide on what work routines to call based on the inode size.
388 	 */
389 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
390 		retval = xfs_dir_shortform_removename(&args);
391 	} else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
392 		retval = xfs_dir_leaf_removename(&args, &count, &totallen);
393 		if (retval == 0) {
394 			newsize = XFS_DIR_SF_ALLFIT(count, totallen);
395 			if (newsize <= XFS_IFORK_DSIZE(dp)) {
396 				retval = xfs_dir_leaf_to_shortform(&args);
397 			}
398 		}
399 	} else {
400 		retval = xfs_dir_node_removename(&args);
401 	}
402 	return(retval);
403 }
404 
405 static int							/* error */
xfs_dir_lookup(xfs_trans_t * trans,xfs_inode_t * dp,char * name,int namelen,xfs_ino_t * inum)406 xfs_dir_lookup(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen,
407 				   xfs_ino_t *inum)
408 {
409 	xfs_da_args_t args;
410 	int retval;
411 
412 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
413 
414 	XFS_STATS_INC(xs_dir_lookup);
415 	/*
416 	 * Fill in the arg structure for this request.
417 	 */
418 	args.name = name;
419 	args.namelen = namelen;
420 	args.hashval = xfs_da_hashname(name, namelen);
421 	args.inumber = 0;
422 	args.dp = dp;
423 	args.firstblock = NULL;
424 	args.flist = NULL;
425 	args.total = 0;
426 	args.whichfork = XFS_DATA_FORK;
427 	args.trans = trans;
428 	args.justcheck = args.addname = 0;
429 	args.oknoent = 1;
430 
431 	/*
432 	 * Decide on what work routines to call based on the inode size.
433 	 */
434 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
435 		retval = xfs_dir_shortform_lookup(&args);
436 	} else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
437 		retval = xfs_dir_leaf_lookup(&args);
438 	} else {
439 		retval = xfs_dir_node_lookup(&args);
440 	}
441 	if (retval == EEXIST)
442 		retval = 0;
443 	*inum = args.inumber;
444 	return(retval);
445 }
446 
447 /*
448  * Implement readdir.
449  */
450 static int							/* error */
xfs_dir_getdents(xfs_trans_t * trans,xfs_inode_t * dp,uio_t * uio,int * eofp)451 xfs_dir_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, int *eofp)
452 {
453 	xfs_dirent_t *dbp;
454 	int  alignment, retval;
455 	xfs_dir_put_t put;
456 
457 	XFS_STATS_INC(xs_dir_getdents);
458 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
459 
460 	/*
461 	 * If our caller has given us a single contiguous memory buffer,
462 	 * just work directly within that buffer.  If it's in user memory,
463 	 * lock it down first.
464 	 */
465 	alignment = sizeof(xfs_off_t) - 1;
466 	if ((uio->uio_iovcnt == 1) &&
467 	    (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) &&
468 	    ((uio->uio_iov[0].iov_len & alignment) == 0)) {
469 		dbp = NULL;
470 		put = xfs_dir_put_dirent64_direct;
471 	} else {
472 		dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP);
473 		put = xfs_dir_put_dirent64_uio;
474 	}
475 
476 	/*
477 	 * Decide on what work routines to call based on the inode size.
478 	 */
479 	*eofp = 0;
480 
481 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
482 		retval = xfs_dir_shortform_getdents(dp, uio, eofp, dbp, put);
483 	} else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
484 		retval = xfs_dir_leaf_getdents(trans, dp, uio, eofp, dbp, put);
485 	} else {
486 		retval = xfs_dir_node_getdents(trans, dp, uio, eofp, dbp, put);
487 	}
488 	if (dbp != NULL)
489 		kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN);
490 
491 	return(retval);
492 }
493 
494 static int							/* error */
xfs_dir_replace(xfs_trans_t * trans,xfs_inode_t * dp,char * name,int namelen,xfs_ino_t inum,xfs_fsblock_t * firstblock,xfs_bmap_free_t * flist,xfs_extlen_t total)495 xfs_dir_replace(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen,
496 				    xfs_ino_t inum, xfs_fsblock_t *firstblock,
497 				    xfs_bmap_free_t *flist, xfs_extlen_t total)
498 {
499 	xfs_da_args_t args;
500 	int retval;
501 
502 	ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
503 
504 	if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum)))
505 		return retval;
506 
507 	/*
508 	 * Fill in the arg structure for this request.
509 	 */
510 	args.name = name;
511 	args.namelen = namelen;
512 	args.hashval = xfs_da_hashname(name, namelen);
513 	args.inumber = inum;
514 	args.dp = dp;
515 	args.firstblock = firstblock;
516 	args.flist = flist;
517 	args.total = total;
518 	args.whichfork = XFS_DATA_FORK;
519 	args.trans = trans;
520 	args.justcheck = args.addname = args.oknoent = 0;
521 
522 	/*
523 	 * Decide on what work routines to call based on the inode size.
524 	 */
525 	if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
526 		retval = xfs_dir_shortform_replace(&args);
527 	} else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
528 		retval = xfs_dir_leaf_replace(&args);
529 	} else {
530 		retval = xfs_dir_node_replace(&args);
531 	}
532 
533 	return(retval);
534 }
535 
536 static int
xfs_dir_shortform_validate_ondisk(xfs_mount_t * mp,xfs_dinode_t * dp)537 xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp)
538 {
539 	xfs_ino_t		ino;
540 	int			namelen_sum;
541 	int			count;
542 	xfs_dir_shortform_t	*sf;
543 	xfs_dir_sf_entry_t	*sfe;
544 	int			i;
545 
546 
547 
548 	if ((INT_GET(dp->di_core.di_mode, ARCH_CONVERT) & S_IFMT) != S_IFDIR) {
549 		return 0;
550 	}
551 	if (INT_GET(dp->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_LOCAL) {
552 		return 0;
553 	}
554 	if (INT_GET(dp->di_core.di_size, ARCH_CONVERT) < sizeof(sf->hdr)) {
555 		xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p",
556 			dp);
557 		return 1;
558 	}
559 	sf = (xfs_dir_shortform_t *)(&dp->di_u.di_dirsf);
560 	ino = XFS_GET_DIR_INO_ARCH(mp, sf->hdr.parent, ARCH_CONVERT);
561 	if (xfs_dir_ino_validate(mp, ino))
562 		return 1;
563 
564 	count =	sf->hdr.count;
565 	if ((count < 0) || ((count * 10) > XFS_LITINO(mp))) {
566 		xfs_fs_cmn_err(CE_WARN, mp,
567 			"Invalid shortform count: dp 0x%p", dp);
568 		return(1);
569 	}
570 
571 	if (count == 0) {
572 		return 0;
573 	}
574 
575 	namelen_sum = 0;
576 	sfe = &sf->list[0];
577 	for (i = sf->hdr.count - 1; i >= 0; i--) {
578 		ino = XFS_GET_DIR_INO_ARCH(mp, sfe->inumber, ARCH_CONVERT);
579 		xfs_dir_ino_validate(mp, ino);
580 		if (sfe->namelen >= XFS_LITINO(mp)) {
581 			xfs_fs_cmn_err(CE_WARN, mp,
582 				"Invalid shortform namelen: dp 0x%p", dp);
583 			return 1;
584 		}
585 		namelen_sum += sfe->namelen;
586 		sfe = XFS_DIR_SF_NEXTENTRY(sfe);
587 	}
588 	if (namelen_sum >= XFS_LITINO(mp)) {
589 		xfs_fs_cmn_err(CE_WARN, mp,
590 			"Invalid shortform namelen: dp 0x%p", dp);
591 		return 1;
592 	}
593 
594 	return 0;
595 }
596 
597 /*========================================================================
598  * External routines when dirsize == XFS_LBSIZE(dp->i_mount).
599  *========================================================================*/
600 
601 /*
602  * Add a name to the leaf directory structure
603  * This is the external routine.
604  */
605 int
xfs_dir_leaf_addname(xfs_da_args_t * args)606 xfs_dir_leaf_addname(xfs_da_args_t *args)
607 {
608 	int index, retval;
609 	xfs_dabuf_t *bp;
610 
611 	retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
612 					      XFS_DATA_FORK);
613 	if (retval)
614 		return(retval);
615 	ASSERT(bp != NULL);
616 
617 	retval = xfs_dir_leaf_lookup_int(bp, args, &index);
618 	if (retval == ENOENT)
619 		retval = xfs_dir_leaf_add(bp, args, index);
620 	xfs_da_buf_done(bp);
621 	return(retval);
622 }
623 
624 /*
625  * Remove a name from the leaf directory structure
626  * This is the external routine.
627  */
628 STATIC int
xfs_dir_leaf_removename(xfs_da_args_t * args,int * count,int * totallen)629 xfs_dir_leaf_removename(xfs_da_args_t *args, int *count, int *totallen)
630 {
631 	xfs_dir_leafblock_t *leaf;
632 	int index, retval;
633 	xfs_dabuf_t *bp;
634 
635 	retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
636 					      XFS_DATA_FORK);
637 	if (retval)
638 		return(retval);
639 	ASSERT(bp != NULL);
640 	leaf = bp->data;
641 	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
642 	retval = xfs_dir_leaf_lookup_int(bp, args, &index);
643 	if (retval == EEXIST) {
644 		(void)xfs_dir_leaf_remove(args->trans, bp, index);
645 		*count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
646 		*totallen = INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
647 		retval = 0;
648 	}
649 	xfs_da_buf_done(bp);
650 	return(retval);
651 }
652 
653 /*
654  * Look up a name in a leaf directory structure.
655  * This is the external routine.
656  */
657 STATIC int
xfs_dir_leaf_lookup(xfs_da_args_t * args)658 xfs_dir_leaf_lookup(xfs_da_args_t *args)
659 {
660 	int index, retval;
661 	xfs_dabuf_t *bp;
662 
663 	retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
664 					      XFS_DATA_FORK);
665 	if (retval)
666 		return(retval);
667 	ASSERT(bp != NULL);
668 	retval = xfs_dir_leaf_lookup_int(bp, args, &index);
669 	xfs_da_brelse(args->trans, bp);
670 	return(retval);
671 }
672 
673 /*
674  * Copy out directory entries for getdents(), for leaf directories.
675  */
676 STATIC int
xfs_dir_leaf_getdents(xfs_trans_t * trans,xfs_inode_t * dp,uio_t * uio,int * eofp,xfs_dirent_t * dbp,xfs_dir_put_t put)677 xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio,
678 				  int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put)
679 {
680 	xfs_dabuf_t *bp;
681 	int retval, eob;
682 
683 	retval = xfs_da_read_buf(dp->i_transp, dp, 0, -1, &bp, XFS_DATA_FORK);
684 	if (retval)
685 		return(retval);
686 	ASSERT(bp != NULL);
687 	retval = xfs_dir_leaf_getdents_int(bp, dp, 0, uio, &eob, dbp, put, -1);
688 	xfs_da_brelse(trans, bp);
689 	*eofp = (eob == 0);
690 	return(retval);
691 }
692 
693 /*
694  * Look up a name in a leaf directory structure, replace the inode number.
695  * This is the external routine.
696  */
697 STATIC int
xfs_dir_leaf_replace(xfs_da_args_t * args)698 xfs_dir_leaf_replace(xfs_da_args_t *args)
699 {
700 	int index, retval;
701 	xfs_dabuf_t *bp;
702 	xfs_ino_t inum;
703 	xfs_dir_leafblock_t *leaf;
704 	xfs_dir_leaf_entry_t *entry;
705 	xfs_dir_leaf_name_t *namest;
706 
707 	inum = args->inumber;
708 	retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
709 					      XFS_DATA_FORK);
710 	if (retval)
711 		return(retval);
712 	ASSERT(bp != NULL);
713 	retval = xfs_dir_leaf_lookup_int(bp, args, &index);
714 	if (retval == EEXIST) {
715 		leaf = bp->data;
716 		entry = &leaf->entries[index];
717 		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
718 		/* XXX - replace assert? */
719 		XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT);
720 		xfs_da_log_buf(args->trans, bp,
721 		    XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber)));
722 		xfs_da_buf_done(bp);
723 		retval = 0;
724 	} else
725 		xfs_da_brelse(args->trans, bp);
726 	return(retval);
727 }
728 
729 
730 /*========================================================================
731  * External routines when dirsize > XFS_LBSIZE(mp).
732  *========================================================================*/
733 
734 /*
735  * Add a name to a Btree-format directory.
736  *
737  * This will involve walking down the Btree, and may involve splitting
738  * leaf nodes and even splitting intermediate nodes up to and including
739  * the root node (a special case of an intermediate node).
740  */
741 STATIC int
xfs_dir_node_addname(xfs_da_args_t * args)742 xfs_dir_node_addname(xfs_da_args_t *args)
743 {
744 	xfs_da_state_t *state;
745 	xfs_da_state_blk_t *blk;
746 	int retval, error;
747 
748 	/*
749 	 * Fill in bucket of arguments/results/context to carry around.
750 	 */
751 	state = xfs_da_state_alloc();
752 	state->args = args;
753 	state->mp = args->dp->i_mount;
754 	state->blocksize = state->mp->m_sb.sb_blocksize;
755 	state->node_ents = state->mp->m_dir_node_ents;
756 
757 	/*
758 	 * Search to see if name already exists, and get back a pointer
759 	 * to where it should go.
760 	 */
761 	error = xfs_da_node_lookup_int(state, &retval);
762 	if (error)
763 		retval = error;
764 	if (retval != ENOENT)
765 		goto error;
766 	blk = &state->path.blk[ state->path.active-1 ];
767 	ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC);
768 	retval = xfs_dir_leaf_add(blk->bp, args, blk->index);
769 	if (retval == 0) {
770 		/*
771 		 * Addition succeeded, update Btree hashvals.
772 		 */
773 		if (!args->justcheck)
774 			xfs_da_fixhashpath(state, &state->path);
775 	} else {
776 		/*
777 		 * Addition failed, split as many Btree elements as required.
778 		 */
779 		if (args->total == 0) {
780 			ASSERT(retval == ENOSPC);
781 			goto error;
782 		}
783 		retval = xfs_da_split(state);
784 	}
785 error:
786 	xfs_da_state_free(state);
787 
788 	return(retval);
789 }
790 
791 /*
792  * Remove a name from a B-tree directory.
793  *
794  * This will involve walking down the Btree, and may involve joining
795  * leaf nodes and even joining intermediate nodes up to and including
796  * the root node (a special case of an intermediate node).
797  */
798 STATIC int
xfs_dir_node_removename(xfs_da_args_t * args)799 xfs_dir_node_removename(xfs_da_args_t *args)
800 {
801 	xfs_da_state_t *state;
802 	xfs_da_state_blk_t *blk;
803 	int retval, error;
804 
805 	state = xfs_da_state_alloc();
806 	state->args = args;
807 	state->mp = args->dp->i_mount;
808 	state->blocksize = state->mp->m_sb.sb_blocksize;
809 	state->node_ents = state->mp->m_dir_node_ents;
810 
811 	/*
812 	 * Search to see if name exists, and get back a pointer to it.
813 	 */
814 	error = xfs_da_node_lookup_int(state, &retval);
815 	if (error)
816 		retval = error;
817 	if (retval != EEXIST) {
818 		xfs_da_state_free(state);
819 		return(retval);
820 	}
821 
822 	/*
823 	 * Remove the name and update the hashvals in the tree.
824 	 */
825 	blk = &state->path.blk[ state->path.active-1 ];
826 	ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC);
827 	retval = xfs_dir_leaf_remove(args->trans, blk->bp, blk->index);
828 	xfs_da_fixhashpath(state, &state->path);
829 
830 	/*
831 	 * Check to see if the tree needs to be collapsed.
832 	 */
833 	error = 0;
834 	if (retval) {
835 		error = xfs_da_join(state);
836 	}
837 
838 	xfs_da_state_free(state);
839 	if (error)
840 		return(error);
841 	return(0);
842 }
843 
844 /*
845  * Look up a filename in a int directory.
846  * Use an internal routine to actually do all the work.
847  */
848 STATIC int
xfs_dir_node_lookup(xfs_da_args_t * args)849 xfs_dir_node_lookup(xfs_da_args_t *args)
850 {
851 	xfs_da_state_t *state;
852 	int retval, error, i;
853 
854 	state = xfs_da_state_alloc();
855 	state->args = args;
856 	state->mp = args->dp->i_mount;
857 	state->blocksize = state->mp->m_sb.sb_blocksize;
858 	state->node_ents = state->mp->m_dir_node_ents;
859 
860 	/*
861 	 * Search to see if name exists,
862 	 * and get back a pointer to it.
863 	 */
864 	error = xfs_da_node_lookup_int(state, &retval);
865 	if (error) {
866 		retval = error;
867 	}
868 
869 	/*
870 	 * If not in a transaction, we have to release all the buffers.
871 	 */
872 	for (i = 0; i < state->path.active; i++) {
873 		xfs_da_brelse(args->trans, state->path.blk[i].bp);
874 		state->path.blk[i].bp = NULL;
875 	}
876 
877 	xfs_da_state_free(state);
878 	return(retval);
879 }
880 
881 STATIC int
xfs_dir_node_getdents(xfs_trans_t * trans,xfs_inode_t * dp,uio_t * uio,int * eofp,xfs_dirent_t * dbp,xfs_dir_put_t put)882 xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio,
883 				  int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put)
884 {
885 	xfs_da_intnode_t *node;
886 	xfs_da_node_entry_t *btree;
887 	xfs_dir_leafblock_t *leaf = NULL;
888 	xfs_dablk_t bno, nextbno;
889 	xfs_dahash_t cookhash;
890 	xfs_mount_t *mp;
891 	int error, eob, i;
892 	xfs_dabuf_t *bp;
893 	xfs_daddr_t nextda;
894 
895 	/*
896 	 * Pick up our context.
897 	 */
898 	mp = dp->i_mount;
899 	bp = NULL;
900 	bno = XFS_DA_COOKIE_BNO(mp, uio->uio_offset);
901 	cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset);
902 
903 	xfs_dir_trace_g_du("node: start", dp, uio);
904 
905 	/*
906 	 * Re-find our place, even if we're confused about what our place is.
907 	 *
908 	 * First we check the block number from the magic cookie, it is a
909 	 * cache of where we ended last time.  If we find a leaf block, and
910 	 * the starting hashval in that block is less than our desired
911 	 * hashval, then we run with it.
912 	 */
913 	if (bno > 0) {
914 		error = xfs_da_read_buf(trans, dp, bno, -2, &bp, XFS_DATA_FORK);
915 		if ((error != 0) && (error != EFSCORRUPTED))
916 			return(error);
917 		if (bp)
918 			leaf = bp->data;
919 		if (bp && INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) {
920 			xfs_dir_trace_g_dub("node: block not a leaf",
921 						   dp, uio, bno);
922 			xfs_da_brelse(trans, bp);
923 			bp = NULL;
924 		}
925 		if (bp && INT_GET(leaf->entries[0].hashval, ARCH_CONVERT) > cookhash) {
926 			xfs_dir_trace_g_dub("node: leaf hash too large",
927 						   dp, uio, bno);
928 			xfs_da_brelse(trans, bp);
929 			bp = NULL;
930 		}
931 		if (bp &&
932 		    cookhash > INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT)) {
933 			xfs_dir_trace_g_dub("node: leaf hash too small",
934 						   dp, uio, bno);
935 			xfs_da_brelse(trans, bp);
936 			bp = NULL;
937 		}
938 	}
939 
940 	/*
941 	 * If we did not find a leaf block from the blockno in the cookie,
942 	 * or we there was no blockno in the cookie (eg: first time thru),
943 	 * the we start at the top of the Btree and re-find our hashval.
944 	 */
945 	if (bp == NULL) {
946 		xfs_dir_trace_g_du("node: start at root" , dp, uio);
947 		bno = 0;
948 		for (;;) {
949 			error = xfs_da_read_buf(trans, dp, bno, -1, &bp,
950 						       XFS_DATA_FORK);
951 			if (error)
952 				return(error);
953 			if (bp == NULL)
954 				return(XFS_ERROR(EFSCORRUPTED));
955 			node = bp->data;
956 			if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC)
957 				break;
958 			btree = &node->btree[0];
959 			xfs_dir_trace_g_dun("node: node detail", dp, uio, node);
960 			for (i = 0; i < INT_GET(node->hdr.count, ARCH_CONVERT); btree++, i++) {
961 				if (INT_GET(btree->hashval, ARCH_CONVERT) >= cookhash) {
962 					bno = INT_GET(btree->before, ARCH_CONVERT);
963 					break;
964 				}
965 			}
966 			if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) {
967 				xfs_da_brelse(trans, bp);
968 				xfs_dir_trace_g_du("node: hash beyond EOF",
969 							  dp, uio);
970 				uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0,
971 							     XFS_DA_MAXHASH);
972 				*eofp = 1;
973 				return(0);
974 			}
975 			xfs_dir_trace_g_dub("node: going to block",
976 						   dp, uio, bno);
977 			xfs_da_brelse(trans, bp);
978 		}
979 	}
980 	ASSERT(cookhash != XFS_DA_MAXHASH);
981 
982 	/*
983 	 * We've dropped down to the (first) leaf block that contains the
984 	 * hashval we are interested in.  Continue rolling upward thru the
985 	 * leaf blocks until we fill up our buffer.
986 	 */
987 	for (;;) {
988 		leaf = bp->data;
989 		if (unlikely(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC)) {
990 			xfs_dir_trace_g_dul("node: not a leaf", dp, uio, leaf);
991 			xfs_da_brelse(trans, bp);
992 			XFS_CORRUPTION_ERROR("xfs_dir_node_getdents(1)",
993 					     XFS_ERRLEVEL_LOW, mp, leaf);
994 			return XFS_ERROR(EFSCORRUPTED);
995 		}
996 		xfs_dir_trace_g_dul("node: leaf detail", dp, uio, leaf);
997 		if ((nextbno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT))) {
998 			nextda = xfs_da_reada_buf(trans, dp, nextbno,
999 						  XFS_DATA_FORK);
1000 		} else
1001 			nextda = -1;
1002 		error = xfs_dir_leaf_getdents_int(bp, dp, bno, uio, &eob, dbp,
1003 						  put, nextda);
1004 		xfs_da_brelse(trans, bp);
1005 		bno = nextbno;
1006 		if (eob) {
1007 			xfs_dir_trace_g_dub("node: E-O-B", dp, uio, bno);
1008 			*eofp = 0;
1009 			return(error);
1010 		}
1011 		if (bno == 0)
1012 			break;
1013 		error = xfs_da_read_buf(trans, dp, bno, nextda, &bp,
1014 					XFS_DATA_FORK);
1015 		if (error)
1016 			return(error);
1017 		if (unlikely(bp == NULL)) {
1018 			XFS_ERROR_REPORT("xfs_dir_node_getdents(2)",
1019 					 XFS_ERRLEVEL_LOW, mp);
1020 			return(XFS_ERROR(EFSCORRUPTED));
1021 		}
1022 	}
1023 	*eofp = 1;
1024 	xfs_dir_trace_g_du("node: E-O-F", dp, uio);
1025 	return(0);
1026 }
1027 
1028 /*
1029  * Look up a filename in an int directory, replace the inode number.
1030  * Use an internal routine to actually do the lookup.
1031  */
1032 STATIC int
xfs_dir_node_replace(xfs_da_args_t * args)1033 xfs_dir_node_replace(xfs_da_args_t *args)
1034 {
1035 	xfs_da_state_t *state;
1036 	xfs_da_state_blk_t *blk;
1037 	xfs_dir_leafblock_t *leaf;
1038 	xfs_dir_leaf_entry_t *entry;
1039 	xfs_dir_leaf_name_t *namest;
1040 	xfs_ino_t inum;
1041 	int retval, error, i;
1042 	xfs_dabuf_t *bp;
1043 
1044 	state = xfs_da_state_alloc();
1045 	state->args = args;
1046 	state->mp = args->dp->i_mount;
1047 	state->blocksize = state->mp->m_sb.sb_blocksize;
1048 	state->node_ents = state->mp->m_dir_node_ents;
1049 	inum = args->inumber;
1050 
1051 	/*
1052 	 * Search to see if name exists,
1053 	 * and get back a pointer to it.
1054 	 */
1055 	error = xfs_da_node_lookup_int(state, &retval);
1056 	if (error) {
1057 		retval = error;
1058 	}
1059 
1060 	if (retval == EEXIST) {
1061 		blk = &state->path.blk[state->path.active - 1];
1062 		ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC);
1063 		bp = blk->bp;
1064 		leaf = bp->data;
1065 		entry = &leaf->entries[blk->index];
1066 		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
1067 		/* XXX - replace assert ? */
1068 		XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT);
1069 		xfs_da_log_buf(args->trans, bp,
1070 		    XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber)));
1071 		xfs_da_buf_done(bp);
1072 		blk->bp = NULL;
1073 		retval = 0;
1074 	} else {
1075 		i = state->path.active - 1;
1076 		xfs_da_brelse(args->trans, state->path.blk[i].bp);
1077 		state->path.blk[i].bp = NULL;
1078 	}
1079 	for (i = 0; i < state->path.active - 1; i++) {
1080 		xfs_da_brelse(args->trans, state->path.blk[i].bp);
1081 		state->path.blk[i].bp = NULL;
1082 	}
1083 
1084 	xfs_da_state_free(state);
1085 	return(retval);
1086 }
1087 
1088 #if defined(XFS_DIR_TRACE)
1089 /*
1090  * Add a trace buffer entry for an inode and a uio.
1091  */
1092 void
xfs_dir_trace_g_du(char * where,xfs_inode_t * dp,uio_t * uio)1093 xfs_dir_trace_g_du(char *where, xfs_inode_t *dp, uio_t *uio)
1094 {
1095 	xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DU, where,
1096 		     (void *)dp, (void *)dp->i_mount,
1097 		     (void *)((unsigned long)(uio->uio_offset >> 32)),
1098 		     (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
1099 		     (void *)(unsigned long)uio->uio_resid,
1100 		     NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1101 }
1102 
1103 /*
1104  * Add a trace buffer entry for an inode and a uio.
1105  */
1106 void
xfs_dir_trace_g_dub(char * where,xfs_inode_t * dp,uio_t * uio,xfs_dablk_t bno)1107 xfs_dir_trace_g_dub(char *where, xfs_inode_t *dp, uio_t *uio, xfs_dablk_t bno)
1108 {
1109 	xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUB, where,
1110 		     (void *)dp, (void *)dp->i_mount,
1111 		     (void *)((unsigned long)(uio->uio_offset >> 32)),
1112 		     (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
1113 		     (void *)(unsigned long)uio->uio_resid,
1114 		     (void *)(unsigned long)bno,
1115 		     NULL, NULL, NULL, NULL, NULL, NULL);
1116 }
1117 
1118 /*
1119  * Add a trace buffer entry for an inode and a uio.
1120  */
1121 void
xfs_dir_trace_g_dun(char * where,xfs_inode_t * dp,uio_t * uio,xfs_da_intnode_t * node)1122 xfs_dir_trace_g_dun(char *where, xfs_inode_t *dp, uio_t *uio,
1123 			xfs_da_intnode_t *node)
1124 {
1125 	int	last = INT_GET(node->hdr.count, ARCH_CONVERT) - 1;
1126 
1127 	xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUN, where,
1128 		     (void *)dp, (void *)dp->i_mount,
1129 		     (void *)((unsigned long)(uio->uio_offset >> 32)),
1130 		     (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
1131 		     (void *)(unsigned long)uio->uio_resid,
1132 		     (void *)(unsigned long)
1133 			INT_GET(node->hdr.info.forw, ARCH_CONVERT),
1134 		     (void *)(unsigned long)
1135 			INT_GET(node->hdr.count, ARCH_CONVERT),
1136 		     (void *)(unsigned long)
1137 			INT_GET(node->btree[0].hashval, ARCH_CONVERT),
1138 		     (void *)(unsigned long)
1139 			INT_GET(node->btree[last].hashval, ARCH_CONVERT),
1140 		     NULL, NULL, NULL);
1141 }
1142 
1143 /*
1144  * Add a trace buffer entry for an inode and a uio.
1145  */
1146 void
xfs_dir_trace_g_dul(char * where,xfs_inode_t * dp,uio_t * uio,xfs_dir_leafblock_t * leaf)1147 xfs_dir_trace_g_dul(char *where, xfs_inode_t *dp, uio_t *uio,
1148 			xfs_dir_leafblock_t *leaf)
1149 {
1150 	int	last = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1;
1151 
1152 	xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUL, where,
1153 		     (void *)dp, (void *)dp->i_mount,
1154 		     (void *)((unsigned long)(uio->uio_offset >> 32)),
1155 		     (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
1156 		     (void *)(unsigned long)uio->uio_resid,
1157 		     (void *)(unsigned long)
1158 			INT_GET(leaf->hdr.info.forw, ARCH_CONVERT),
1159 		     (void *)(unsigned long)
1160 			INT_GET(leaf->hdr.count, ARCH_CONVERT),
1161 		     (void *)(unsigned long)
1162 			INT_GET(leaf->entries[0].hashval, ARCH_CONVERT),
1163 		     (void *)(unsigned long)
1164 			INT_GET(leaf->entries[last].hashval, ARCH_CONVERT),
1165 		     NULL, NULL, NULL);
1166 }
1167 
1168 /*
1169  * Add a trace buffer entry for an inode and a uio.
1170  */
1171 void
xfs_dir_trace_g_due(char * where,xfs_inode_t * dp,uio_t * uio,xfs_dir_leaf_entry_t * entry)1172 xfs_dir_trace_g_due(char *where, xfs_inode_t *dp, uio_t *uio,
1173 			xfs_dir_leaf_entry_t *entry)
1174 {
1175 	xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUE, where,
1176 		     (void *)dp, (void *)dp->i_mount,
1177 		     (void *)((unsigned long)(uio->uio_offset >> 32)),
1178 		     (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
1179 		     (void *)(unsigned long)uio->uio_resid,
1180 		     (void *)(unsigned long)
1181 			INT_GET(entry->hashval, ARCH_CONVERT),
1182 		     NULL, NULL, NULL, NULL, NULL, NULL);
1183 }
1184 
1185 /*
1186  * Add a trace buffer entry for an inode and a uio.
1187  */
1188 void
xfs_dir_trace_g_duc(char * where,xfs_inode_t * dp,uio_t * uio,xfs_off_t cookie)1189 xfs_dir_trace_g_duc(char *where, xfs_inode_t *dp, uio_t *uio, xfs_off_t cookie)
1190 {
1191 	xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUC, where,
1192 		     (void *)dp, (void *)dp->i_mount,
1193 		     (void *)((unsigned long)(uio->uio_offset >> 32)),
1194 		     (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
1195 		     (void *)(unsigned long)uio->uio_resid,
1196 		     (void *)((unsigned long)(cookie >> 32)),
1197 		     (void *)((unsigned long)(cookie & 0xFFFFFFFF)),
1198 		     NULL, NULL, NULL, NULL, NULL);
1199 }
1200 
1201 /*
1202  * Add a trace buffer entry for the arguments given to the routine,
1203  * generic form.
1204  */
1205 void
xfs_dir_trace_enter(int type,char * where,void * a0,void * a1,void * a2,void * a3,void * a4,void * a5,void * a6,void * a7,void * a8,void * a9,void * a10,void * a11)1206 xfs_dir_trace_enter(int type, char *where,
1207 			void * a0, void * a1,
1208 			void * a2, void * a3,
1209 			void * a4, void * a5,
1210 			void * a6, void * a7,
1211 			void * a8, void * a9,
1212 			void * a10, void * a11)
1213 {
1214 	ASSERT(xfs_dir_trace_buf);
1215 	ktrace_enter(xfs_dir_trace_buf, (void *)(unsigned long)type,
1216 					(void *)where,
1217 					(void *)a0, (void *)a1, (void *)a2,
1218 					(void *)a3, (void *)a4, (void *)a5,
1219 					(void *)a6, (void *)a7, (void *)a8,
1220 					(void *)a9, (void *)a10, (void *)a11,
1221 					NULL, NULL);
1222 }
1223 #endif	/* XFS_DIR_TRACE */
1224