brintos

brintos / linux-shallow public Read only

0
0
Text · 49.1 KiB · 64679fe Raw
1959 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2020-2024 Oracle.  All Rights Reserved.4 * Author: Darrick J. Wong <djwong@kernel.org>5 */6#include "xfs.h"7#include "xfs_fs.h"8#include "xfs_shared.h"9#include "xfs_format.h"10#include "xfs_trans_resv.h"11#include "xfs_mount.h"12#include "xfs_defer.h"13#include "xfs_bit.h"14#include "xfs_log_format.h"15#include "xfs_trans.h"16#include "xfs_sb.h"17#include "xfs_inode.h"18#include "xfs_icache.h"19#include "xfs_da_format.h"20#include "xfs_da_btree.h"21#include "xfs_dir2.h"22#include "xfs_dir2_priv.h"23#include "xfs_bmap.h"24#include "xfs_quota.h"25#include "xfs_bmap_btree.h"26#include "xfs_trans_space.h"27#include "xfs_bmap_util.h"28#include "xfs_exchmaps.h"29#include "xfs_exchrange.h"30#include "xfs_ag.h"31#include "xfs_parent.h"32#include "scrub/xfs_scrub.h"33#include "scrub/scrub.h"34#include "scrub/common.h"35#include "scrub/trace.h"36#include "scrub/repair.h"37#include "scrub/tempfile.h"38#include "scrub/tempexch.h"39#include "scrub/xfile.h"40#include "scrub/xfarray.h"41#include "scrub/xfblob.h"42#include "scrub/iscan.h"43#include "scrub/readdir.h"44#include "scrub/reap.h"45#include "scrub/findparent.h"46#include "scrub/orphanage.h"47#include "scrub/listxattr.h"48 49/*50 * Directory Repair51 * ================52 *53 * We repair directories by reading the directory data blocks looking for54 * directory entries that look salvageable (name passes verifiers, entry points55 * to a valid allocated inode, etc).  Each entry worth salvaging is stashed in56 * memory, and the stashed entries are periodically replayed into a temporary57 * directory to constrain memory use.  Batching the construction of the58 * temporary directory in this fashion reduces lock cycling of the directory59 * being repaired and the temporary directory, and will later become important60 * for parent pointer scanning.61 *62 * If parent pointers are enabled on this filesystem, we instead reconstruct63 * the directory by visiting each parent pointer of each file in the filesystem64 * and translating the relevant parent pointer records into dirents.  In this65 * case, it is advantageous to stash all directory entries created from parent66 * pointers for a single child file before replaying them into the temporary67 * directory.  To save memory, the live filesystem scan reuses the findparent68 * fields.  Directory repair chooses either parent pointer scanning or69 * directory entry salvaging, but not both.70 *71 * Directory entries added to the temporary directory do not elevate the link72 * counts of the inodes found.  When salvaging completes, the remaining stashed73 * entries are replayed to the temporary directory.  An atomic mapping exchange74 * is used to commit the new directory blocks to the directory being repaired.75 * This will disrupt readdir cursors.76 *77 * Locking Issues78 * --------------79 *80 * If /a, /a/b, and /c are all directories, the VFS does not take i_rwsem on81 * /a/b for a "mv /a/b /c/" operation.  This means that only b's ILOCK protects82 * b's dotdot update.  This is in contrast to every other dotdot update (link,83 * remove, mkdir).  If the repair code drops the ILOCK, it must either84 * revalidate the dotdot entry or use dirent hooks to capture updates from85 * other threads.86 */87 88/* Create a dirent in the tempdir. */89#define XREP_DIRENT_ADD		(1)90 91/* Remove a dirent from the tempdir. */92#define XREP_DIRENT_REMOVE	(2)93 94/* Directory entry to be restored in the new directory. */95struct xrep_dirent {96	/* Cookie for retrieval of the dirent name. */97	xfblob_cookie		name_cookie;98 99	/* Target inode number. */100	xfs_ino_t		ino;101 102	/* Length of the dirent name. */103	uint8_t			namelen;104 105	/* File type of the dirent. */106	uint8_t			ftype;107 108	/* XREP_DIRENT_{ADD,REMOVE} */109	uint8_t			action;110};111 112/*113 * Stash up to 8 pages of recovered dirent data in dir_entries and dir_names114 * before we write them to the temp dir.115 */116#define XREP_DIR_MAX_STASH_BYTES	(PAGE_SIZE * 8)117 118struct xrep_dir {119	struct xfs_scrub	*sc;120 121	/* Fixed-size array of xrep_dirent structures. */122	struct xfarray		*dir_entries;123 124	/* Blobs containing directory entry names. */125	struct xfblob		*dir_names;126 127	/* Information for exchanging data forks at the end. */128	struct xrep_tempexch	tx;129 130	/* Preallocated args struct for performing dir operations */131	struct xfs_da_args	args;132 133	/*134	 * Information used to scan the filesystem to find the inumber of the135	 * dotdot entry for this directory.  For directory salvaging when136	 * parent pointers are not enabled, we use the findparent_* functions137	 * on this object and access only the parent_ino field directly.138	 *139	 * When parent pointers are enabled, however, the pptr scanner uses the140	 * iscan, hooks, lock, and parent_ino fields of this object directly.141	 * @pscan.lock coordinates access to dir_entries, dir_names,142	 * parent_ino, subdirs, dirents, and args.  This reduces the memory143	 * requirements of this structure.144	 */145	struct xrep_parent_scan_info pscan;146 147	/*148	 * Context information for attaching this directory to the lost+found149	 * if this directory does not have a parent.150	 */151	struct xrep_adoption	adoption;152 153	/* How many subdirectories did we find? */154	uint64_t		subdirs;155 156	/* How many dirents did we find? */157	unsigned int		dirents;158 159	/* Should we move this directory to the orphanage? */160	bool			needs_adoption;161 162	/* Directory entry name, plus the trailing null. */163	struct xfs_name		xname;164	unsigned char		namebuf[MAXNAMELEN];165};166 167/* Tear down all the incore stuff we created. */168static void169xrep_dir_teardown(170	struct xfs_scrub	*sc)171{172	struct xrep_dir		*rd = sc->buf;173 174	xrep_findparent_scan_teardown(&rd->pscan);175	xfblob_destroy(rd->dir_names);176	xfarray_destroy(rd->dir_entries);177}178 179/* Set up for a directory repair. */180int181xrep_setup_directory(182	struct xfs_scrub	*sc)183{184	struct xrep_dir		*rd;185	int			error;186 187	xchk_fsgates_enable(sc, XCHK_FSGATES_DIRENTS);188 189	error = xrep_orphanage_try_create(sc);190	if (error)191		return error;192 193	error = xrep_tempfile_create(sc, S_IFDIR);194	if (error)195		return error;196 197	rd = kvzalloc(sizeof(struct xrep_dir), XCHK_GFP_FLAGS);198	if (!rd)199		return -ENOMEM;200	rd->sc = sc;201	rd->xname.name = rd->namebuf;202	sc->buf = rd;203 204	return 0;205}206 207/*208 * Look up the dotdot entry and confirm that it's really the parent.209 * Returns NULLFSINO if we don't know what to do.210 */211static inline xfs_ino_t212xrep_dir_lookup_parent(213	struct xrep_dir		*rd)214{215	struct xfs_scrub	*sc = rd->sc;216	xfs_ino_t		ino;217	int			error;218 219	error = xfs_dir_lookup(sc->tp, sc->ip, &xfs_name_dotdot, &ino, NULL);220	if (error)221		return NULLFSINO;222	if (!xfs_verify_dir_ino(sc->mp, ino))223		return NULLFSINO;224 225	error = xrep_findparent_confirm(sc, &ino);226	if (error)227		return NULLFSINO;228 229	return ino;230}231 232/*233 * Look up '..' in the dentry cache and confirm that it's really the parent.234 * Returns NULLFSINO if the dcache misses or if the hit is implausible.235 */236static inline xfs_ino_t237xrep_dir_dcache_parent(238	struct xrep_dir		*rd)239{240	struct xfs_scrub	*sc = rd->sc;241	xfs_ino_t		parent_ino;242	int			error;243 244	parent_ino = xrep_findparent_from_dcache(sc);245	if (parent_ino == NULLFSINO)246		return parent_ino;247 248	error = xrep_findparent_confirm(sc, &parent_ino);249	if (error)250		return NULLFSINO;251 252	return parent_ino;253}254 255/* Try to find the parent of the directory being repaired. */256STATIC int257xrep_dir_find_parent(258	struct xrep_dir		*rd)259{260	xfs_ino_t		ino;261 262	ino = xrep_findparent_self_reference(rd->sc);263	if (ino != NULLFSINO) {264		xrep_findparent_scan_finish_early(&rd->pscan, ino);265		return 0;266	}267 268	ino = xrep_dir_dcache_parent(rd);269	if (ino != NULLFSINO) {270		xrep_findparent_scan_finish_early(&rd->pscan, ino);271		return 0;272	}273 274	ino = xrep_dir_lookup_parent(rd);275	if (ino != NULLFSINO) {276		xrep_findparent_scan_finish_early(&rd->pscan, ino);277		return 0;278	}279 280	/*281	 * A full filesystem scan is the last resort.  On a busy filesystem,282	 * the scan can fail with -EBUSY if we cannot grab IOLOCKs.  That means283	 * that we don't know what who the parent is, so we should return to284	 * userspace.285	 */286	return xrep_findparent_scan(&rd->pscan);287}288 289/*290 * Decide if we want to salvage this entry.  We don't bother with oversized291 * names or the dot entry.292 */293STATIC int294xrep_dir_want_salvage(295	struct xrep_dir		*rd,296	const char		*name,297	int			namelen,298	xfs_ino_t		ino)299{300	struct xfs_mount	*mp = rd->sc->mp;301 302	/* No pointers to ourselves or to garbage. */303	if (ino == rd->sc->ip->i_ino)304		return false;305	if (!xfs_verify_dir_ino(mp, ino))306		return false;307 308	/* No weird looking names or dot entries. */309	if (namelen >= MAXNAMELEN || namelen <= 0)310		return false;311	if (namelen == 1 && name[0] == '.')312		return false;313	if (!xfs_dir2_namecheck(name, namelen))314		return false;315 316	return true;317}318 319/*320 * Remember that we want to create a dirent in the tempdir.  These stashed321 * actions will be replayed later.322 */323STATIC int324xrep_dir_stash_createname(325	struct xrep_dir		*rd,326	const struct xfs_name	*name,327	xfs_ino_t		ino)328{329	struct xrep_dirent	dirent = {330		.action		= XREP_DIRENT_ADD,331		.ino		= ino,332		.namelen	= name->len,333		.ftype		= name->type,334	};335	int			error;336 337	trace_xrep_dir_stash_createname(rd->sc->tempip, name, ino);338 339	error = xfblob_storename(rd->dir_names, &dirent.name_cookie, name);340	if (error)341		return error;342 343	return xfarray_append(rd->dir_entries, &dirent);344}345 346/*347 * Remember that we want to remove a dirent from the tempdir.  These stashed348 * actions will be replayed later.349 */350STATIC int351xrep_dir_stash_removename(352	struct xrep_dir		*rd,353	const struct xfs_name	*name,354	xfs_ino_t		ino)355{356	struct xrep_dirent	dirent = {357		.action		= XREP_DIRENT_REMOVE,358		.ino		= ino,359		.namelen	= name->len,360		.ftype		= name->type,361	};362	int			error;363 364	trace_xrep_dir_stash_removename(rd->sc->tempip, name, ino);365 366	error = xfblob_storename(rd->dir_names, &dirent.name_cookie, name);367	if (error)368		return error;369 370	return xfarray_append(rd->dir_entries, &dirent);371}372 373/* Allocate an in-core record to hold entries while we rebuild the dir data. */374STATIC int375xrep_dir_salvage_entry(376	struct xrep_dir		*rd,377	unsigned char		*name,378	unsigned int		namelen,379	xfs_ino_t		ino)380{381	struct xfs_name		xname = {382		.name		= name,383	};384	struct xfs_scrub	*sc = rd->sc;385	struct xfs_inode	*ip;386	unsigned int		i = 0;387	int			error = 0;388 389	if (xchk_should_terminate(sc, &error))390		return error;391 392	/*393	 * Truncate the name to the first character that would trip namecheck.394	 * If we no longer have a name after that, ignore this entry.395	 */396	while (i < namelen && name[i] != 0 && name[i] != '/')397		i++;398	if (i == 0)399		return 0;400	xname.len = i;401 402	/* Ignore '..' entries; we already picked the new parent. */403	if (xname.len == 2 && name[0] == '.' && name[1] == '.') {404		trace_xrep_dir_salvaged_parent(sc->ip, ino);405		return 0;406	}407 408	trace_xrep_dir_salvage_entry(sc->ip, &xname, ino);409 410	/*411	 * Compute the ftype or dump the entry if we can't.  We don't lock the412	 * inode because inodes can't change type while we have a reference.413	 */414	error = xchk_iget(sc, ino, &ip);415	if (error)416		return 0;417 418	xname.type = xfs_mode_to_ftype(VFS_I(ip)->i_mode);419	xchk_irele(sc, ip);420 421	return xrep_dir_stash_createname(rd, &xname, ino);422}423 424/* Record a shortform directory entry for later reinsertion. */425STATIC int426xrep_dir_salvage_sf_entry(427	struct xrep_dir			*rd,428	struct xfs_dir2_sf_hdr		*sfp,429	struct xfs_dir2_sf_entry	*sfep)430{431	xfs_ino_t			ino;432 433	ino = xfs_dir2_sf_get_ino(rd->sc->mp, sfp, sfep);434	if (!xrep_dir_want_salvage(rd, sfep->name, sfep->namelen, ino))435		return 0;436 437	return xrep_dir_salvage_entry(rd, sfep->name, sfep->namelen, ino);438}439 440/* Record a regular directory entry for later reinsertion. */441STATIC int442xrep_dir_salvage_data_entry(443	struct xrep_dir			*rd,444	struct xfs_dir2_data_entry	*dep)445{446	xfs_ino_t			ino;447 448	ino = be64_to_cpu(dep->inumber);449	if (!xrep_dir_want_salvage(rd, dep->name, dep->namelen, ino))450		return 0;451 452	return xrep_dir_salvage_entry(rd, dep->name, dep->namelen, ino);453}454 455/* Try to recover block/data format directory entries. */456STATIC int457xrep_dir_recover_data(458	struct xrep_dir		*rd,459	struct xfs_buf		*bp)460{461	struct xfs_da_geometry	*geo = rd->sc->mp->m_dir_geo;462	unsigned int		offset;463	unsigned int		end;464	int			error = 0;465 466	/*467	 * Loop over the data portion of the block.468	 * Each object is a real entry (dep) or an unused one (dup).469	 */470	offset = geo->data_entry_offset;471	end = min_t(unsigned int, BBTOB(bp->b_length),472			xfs_dir3_data_end_offset(geo, bp->b_addr));473 474	while (offset < end) {475		struct xfs_dir2_data_unused	*dup = bp->b_addr + offset;476		struct xfs_dir2_data_entry	*dep = bp->b_addr + offset;477 478		if (xchk_should_terminate(rd->sc, &error))479			return error;480 481		/* Skip unused entries. */482		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {483			offset += be16_to_cpu(dup->length);484			continue;485		}486 487		/* Don't walk off the end of the block. */488		offset += xfs_dir2_data_entsize(rd->sc->mp, dep->namelen);489		if (offset > end)490			break;491 492		/* Ok, let's save this entry. */493		error = xrep_dir_salvage_data_entry(rd, dep);494		if (error)495			return error;496 497	}498 499	return 0;500}501 502/* Try to recover shortform directory entries. */503STATIC int504xrep_dir_recover_sf(505	struct xrep_dir			*rd)506{507	struct xfs_dir2_sf_hdr		*hdr;508	struct xfs_dir2_sf_entry	*sfep;509	struct xfs_dir2_sf_entry	*next;510	struct xfs_ifork		*ifp;511	xfs_ino_t			ino;512	unsigned char			*end;513	int				error = 0;514 515	ifp = xfs_ifork_ptr(rd->sc->ip, XFS_DATA_FORK);516	hdr = ifp->if_data;517	end = (unsigned char *)ifp->if_data + ifp->if_bytes;518 519	ino = xfs_dir2_sf_get_parent_ino(hdr);520	trace_xrep_dir_salvaged_parent(rd->sc->ip, ino);521 522	sfep = xfs_dir2_sf_firstentry(hdr);523	while ((unsigned char *)sfep < end) {524		if (xchk_should_terminate(rd->sc, &error))525			return error;526 527		next = xfs_dir2_sf_nextentry(rd->sc->mp, hdr, sfep);528		if ((unsigned char *)next > end)529			break;530 531		/* Ok, let's save this entry. */532		error = xrep_dir_salvage_sf_entry(rd, hdr, sfep);533		if (error)534			return error;535 536		sfep = next;537	}538 539	return 0;540}541 542/*543 * Try to figure out the format of this directory from the data fork mappings544 * and the directory size.  If we can be reasonably sure of format, we can be545 * more aggressive in salvaging directory entries.  On return, @magic_guess546 * will be set to DIR3_BLOCK_MAGIC if we think this is a "block format"547 * directory; DIR3_DATA_MAGIC if we think this is a "data format" directory,548 * and 0 if we can't tell.549 */550STATIC void551xrep_dir_guess_format(552	struct xrep_dir		*rd,553	__be32			*magic_guess)554{555	struct xfs_inode	*dp = rd->sc->ip;556	struct xfs_mount	*mp = rd->sc->mp;557	struct xfs_da_geometry	*geo = mp->m_dir_geo;558	xfs_fileoff_t		last;559	int			error;560 561	ASSERT(xfs_has_crc(mp));562 563	*magic_guess = 0;564 565	/*566	 * If there's a single directory block and the directory size is567	 * exactly one block, this has to be a single block format directory.568	 */569	error = xfs_bmap_last_offset(dp, &last, XFS_DATA_FORK);570	if (!error && XFS_FSB_TO_B(mp, last) == geo->blksize &&571	    dp->i_disk_size == geo->blksize) {572		*magic_guess = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);573		return;574	}575 576	/*577	 * If the last extent before the leaf offset matches the directory578	 * size and the directory size is larger than 1 block, this is a579	 * data format directory.580	 */581	last = geo->leafblk;582	error = xfs_bmap_last_before(rd->sc->tp, dp, &last, XFS_DATA_FORK);583	if (!error &&584	    XFS_FSB_TO_B(mp, last) > geo->blksize &&585	    XFS_FSB_TO_B(mp, last) == dp->i_disk_size) {586		*magic_guess = cpu_to_be32(XFS_DIR3_DATA_MAGIC);587		return;588	}589}590 591/* Recover directory entries from a specific directory block. */592STATIC int593xrep_dir_recover_dirblock(594	struct xrep_dir		*rd,595	__be32			magic_guess,596	xfs_dablk_t		dabno)597{598	struct xfs_dir2_data_hdr *hdr;599	struct xfs_buf		*bp;600	__be32			oldmagic;601	int			error;602 603	/*604	 * Try to read buffer.  We invalidate them in the next step so we don't605	 * bother to set a buffer type or ops.606	 */607	error = xfs_da_read_buf(rd->sc->tp, rd->sc->ip, dabno,608			XFS_DABUF_MAP_HOLE_OK, &bp, XFS_DATA_FORK, NULL);609	if (error || !bp)610		return error;611 612	hdr = bp->b_addr;613	oldmagic = hdr->magic;614 615	trace_xrep_dir_recover_dirblock(rd->sc->ip, dabno,616			be32_to_cpu(hdr->magic), be32_to_cpu(magic_guess));617 618	/*619	 * If we're sure of the block's format, proceed with the salvage620	 * operation using the specified magic number.621	 */622	if (magic_guess) {623		hdr->magic = magic_guess;624		goto recover;625	}626 627	/*628	 * If we couldn't guess what type of directory this is, then we will629	 * only salvage entries from directory blocks that match the magic630	 * number and pass verifiers.631	 */632	switch (hdr->magic) {633	case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):634	case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):635		if (!xrep_buf_verify_struct(bp, &xfs_dir3_block_buf_ops))636			goto out;637		if (xfs_dir3_block_header_check(bp, rd->sc->ip->i_ino) != NULL)638			goto out;639		break;640	case cpu_to_be32(XFS_DIR2_DATA_MAGIC):641	case cpu_to_be32(XFS_DIR3_DATA_MAGIC):642		if (!xrep_buf_verify_struct(bp, &xfs_dir3_data_buf_ops))643			goto out;644		if (xfs_dir3_data_header_check(bp, rd->sc->ip->i_ino) != NULL)645			goto out;646		break;647	default:648		goto out;649	}650 651recover:652	error = xrep_dir_recover_data(rd, bp);653 654out:655	hdr->magic = oldmagic;656	xfs_trans_brelse(rd->sc->tp, bp);657	return error;658}659 660static inline void661xrep_dir_init_args(662	struct xrep_dir		*rd,663	struct xfs_inode	*dp,664	const struct xfs_name	*name)665{666	memset(&rd->args, 0, sizeof(struct xfs_da_args));667	rd->args.geo = rd->sc->mp->m_dir_geo;668	rd->args.whichfork = XFS_DATA_FORK;669	rd->args.owner = rd->sc->ip->i_ino;670	rd->args.trans = rd->sc->tp;671	rd->args.dp = dp;672	if (!name)673		return;674	rd->args.name = name->name;675	rd->args.namelen = name->len;676	rd->args.filetype = name->type;677	rd->args.hashval = xfs_dir2_hashname(rd->sc->mp, name);678}679 680/* Replay a stashed createname into the temporary directory. */681STATIC int682xrep_dir_replay_createname(683	struct xrep_dir		*rd,684	const struct xfs_name	*name,685	xfs_ino_t		inum,686	xfs_extlen_t		total)687{688	struct xfs_scrub	*sc = rd->sc;689	struct xfs_inode	*dp = rd->sc->tempip;690	int			error;691 692	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));693 694	error = xfs_dir_ino_validate(sc->mp, inum);695	if (error)696		return error;697 698	trace_xrep_dir_replay_createname(dp, name, inum);699 700	xrep_dir_init_args(rd, dp, name);701	rd->args.inumber = inum;702	rd->args.total = total;703	rd->args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;704	return xfs_dir_createname_args(&rd->args);705}706 707/* Replay a stashed removename onto the temporary directory. */708STATIC int709xrep_dir_replay_removename(710	struct xrep_dir		*rd,711	const struct xfs_name	*name,712	xfs_extlen_t		total)713{714	struct xfs_inode	*dp = rd->args.dp;715 716	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));717 718	xrep_dir_init_args(rd, dp, name);719	rd->args.op_flags = 0;720	rd->args.total = total;721 722	trace_xrep_dir_replay_removename(dp, name, 0);723	return xfs_dir_removename_args(&rd->args);724}725 726/*727 * Add this stashed incore directory entry to the temporary directory.728 * The caller must hold the tempdir's IOLOCK, must not hold any ILOCKs, and729 * must not be in transaction context.730 */731STATIC int732xrep_dir_replay_update(733	struct xrep_dir			*rd,734	const struct xfs_name		*xname,735	const struct xrep_dirent	*dirent)736{737	struct xfs_mount		*mp = rd->sc->mp;738#ifdef DEBUG739	xfs_ino_t			ino;740#endif741	uint				resblks;742	int				error;743 744	resblks = xfs_link_space_res(mp, xname->len);745	error = xchk_trans_alloc(rd->sc, resblks);746	if (error)747		return error;748 749	/* Lock the temporary directory and join it to the transaction */750	xrep_tempfile_ilock(rd->sc);751	xfs_trans_ijoin(rd->sc->tp, rd->sc->tempip, 0);752 753	switch (dirent->action) {754	case XREP_DIRENT_ADD:755		/*756		 * Create a replacement dirent in the temporary directory.757		 * Note that _createname doesn't check for existing entries.758		 * There shouldn't be any in the temporary dir, but we'll759		 * verify this in debug mode.760		 */761#ifdef DEBUG762		error = xchk_dir_lookup(rd->sc, rd->sc->tempip, xname, &ino);763		if (error != -ENOENT) {764			ASSERT(error != -ENOENT);765			goto out_cancel;766		}767#endif768 769		error = xrep_dir_replay_createname(rd, xname, dirent->ino,770				resblks);771		if (error)772			goto out_cancel;773 774		if (xname->type == XFS_DIR3_FT_DIR)775			rd->subdirs++;776		rd->dirents++;777		break;778	case XREP_DIRENT_REMOVE:779		/*780		 * Remove a dirent from the temporary directory.  Note that781		 * _removename doesn't check the inode target of the exist782		 * entry.  There should be a perfect match in the temporary783		 * dir, but we'll verify this in debug mode.784		 */785#ifdef DEBUG786		error = xchk_dir_lookup(rd->sc, rd->sc->tempip, xname, &ino);787		if (error) {788			ASSERT(error != 0);789			goto out_cancel;790		}791		if (ino != dirent->ino) {792			ASSERT(ino == dirent->ino);793			error = -EIO;794			goto out_cancel;795		}796#endif797 798		error = xrep_dir_replay_removename(rd, xname, resblks);799		if (error)800			goto out_cancel;801 802		if (xname->type == XFS_DIR3_FT_DIR)803			rd->subdirs--;804		rd->dirents--;805		break;806	default:807		ASSERT(0);808		error = -EIO;809		goto out_cancel;810	}811 812	/* Commit and unlock. */813	error = xrep_trans_commit(rd->sc);814	if (error)815		return error;816 817	xrep_tempfile_iunlock(rd->sc);818	return 0;819out_cancel:820	xchk_trans_cancel(rd->sc);821	xrep_tempfile_iunlock(rd->sc);822	return error;823}824 825/*826 * Flush stashed incore dirent updates that have been recorded by the scanner.827 * This is done to reduce the memory requirements of the directory rebuild,828 * since directories can contain up to 32GB of directory data.829 *830 * Caller must not hold transactions or ILOCKs.  Caller must hold the tempdir831 * IOLOCK.832 */833STATIC int834xrep_dir_replay_updates(835	struct xrep_dir		*rd)836{837	xfarray_idx_t		array_cur;838	int			error;839 840	/* Add all the salvaged dirents to the temporary directory. */841	mutex_lock(&rd->pscan.lock);842	foreach_xfarray_idx(rd->dir_entries, array_cur) {843		struct xrep_dirent	dirent;844 845		error = xfarray_load(rd->dir_entries, array_cur, &dirent);846		if (error)847			goto out_unlock;848 849		error = xfblob_loadname(rd->dir_names, dirent.name_cookie,850				&rd->xname, dirent.namelen);851		if (error)852			goto out_unlock;853		rd->xname.type = dirent.ftype;854		mutex_unlock(&rd->pscan.lock);855 856		error = xrep_dir_replay_update(rd, &rd->xname, &dirent);857		if (error)858			return error;859		mutex_lock(&rd->pscan.lock);860	}861 862	/* Empty out both arrays now that we've added the entries. */863	xfarray_truncate(rd->dir_entries);864	xfblob_truncate(rd->dir_names);865	mutex_unlock(&rd->pscan.lock);866	return 0;867out_unlock:868	mutex_unlock(&rd->pscan.lock);869	return error;870}871 872/*873 * Periodically flush stashed directory entries to the temporary dir.  This874 * is done to reduce the memory requirements of the directory rebuild, since875 * directories can contain up to 32GB of directory data.876 */877STATIC int878xrep_dir_flush_stashed(879	struct xrep_dir		*rd)880{881	int			error;882 883	/*884	 * Entering this function, the scrub context has a reference to the885	 * inode being repaired, the temporary file, and a scrub transaction886	 * that we use during dirent salvaging to avoid livelocking if there887	 * are cycles in the directory structures.  We hold ILOCK_EXCL on both888	 * the inode being repaired and the temporary file, though they are889	 * not ijoined to the scrub transaction.890	 *891	 * To constrain kernel memory use, we occasionally write salvaged892	 * dirents from the xfarray and xfblob structures into the temporary893	 * directory in preparation for exchanging the directory structures at894	 * the end.  Updating the temporary file requires a transaction, so we895	 * commit the scrub transaction and drop the two ILOCKs so that896	 * we can allocate whatever transaction we want.897	 *898	 * We still hold IOLOCK_EXCL on the inode being repaired, which899	 * prevents anyone from accessing the damaged directory data while we900	 * repair it.901	 */902	error = xrep_trans_commit(rd->sc);903	if (error)904		return error;905	xchk_iunlock(rd->sc, XFS_ILOCK_EXCL);906 907	/*908	 * Take the IOLOCK of the temporary file while we modify dirents.  This909	 * isn't strictly required because the temporary file is never revealed910	 * to userspace, but we follow the same locking rules.  We still hold911	 * sc->ip's IOLOCK.912	 */913	error = xrep_tempfile_iolock_polled(rd->sc);914	if (error)915		return error;916 917	/* Write to the tempdir all the updates that we've stashed. */918	error = xrep_dir_replay_updates(rd);919	xrep_tempfile_iounlock(rd->sc);920	if (error)921		return error;922 923	/*924	 * Recreate the salvage transaction and relock the dir we're salvaging.925	 */926	error = xchk_trans_alloc(rd->sc, 0);927	if (error)928		return error;929	xchk_ilock(rd->sc, XFS_ILOCK_EXCL);930	return 0;931}932 933/* Decide if we've stashed too much dirent data in memory. */934static inline bool935xrep_dir_want_flush_stashed(936	struct xrep_dir		*rd)937{938	unsigned long long	bytes;939 940	bytes = xfarray_bytes(rd->dir_entries) + xfblob_bytes(rd->dir_names);941	return bytes > XREP_DIR_MAX_STASH_BYTES;942}943 944/* Extract as many directory entries as we can. */945STATIC int946xrep_dir_recover(947	struct xrep_dir		*rd)948{949	struct xfs_bmbt_irec	got;950	struct xfs_scrub	*sc = rd->sc;951	struct xfs_da_geometry	*geo = sc->mp->m_dir_geo;952	xfs_fileoff_t		offset;953	xfs_dablk_t		dabno;954	__be32			magic_guess;955	int			nmap;956	int			error;957 958	xrep_dir_guess_format(rd, &magic_guess);959 960	/* Iterate each directory data block in the data fork. */961	for (offset = 0;962	     offset < geo->leafblk;963	     offset = got.br_startoff + got.br_blockcount) {964		nmap = 1;965		error = xfs_bmapi_read(sc->ip, offset, geo->leafblk - offset,966				&got, &nmap, 0);967		if (error)968			return error;969		if (nmap != 1)970			return -EFSCORRUPTED;971		if (!xfs_bmap_is_written_extent(&got))972			continue;973 974		for (dabno = round_up(got.br_startoff, geo->fsbcount);975		     dabno < got.br_startoff + got.br_blockcount;976		     dabno += geo->fsbcount) {977			if (xchk_should_terminate(rd->sc, &error))978				return error;979 980			error = xrep_dir_recover_dirblock(rd,981					magic_guess, dabno);982			if (error)983				return error;984 985			/* Flush dirents to constrain memory usage. */986			if (xrep_dir_want_flush_stashed(rd)) {987				error = xrep_dir_flush_stashed(rd);988				if (error)989					return error;990			}991		}992	}993 994	return 0;995}996 997/*998 * Find all the directory entries for this inode by scraping them out of the999 * directory leaf blocks by hand, and flushing them into the temp dir.1000 */1001STATIC int1002xrep_dir_find_entries(1003	struct xrep_dir		*rd)1004{1005	struct xfs_inode	*dp = rd->sc->ip;1006	int			error;1007 1008	/*1009	 * Salvage directory entries from the old directory, and write them to1010	 * the temporary directory.1011	 */1012	if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {1013		error = xrep_dir_recover_sf(rd);1014	} else {1015		error = xfs_iread_extents(rd->sc->tp, dp, XFS_DATA_FORK);1016		if (error)1017			return error;1018 1019		error = xrep_dir_recover(rd);1020	}1021	if (error)1022		return error;1023 1024	return xrep_dir_flush_stashed(rd);1025}1026 1027/* Scan all files in the filesystem for dirents. */1028STATIC int1029xrep_dir_salvage_entries(1030	struct xrep_dir		*rd)1031{1032	struct xfs_scrub	*sc = rd->sc;1033	int			error;1034 1035	/*1036	 * Drop the ILOCK on this directory so that we can scan for this1037	 * directory's parent.  Figure out who is going to be the parent of1038	 * this directory, then retake the ILOCK so that we can salvage1039	 * directory entries.1040	 */1041	xchk_iunlock(sc, XFS_ILOCK_EXCL);1042	error = xrep_dir_find_parent(rd);1043	xchk_ilock(sc, XFS_ILOCK_EXCL);1044	if (error)1045		return error;1046 1047	/*1048	 * Collect directory entries by parsing raw leaf blocks to salvage1049	 * whatever we can.  When we're done, free the staging memory before1050	 * exchanging the directories to reduce memory usage.1051	 */1052	error = xrep_dir_find_entries(rd);1053	if (error)1054		return error;1055 1056	/*1057	 * Cancel the repair transaction and drop the ILOCK so that we can1058	 * (later) use the atomic mapping exchange functions to compute the1059	 * correct block reservations and re-lock the inodes.1060	 *1061	 * We still hold IOLOCK_EXCL (aka i_rwsem) which will prevent directory1062	 * modifications, but there's nothing to prevent userspace from reading1063	 * the directory until we're ready for the exchange operation.  Reads1064	 * will return -EIO without shutting down the fs, so we're ok with1065	 * that.1066	 *1067	 * The VFS can change dotdot on us, but the findparent scan will keep1068	 * our incore parent inode up to date.  See the note on locking issues1069	 * for more details.1070	 */1071	error = xrep_trans_commit(sc);1072	if (error)1073		return error;1074 1075	xchk_iunlock(sc, XFS_ILOCK_EXCL);1076	return 0;1077}1078 1079 1080/*1081 * Examine a parent pointer of a file.  If it leads us back to the directory1082 * that we're rebuilding, create an incore dirent from the parent pointer and1083 * stash it.1084 */1085STATIC int1086xrep_dir_scan_pptr(1087	struct xfs_scrub		*sc,1088	struct xfs_inode		*ip,1089	unsigned int			attr_flags,1090	const unsigned char		*name,1091	unsigned int			namelen,1092	const void			*value,1093	unsigned int			valuelen,1094	void				*priv)1095{1096	struct xfs_name			xname = {1097		.name			= name,1098		.len			= namelen,1099		.type			= xfs_mode_to_ftype(VFS_I(ip)->i_mode),1100	};1101	xfs_ino_t			parent_ino;1102	uint32_t			parent_gen;1103	struct xrep_dir			*rd = priv;1104	int				error;1105 1106	if (!(attr_flags & XFS_ATTR_PARENT))1107		return 0;1108 1109	/*1110	 * Ignore parent pointers that point back to a different dir, list the1111	 * wrong generation number, or are invalid.1112	 */1113	error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value,1114			valuelen, &parent_ino, &parent_gen);1115	if (error)1116		return error;1117 1118	if (parent_ino != sc->ip->i_ino ||1119	    parent_gen != VFS_I(sc->ip)->i_generation)1120		return 0;1121 1122	mutex_lock(&rd->pscan.lock);1123	error = xrep_dir_stash_createname(rd, &xname, ip->i_ino);1124	mutex_unlock(&rd->pscan.lock);1125	return error;1126}1127 1128/*1129 * If this child dirent points to the directory being repaired, remember that1130 * fact so that we can reset the dotdot entry if necessary.1131 */1132STATIC int1133xrep_dir_scan_dirent(1134	struct xfs_scrub	*sc,1135	struct xfs_inode	*dp,1136	xfs_dir2_dataptr_t	dapos,1137	const struct xfs_name	*name,1138	xfs_ino_t		ino,1139	void			*priv)1140{1141	struct xrep_dir		*rd = priv;1142 1143	/* Dirent doesn't point to this directory. */1144	if (ino != rd->sc->ip->i_ino)1145		return 0;1146 1147	/* Ignore garbage inum. */1148	if (!xfs_verify_dir_ino(rd->sc->mp, ino))1149		return 0;1150 1151	/* No weird looking names. */1152	if (name->len >= MAXNAMELEN || name->len <= 0)1153		return 0;1154 1155	/* Don't pick up dot or dotdot entries; we only want child dirents. */1156	if (xfs_dir2_samename(name, &xfs_name_dotdot) ||1157	    xfs_dir2_samename(name, &xfs_name_dot))1158		return 0;1159 1160	trace_xrep_dir_stash_createname(sc->tempip, &xfs_name_dotdot,1161			dp->i_ino);1162 1163	xrep_findparent_scan_found(&rd->pscan, dp->i_ino);1164	return 0;1165}1166 1167/*1168 * Decide if we want to look for child dirents or parent pointers in this file.1169 * Skip the dir being repaired and any files being used to stage repairs.1170 */1171static inline bool1172xrep_dir_want_scan(1173	struct xrep_dir		*rd,1174	const struct xfs_inode	*ip)1175{1176	return ip != rd->sc->ip && !xrep_is_tempfile(ip);1177}1178 1179/*1180 * Take ILOCK on a file that we want to scan.1181 *1182 * Select ILOCK_EXCL if the file is a directory with an unloaded data bmbt or1183 * has an unloaded attr bmbt.  Otherwise, take ILOCK_SHARED.1184 */1185static inline unsigned int1186xrep_dir_scan_ilock(1187	struct xrep_dir		*rd,1188	struct xfs_inode	*ip)1189{1190	uint			lock_mode = XFS_ILOCK_SHARED;1191 1192	/* Need to take the shared ILOCK to advance the iscan cursor. */1193	if (!xrep_dir_want_scan(rd, ip))1194		goto lock;1195 1196	if (S_ISDIR(VFS_I(ip)->i_mode) && xfs_need_iread_extents(&ip->i_df)) {1197		lock_mode = XFS_ILOCK_EXCL;1198		goto lock;1199	}1200 1201	if (xfs_inode_has_attr_fork(ip) && xfs_need_iread_extents(&ip->i_af))1202		lock_mode = XFS_ILOCK_EXCL;1203 1204lock:1205	xfs_ilock(ip, lock_mode);1206	return lock_mode;1207}1208 1209/*1210 * Scan this file for relevant child dirents or parent pointers that point to1211 * the directory we're rebuilding.1212 */1213STATIC int1214xrep_dir_scan_file(1215	struct xrep_dir		*rd,1216	struct xfs_inode	*ip)1217{1218	unsigned int		lock_mode;1219	int			error = 0;1220 1221	lock_mode = xrep_dir_scan_ilock(rd, ip);1222 1223	if (!xrep_dir_want_scan(rd, ip))1224		goto scan_done;1225 1226	/*1227	 * If the extended attributes look as though they has been zapped by1228	 * the inode record repair code, we cannot scan for parent pointers.1229	 */1230	if (xchk_pptr_looks_zapped(ip)) {1231		error = -EBUSY;1232		goto scan_done;1233	}1234 1235	error = xchk_xattr_walk(rd->sc, ip, xrep_dir_scan_pptr, NULL, rd);1236	if (error)1237		goto scan_done;1238 1239	if (S_ISDIR(VFS_I(ip)->i_mode)) {1240		/*1241		 * If the directory looks as though it has been zapped by the1242		 * inode record repair code, we cannot scan for child dirents.1243		 */1244		if (xchk_dir_looks_zapped(ip)) {1245			error = -EBUSY;1246			goto scan_done;1247		}1248 1249		error = xchk_dir_walk(rd->sc, ip, xrep_dir_scan_dirent, rd);1250		if (error)1251			goto scan_done;1252	}1253 1254scan_done:1255	xchk_iscan_mark_visited(&rd->pscan.iscan, ip);1256	xfs_iunlock(ip, lock_mode);1257	return error;1258}1259 1260/*1261 * Scan all files in the filesystem for parent pointers that we can turn into1262 * replacement dirents, and a dirent that we can use to set the dotdot pointer.1263 */1264STATIC int1265xrep_dir_scan_dirtree(1266	struct xrep_dir		*rd)1267{1268	struct xfs_scrub	*sc = rd->sc;1269	struct xfs_inode	*ip;1270	int			error;1271 1272	/* Roots of directory trees are their own parents. */1273	if (sc->ip == sc->mp->m_rootip)1274		xrep_findparent_scan_found(&rd->pscan, sc->ip->i_ino);1275 1276	/*1277	 * Filesystem scans are time consuming.  Drop the directory ILOCK and1278	 * all other resources for the duration of the scan and hope for the1279	 * best.  The live update hooks will keep our scan information up to1280	 * date even though we've dropped the locks.1281	 */1282	xchk_trans_cancel(sc);1283	if (sc->ilock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL))1284		xchk_iunlock(sc, sc->ilock_flags & (XFS_ILOCK_SHARED |1285						    XFS_ILOCK_EXCL));1286	error = xchk_trans_alloc_empty(sc);1287	if (error)1288		return error;1289 1290	while ((error = xchk_iscan_iter(&rd->pscan.iscan, &ip)) == 1) {1291		bool		flush;1292 1293		error = xrep_dir_scan_file(rd, ip);1294		xchk_irele(sc, ip);1295		if (error)1296			break;1297 1298		/* Flush stashed dirent updates to constrain memory usage. */1299		mutex_lock(&rd->pscan.lock);1300		flush = xrep_dir_want_flush_stashed(rd);1301		mutex_unlock(&rd->pscan.lock);1302		if (flush) {1303			xchk_trans_cancel(sc);1304 1305			error = xrep_tempfile_iolock_polled(sc);1306			if (error)1307				break;1308 1309			error = xrep_dir_replay_updates(rd);1310			xrep_tempfile_iounlock(sc);1311			if (error)1312				break;1313 1314			error = xchk_trans_alloc_empty(sc);1315			if (error)1316				break;1317		}1318 1319		if (xchk_should_terminate(sc, &error))1320			break;1321	}1322	xchk_iscan_iter_finish(&rd->pscan.iscan);1323	if (error) {1324		/*1325		 * If we couldn't grab an inode that was busy with a state1326		 * change, change the error code so that we exit to userspace1327		 * as quickly as possible.1328		 */1329		if (error == -EBUSY)1330			return -ECANCELED;1331		return error;1332	}1333 1334	/*1335	 * Cancel the empty transaction so that we can (later) use the atomic1336	 * file mapping exchange functions to lock files and commit the new1337	 * directory.1338	 */1339	xchk_trans_cancel(rd->sc);1340	return 0;1341}1342 1343/*1344 * Capture dirent updates being made by other threads which are relevant to the1345 * directory being repaired.1346 */1347STATIC int1348xrep_dir_live_update(1349	struct notifier_block		*nb,1350	unsigned long			action,1351	void				*data)1352{1353	struct xfs_dir_update_params	*p = data;1354	struct xrep_dir			*rd;1355	struct xfs_scrub		*sc;1356	int				error = 0;1357 1358	rd = container_of(nb, struct xrep_dir, pscan.dhook.dirent_hook.nb);1359	sc = rd->sc;1360 1361	/*1362	 * This thread updated a child dirent in the directory that we're1363	 * rebuilding.  Stash the update for replay against the temporary1364	 * directory.1365	 */1366	if (p->dp->i_ino == sc->ip->i_ino &&1367	    xchk_iscan_want_live_update(&rd->pscan.iscan, p->ip->i_ino)) {1368		mutex_lock(&rd->pscan.lock);1369		if (p->delta > 0)1370			error = xrep_dir_stash_createname(rd, p->name,1371					p->ip->i_ino);1372		else1373			error = xrep_dir_stash_removename(rd, p->name,1374					p->ip->i_ino);1375		mutex_unlock(&rd->pscan.lock);1376		if (error)1377			goto out_abort;1378	}1379 1380	/*1381	 * This thread updated another directory's child dirent that points to1382	 * the directory that we're rebuilding, so remember the new dotdot1383	 * target.1384	 */1385	if (p->ip->i_ino == sc->ip->i_ino &&1386	    xchk_iscan_want_live_update(&rd->pscan.iscan, p->dp->i_ino)) {1387		if (p->delta > 0) {1388			trace_xrep_dir_stash_createname(sc->tempip,1389					&xfs_name_dotdot,1390					p->dp->i_ino);1391 1392			xrep_findparent_scan_found(&rd->pscan, p->dp->i_ino);1393		} else {1394			trace_xrep_dir_stash_removename(sc->tempip,1395					&xfs_name_dotdot,1396					rd->pscan.parent_ino);1397 1398			xrep_findparent_scan_found(&rd->pscan, NULLFSINO);1399		}1400	}1401 1402	return NOTIFY_DONE;1403out_abort:1404	xchk_iscan_abort(&rd->pscan.iscan);1405	return NOTIFY_DONE;1406}1407 1408/*1409 * Free all the directory blocks and reset the data fork.  The caller must1410 * join the inode to the transaction.  This function returns with the inode1411 * joined to a clean scrub transaction.1412 */1413STATIC int1414xrep_dir_reset_fork(1415	struct xrep_dir		*rd,1416	xfs_ino_t		parent_ino)1417{1418	struct xfs_scrub	*sc = rd->sc;1419	struct xfs_ifork	*ifp = xfs_ifork_ptr(sc->tempip, XFS_DATA_FORK);1420	int			error;1421 1422	/* Unmap all the directory buffers. */1423	if (xfs_ifork_has_extents(ifp)) {1424		error = xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);1425		if (error)1426			return error;1427	}1428 1429	trace_xrep_dir_reset_fork(sc->tempip, parent_ino);1430 1431	/* Reset the data fork to an empty data fork. */1432	xfs_idestroy_fork(ifp);1433	ifp->if_bytes = 0;1434	sc->tempip->i_disk_size = 0;1435 1436	/* Reinitialize the short form directory. */1437	xrep_dir_init_args(rd, sc->tempip, NULL);1438	return xfs_dir2_sf_create(&rd->args, parent_ino);1439}1440 1441/*1442 * Prepare both inodes' directory forks for exchanging mappings.  Promote the1443 * tempfile from short format to leaf format, and if the file being repaired1444 * has a short format data fork, turn it into an empty extent list.1445 */1446STATIC int1447xrep_dir_swap_prep(1448	struct xfs_scrub	*sc,1449	bool			temp_local,1450	bool			ip_local)1451{1452	int			error;1453 1454	/*1455	 * If the tempfile's directory is in shortform format, convert that to1456	 * a single leaf extent so that we can use the atomic mapping exchange.1457	 */1458	if (temp_local) {1459		struct xfs_da_args	args = {1460			.dp		= sc->tempip,1461			.geo		= sc->mp->m_dir_geo,1462			.whichfork	= XFS_DATA_FORK,1463			.trans		= sc->tp,1464			.total		= 1,1465			.owner		= sc->ip->i_ino,1466		};1467 1468		error = xfs_dir2_sf_to_block(&args);1469		if (error)1470			return error;1471 1472		/*1473		 * Roll the deferred log items to get us back to a clean1474		 * transaction.1475		 */1476		error = xfs_defer_finish(&sc->tp);1477		if (error)1478			return error;1479	}1480 1481	/*1482	 * If the file being repaired had a shortform data fork, convert that1483	 * to an empty extent list in preparation for the atomic mapping1484	 * exchange.1485	 */1486	if (ip_local) {1487		struct xfs_ifork	*ifp;1488 1489		ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK);1490		xfs_idestroy_fork(ifp);1491		ifp->if_format = XFS_DINODE_FMT_EXTENTS;1492		ifp->if_nextents = 0;1493		ifp->if_bytes = 0;1494		ifp->if_data = NULL;1495		ifp->if_height = 0;1496 1497		xfs_trans_log_inode(sc->tp, sc->ip,1498				XFS_ILOG_CORE | XFS_ILOG_DDATA);1499	}1500 1501	return 0;1502}1503 1504/*1505 * Replace the inode number of a directory entry.1506 */1507static int1508xrep_dir_replace(1509	struct xrep_dir		*rd,1510	struct xfs_inode	*dp,1511	const struct xfs_name	*name,1512	xfs_ino_t		inum,1513	xfs_extlen_t		total)1514{1515	struct xfs_scrub	*sc = rd->sc;1516	int			error;1517 1518	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));1519 1520	error = xfs_dir_ino_validate(sc->mp, inum);1521	if (error)1522		return error;1523 1524	xrep_dir_init_args(rd, dp, name);1525	rd->args.inumber = inum;1526	rd->args.total = total;1527	return xfs_dir_replace_args(&rd->args);1528}1529 1530/*1531 * Reset the link count of this directory and adjust the unlinked list pointers1532 * as needed.1533 */1534STATIC int1535xrep_dir_set_nlink(1536	struct xrep_dir		*rd)1537{1538	struct xfs_scrub	*sc = rd->sc;1539	struct xfs_inode	*dp = sc->ip;1540	struct xfs_perag	*pag;1541	unsigned int		new_nlink = min_t(unsigned long long,1542						  rd->subdirs + 2,1543						  XFS_NLINK_PINNED);1544	int			error;1545 1546	/*1547	 * The directory is not on the incore unlinked list, which means that1548	 * it needs to be reachable via the directory tree.  Update the nlink1549	 * with our observed link count.  If the directory has no parent, it1550	 * will be moved to the orphanage.1551	 */1552	if (!xfs_inode_on_unlinked_list(dp))1553		goto reset_nlink;1554 1555	/*1556	 * The directory is on the unlinked list and we did not find any1557	 * dirents.  Set the link count to zero and let the directory1558	 * inactivate when the last reference drops.1559	 */1560	if (rd->dirents == 0) {1561		rd->needs_adoption = false;1562		new_nlink = 0;1563		goto reset_nlink;1564	}1565 1566	/*1567	 * The directory is on the unlinked list and we found dirents.  This1568	 * directory needs to be reachable via the directory tree.  Remove the1569	 * dir from the unlinked list and update nlink with the observed link1570	 * count.  If the directory has no parent, it will be moved to the1571	 * orphanage.1572	 */1573	pag = xfs_perag_get(sc->mp, XFS_INO_TO_AGNO(sc->mp, dp->i_ino));1574	if (!pag) {1575		ASSERT(0);1576		return -EFSCORRUPTED;1577	}1578 1579	error = xfs_iunlink_remove(sc->tp, pag, dp);1580	xfs_perag_put(pag);1581	if (error)1582		return error;1583 1584reset_nlink:1585	if (VFS_I(dp)->i_nlink != new_nlink)1586		set_nlink(VFS_I(dp), new_nlink);1587	return 0;1588}1589 1590/*1591 * Finish replaying stashed dirent updates, allocate a transaction for1592 * exchanging data fork mappings, and take the ILOCKs of both directories1593 * before we commit the new directory structure.1594 */1595STATIC int1596xrep_dir_finalize_tempdir(1597	struct xrep_dir		*rd)1598{1599	struct xfs_scrub	*sc = rd->sc;1600	int			error;1601 1602	if (!xfs_has_parent(sc->mp))1603		return xrep_tempexch_trans_alloc(sc, XFS_DATA_FORK, &rd->tx);1604 1605	/*1606	 * Repair relies on the ILOCK to quiesce all possible dirent updates.1607	 * Replay all queued dirent updates into the tempdir before exchanging1608	 * the contents, even if that means dropping the ILOCKs and the1609	 * transaction.1610	 */1611	do {1612		error = xrep_dir_replay_updates(rd);1613		if (error)1614			return error;1615 1616		error = xrep_tempexch_trans_alloc(sc, XFS_DATA_FORK, &rd->tx);1617		if (error)1618			return error;1619 1620		if (xfarray_length(rd->dir_entries) == 0)1621			break;1622 1623		xchk_trans_cancel(sc);1624		xrep_tempfile_iunlock_both(sc);1625	} while (!xchk_should_terminate(sc, &error));1626	return error;1627}1628 1629/* Exchange the temporary directory's data fork with the one being repaired. */1630STATIC int1631xrep_dir_swap(1632	struct xrep_dir		*rd)1633{1634	struct xfs_scrub	*sc = rd->sc;1635	bool			ip_local, temp_local;1636	int			error = 0;1637 1638	/*1639	 * If we never found the parent for this directory, temporarily assign1640	 * the root dir as the parent; we'll move this to the orphanage after1641	 * exchanging the dir contents.  We hold the ILOCK of the dir being1642	 * repaired, so we're not worried about racy updates of dotdot.1643	 */1644	ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL);1645	if (rd->pscan.parent_ino == NULLFSINO) {1646		rd->needs_adoption = true;1647		rd->pscan.parent_ino = rd->sc->mp->m_sb.sb_rootino;1648	}1649 1650	/*1651	 * Reset the temporary directory's '..' entry to point to the parent1652	 * that we found.  The temporary directory was created with the root1653	 * directory as the parent, so we can skip this if repairing a1654	 * subdirectory of the root.1655	 *1656	 * It's also possible that this replacement could also expand a sf1657	 * tempdir into block format.1658	 */1659	if (rd->pscan.parent_ino != sc->mp->m_rootip->i_ino) {1660		error = xrep_dir_replace(rd, rd->sc->tempip, &xfs_name_dotdot,1661				rd->pscan.parent_ino, rd->tx.req.resblks);1662		if (error)1663			return error;1664	}1665 1666	/*1667	 * Changing the dot and dotdot entries could have changed the shape of1668	 * the directory, so we recompute these.1669	 */1670	ip_local = sc->ip->i_df.if_format == XFS_DINODE_FMT_LOCAL;1671	temp_local = sc->tempip->i_df.if_format == XFS_DINODE_FMT_LOCAL;1672 1673	/*1674	 * If the both files have a local format data fork and the rebuilt1675	 * directory data would fit in the repaired file's data fork, copy1676	 * the contents from the tempfile and update the directory link count.1677	 * We're done now.1678	 */1679	if (ip_local && temp_local &&1680	    sc->tempip->i_disk_size <= xfs_inode_data_fork_size(sc->ip)) {1681		xrep_tempfile_copyout_local(sc, XFS_DATA_FORK);1682		return xrep_dir_set_nlink(rd);1683	}1684 1685	/*1686	 * Clean the transaction before we start working on exchanging1687	 * directory contents.1688	 */1689	error = xrep_tempfile_roll_trans(rd->sc);1690	if (error)1691		return error;1692 1693	/* Otherwise, make sure both data forks are in block-mapping mode. */1694	error = xrep_dir_swap_prep(sc, temp_local, ip_local);1695	if (error)1696		return error;1697 1698	/*1699	 * Set nlink of the directory in the same transaction sequence that1700	 * (atomically) commits the new directory data.1701	 */1702	error = xrep_dir_set_nlink(rd);1703	if (error)1704		return error;1705 1706	return xrep_tempexch_contents(sc, &rd->tx);1707}1708 1709/*1710 * Exchange the new directory contents (which we created in the tempfile) with1711 * the directory being repaired.1712 */1713STATIC int1714xrep_dir_rebuild_tree(1715	struct xrep_dir		*rd)1716{1717	struct xfs_scrub	*sc = rd->sc;1718	int			error;1719 1720	trace_xrep_dir_rebuild_tree(sc->ip, rd->pscan.parent_ino);1721 1722	/*1723	 * Take the IOLOCK on the temporary file so that we can run dir1724	 * operations with the same locks held as we would for a normal file.1725	 * We still hold sc->ip's IOLOCK.1726	 */1727	error = xrep_tempfile_iolock_polled(rd->sc);1728	if (error)1729		return error;1730 1731	/*1732	 * Allocate transaction, lock inodes, and make sure that we've replayed1733	 * all the stashed dirent updates to the tempdir.  After this point,1734	 * we're ready to exchange data fork mappings.1735	 */1736	error = xrep_dir_finalize_tempdir(rd);1737	if (error)1738		return error;1739 1740	if (xchk_iscan_aborted(&rd->pscan.iscan))1741		return -ECANCELED;1742 1743	/*1744	 * Exchange the tempdir's data fork with the file being repaired.  This1745	 * recreates the transaction and re-takes the ILOCK in the scrub1746	 * context.1747	 */1748	error = xrep_dir_swap(rd);1749	if (error)1750		return error;1751 1752	/*1753	 * Release the old directory blocks and reset the data fork of the temp1754	 * directory to an empty shortform directory because inactivation does1755	 * nothing for directories.1756	 */1757	error = xrep_dir_reset_fork(rd, sc->mp->m_rootip->i_ino);1758	if (error)1759		return error;1760 1761	/*1762	 * Roll to get a transaction without any inodes joined to it.  Then we1763	 * can drop the tempfile's ILOCK and IOLOCK before doing more work on1764	 * the scrub target directory.1765	 */1766	error = xfs_trans_roll(&sc->tp);1767	if (error)1768		return error;1769 1770	xrep_tempfile_iunlock(sc);1771	xrep_tempfile_iounlock(sc);1772	return 0;1773}1774 1775/* Set up the filesystem scan so we can regenerate directory entries. */1776STATIC int1777xrep_dir_setup_scan(1778	struct xrep_dir		*rd)1779{1780	struct xfs_scrub	*sc = rd->sc;1781	char			*descr;1782	int			error;1783 1784	/* Set up some staging memory for salvaging dirents. */1785	descr = xchk_xfile_ino_descr(sc, "directory entries");1786	error = xfarray_create(descr, 0, sizeof(struct xrep_dirent),1787			&rd->dir_entries);1788	kfree(descr);1789	if (error)1790		return error;1791 1792	descr = xchk_xfile_ino_descr(sc, "directory entry names");1793	error = xfblob_create(descr, &rd->dir_names);1794	kfree(descr);1795	if (error)1796		goto out_xfarray;1797 1798	if (xfs_has_parent(sc->mp))1799		error = __xrep_findparent_scan_start(sc, &rd->pscan,1800				xrep_dir_live_update);1801	else1802		error = xrep_findparent_scan_start(sc, &rd->pscan);1803	if (error)1804		goto out_xfblob;1805 1806	return 0;1807 1808out_xfblob:1809	xfblob_destroy(rd->dir_names);1810	rd->dir_names = NULL;1811out_xfarray:1812	xfarray_destroy(rd->dir_entries);1813	rd->dir_entries = NULL;1814	return error;1815}1816 1817/*1818 * Move the current file to the orphanage.1819 *1820 * Caller must hold IOLOCK_EXCL on @sc->ip, and no other inode locks.  Upon1821 * successful return, the scrub transaction will have enough extra reservation1822 * to make the move; it will hold IOLOCK_EXCL and ILOCK_EXCL of @sc->ip and the1823 * orphanage; and both inodes will be ijoined.1824 */1825STATIC int1826xrep_dir_move_to_orphanage(1827	struct xrep_dir		*rd)1828{1829	struct xfs_scrub	*sc = rd->sc;1830	xfs_ino_t		orig_parent, new_parent;1831	int			error;1832 1833	/*1834	 * We are about to drop the ILOCK on sc->ip to lock the orphanage and1835	 * prepare for the adoption.  Therefore, look up the old dotdot entry1836	 * for sc->ip so that we can compare it after we re-lock sc->ip.1837	 */1838	error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &orig_parent);1839	if (error)1840		return error;1841 1842	/*1843	 * Drop the ILOCK on the scrub target and commit the transaction.1844	 * Adoption computes its own resource requirements and gathers the1845	 * necessary components.1846	 */1847	error = xrep_trans_commit(sc);1848	if (error)1849		return error;1850	xchk_iunlock(sc, XFS_ILOCK_EXCL);1851 1852	/* If we can take the orphanage's iolock then we're ready to move. */1853	if (!xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL)) {1854		xchk_iunlock(sc, sc->ilock_flags);1855		error = xrep_orphanage_iolock_two(sc);1856		if (error)1857			return error;1858	}1859 1860	/* Grab transaction and ILOCK the two files. */1861	error = xrep_adoption_trans_alloc(sc, &rd->adoption);1862	if (error)1863		return error;1864 1865	error = xrep_adoption_compute_name(&rd->adoption, &rd->xname);1866	if (error)1867		return error;1868 1869	/*1870	 * Now that we've reacquired the ILOCK on sc->ip, look up the dotdot1871	 * entry again.  If the parent changed or the child was unlinked while1872	 * the child directory was unlocked, we don't need to move the child to1873	 * the orphanage after all.1874	 */1875	error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &new_parent);1876	if (error)1877		return error;1878 1879	/*1880	 * Attach to the orphanage if we still have a linked directory and it1881	 * hasn't been moved.1882	 */1883	if (orig_parent == new_parent && VFS_I(sc->ip)->i_nlink > 0) {1884		error = xrep_adoption_move(&rd->adoption);1885		if (error)1886			return error;1887	}1888 1889	/*1890	 * Launder the scrub transaction so we can drop the orphanage ILOCK1891	 * and IOLOCK.  Return holding the scrub target's ILOCK and IOLOCK.1892	 */1893	error = xrep_adoption_trans_roll(&rd->adoption);1894	if (error)1895		return error;1896 1897	xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);1898	xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);1899	return 0;1900}1901 1902/*1903 * Repair the directory metadata.1904 *1905 * XXX: Directory entry buffers can be multiple fsblocks in size.  The buffer1906 * cache in XFS can't handle aliased multiblock buffers, so this might1907 * misbehave if the directory blocks are crosslinked with other filesystem1908 * metadata.1909 *1910 * XXX: Is it necessary to check the dcache for this directory to make sure1911 * that we always recreate every cached entry?1912 */1913int1914xrep_directory(1915	struct xfs_scrub	*sc)1916{1917	struct xrep_dir		*rd = sc->buf;1918	int			error;1919 1920	/* The rmapbt is required to reap the old data fork. */1921	if (!xfs_has_rmapbt(sc->mp))1922		return -EOPNOTSUPP;1923	/* We require atomic file exchange range to rebuild anything. */1924	if (!xfs_has_exchange_range(sc->mp))1925		return -EOPNOTSUPP;1926 1927	error = xrep_dir_setup_scan(rd);1928	if (error)1929		return error;1930 1931	if (xfs_has_parent(sc->mp))1932		error = xrep_dir_scan_dirtree(rd);1933	else1934		error = xrep_dir_salvage_entries(rd);1935	if (error)1936		goto out_teardown;1937 1938	/* Last chance to abort before we start committing fixes. */1939	if (xchk_should_terminate(sc, &error))1940		goto out_teardown;1941 1942	error = xrep_dir_rebuild_tree(rd);1943	if (error)1944		goto out_teardown;1945 1946	if (rd->needs_adoption) {1947		if (!xrep_orphanage_can_adopt(rd->sc))1948			error = -EFSCORRUPTED;1949		else1950			error = xrep_dir_move_to_orphanage(rd);1951		if (error)1952			goto out_teardown;1953	}1954 1955out_teardown:1956	xrep_dir_teardown(sc);1957	return error;1958}1959