brintos

brintos / linux-shallow public Read only

0
0
Text · 34.7 KiB · 2024682 Raw
1414 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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#include "xfs_health.h"22#include "xfs_bmap_btree.h"23#include "xfs_trans_space.h"24#include "xfs_parent.h"25#include "xfs_ag.h"26#include "xfs_ialloc.h"27 28const struct xfs_name xfs_name_dotdot = {29	.name	= (const unsigned char *)"..",30	.len	= 2,31	.type	= XFS_DIR3_FT_DIR,32};33 34const struct xfs_name xfs_name_dot = {35	.name	= (const unsigned char *)".",36	.len	= 1,37	.type	= XFS_DIR3_FT_DIR,38};39 40/*41 * Convert inode mode to directory entry filetype42 */43unsigned char44xfs_mode_to_ftype(45	int		mode)46{47	switch (mode & S_IFMT) {48	case S_IFREG:49		return XFS_DIR3_FT_REG_FILE;50	case S_IFDIR:51		return XFS_DIR3_FT_DIR;52	case S_IFCHR:53		return XFS_DIR3_FT_CHRDEV;54	case S_IFBLK:55		return XFS_DIR3_FT_BLKDEV;56	case S_IFIFO:57		return XFS_DIR3_FT_FIFO;58	case S_IFSOCK:59		return XFS_DIR3_FT_SOCK;60	case S_IFLNK:61		return XFS_DIR3_FT_SYMLINK;62	default:63		return XFS_DIR3_FT_UNKNOWN;64	}65}66 67/*68 * ASCII case-insensitive (ie. A-Z) support for directories that was69 * used in IRIX.70 */71xfs_dahash_t72xfs_ascii_ci_hashname(73	const struct xfs_name	*name)74{75	xfs_dahash_t		hash;76	int			i;77 78	for (i = 0, hash = 0; i < name->len; i++)79		hash = xfs_ascii_ci_xfrm(name->name[i]) ^ rol32(hash, 7);80 81	return hash;82}83 84enum xfs_dacmp85xfs_ascii_ci_compname(86	struct xfs_da_args	*args,87	const unsigned char	*name,88	int			len)89{90	enum xfs_dacmp		result;91	int			i;92 93	if (args->namelen != len)94		return XFS_CMP_DIFFERENT;95 96	result = XFS_CMP_EXACT;97	for (i = 0; i < len; i++) {98		if (args->name[i] == name[i])99			continue;100		if (xfs_ascii_ci_xfrm(args->name[i]) !=101		    xfs_ascii_ci_xfrm(name[i]))102			return XFS_CMP_DIFFERENT;103		result = XFS_CMP_CASE;104	}105 106	return result;107}108 109int110xfs_da_mount(111	struct xfs_mount	*mp)112{113	struct xfs_da_geometry	*dageo;114 115 116	ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);117	ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE);118 119	mp->m_dir_geo = kzalloc(sizeof(struct xfs_da_geometry),120				GFP_KERNEL | __GFP_RETRY_MAYFAIL);121	mp->m_attr_geo = kzalloc(sizeof(struct xfs_da_geometry),122				GFP_KERNEL | __GFP_RETRY_MAYFAIL);123	if (!mp->m_dir_geo || !mp->m_attr_geo) {124		kfree(mp->m_dir_geo);125		kfree(mp->m_attr_geo);126		return -ENOMEM;127	}128 129	/* set up directory geometry */130	dageo = mp->m_dir_geo;131	dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog;132	dageo->fsblog = mp->m_sb.sb_blocklog;133	dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb);134	dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;135	if (xfs_has_crc(mp)) {136		dageo->node_hdr_size = sizeof(struct xfs_da3_node_hdr);137		dageo->leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr);138		dageo->free_hdr_size = sizeof(struct xfs_dir3_free_hdr);139		dageo->data_entry_offset =140				sizeof(struct xfs_dir3_data_hdr);141	} else {142		dageo->node_hdr_size = sizeof(struct xfs_da_node_hdr);143		dageo->leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr);144		dageo->free_hdr_size = sizeof(struct xfs_dir2_free_hdr);145		dageo->data_entry_offset =146				sizeof(struct xfs_dir2_data_hdr);147	}148	dageo->leaf_max_ents = (dageo->blksize - dageo->leaf_hdr_size) /149			sizeof(struct xfs_dir2_leaf_entry);150	dageo->free_max_bests = (dageo->blksize - dageo->free_hdr_size) /151			sizeof(xfs_dir2_data_off_t);152 153	dageo->data_first_offset = dageo->data_entry_offset +154			xfs_dir2_data_entsize(mp, 1) +155			xfs_dir2_data_entsize(mp, 2);156 157	/*158	 * Now we've set up the block conversion variables, we can calculate the159	 * segment block constants using the geometry structure.160	 */161	dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);162	dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);163	dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);164	dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /165				(uint)sizeof(xfs_da_node_entry_t);166	dageo->max_extents = (XFS_DIR2_MAX_SPACES * XFS_DIR2_SPACE_SIZE) >>167					mp->m_sb.sb_blocklog;168	dageo->magicpct = (dageo->blksize * 37) / 100;169 170	/* set up attribute geometry - single fsb only */171	dageo = mp->m_attr_geo;172	dageo->blklog = mp->m_sb.sb_blocklog;173	dageo->fsblog = mp->m_sb.sb_blocklog;174	dageo->blksize = 1 << dageo->blklog;175	dageo->fsbcount = 1;176	dageo->node_hdr_size = mp->m_dir_geo->node_hdr_size;177	dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /178				(uint)sizeof(xfs_da_node_entry_t);179 180	if (xfs_has_large_extent_counts(mp))181		dageo->max_extents = XFS_MAX_EXTCNT_ATTR_FORK_LARGE;182	else183		dageo->max_extents = XFS_MAX_EXTCNT_ATTR_FORK_SMALL;184 185	dageo->magicpct = (dageo->blksize * 37) / 100;186	return 0;187}188 189void190xfs_da_unmount(191	struct xfs_mount	*mp)192{193	kfree(mp->m_dir_geo);194	kfree(mp->m_attr_geo);195}196 197/*198 * Return 1 if directory contains only "." and "..".199 */200int201xfs_dir_isempty(202	xfs_inode_t	*dp)203{204	xfs_dir2_sf_hdr_t	*sfp;205 206	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));207	if (dp->i_disk_size == 0)	/* might happen during shutdown. */208		return 1;209	if (dp->i_disk_size > xfs_inode_data_fork_size(dp))210		return 0;211	sfp = dp->i_df.if_data;212	return !sfp->count;213}214 215/*216 * Validate a given inode number.217 */218int219xfs_dir_ino_validate(220	xfs_mount_t	*mp,221	xfs_ino_t	ino)222{223	bool		ino_ok = xfs_verify_dir_ino(mp, ino);224 225	if (XFS_IS_CORRUPT(mp, !ino_ok) ||226	    XFS_TEST_ERROR(false, mp, XFS_ERRTAG_DIR_INO_VALIDATE)) {227		xfs_warn(mp, "Invalid inode number 0x%Lx",228				(unsigned long long) ino);229		return -EFSCORRUPTED;230	}231	return 0;232}233 234/*235 * Initialize a directory with its "." and ".." entries.236 */237int238xfs_dir_init(239	xfs_trans_t	*tp,240	xfs_inode_t	*dp,241	xfs_inode_t	*pdp)242{243	struct xfs_da_args *args;244	int		error;245 246	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));247	error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino);248	if (error)249		return error;250 251	args = kzalloc(sizeof(*args), GFP_KERNEL | __GFP_NOFAIL);252	if (!args)253		return -ENOMEM;254 255	args->geo = dp->i_mount->m_dir_geo;256	args->dp = dp;257	args->trans = tp;258	args->owner = dp->i_ino;259	error = xfs_dir2_sf_create(args, pdp->i_ino);260	kfree(args);261	return error;262}263 264enum xfs_dir2_fmt265xfs_dir2_format(266	struct xfs_da_args	*args,267	int			*error)268{269	struct xfs_inode	*dp = args->dp;270	struct xfs_mount	*mp = dp->i_mount;271	struct xfs_da_geometry	*geo = mp->m_dir_geo;272	xfs_fileoff_t		eof;273 274	xfs_assert_ilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);275 276	*error = 0;277	if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)278		return XFS_DIR2_FMT_SF;279 280	*error = xfs_bmap_last_offset(dp, &eof, XFS_DATA_FORK);281	if (*error)282		return XFS_DIR2_FMT_ERROR;283 284	if (eof == XFS_B_TO_FSB(mp, geo->blksize)) {285		if (XFS_IS_CORRUPT(mp, dp->i_disk_size != geo->blksize)) {286			xfs_da_mark_sick(args);287			*error = -EFSCORRUPTED;288			return XFS_DIR2_FMT_ERROR;289		}290		return XFS_DIR2_FMT_BLOCK;291	}292	if (eof == geo->leafblk + geo->fsbcount)293		return XFS_DIR2_FMT_LEAF;294	return XFS_DIR2_FMT_NODE;295}296 297int298xfs_dir_createname_args(299	struct xfs_da_args	*args)300{301	int			error;302 303	if (!args->inumber)304		args->op_flags |= XFS_DA_OP_JUSTCHECK;305 306	switch (xfs_dir2_format(args, &error)) {307	case XFS_DIR2_FMT_SF:308		return xfs_dir2_sf_addname(args);309	case XFS_DIR2_FMT_BLOCK:310		return xfs_dir2_block_addname(args);311	case XFS_DIR2_FMT_LEAF:312		return xfs_dir2_leaf_addname(args);313	case XFS_DIR2_FMT_NODE:314		return xfs_dir2_node_addname(args);315	default:316		return error;317	}318}319 320/*321 * Enter a name in a directory, or check for available space.322 * If inum is 0, only the available space test is performed.323 */324int325xfs_dir_createname(326	struct xfs_trans	*tp,327	struct xfs_inode	*dp,328	const struct xfs_name	*name,329	xfs_ino_t		inum,		/* new entry inode number */330	xfs_extlen_t		total)		/* bmap's total block count */331{332	struct xfs_da_args	*args;333	int			rval;334 335	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));336 337	if (inum) {338		rval = xfs_dir_ino_validate(tp->t_mountp, inum);339		if (rval)340			return rval;341		XFS_STATS_INC(dp->i_mount, xs_dir_create);342	}343 344	args = kzalloc(sizeof(*args), GFP_KERNEL | __GFP_NOFAIL);345	if (!args)346		return -ENOMEM;347 348	args->geo = dp->i_mount->m_dir_geo;349	args->name = name->name;350	args->namelen = name->len;351	args->filetype = name->type;352	args->hashval = xfs_dir2_hashname(dp->i_mount, name);353	args->inumber = inum;354	args->dp = dp;355	args->total = total;356	args->whichfork = XFS_DATA_FORK;357	args->trans = tp;358	args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;359	args->owner = dp->i_ino;360 361	rval = xfs_dir_createname_args(args);362	kfree(args);363	return rval;364}365 366/*367 * If doing a CI lookup and case-insensitive match, dup actual name into368 * args.value. Return EEXIST for success (ie. name found) or an error.369 */370int371xfs_dir_cilookup_result(372	struct xfs_da_args *args,373	const unsigned char *name,374	int		len)375{376	if (args->cmpresult == XFS_CMP_DIFFERENT)377		return -ENOENT;378	if (args->cmpresult != XFS_CMP_CASE ||379					!(args->op_flags & XFS_DA_OP_CILOOKUP))380		return -EEXIST;381 382	args->value = kmalloc(len,383			GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_RETRY_MAYFAIL);384	if (!args->value)385		return -ENOMEM;386 387	memcpy(args->value, name, len);388	args->valuelen = len;389	return -EEXIST;390}391 392int393xfs_dir_lookup_args(394	struct xfs_da_args	*args)395{396	int			error;397 398	switch (xfs_dir2_format(args, &error)) {399	case XFS_DIR2_FMT_SF:400		error = xfs_dir2_sf_lookup(args);401		break;402	case XFS_DIR2_FMT_BLOCK:403		error = xfs_dir2_block_lookup(args);404		break;405	case XFS_DIR2_FMT_LEAF:406		error = xfs_dir2_leaf_lookup(args);407		break;408	case XFS_DIR2_FMT_NODE:409		error = xfs_dir2_node_lookup(args);410		break;411	default:412		break;413	}414 415	if (error != -EEXIST)416		return error;417	return 0;418}419 420/*421 * Lookup a name in a directory, give back the inode number.422 * If ci_name is not NULL, returns the actual name in ci_name if it differs423 * to name, or ci_name->name is set to NULL for an exact match.424 */425 426int427xfs_dir_lookup(428	struct xfs_trans	*tp,429	struct xfs_inode	*dp,430	const struct xfs_name	*name,431	xfs_ino_t		*inum,	  /* out: inode number */432	struct xfs_name		*ci_name) /* out: actual name if CI match */433{434	struct xfs_da_args	*args;435	int			rval;436	int			lock_mode;437 438	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));439	XFS_STATS_INC(dp->i_mount, xs_dir_lookup);440 441	args = kzalloc(sizeof(*args),442			GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL);443	args->geo = dp->i_mount->m_dir_geo;444	args->name = name->name;445	args->namelen = name->len;446	args->filetype = name->type;447	args->hashval = xfs_dir2_hashname(dp->i_mount, name);448	args->dp = dp;449	args->whichfork = XFS_DATA_FORK;450	args->trans = tp;451	args->op_flags = XFS_DA_OP_OKNOENT;452	args->owner = dp->i_ino;453	if (ci_name)454		args->op_flags |= XFS_DA_OP_CILOOKUP;455 456	lock_mode = xfs_ilock_data_map_shared(dp);457	rval = xfs_dir_lookup_args(args);458	if (!rval) {459		*inum = args->inumber;460		if (ci_name) {461			ci_name->name = args->value;462			ci_name->len = args->valuelen;463		}464	}465	xfs_iunlock(dp, lock_mode);466	kfree(args);467	return rval;468}469 470int471xfs_dir_removename_args(472	struct xfs_da_args	*args)473{474	int			error;475 476	switch (xfs_dir2_format(args, &error)) {477	case XFS_DIR2_FMT_SF:478		return xfs_dir2_sf_removename(args);479	case XFS_DIR2_FMT_BLOCK:480		return xfs_dir2_block_removename(args);481	case XFS_DIR2_FMT_LEAF:482		return xfs_dir2_leaf_removename(args);483	case XFS_DIR2_FMT_NODE:484		return xfs_dir2_node_removename(args);485	default:486		return error;487	}488}489 490/*491 * Remove an entry from a directory.492 */493int494xfs_dir_removename(495	struct xfs_trans	*tp,496	struct xfs_inode	*dp,497	const struct xfs_name	*name,498	xfs_ino_t		ino,499	xfs_extlen_t		total)		/* bmap's total block count */500{501	struct xfs_da_args	*args;502	int			rval;503 504	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));505	XFS_STATS_INC(dp->i_mount, xs_dir_remove);506 507	args = kzalloc(sizeof(*args), GFP_KERNEL | __GFP_NOFAIL);508	if (!args)509		return -ENOMEM;510 511	args->geo = dp->i_mount->m_dir_geo;512	args->name = name->name;513	args->namelen = name->len;514	args->filetype = name->type;515	args->hashval = xfs_dir2_hashname(dp->i_mount, name);516	args->inumber = ino;517	args->dp = dp;518	args->total = total;519	args->whichfork = XFS_DATA_FORK;520	args->trans = tp;521	args->owner = dp->i_ino;522	rval = xfs_dir_removename_args(args);523	kfree(args);524	return rval;525}526 527int528xfs_dir_replace_args(529	struct xfs_da_args	*args)530{531	int			error;532 533	switch (xfs_dir2_format(args, &error)) {534	case XFS_DIR2_FMT_SF:535		return xfs_dir2_sf_replace(args);536	case XFS_DIR2_FMT_BLOCK:537		return xfs_dir2_block_replace(args);538	case XFS_DIR2_FMT_LEAF:539		return xfs_dir2_leaf_replace(args);540	case XFS_DIR2_FMT_NODE:541		return xfs_dir2_node_replace(args);542	default:543		return error;544	}545}546 547/*548 * Replace the inode number of a directory entry.549 */550int551xfs_dir_replace(552	struct xfs_trans	*tp,553	struct xfs_inode	*dp,554	const struct xfs_name	*name,		/* name of entry to replace */555	xfs_ino_t		inum,		/* new inode number */556	xfs_extlen_t		total)		/* bmap's total block count */557{558	struct xfs_da_args	*args;559	int			rval;560 561	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));562 563	rval = xfs_dir_ino_validate(tp->t_mountp, inum);564	if (rval)565		return rval;566 567	args = kzalloc(sizeof(*args), GFP_KERNEL | __GFP_NOFAIL);568	if (!args)569		return -ENOMEM;570 571	args->geo = dp->i_mount->m_dir_geo;572	args->name = name->name;573	args->namelen = name->len;574	args->filetype = name->type;575	args->hashval = xfs_dir2_hashname(dp->i_mount, name);576	args->inumber = inum;577	args->dp = dp;578	args->total = total;579	args->whichfork = XFS_DATA_FORK;580	args->trans = tp;581	args->owner = dp->i_ino;582	rval = xfs_dir_replace_args(args);583	kfree(args);584	return rval;585}586 587/*588 * See if this entry can be added to the directory without allocating space.589 */590int591xfs_dir_canenter(592	struct xfs_trans	*tp,593	struct xfs_inode	*dp,594	const struct xfs_name	*name)		/* name of entry to add */595{596	return xfs_dir_createname(tp, dp, name, 0, 0);597}598 599/*600 * Utility routines.601 */602 603/*604 * Add a block to the directory.605 *606 * This routine is for data and free blocks, not leaf/node blocks which are607 * handled by xfs_da_grow_inode.608 */609int610xfs_dir2_grow_inode(611	struct xfs_da_args	*args,612	int			space,	/* v2 dir's space XFS_DIR2_xxx_SPACE */613	xfs_dir2_db_t		*dbp)	/* out: block number added */614{615	struct xfs_inode	*dp = args->dp;616	struct xfs_mount	*mp = dp->i_mount;617	xfs_fileoff_t		bno;	/* directory offset of new block */618	int			count;	/* count of filesystem blocks */619	int			error;620 621	trace_xfs_dir2_grow_inode(args, space);622 623	/*624	 * Set lowest possible block in the space requested.625	 */626	bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);627	count = args->geo->fsbcount;628 629	error = xfs_da_grow_inode_int(args, &bno, count);630	if (error)631		return error;632 633	*dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);634 635	/*636	 * Update file's size if this is the data space and it grew.637	 */638	if (space == XFS_DIR2_DATA_SPACE) {639		xfs_fsize_t	size;		/* directory file (data) size */640 641		size = XFS_FSB_TO_B(mp, bno + count);642		if (size > dp->i_disk_size) {643			dp->i_disk_size = size;644			xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);645		}646	}647	return 0;648}649 650/*651 * Remove the given block from the directory.652 * This routine is used for data and free blocks, leaf/node are done653 * by xfs_da_shrink_inode.654 */655int656xfs_dir2_shrink_inode(657	struct xfs_da_args	*args,658	xfs_dir2_db_t		db,659	struct xfs_buf		*bp)660{661	xfs_fileoff_t		bno;		/* directory file offset */662	xfs_dablk_t		da;		/* directory file offset */663	int			done;		/* bunmap is finished */664	struct xfs_inode	*dp;665	int			error;666	struct xfs_mount	*mp;667	struct xfs_trans	*tp;668 669	trace_xfs_dir2_shrink_inode(args, db);670 671	dp = args->dp;672	mp = dp->i_mount;673	tp = args->trans;674	da = xfs_dir2_db_to_da(args->geo, db);675 676	/* Unmap the fsblock(s). */677	error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, &done);678	if (error) {679		/*680		 * ENOSPC actually can happen if we're in a removename with no681		 * space reservation, and the resulting block removal would682		 * cause a bmap btree split or conversion from extents to btree.683		 * This can only happen for un-fragmented directory blocks,684		 * since you need to be punching out the middle of an extent.685		 * In this case we need to leave the block in the file, and not686		 * binval it.  So the block has to be in a consistent empty687		 * state and appropriately logged.  We don't free up the buffer,688		 * the caller can tell it hasn't happened since it got an error689		 * back.690		 */691		return error;692	}693	ASSERT(done);694	/*695	 * Invalidate the buffer from the transaction.696	 */697	xfs_trans_binval(tp, bp);698	/*699	 * If it's not a data block, we're done.700	 */701	if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))702		return 0;703	/*704	 * If the block isn't the last one in the directory, we're done.705	 */706	if (dp->i_disk_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))707		return 0;708	bno = da;709	if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {710		/*711		 * This can't really happen unless there's kernel corruption.712		 */713		return error;714	}715	if (db == args->geo->datablk)716		ASSERT(bno == 0);717	else718		ASSERT(bno > 0);719	/*720	 * Set the size to the new last block.721	 */722	dp->i_disk_size = XFS_FSB_TO_B(mp, bno);723	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);724	return 0;725}726 727/* Returns true if the directory entry name is valid. */728bool729xfs_dir2_namecheck(730	const void	*name,731	size_t		length)732{733	/*734	 * MAXNAMELEN includes the trailing null, but (name/length) leave it735	 * out, so use >= for the length check.736	 */737	if (length >= MAXNAMELEN)738		return false;739 740	/* There shouldn't be any slashes or nulls here */741	return !memchr(name, '/', length) && !memchr(name, 0, length);742}743 744xfs_dahash_t745xfs_dir2_hashname(746	struct xfs_mount	*mp,747	const struct xfs_name	*name)748{749	if (unlikely(xfs_has_asciici(mp)))750		return xfs_ascii_ci_hashname(name);751	return xfs_da_hashname(name->name, name->len);752}753 754enum xfs_dacmp755xfs_dir2_compname(756	struct xfs_da_args	*args,757	const unsigned char	*name,758	int			len)759{760	if (unlikely(xfs_has_asciici(args->dp->i_mount)))761		return xfs_ascii_ci_compname(args, name, len);762	return xfs_da_compname(args, name, len);763}764 765#ifdef CONFIG_XFS_LIVE_HOOKS766/*767 * Use a static key here to reduce the overhead of directory live update hooks.768 * If the compiler supports jump labels, the static branch will be replaced by769 * a nop sled when there are no hook users.  Online fsck is currently the only770 * caller, so this is a reasonable tradeoff.771 *772 * Note: Patching the kernel code requires taking the cpu hotplug lock.  Other773 * parts of the kernel allocate memory with that lock held, which means that774 * XFS callers cannot hold any locks that might be used by memory reclaim or775 * writeback when calling the static_branch_{inc,dec} functions.776 */777DEFINE_STATIC_XFS_HOOK_SWITCH(xfs_dir_hooks_switch);778 779void780xfs_dir_hook_disable(void)781{782	xfs_hooks_switch_off(&xfs_dir_hooks_switch);783}784 785void786xfs_dir_hook_enable(void)787{788	xfs_hooks_switch_on(&xfs_dir_hooks_switch);789}790 791/* Call hooks for a directory update relating to a child dirent update. */792inline void793xfs_dir_update_hook(794	struct xfs_inode		*dp,795	struct xfs_inode		*ip,796	int				delta,797	const struct xfs_name		*name)798{799	if (xfs_hooks_switched_on(&xfs_dir_hooks_switch)) {800		struct xfs_dir_update_params	p = {801			.dp		= dp,802			.ip		= ip,803			.delta		= delta,804			.name		= name,805		};806		struct xfs_mount	*mp = ip->i_mount;807 808		xfs_hooks_call(&mp->m_dir_update_hooks, 0, &p);809	}810}811 812/* Call the specified function during a directory update. */813int814xfs_dir_hook_add(815	struct xfs_mount	*mp,816	struct xfs_dir_hook	*hook)817{818	return xfs_hooks_add(&mp->m_dir_update_hooks, &hook->dirent_hook);819}820 821/* Stop calling the specified function during a directory update. */822void823xfs_dir_hook_del(824	struct xfs_mount	*mp,825	struct xfs_dir_hook	*hook)826{827	xfs_hooks_del(&mp->m_dir_update_hooks, &hook->dirent_hook);828}829 830/* Configure directory update hook functions. */831void832xfs_dir_hook_setup(833	struct xfs_dir_hook	*hook,834	notifier_fn_t		mod_fn)835{836	xfs_hook_setup(&hook->dirent_hook, mod_fn);837}838#endif /* CONFIG_XFS_LIVE_HOOKS */839 840/*841 * Given a directory @dp, a newly allocated inode @ip, and a @name, link @ip842 * into @dp under the given @name.  If @ip is a directory, it will be843 * initialized.  Both inodes must have the ILOCK held and the transaction must844 * have sufficient blocks reserved.845 */846int847xfs_dir_create_child(848	struct xfs_trans	*tp,849	unsigned int		resblks,850	struct xfs_dir_update	*du)851{852	struct xfs_inode	*dp = du->dp;853	const struct xfs_name	*name = du->name;854	struct xfs_inode	*ip = du->ip;855	int			error;856 857	xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);858	xfs_assert_ilocked(dp, XFS_ILOCK_EXCL);859 860	error = xfs_dir_createname(tp, dp, name, ip->i_ino, resblks);861	if (error) {862		ASSERT(error != -ENOSPC);863		return error;864	}865 866	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);867	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);868 869	if (S_ISDIR(VFS_I(ip)->i_mode)) {870		error = xfs_dir_init(tp, ip, dp);871		if (error)872			return error;873 874		xfs_bumplink(tp, dp);875	}876 877	/*878	 * If we have parent pointers, we need to add the attribute containing879	 * the parent information now.880	 */881	if (du->ppargs) {882		error = xfs_parent_addname(tp, du->ppargs, dp, name, ip);883		if (error)884			return error;885	}886 887	xfs_dir_update_hook(dp, ip, 1, name);888	return 0;889}890 891/*892 * Given a directory @dp, an existing non-directory inode @ip, and a @name,893 * link @ip into @dp under the given @name.  Both inodes must have the ILOCK894 * held.895 */896int897xfs_dir_add_child(898	struct xfs_trans	*tp,899	unsigned int		resblks,900	struct xfs_dir_update	*du)901{902	struct xfs_inode	*dp = du->dp;903	const struct xfs_name	*name = du->name;904	struct xfs_inode	*ip = du->ip;905	struct xfs_mount	*mp = tp->t_mountp;906	int			error;907 908	xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);909	xfs_assert_ilocked(dp, XFS_ILOCK_EXCL);910	ASSERT(!S_ISDIR(VFS_I(ip)->i_mode));911 912	if (!resblks) {913		error = xfs_dir_canenter(tp, dp, name);914		if (error)915			return error;916	}917 918	/*919	 * Handle initial link state of O_TMPFILE inode920	 */921	if (VFS_I(ip)->i_nlink == 0) {922		struct xfs_perag	*pag;923 924		pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));925		error = xfs_iunlink_remove(tp, pag, ip);926		xfs_perag_put(pag);927		if (error)928			return error;929	}930 931	error = xfs_dir_createname(tp, dp, name, ip->i_ino, resblks);932	if (error)933		return error;934 935	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);936	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);937 938	xfs_bumplink(tp, ip);939 940	/*941	 * If we have parent pointers, we now need to add the parent record to942	 * the attribute fork of the inode. If this is the initial parent943	 * attribute, we need to create it correctly, otherwise we can just add944	 * the parent to the inode.945	 */946	if (du->ppargs) {947		error = xfs_parent_addname(tp, du->ppargs, dp, name, ip);948		if (error)949			return error;950	}951 952	xfs_dir_update_hook(dp, ip, 1, name);953	return 0;954}955 956/*957 * Given a directory @dp, a child @ip, and a @name, remove the (@name, @ip)958 * entry from the directory.  Both inodes must have the ILOCK held.959 */960int961xfs_dir_remove_child(962	struct xfs_trans	*tp,963	unsigned int		resblks,964	struct xfs_dir_update	*du)965{966	struct xfs_inode	*dp = du->dp;967	const struct xfs_name	*name = du->name;968	struct xfs_inode	*ip = du->ip;969	int			error;970 971	xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);972	xfs_assert_ilocked(dp, XFS_ILOCK_EXCL);973 974	/*975	 * If we're removing a directory perform some additional validation.976	 */977	if (S_ISDIR(VFS_I(ip)->i_mode)) {978		ASSERT(VFS_I(ip)->i_nlink >= 2);979		if (VFS_I(ip)->i_nlink != 2)980			return -ENOTEMPTY;981		if (!xfs_dir_isempty(ip))982			return -ENOTEMPTY;983 984		/* Drop the link from ip's "..".  */985		error = xfs_droplink(tp, dp);986		if (error)987			return error;988 989		/* Drop the "." link from ip to self.  */990		error = xfs_droplink(tp, ip);991		if (error)992			return error;993 994		/*995		 * Point the unlinked child directory's ".." entry to the root996		 * directory to eliminate back-references to inodes that may997		 * get freed before the child directory is closed.  If the fs998		 * gets shrunk, this can lead to dirent inode validation errors.999		 */1000		if (dp->i_ino != tp->t_mountp->m_sb.sb_rootino) {1001			error = xfs_dir_replace(tp, ip, &xfs_name_dotdot,1002					tp->t_mountp->m_sb.sb_rootino, 0);1003			if (error)1004				return error;1005		}1006	} else {1007		/*1008		 * When removing a non-directory we need to log the parent1009		 * inode here.  For a directory this is done implicitly1010		 * by the xfs_droplink call for the ".." entry.1011		 */1012		xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);1013	}1014	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);1015 1016	/* Drop the link from dp to ip. */1017	error = xfs_droplink(tp, ip);1018	if (error)1019		return error;1020 1021	error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks);1022	if (error) {1023		ASSERT(error != -ENOENT);1024		return error;1025	}1026 1027	/* Remove parent pointer. */1028	if (du->ppargs) {1029		error = xfs_parent_removename(tp, du->ppargs, dp, name, ip);1030		if (error)1031			return error;1032	}1033 1034	xfs_dir_update_hook(dp, ip, -1, name);1035	return 0;1036}1037 1038/*1039 * Exchange the entry (@name1, @ip1) in directory @dp1 with the entry (@name2,1040 * @ip2) in directory @dp2, and update '..' @ip1 and @ip2's entries as needed.1041 * @ip1 and @ip2 need not be of the same type.1042 *1043 * All inodes must have the ILOCK held, and both entries must already exist.1044 */1045int1046xfs_dir_exchange_children(1047	struct xfs_trans	*tp,1048	struct xfs_dir_update	*du1,1049	struct xfs_dir_update	*du2,1050	unsigned int		spaceres)1051{1052	struct xfs_inode	*dp1 = du1->dp;1053	const struct xfs_name	*name1 = du1->name;1054	struct xfs_inode	*ip1 = du1->ip;1055	struct xfs_inode	*dp2 = du2->dp;1056	const struct xfs_name	*name2 = du2->name;1057	struct xfs_inode	*ip2 = du2->ip;1058	int			ip1_flags = 0;1059	int			ip2_flags = 0;1060	int			dp2_flags = 0;1061	int			error;1062 1063	/* Swap inode number for dirent in first parent */1064	error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres);1065	if (error)1066		return error;1067 1068	/* Swap inode number for dirent in second parent */1069	error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, spaceres);1070	if (error)1071		return error;1072 1073	/*1074	 * If we're renaming one or more directories across different parents,1075	 * update the respective ".." entries (and link counts) to match the new1076	 * parents.1077	 */1078	if (dp1 != dp2) {1079		dp2_flags = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;1080 1081		if (S_ISDIR(VFS_I(ip2)->i_mode)) {1082			error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,1083						dp1->i_ino, spaceres);1084			if (error)1085				return error;1086 1087			/* transfer ip2 ".." reference to dp1 */1088			if (!S_ISDIR(VFS_I(ip1)->i_mode)) {1089				error = xfs_droplink(tp, dp2);1090				if (error)1091					return error;1092				xfs_bumplink(tp, dp1);1093			}1094 1095			/*1096			 * Although ip1 isn't changed here, userspace needs1097			 * to be warned about the change, so that applications1098			 * relying on it (like backup ones), will properly1099			 * notify the change1100			 */1101			ip1_flags |= XFS_ICHGTIME_CHG;1102			ip2_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;1103		}1104 1105		if (S_ISDIR(VFS_I(ip1)->i_mode)) {1106			error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,1107						dp2->i_ino, spaceres);1108			if (error)1109				return error;1110 1111			/* transfer ip1 ".." reference to dp2 */1112			if (!S_ISDIR(VFS_I(ip2)->i_mode)) {1113				error = xfs_droplink(tp, dp1);1114				if (error)1115					return error;1116				xfs_bumplink(tp, dp2);1117			}1118 1119			/*1120			 * Although ip2 isn't changed here, userspace needs1121			 * to be warned about the change, so that applications1122			 * relying on it (like backup ones), will properly1123			 * notify the change1124			 */1125			ip1_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;1126			ip2_flags |= XFS_ICHGTIME_CHG;1127		}1128	}1129 1130	if (ip1_flags) {1131		xfs_trans_ichgtime(tp, ip1, ip1_flags);1132		xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE);1133	}1134	if (ip2_flags) {1135		xfs_trans_ichgtime(tp, ip2, ip2_flags);1136		xfs_trans_log_inode(tp, ip2, XFS_ILOG_CORE);1137	}1138	if (dp2_flags) {1139		xfs_trans_ichgtime(tp, dp2, dp2_flags);1140		xfs_trans_log_inode(tp, dp2, XFS_ILOG_CORE);1141	}1142	xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);1143	xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE);1144 1145	/* Schedule parent pointer replacements */1146	if (du1->ppargs) {1147		error = xfs_parent_replacename(tp, du1->ppargs, dp1, name1,1148				dp2, name2, ip1);1149		if (error)1150			return error;1151	}1152 1153	if (du2->ppargs) {1154		error = xfs_parent_replacename(tp, du2->ppargs, dp2, name2,1155				dp1, name1, ip2);1156		if (error)1157			return error;1158	}1159 1160	/*1161	 * Inform our hook clients that we've finished an exchange operation as1162	 * follows: removed the source and target files from their directories;1163	 * added the target to the source directory; and added the source to1164	 * the target directory.  All inodes are locked, so it's ok to model a1165	 * rename this way so long as we say we deleted entries before we add1166	 * new ones.1167	 */1168	xfs_dir_update_hook(dp1, ip1, -1, name1);1169	xfs_dir_update_hook(dp2, ip2, -1, name2);1170	xfs_dir_update_hook(dp1, ip2, 1, name1);1171	xfs_dir_update_hook(dp2, ip1, 1, name2);1172	return 0;1173}1174 1175/*1176 * Given an entry (@src_name, @src_ip) in directory @src_dp, make the entry1177 * @target_name in directory @target_dp point to @src_ip and remove the1178 * original entry, cleaning up everything left behind.1179 *1180 * Cleanup involves dropping a link count on @target_ip, and either removing1181 * the (@src_name, @src_ip) entry from @src_dp or simply replacing the entry1182 * with (@src_name, @wip) if a whiteout inode @wip is supplied.1183 *1184 * All inodes must have the ILOCK held.  We assume that if @src_ip is a1185 * directory then its '..' doesn't already point to @target_dp, and that @wip1186 * is a freshly allocated whiteout.1187 */1188int1189xfs_dir_rename_children(1190	struct xfs_trans	*tp,1191	struct xfs_dir_update	*du_src,1192	struct xfs_dir_update	*du_tgt,1193	unsigned int		spaceres,1194	struct xfs_dir_update	*du_wip)1195{1196	struct xfs_mount	*mp = tp->t_mountp;1197	struct xfs_inode	*src_dp = du_src->dp;1198	const struct xfs_name	*src_name = du_src->name;1199	struct xfs_inode	*src_ip = du_src->ip;1200	struct xfs_inode	*target_dp = du_tgt->dp;1201	const struct xfs_name	*target_name = du_tgt->name;1202	struct xfs_inode	*target_ip = du_tgt->ip;1203	bool			new_parent = (src_dp != target_dp);1204	bool			src_is_directory;1205	int			error;1206 1207	src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);1208 1209	/*1210	 * Check for expected errors before we dirty the transaction1211	 * so we can return an error without a transaction abort.1212	 */1213	if (target_ip == NULL) {1214		/*1215		 * If there's no space reservation, check the entry will1216		 * fit before actually inserting it.1217		 */1218		if (!spaceres) {1219			error = xfs_dir_canenter(tp, target_dp, target_name);1220			if (error)1221				return error;1222		}1223	} else {1224		/*1225		 * If target exists and it's a directory, check that whether1226		 * it can be destroyed.1227		 */1228		if (S_ISDIR(VFS_I(target_ip)->i_mode) &&1229		    (!xfs_dir_isempty(target_ip) ||1230		     (VFS_I(target_ip)->i_nlink > 2)))1231			return -EEXIST;1232	}1233 1234	/*1235	 * Directory entry creation below may acquire the AGF. Remove1236	 * the whiteout from the unlinked list first to preserve correct1237	 * AGI/AGF locking order. This dirties the transaction so failures1238	 * after this point will abort and log recovery will clean up the1239	 * mess.1240	 *1241	 * For whiteouts, we need to bump the link count on the whiteout1242	 * inode. After this point, we have a real link, clear the tmpfile1243	 * state flag from the inode so it doesn't accidentally get misused1244	 * in future.1245	 */1246	if (du_wip->ip) {1247		struct xfs_perag	*pag;1248 1249		ASSERT(VFS_I(du_wip->ip)->i_nlink == 0);1250 1251		pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, du_wip->ip->i_ino));1252		error = xfs_iunlink_remove(tp, pag, du_wip->ip);1253		xfs_perag_put(pag);1254		if (error)1255			return error;1256 1257		xfs_bumplink(tp, du_wip->ip);1258	}1259 1260	/*1261	 * Set up the target.1262	 */1263	if (target_ip == NULL) {1264		/*1265		 * If target does not exist and the rename crosses1266		 * directories, adjust the target directory link count1267		 * to account for the ".." reference from the new entry.1268		 */1269		error = xfs_dir_createname(tp, target_dp, target_name,1270					   src_ip->i_ino, spaceres);1271		if (error)1272			return error;1273 1274		xfs_trans_ichgtime(tp, target_dp,1275					XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);1276 1277		if (new_parent && src_is_directory) {1278			xfs_bumplink(tp, target_dp);1279		}1280	} else { /* target_ip != NULL */1281		/*1282		 * Link the source inode under the target name.1283		 * If the source inode is a directory and we are moving1284		 * it across directories, its ".." entry will be1285		 * inconsistent until we replace that down below.1286		 *1287		 * In case there is already an entry with the same1288		 * name at the destination directory, remove it first.1289		 */1290		error = xfs_dir_replace(tp, target_dp, target_name,1291					src_ip->i_ino, spaceres);1292		if (error)1293			return error;1294 1295		xfs_trans_ichgtime(tp, target_dp,1296					XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);1297 1298		/*1299		 * Decrement the link count on the target since the target1300		 * dir no longer points to it.1301		 */1302		error = xfs_droplink(tp, target_ip);1303		if (error)1304			return error;1305 1306		if (src_is_directory) {1307			/*1308			 * Drop the link from the old "." entry.1309			 */1310			error = xfs_droplink(tp, target_ip);1311			if (error)1312				return error;1313		}1314	} /* target_ip != NULL */1315 1316	/*1317	 * Remove the source.1318	 */1319	if (new_parent && src_is_directory) {1320		/*1321		 * Rewrite the ".." entry to point to the new1322		 * directory.1323		 */1324		error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,1325					target_dp->i_ino, spaceres);1326		ASSERT(error != -EEXIST);1327		if (error)1328			return error;1329	}1330 1331	/*1332	 * We always want to hit the ctime on the source inode.1333	 *1334	 * This isn't strictly required by the standards since the source1335	 * inode isn't really being changed, but old unix file systems did1336	 * it and some incremental backup programs won't work without it.1337	 */1338	xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG);1339	xfs_trans_log_inode(tp, src_ip, XFS_ILOG_CORE);1340 1341	/*1342	 * Adjust the link count on src_dp.  This is necessary when1343	 * renaming a directory, either within one parent when1344	 * the target existed, or across two parent directories.1345	 */1346	if (src_is_directory && (new_parent || target_ip != NULL)) {1347 1348		/*1349		 * Decrement link count on src_directory since the1350		 * entry that's moved no longer points to it.1351		 */1352		error = xfs_droplink(tp, src_dp);1353		if (error)1354			return error;1355	}1356 1357	/*1358	 * For whiteouts, we only need to update the source dirent with the1359	 * inode number of the whiteout inode rather than removing it1360	 * altogether.1361	 */1362	if (du_wip->ip)1363		error = xfs_dir_replace(tp, src_dp, src_name, du_wip->ip->i_ino,1364					spaceres);1365	else1366		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,1367					   spaceres);1368	if (error)1369		return error;1370 1371	xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);1372	xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);1373	if (new_parent)1374		xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);1375 1376	/* Schedule parent pointer updates. */1377	if (du_wip->ppargs) {1378		error = xfs_parent_addname(tp, du_wip->ppargs, src_dp,1379				src_name, du_wip->ip);1380		if (error)1381			return error;1382	}1383 1384	if (du_src->ppargs) {1385		error = xfs_parent_replacename(tp, du_src->ppargs, src_dp,1386				src_name, target_dp, target_name, src_ip);1387		if (error)1388			return error;1389	}1390 1391	if (du_tgt->ppargs) {1392		error = xfs_parent_removename(tp, du_tgt->ppargs, target_dp,1393				target_name, target_ip);1394		if (error)1395			return error;1396	}1397 1398	/*1399	 * Inform our hook clients that we've finished a rename operation as1400	 * follows: removed the source and target files from their directories;1401	 * that we've added the source to the target directory; and finally1402	 * that we've added the whiteout, if there was one.  All inodes are1403	 * locked, so it's ok to model a rename this way so long as we say we1404	 * deleted entries before we add new ones.1405	 */1406	if (target_ip)1407		xfs_dir_update_hook(target_dp, target_ip, -1, target_name);1408	xfs_dir_update_hook(src_dp, src_ip, -1, src_name);1409	xfs_dir_update_hook(target_dp, src_ip, 1, target_name);1410	if (du_wip->ip)1411		xfs_dir_update_hook(src_dp, du_wip->ip, 1, src_name);1412	return 0;1413}1414