cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xfs_dir2.c (17956B)


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