xref: /OK3568_Linux_fs/kernel/fs/xfs/libxfs/xfs_dir2.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4*4882a593Smuzhiyun  * All Rights Reserved.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include "xfs.h"
7*4882a593Smuzhiyun #include "xfs_fs.h"
8*4882a593Smuzhiyun #include "xfs_shared.h"
9*4882a593Smuzhiyun #include "xfs_format.h"
10*4882a593Smuzhiyun #include "xfs_log_format.h"
11*4882a593Smuzhiyun #include "xfs_trans_resv.h"
12*4882a593Smuzhiyun #include "xfs_mount.h"
13*4882a593Smuzhiyun #include "xfs_inode.h"
14*4882a593Smuzhiyun #include "xfs_trans.h"
15*4882a593Smuzhiyun #include "xfs_bmap.h"
16*4882a593Smuzhiyun #include "xfs_dir2.h"
17*4882a593Smuzhiyun #include "xfs_dir2_priv.h"
18*4882a593Smuzhiyun #include "xfs_errortag.h"
19*4882a593Smuzhiyun #include "xfs_error.h"
20*4882a593Smuzhiyun #include "xfs_trace.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /*
25*4882a593Smuzhiyun  * Convert inode mode to directory entry filetype
26*4882a593Smuzhiyun  */
27*4882a593Smuzhiyun unsigned char
xfs_mode_to_ftype(int mode)28*4882a593Smuzhiyun xfs_mode_to_ftype(
29*4882a593Smuzhiyun 	int		mode)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	switch (mode & S_IFMT) {
32*4882a593Smuzhiyun 	case S_IFREG:
33*4882a593Smuzhiyun 		return XFS_DIR3_FT_REG_FILE;
34*4882a593Smuzhiyun 	case S_IFDIR:
35*4882a593Smuzhiyun 		return XFS_DIR3_FT_DIR;
36*4882a593Smuzhiyun 	case S_IFCHR:
37*4882a593Smuzhiyun 		return XFS_DIR3_FT_CHRDEV;
38*4882a593Smuzhiyun 	case S_IFBLK:
39*4882a593Smuzhiyun 		return XFS_DIR3_FT_BLKDEV;
40*4882a593Smuzhiyun 	case S_IFIFO:
41*4882a593Smuzhiyun 		return XFS_DIR3_FT_FIFO;
42*4882a593Smuzhiyun 	case S_IFSOCK:
43*4882a593Smuzhiyun 		return XFS_DIR3_FT_SOCK;
44*4882a593Smuzhiyun 	case S_IFLNK:
45*4882a593Smuzhiyun 		return XFS_DIR3_FT_SYMLINK;
46*4882a593Smuzhiyun 	default:
47*4882a593Smuzhiyun 		return XFS_DIR3_FT_UNKNOWN;
48*4882a593Smuzhiyun 	}
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /*
52*4882a593Smuzhiyun  * ASCII case-insensitive (ie. A-Z) support for directories that was
53*4882a593Smuzhiyun  * used in IRIX.
54*4882a593Smuzhiyun  */
55*4882a593Smuzhiyun xfs_dahash_t
xfs_ascii_ci_hashname(struct xfs_name * name)56*4882a593Smuzhiyun xfs_ascii_ci_hashname(
57*4882a593Smuzhiyun 	struct xfs_name	*name)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	xfs_dahash_t	hash;
60*4882a593Smuzhiyun 	int		i;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	for (i = 0, hash = 0; i < name->len; i++)
63*4882a593Smuzhiyun 		hash = tolower(name->name[i]) ^ rol32(hash, 7);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	return hash;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun enum xfs_dacmp
xfs_ascii_ci_compname(struct xfs_da_args * args,const unsigned char * name,int len)69*4882a593Smuzhiyun xfs_ascii_ci_compname(
70*4882a593Smuzhiyun 	struct xfs_da_args	*args,
71*4882a593Smuzhiyun 	const unsigned char	*name,
72*4882a593Smuzhiyun 	int			len)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	enum xfs_dacmp		result;
75*4882a593Smuzhiyun 	int			i;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	if (args->namelen != len)
78*4882a593Smuzhiyun 		return XFS_CMP_DIFFERENT;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	result = XFS_CMP_EXACT;
81*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
82*4882a593Smuzhiyun 		if (args->name[i] == name[i])
83*4882a593Smuzhiyun 			continue;
84*4882a593Smuzhiyun 		if (tolower(args->name[i]) != tolower(name[i]))
85*4882a593Smuzhiyun 			return XFS_CMP_DIFFERENT;
86*4882a593Smuzhiyun 		result = XFS_CMP_CASE;
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	return result;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun int
xfs_da_mount(struct xfs_mount * mp)93*4882a593Smuzhiyun xfs_da_mount(
94*4882a593Smuzhiyun 	struct xfs_mount	*mp)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	struct xfs_da_geometry	*dageo;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
100*4882a593Smuzhiyun 	ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
103*4882a593Smuzhiyun 				    KM_MAYFAIL);
104*4882a593Smuzhiyun 	mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
105*4882a593Smuzhiyun 				     KM_MAYFAIL);
106*4882a593Smuzhiyun 	if (!mp->m_dir_geo || !mp->m_attr_geo) {
107*4882a593Smuzhiyun 		kmem_free(mp->m_dir_geo);
108*4882a593Smuzhiyun 		kmem_free(mp->m_attr_geo);
109*4882a593Smuzhiyun 		return -ENOMEM;
110*4882a593Smuzhiyun 	}
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	/* set up directory geometry */
113*4882a593Smuzhiyun 	dageo = mp->m_dir_geo;
114*4882a593Smuzhiyun 	dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog;
115*4882a593Smuzhiyun 	dageo->fsblog = mp->m_sb.sb_blocklog;
116*4882a593Smuzhiyun 	dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb);
117*4882a593Smuzhiyun 	dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
118*4882a593Smuzhiyun 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
119*4882a593Smuzhiyun 		dageo->node_hdr_size = sizeof(struct xfs_da3_node_hdr);
120*4882a593Smuzhiyun 		dageo->leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr);
121*4882a593Smuzhiyun 		dageo->free_hdr_size = sizeof(struct xfs_dir3_free_hdr);
122*4882a593Smuzhiyun 		dageo->data_entry_offset =
123*4882a593Smuzhiyun 				sizeof(struct xfs_dir3_data_hdr);
124*4882a593Smuzhiyun 	} else {
125*4882a593Smuzhiyun 		dageo->node_hdr_size = sizeof(struct xfs_da_node_hdr);
126*4882a593Smuzhiyun 		dageo->leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr);
127*4882a593Smuzhiyun 		dageo->free_hdr_size = sizeof(struct xfs_dir2_free_hdr);
128*4882a593Smuzhiyun 		dageo->data_entry_offset =
129*4882a593Smuzhiyun 				sizeof(struct xfs_dir2_data_hdr);
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 	dageo->leaf_max_ents = (dageo->blksize - dageo->leaf_hdr_size) /
132*4882a593Smuzhiyun 			sizeof(struct xfs_dir2_leaf_entry);
133*4882a593Smuzhiyun 	dageo->free_max_bests = (dageo->blksize - dageo->free_hdr_size) /
134*4882a593Smuzhiyun 			sizeof(xfs_dir2_data_off_t);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	dageo->data_first_offset = dageo->data_entry_offset +
137*4882a593Smuzhiyun 			xfs_dir2_data_entsize(mp, 1) +
138*4882a593Smuzhiyun 			xfs_dir2_data_entsize(mp, 2);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	/*
141*4882a593Smuzhiyun 	 * Now we've set up the block conversion variables, we can calculate the
142*4882a593Smuzhiyun 	 * segment block constants using the geometry structure.
143*4882a593Smuzhiyun 	 */
144*4882a593Smuzhiyun 	dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);
145*4882a593Smuzhiyun 	dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);
146*4882a593Smuzhiyun 	dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
147*4882a593Smuzhiyun 	dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
148*4882a593Smuzhiyun 				(uint)sizeof(xfs_da_node_entry_t);
149*4882a593Smuzhiyun 	dageo->magicpct = (dageo->blksize * 37) / 100;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	/* set up attribute geometry - single fsb only */
152*4882a593Smuzhiyun 	dageo = mp->m_attr_geo;
153*4882a593Smuzhiyun 	dageo->blklog = mp->m_sb.sb_blocklog;
154*4882a593Smuzhiyun 	dageo->fsblog = mp->m_sb.sb_blocklog;
155*4882a593Smuzhiyun 	dageo->blksize = 1 << dageo->blklog;
156*4882a593Smuzhiyun 	dageo->fsbcount = 1;
157*4882a593Smuzhiyun 	dageo->node_hdr_size = mp->m_dir_geo->node_hdr_size;
158*4882a593Smuzhiyun 	dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
159*4882a593Smuzhiyun 				(uint)sizeof(xfs_da_node_entry_t);
160*4882a593Smuzhiyun 	dageo->magicpct = (dageo->blksize * 37) / 100;
161*4882a593Smuzhiyun 	return 0;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun void
xfs_da_unmount(struct xfs_mount * mp)165*4882a593Smuzhiyun xfs_da_unmount(
166*4882a593Smuzhiyun 	struct xfs_mount	*mp)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	kmem_free(mp->m_dir_geo);
169*4882a593Smuzhiyun 	kmem_free(mp->m_attr_geo);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun  * Return 1 if directory contains only "." and "..".
174*4882a593Smuzhiyun  */
175*4882a593Smuzhiyun int
xfs_dir_isempty(xfs_inode_t * dp)176*4882a593Smuzhiyun xfs_dir_isempty(
177*4882a593Smuzhiyun 	xfs_inode_t	*dp)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	xfs_dir2_sf_hdr_t	*sfp;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
182*4882a593Smuzhiyun 	if (dp->i_d.di_size == 0)	/* might happen during shutdown. */
183*4882a593Smuzhiyun 		return 1;
184*4882a593Smuzhiyun 	if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
185*4882a593Smuzhiyun 		return 0;
186*4882a593Smuzhiyun 	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
187*4882a593Smuzhiyun 	return !sfp->count;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun /*
191*4882a593Smuzhiyun  * Validate a given inode number.
192*4882a593Smuzhiyun  */
193*4882a593Smuzhiyun int
xfs_dir_ino_validate(xfs_mount_t * mp,xfs_ino_t ino)194*4882a593Smuzhiyun xfs_dir_ino_validate(
195*4882a593Smuzhiyun 	xfs_mount_t	*mp,
196*4882a593Smuzhiyun 	xfs_ino_t	ino)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	bool		ino_ok = xfs_verify_dir_ino(mp, ino);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (XFS_IS_CORRUPT(mp, !ino_ok) ||
201*4882a593Smuzhiyun 	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_DIR_INO_VALIDATE)) {
202*4882a593Smuzhiyun 		xfs_warn(mp, "Invalid inode number 0x%Lx",
203*4882a593Smuzhiyun 				(unsigned long long) ino);
204*4882a593Smuzhiyun 		return -EFSCORRUPTED;
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 	return 0;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun /*
210*4882a593Smuzhiyun  * Initialize a directory with its "." and ".." entries.
211*4882a593Smuzhiyun  */
212*4882a593Smuzhiyun int
xfs_dir_init(xfs_trans_t * tp,xfs_inode_t * dp,xfs_inode_t * pdp)213*4882a593Smuzhiyun xfs_dir_init(
214*4882a593Smuzhiyun 	xfs_trans_t	*tp,
215*4882a593Smuzhiyun 	xfs_inode_t	*dp,
216*4882a593Smuzhiyun 	xfs_inode_t	*pdp)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	struct xfs_da_args *args;
219*4882a593Smuzhiyun 	int		error;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
222*4882a593Smuzhiyun 	error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino);
223*4882a593Smuzhiyun 	if (error)
224*4882a593Smuzhiyun 		return error;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	args = kmem_zalloc(sizeof(*args), KM_NOFS);
227*4882a593Smuzhiyun 	if (!args)
228*4882a593Smuzhiyun 		return -ENOMEM;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	args->geo = dp->i_mount->m_dir_geo;
231*4882a593Smuzhiyun 	args->dp = dp;
232*4882a593Smuzhiyun 	args->trans = tp;
233*4882a593Smuzhiyun 	error = xfs_dir2_sf_create(args, pdp->i_ino);
234*4882a593Smuzhiyun 	kmem_free(args);
235*4882a593Smuzhiyun 	return error;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun /*
239*4882a593Smuzhiyun  * Enter a name in a directory, or check for available space.
240*4882a593Smuzhiyun  * If inum is 0, only the available space test is performed.
241*4882a593Smuzhiyun  */
242*4882a593Smuzhiyun int
xfs_dir_createname(struct xfs_trans * tp,struct xfs_inode * dp,struct xfs_name * name,xfs_ino_t inum,xfs_extlen_t total)243*4882a593Smuzhiyun xfs_dir_createname(
244*4882a593Smuzhiyun 	struct xfs_trans	*tp,
245*4882a593Smuzhiyun 	struct xfs_inode	*dp,
246*4882a593Smuzhiyun 	struct xfs_name		*name,
247*4882a593Smuzhiyun 	xfs_ino_t		inum,		/* new entry inode number */
248*4882a593Smuzhiyun 	xfs_extlen_t		total)		/* bmap's total block count */
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	struct xfs_da_args	*args;
251*4882a593Smuzhiyun 	int			rval;
252*4882a593Smuzhiyun 	int			v;		/* type-checking value */
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (inum) {
257*4882a593Smuzhiyun 		rval = xfs_dir_ino_validate(tp->t_mountp, inum);
258*4882a593Smuzhiyun 		if (rval)
259*4882a593Smuzhiyun 			return rval;
260*4882a593Smuzhiyun 		XFS_STATS_INC(dp->i_mount, xs_dir_create);
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	args = kmem_zalloc(sizeof(*args), KM_NOFS);
264*4882a593Smuzhiyun 	if (!args)
265*4882a593Smuzhiyun 		return -ENOMEM;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	args->geo = dp->i_mount->m_dir_geo;
268*4882a593Smuzhiyun 	args->name = name->name;
269*4882a593Smuzhiyun 	args->namelen = name->len;
270*4882a593Smuzhiyun 	args->filetype = name->type;
271*4882a593Smuzhiyun 	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
272*4882a593Smuzhiyun 	args->inumber = inum;
273*4882a593Smuzhiyun 	args->dp = dp;
274*4882a593Smuzhiyun 	args->total = total;
275*4882a593Smuzhiyun 	args->whichfork = XFS_DATA_FORK;
276*4882a593Smuzhiyun 	args->trans = tp;
277*4882a593Smuzhiyun 	args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
278*4882a593Smuzhiyun 	if (!inum)
279*4882a593Smuzhiyun 		args->op_flags |= XFS_DA_OP_JUSTCHECK;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
282*4882a593Smuzhiyun 		rval = xfs_dir2_sf_addname(args);
283*4882a593Smuzhiyun 		goto out_free;
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	rval = xfs_dir2_isblock(args, &v);
287*4882a593Smuzhiyun 	if (rval)
288*4882a593Smuzhiyun 		goto out_free;
289*4882a593Smuzhiyun 	if (v) {
290*4882a593Smuzhiyun 		rval = xfs_dir2_block_addname(args);
291*4882a593Smuzhiyun 		goto out_free;
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	rval = xfs_dir2_isleaf(args, &v);
295*4882a593Smuzhiyun 	if (rval)
296*4882a593Smuzhiyun 		goto out_free;
297*4882a593Smuzhiyun 	if (v)
298*4882a593Smuzhiyun 		rval = xfs_dir2_leaf_addname(args);
299*4882a593Smuzhiyun 	else
300*4882a593Smuzhiyun 		rval = xfs_dir2_node_addname(args);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun out_free:
303*4882a593Smuzhiyun 	kmem_free(args);
304*4882a593Smuzhiyun 	return rval;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun /*
308*4882a593Smuzhiyun  * If doing a CI lookup and case-insensitive match, dup actual name into
309*4882a593Smuzhiyun  * args.value. Return EEXIST for success (ie. name found) or an error.
310*4882a593Smuzhiyun  */
311*4882a593Smuzhiyun int
xfs_dir_cilookup_result(struct xfs_da_args * args,const unsigned char * name,int len)312*4882a593Smuzhiyun xfs_dir_cilookup_result(
313*4882a593Smuzhiyun 	struct xfs_da_args *args,
314*4882a593Smuzhiyun 	const unsigned char *name,
315*4882a593Smuzhiyun 	int		len)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	if (args->cmpresult == XFS_CMP_DIFFERENT)
318*4882a593Smuzhiyun 		return -ENOENT;
319*4882a593Smuzhiyun 	if (args->cmpresult != XFS_CMP_CASE ||
320*4882a593Smuzhiyun 					!(args->op_flags & XFS_DA_OP_CILOOKUP))
321*4882a593Smuzhiyun 		return -EEXIST;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);
324*4882a593Smuzhiyun 	if (!args->value)
325*4882a593Smuzhiyun 		return -ENOMEM;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	memcpy(args->value, name, len);
328*4882a593Smuzhiyun 	args->valuelen = len;
329*4882a593Smuzhiyun 	return -EEXIST;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun /*
333*4882a593Smuzhiyun  * Lookup a name in a directory, give back the inode number.
334*4882a593Smuzhiyun  * If ci_name is not NULL, returns the actual name in ci_name if it differs
335*4882a593Smuzhiyun  * to name, or ci_name->name is set to NULL for an exact match.
336*4882a593Smuzhiyun  */
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun int
xfs_dir_lookup(xfs_trans_t * tp,xfs_inode_t * dp,struct xfs_name * name,xfs_ino_t * inum,struct xfs_name * ci_name)339*4882a593Smuzhiyun xfs_dir_lookup(
340*4882a593Smuzhiyun 	xfs_trans_t	*tp,
341*4882a593Smuzhiyun 	xfs_inode_t	*dp,
342*4882a593Smuzhiyun 	struct xfs_name	*name,
343*4882a593Smuzhiyun 	xfs_ino_t	*inum,		/* out: inode number */
344*4882a593Smuzhiyun 	struct xfs_name *ci_name)	/* out: actual name if CI match */
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun 	struct xfs_da_args *args;
347*4882a593Smuzhiyun 	int		rval;
348*4882a593Smuzhiyun 	int		v;		/* type-checking value */
349*4882a593Smuzhiyun 	int		lock_mode;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
352*4882a593Smuzhiyun 	XFS_STATS_INC(dp->i_mount, xs_dir_lookup);
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	/*
355*4882a593Smuzhiyun 	 * We need to use KM_NOFS here so that lockdep will not throw false
356*4882a593Smuzhiyun 	 * positive deadlock warnings on a non-transactional lookup path. It is
357*4882a593Smuzhiyun 	 * safe to recurse into inode recalim in that case, but lockdep can't
358*4882a593Smuzhiyun 	 * easily be taught about it. Hence KM_NOFS avoids having to add more
359*4882a593Smuzhiyun 	 * lockdep Doing this avoids having to add a bunch of lockdep class
360*4882a593Smuzhiyun 	 * annotations into the reclaim path for the ilock.
361*4882a593Smuzhiyun 	 */
362*4882a593Smuzhiyun 	args = kmem_zalloc(sizeof(*args), KM_NOFS);
363*4882a593Smuzhiyun 	args->geo = dp->i_mount->m_dir_geo;
364*4882a593Smuzhiyun 	args->name = name->name;
365*4882a593Smuzhiyun 	args->namelen = name->len;
366*4882a593Smuzhiyun 	args->filetype = name->type;
367*4882a593Smuzhiyun 	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
368*4882a593Smuzhiyun 	args->dp = dp;
369*4882a593Smuzhiyun 	args->whichfork = XFS_DATA_FORK;
370*4882a593Smuzhiyun 	args->trans = tp;
371*4882a593Smuzhiyun 	args->op_flags = XFS_DA_OP_OKNOENT;
372*4882a593Smuzhiyun 	if (ci_name)
373*4882a593Smuzhiyun 		args->op_flags |= XFS_DA_OP_CILOOKUP;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	lock_mode = xfs_ilock_data_map_shared(dp);
376*4882a593Smuzhiyun 	if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
377*4882a593Smuzhiyun 		rval = xfs_dir2_sf_lookup(args);
378*4882a593Smuzhiyun 		goto out_check_rval;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	rval = xfs_dir2_isblock(args, &v);
382*4882a593Smuzhiyun 	if (rval)
383*4882a593Smuzhiyun 		goto out_free;
384*4882a593Smuzhiyun 	if (v) {
385*4882a593Smuzhiyun 		rval = xfs_dir2_block_lookup(args);
386*4882a593Smuzhiyun 		goto out_check_rval;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	rval = xfs_dir2_isleaf(args, &v);
390*4882a593Smuzhiyun 	if (rval)
391*4882a593Smuzhiyun 		goto out_free;
392*4882a593Smuzhiyun 	if (v)
393*4882a593Smuzhiyun 		rval = xfs_dir2_leaf_lookup(args);
394*4882a593Smuzhiyun 	else
395*4882a593Smuzhiyun 		rval = xfs_dir2_node_lookup(args);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun out_check_rval:
398*4882a593Smuzhiyun 	if (rval == -EEXIST)
399*4882a593Smuzhiyun 		rval = 0;
400*4882a593Smuzhiyun 	if (!rval) {
401*4882a593Smuzhiyun 		*inum = args->inumber;
402*4882a593Smuzhiyun 		if (ci_name) {
403*4882a593Smuzhiyun 			ci_name->name = args->value;
404*4882a593Smuzhiyun 			ci_name->len = args->valuelen;
405*4882a593Smuzhiyun 		}
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun out_free:
408*4882a593Smuzhiyun 	xfs_iunlock(dp, lock_mode);
409*4882a593Smuzhiyun 	kmem_free(args);
410*4882a593Smuzhiyun 	return rval;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun /*
414*4882a593Smuzhiyun  * Remove an entry from a directory.
415*4882a593Smuzhiyun  */
416*4882a593Smuzhiyun int
xfs_dir_removename(struct xfs_trans * tp,struct xfs_inode * dp,struct xfs_name * name,xfs_ino_t ino,xfs_extlen_t total)417*4882a593Smuzhiyun xfs_dir_removename(
418*4882a593Smuzhiyun 	struct xfs_trans	*tp,
419*4882a593Smuzhiyun 	struct xfs_inode	*dp,
420*4882a593Smuzhiyun 	struct xfs_name		*name,
421*4882a593Smuzhiyun 	xfs_ino_t		ino,
422*4882a593Smuzhiyun 	xfs_extlen_t		total)		/* bmap's total block count */
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	struct xfs_da_args	*args;
425*4882a593Smuzhiyun 	int			rval;
426*4882a593Smuzhiyun 	int			v;		/* type-checking value */
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
429*4882a593Smuzhiyun 	XFS_STATS_INC(dp->i_mount, xs_dir_remove);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	args = kmem_zalloc(sizeof(*args), KM_NOFS);
432*4882a593Smuzhiyun 	if (!args)
433*4882a593Smuzhiyun 		return -ENOMEM;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	args->geo = dp->i_mount->m_dir_geo;
436*4882a593Smuzhiyun 	args->name = name->name;
437*4882a593Smuzhiyun 	args->namelen = name->len;
438*4882a593Smuzhiyun 	args->filetype = name->type;
439*4882a593Smuzhiyun 	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
440*4882a593Smuzhiyun 	args->inumber = ino;
441*4882a593Smuzhiyun 	args->dp = dp;
442*4882a593Smuzhiyun 	args->total = total;
443*4882a593Smuzhiyun 	args->whichfork = XFS_DATA_FORK;
444*4882a593Smuzhiyun 	args->trans = tp;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
447*4882a593Smuzhiyun 		rval = xfs_dir2_sf_removename(args);
448*4882a593Smuzhiyun 		goto out_free;
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	rval = xfs_dir2_isblock(args, &v);
452*4882a593Smuzhiyun 	if (rval)
453*4882a593Smuzhiyun 		goto out_free;
454*4882a593Smuzhiyun 	if (v) {
455*4882a593Smuzhiyun 		rval = xfs_dir2_block_removename(args);
456*4882a593Smuzhiyun 		goto out_free;
457*4882a593Smuzhiyun 	}
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	rval = xfs_dir2_isleaf(args, &v);
460*4882a593Smuzhiyun 	if (rval)
461*4882a593Smuzhiyun 		goto out_free;
462*4882a593Smuzhiyun 	if (v)
463*4882a593Smuzhiyun 		rval = xfs_dir2_leaf_removename(args);
464*4882a593Smuzhiyun 	else
465*4882a593Smuzhiyun 		rval = xfs_dir2_node_removename(args);
466*4882a593Smuzhiyun out_free:
467*4882a593Smuzhiyun 	kmem_free(args);
468*4882a593Smuzhiyun 	return rval;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun /*
472*4882a593Smuzhiyun  * Replace the inode number of a directory entry.
473*4882a593Smuzhiyun  */
474*4882a593Smuzhiyun int
xfs_dir_replace(struct xfs_trans * tp,struct xfs_inode * dp,struct xfs_name * name,xfs_ino_t inum,xfs_extlen_t total)475*4882a593Smuzhiyun xfs_dir_replace(
476*4882a593Smuzhiyun 	struct xfs_trans	*tp,
477*4882a593Smuzhiyun 	struct xfs_inode	*dp,
478*4882a593Smuzhiyun 	struct xfs_name		*name,		/* name of entry to replace */
479*4882a593Smuzhiyun 	xfs_ino_t		inum,		/* new inode number */
480*4882a593Smuzhiyun 	xfs_extlen_t		total)		/* bmap's total block count */
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	struct xfs_da_args	*args;
483*4882a593Smuzhiyun 	int			rval;
484*4882a593Smuzhiyun 	int			v;		/* type-checking value */
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	rval = xfs_dir_ino_validate(tp->t_mountp, inum);
489*4882a593Smuzhiyun 	if (rval)
490*4882a593Smuzhiyun 		return rval;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	args = kmem_zalloc(sizeof(*args), KM_NOFS);
493*4882a593Smuzhiyun 	if (!args)
494*4882a593Smuzhiyun 		return -ENOMEM;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	args->geo = dp->i_mount->m_dir_geo;
497*4882a593Smuzhiyun 	args->name = name->name;
498*4882a593Smuzhiyun 	args->namelen = name->len;
499*4882a593Smuzhiyun 	args->filetype = name->type;
500*4882a593Smuzhiyun 	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
501*4882a593Smuzhiyun 	args->inumber = inum;
502*4882a593Smuzhiyun 	args->dp = dp;
503*4882a593Smuzhiyun 	args->total = total;
504*4882a593Smuzhiyun 	args->whichfork = XFS_DATA_FORK;
505*4882a593Smuzhiyun 	args->trans = tp;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
508*4882a593Smuzhiyun 		rval = xfs_dir2_sf_replace(args);
509*4882a593Smuzhiyun 		goto out_free;
510*4882a593Smuzhiyun 	}
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	rval = xfs_dir2_isblock(args, &v);
513*4882a593Smuzhiyun 	if (rval)
514*4882a593Smuzhiyun 		goto out_free;
515*4882a593Smuzhiyun 	if (v) {
516*4882a593Smuzhiyun 		rval = xfs_dir2_block_replace(args);
517*4882a593Smuzhiyun 		goto out_free;
518*4882a593Smuzhiyun 	}
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	rval = xfs_dir2_isleaf(args, &v);
521*4882a593Smuzhiyun 	if (rval)
522*4882a593Smuzhiyun 		goto out_free;
523*4882a593Smuzhiyun 	if (v)
524*4882a593Smuzhiyun 		rval = xfs_dir2_leaf_replace(args);
525*4882a593Smuzhiyun 	else
526*4882a593Smuzhiyun 		rval = xfs_dir2_node_replace(args);
527*4882a593Smuzhiyun out_free:
528*4882a593Smuzhiyun 	kmem_free(args);
529*4882a593Smuzhiyun 	return rval;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun /*
533*4882a593Smuzhiyun  * See if this entry can be added to the directory without allocating space.
534*4882a593Smuzhiyun  */
535*4882a593Smuzhiyun int
xfs_dir_canenter(xfs_trans_t * tp,xfs_inode_t * dp,struct xfs_name * name)536*4882a593Smuzhiyun xfs_dir_canenter(
537*4882a593Smuzhiyun 	xfs_trans_t	*tp,
538*4882a593Smuzhiyun 	xfs_inode_t	*dp,
539*4882a593Smuzhiyun 	struct xfs_name	*name)		/* name of entry to add */
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun 	return xfs_dir_createname(tp, dp, name, 0, 0);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun /*
545*4882a593Smuzhiyun  * Utility routines.
546*4882a593Smuzhiyun  */
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun /*
549*4882a593Smuzhiyun  * Add a block to the directory.
550*4882a593Smuzhiyun  *
551*4882a593Smuzhiyun  * This routine is for data and free blocks, not leaf/node blocks which are
552*4882a593Smuzhiyun  * handled by xfs_da_grow_inode.
553*4882a593Smuzhiyun  */
554*4882a593Smuzhiyun int
xfs_dir2_grow_inode(struct xfs_da_args * args,int space,xfs_dir2_db_t * dbp)555*4882a593Smuzhiyun xfs_dir2_grow_inode(
556*4882a593Smuzhiyun 	struct xfs_da_args	*args,
557*4882a593Smuzhiyun 	int			space,	/* v2 dir's space XFS_DIR2_xxx_SPACE */
558*4882a593Smuzhiyun 	xfs_dir2_db_t		*dbp)	/* out: block number added */
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	struct xfs_inode	*dp = args->dp;
561*4882a593Smuzhiyun 	struct xfs_mount	*mp = dp->i_mount;
562*4882a593Smuzhiyun 	xfs_fileoff_t		bno;	/* directory offset of new block */
563*4882a593Smuzhiyun 	int			count;	/* count of filesystem blocks */
564*4882a593Smuzhiyun 	int			error;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	trace_xfs_dir2_grow_inode(args, space);
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	/*
569*4882a593Smuzhiyun 	 * Set lowest possible block in the space requested.
570*4882a593Smuzhiyun 	 */
571*4882a593Smuzhiyun 	bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
572*4882a593Smuzhiyun 	count = args->geo->fsbcount;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	error = xfs_da_grow_inode_int(args, &bno, count);
575*4882a593Smuzhiyun 	if (error)
576*4882a593Smuzhiyun 		return error;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	*dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	/*
581*4882a593Smuzhiyun 	 * Update file's size if this is the data space and it grew.
582*4882a593Smuzhiyun 	 */
583*4882a593Smuzhiyun 	if (space == XFS_DIR2_DATA_SPACE) {
584*4882a593Smuzhiyun 		xfs_fsize_t	size;		/* directory file (data) size */
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 		size = XFS_FSB_TO_B(mp, bno + count);
587*4882a593Smuzhiyun 		if (size > dp->i_d.di_size) {
588*4882a593Smuzhiyun 			dp->i_d.di_size = size;
589*4882a593Smuzhiyun 			xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
590*4882a593Smuzhiyun 		}
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun 	return 0;
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun /*
596*4882a593Smuzhiyun  * See if the directory is a single-block form directory.
597*4882a593Smuzhiyun  */
598*4882a593Smuzhiyun int
xfs_dir2_isblock(struct xfs_da_args * args,int * vp)599*4882a593Smuzhiyun xfs_dir2_isblock(
600*4882a593Smuzhiyun 	struct xfs_da_args	*args,
601*4882a593Smuzhiyun 	int			*vp)	/* out: 1 is block, 0 is not block */
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun 	xfs_fileoff_t		last;	/* last file offset */
604*4882a593Smuzhiyun 	int			rval;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
607*4882a593Smuzhiyun 		return rval;
608*4882a593Smuzhiyun 	rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
609*4882a593Smuzhiyun 	if (XFS_IS_CORRUPT(args->dp->i_mount,
610*4882a593Smuzhiyun 			   rval != 0 &&
611*4882a593Smuzhiyun 			   args->dp->i_d.di_size != args->geo->blksize))
612*4882a593Smuzhiyun 		return -EFSCORRUPTED;
613*4882a593Smuzhiyun 	*vp = rval;
614*4882a593Smuzhiyun 	return 0;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun /*
618*4882a593Smuzhiyun  * See if the directory is a single-leaf form directory.
619*4882a593Smuzhiyun  */
620*4882a593Smuzhiyun int
xfs_dir2_isleaf(struct xfs_da_args * args,int * vp)621*4882a593Smuzhiyun xfs_dir2_isleaf(
622*4882a593Smuzhiyun 	struct xfs_da_args	*args,
623*4882a593Smuzhiyun 	int			*vp)	/* out: 1 is block, 0 is not block */
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun 	xfs_fileoff_t		last;	/* last file offset */
626*4882a593Smuzhiyun 	int			rval;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
629*4882a593Smuzhiyun 		return rval;
630*4882a593Smuzhiyun 	*vp = last == args->geo->leafblk + args->geo->fsbcount;
631*4882a593Smuzhiyun 	return 0;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun /*
635*4882a593Smuzhiyun  * Remove the given block from the directory.
636*4882a593Smuzhiyun  * This routine is used for data and free blocks, leaf/node are done
637*4882a593Smuzhiyun  * by xfs_da_shrink_inode.
638*4882a593Smuzhiyun  */
639*4882a593Smuzhiyun int
xfs_dir2_shrink_inode(struct xfs_da_args * args,xfs_dir2_db_t db,struct xfs_buf * bp)640*4882a593Smuzhiyun xfs_dir2_shrink_inode(
641*4882a593Smuzhiyun 	struct xfs_da_args	*args,
642*4882a593Smuzhiyun 	xfs_dir2_db_t		db,
643*4882a593Smuzhiyun 	struct xfs_buf		*bp)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun 	xfs_fileoff_t		bno;		/* directory file offset */
646*4882a593Smuzhiyun 	xfs_dablk_t		da;		/* directory file offset */
647*4882a593Smuzhiyun 	int			done;		/* bunmap is finished */
648*4882a593Smuzhiyun 	struct xfs_inode	*dp;
649*4882a593Smuzhiyun 	int			error;
650*4882a593Smuzhiyun 	struct xfs_mount	*mp;
651*4882a593Smuzhiyun 	struct xfs_trans	*tp;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	trace_xfs_dir2_shrink_inode(args, db);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	dp = args->dp;
656*4882a593Smuzhiyun 	mp = dp->i_mount;
657*4882a593Smuzhiyun 	tp = args->trans;
658*4882a593Smuzhiyun 	da = xfs_dir2_db_to_da(args->geo, db);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	/* Unmap the fsblock(s). */
661*4882a593Smuzhiyun 	error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, &done);
662*4882a593Smuzhiyun 	if (error) {
663*4882a593Smuzhiyun 		/*
664*4882a593Smuzhiyun 		 * ENOSPC actually can happen if we're in a removename with no
665*4882a593Smuzhiyun 		 * space reservation, and the resulting block removal would
666*4882a593Smuzhiyun 		 * cause a bmap btree split or conversion from extents to btree.
667*4882a593Smuzhiyun 		 * This can only happen for un-fragmented directory blocks,
668*4882a593Smuzhiyun 		 * since you need to be punching out the middle of an extent.
669*4882a593Smuzhiyun 		 * In this case we need to leave the block in the file, and not
670*4882a593Smuzhiyun 		 * binval it.  So the block has to be in a consistent empty
671*4882a593Smuzhiyun 		 * state and appropriately logged.  We don't free up the buffer,
672*4882a593Smuzhiyun 		 * the caller can tell it hasn't happened since it got an error
673*4882a593Smuzhiyun 		 * back.
674*4882a593Smuzhiyun 		 */
675*4882a593Smuzhiyun 		return error;
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 	ASSERT(done);
678*4882a593Smuzhiyun 	/*
679*4882a593Smuzhiyun 	 * Invalidate the buffer from the transaction.
680*4882a593Smuzhiyun 	 */
681*4882a593Smuzhiyun 	xfs_trans_binval(tp, bp);
682*4882a593Smuzhiyun 	/*
683*4882a593Smuzhiyun 	 * If it's not a data block, we're done.
684*4882a593Smuzhiyun 	 */
685*4882a593Smuzhiyun 	if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
686*4882a593Smuzhiyun 		return 0;
687*4882a593Smuzhiyun 	/*
688*4882a593Smuzhiyun 	 * If the block isn't the last one in the directory, we're done.
689*4882a593Smuzhiyun 	 */
690*4882a593Smuzhiyun 	if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))
691*4882a593Smuzhiyun 		return 0;
692*4882a593Smuzhiyun 	bno = da;
693*4882a593Smuzhiyun 	if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
694*4882a593Smuzhiyun 		/*
695*4882a593Smuzhiyun 		 * This can't really happen unless there's kernel corruption.
696*4882a593Smuzhiyun 		 */
697*4882a593Smuzhiyun 		return error;
698*4882a593Smuzhiyun 	}
699*4882a593Smuzhiyun 	if (db == args->geo->datablk)
700*4882a593Smuzhiyun 		ASSERT(bno == 0);
701*4882a593Smuzhiyun 	else
702*4882a593Smuzhiyun 		ASSERT(bno > 0);
703*4882a593Smuzhiyun 	/*
704*4882a593Smuzhiyun 	 * Set the size to the new last block.
705*4882a593Smuzhiyun 	 */
706*4882a593Smuzhiyun 	dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
707*4882a593Smuzhiyun 	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
708*4882a593Smuzhiyun 	return 0;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun /* Returns true if the directory entry name is valid. */
712*4882a593Smuzhiyun bool
xfs_dir2_namecheck(const void * name,size_t length)713*4882a593Smuzhiyun xfs_dir2_namecheck(
714*4882a593Smuzhiyun 	const void	*name,
715*4882a593Smuzhiyun 	size_t		length)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun 	/*
718*4882a593Smuzhiyun 	 * MAXNAMELEN includes the trailing null, but (name/length) leave it
719*4882a593Smuzhiyun 	 * out, so use >= for the length check.
720*4882a593Smuzhiyun 	 */
721*4882a593Smuzhiyun 	if (length >= MAXNAMELEN)
722*4882a593Smuzhiyun 		return false;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	/* There shouldn't be any slashes or nulls here */
725*4882a593Smuzhiyun 	return !memchr(name, '/', length) && !memchr(name, 0, length);
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun xfs_dahash_t
xfs_dir2_hashname(struct xfs_mount * mp,struct xfs_name * name)729*4882a593Smuzhiyun xfs_dir2_hashname(
730*4882a593Smuzhiyun 	struct xfs_mount	*mp,
731*4882a593Smuzhiyun 	struct xfs_name		*name)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun 	if (unlikely(xfs_sb_version_hasasciici(&mp->m_sb)))
734*4882a593Smuzhiyun 		return xfs_ascii_ci_hashname(name);
735*4882a593Smuzhiyun 	return xfs_da_hashname(name->name, name->len);
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun enum xfs_dacmp
xfs_dir2_compname(struct xfs_da_args * args,const unsigned char * name,int len)739*4882a593Smuzhiyun xfs_dir2_compname(
740*4882a593Smuzhiyun 	struct xfs_da_args	*args,
741*4882a593Smuzhiyun 	const unsigned char	*name,
742*4882a593Smuzhiyun 	int			len)
743*4882a593Smuzhiyun {
744*4882a593Smuzhiyun 	if (unlikely(xfs_sb_version_hasasciici(&args->dp->i_mount->m_sb)))
745*4882a593Smuzhiyun 		return xfs_ascii_ci_compname(args, name, len);
746*4882a593Smuzhiyun 	return xfs_da_compname(args, name, len);
747*4882a593Smuzhiyun }
748