linux-xfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dave Chinner <david@fromorbit.com>
To: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: linux-xfs@vger.kernel.org
Subject: Re: [PATCH 16/21] xfs: repair damaged symlinks
Date: Wed, 4 Jul 2018 15:45:33 +1000	[thread overview]
Message-ID: <20180704054533.GO2234@dastard> (raw)
In-Reply-To: <152986831674.3155.13573754070174091850.stgit@magnolia>

On Sun, Jun 24, 2018 at 12:25:16PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Repair inconsistent symbolic link data.
.....
> +/*
> + * Symbolic Link Repair
> + * ====================
> + *
> + * There's not much we can do to repair symbolic links -- we truncate them to
> + * the first NULL byte and fix up the remote target block headers if they're
> + * incorrect.  Zero-length symlinks are turned into links to /.
> + */
> +
> +/* Blow out the whole symlink; replace contents. */
> +STATIC int
> +xfs_repair_symlink_rewrite(
> +	struct xfs_trans	**tpp,
> +	struct xfs_inode	*ip,
> +	const char		*target_path,
> +	int			pathlen)
> +{
> +	struct xfs_defer_ops	dfops;
> +	struct xfs_bmbt_irec	mval[XFS_SYMLINK_MAPS];
> +	struct xfs_ifork	*ifp;
> +	const char		*cur_chunk;
> +	struct xfs_mount	*mp = (*tpp)->t_mountp;
> +	struct xfs_buf		*bp;
> +	xfs_fsblock_t		first_block;
> +	xfs_fileoff_t		first_fsb;
> +	xfs_filblks_t		fs_blocks;
> +	xfs_daddr_t		d;
> +	int			byte_cnt;
> +	int			n;
> +	int			nmaps;
> +	int			offset;
> +	int			error = 0;
> +
> +	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
> +
> +	/* Truncate the whole data fork if it wasn't inline. */
> +	if (!(ifp->if_flags & XFS_IFINLINE)) {
> +		error = xfs_itruncate_extents(tpp, ip, XFS_DATA_FORK, 0);
> +		if (error)
> +			goto out;
> +	}
> +
> +	/* Blow out the in-core fork and zero the on-disk fork. */
> +	xfs_idestroy_fork(ip, XFS_DATA_FORK);
> +	ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
> +	ip->i_d.di_nextents = 0;
> +	memset(&ip->i_df, 0, sizeof(struct xfs_ifork));
> +	ip->i_df.if_flags |= XFS_IFEXTENTS;

This looks familiar - doesn't the fork zapping code do exactly this,
too? factor into a helper?

> +
> +	/* Rewrite an inline symlink. */
> +	if (pathlen <= XFS_IFORK_DSIZE(ip)) {
> +		xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
> +
> +		i_size_write(VFS_I(ip), pathlen);
> +		ip->i_d.di_size = pathlen;
> +		ip->i_d.di_format = XFS_DINODE_FMT_LOCAL;
> +		xfs_trans_log_inode(*tpp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
> +		goto out;
> +
> +	}

Might make sense to separate inline vs remote into separate
functions - we tend to do that everywhere else in the symlink code.

> +
> +	/* Rewrite a remote symlink. */
> +	fs_blocks = xfs_symlink_blocks(mp, pathlen);
> +	first_fsb = 0;
> +	nmaps = XFS_SYMLINK_MAPS;
> +
> +	/* Reserve quota for new blocks. */
> +	error = xfs_trans_reserve_quota_nblks(*tpp, ip, fs_blocks, 0,
> +			XFS_QMOPT_RES_REGBLKS);
> +	if (error)
> +		goto out;
> +
> +	/* Map blocks, write symlink target. */
> +	xfs_defer_init(&dfops, &first_block);
> +
> +	error = xfs_bmapi_write(*tpp, ip, first_fsb, fs_blocks,
> +			  XFS_BMAPI_METADATA, &first_block, fs_blocks,
> +			  mval, &nmaps, &dfops);
> +	if (error)
> +		goto out_bmap_cancel;
> +
> +	ip->i_d.di_size = pathlen;
> +	i_size_write(VFS_I(ip), pathlen);
> +	xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
> +
> +	cur_chunk = target_path;
> +	offset = 0;
> +	for (n = 0; n < nmaps; n++) {
> +		char	*buf;
> +
> +		d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
> +		byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
> +		bp = xfs_trans_get_buf(*tpp, mp->m_ddev_targp, d,
> +				       BTOBB(byte_cnt), 0);
> +		if (!bp) {
> +			error = -ENOMEM;
> +			goto out_bmap_cancel;
> +		}
> +		bp->b_ops = &xfs_symlink_buf_ops;
> +
> +		byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
> +		byte_cnt = min(byte_cnt, pathlen);
> +
> +		buf = bp->b_addr;
> +		buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset,
> +					   byte_cnt, bp);
> +
> +		memcpy(buf, cur_chunk, byte_cnt);
> +
> +		cur_chunk += byte_cnt;
> +		pathlen -= byte_cnt;
> +		offset += byte_cnt;
> +
> +		xfs_trans_buf_set_type(*tpp, bp, XFS_BLFT_SYMLINK_BUF);
> +		xfs_trans_log_buf(*tpp, bp, 0, (buf + byte_cnt - 1) -
> +						(char *)bp->b_addr);
> +	}
> +	ASSERT(pathlen == 0);

This just looks like a copynpaste of main loop in xfs_symlink() -
can you factor that into a helper, please?

> +
> +	error = xfs_defer_finish(tpp, &dfops);
> +	if (error)
> +		goto out_bmap_cancel;
> +
> +	return 0;
> +
> +out_bmap_cancel:
> +	xfs_defer_cancel(&dfops);
> +out:
> +	return error;
> +}
> +
> +/* Fix everything that fails the verifiers in the remote blocks. */
> +STATIC int
> +xfs_repair_symlink_fix_remotes(
> +	struct xfs_scrub_context	*sc,
> +	loff_t				len)
> +{
> +	struct xfs_bmbt_irec		mval[XFS_SYMLINK_MAPS];
> +	struct xfs_buf			*bp;
> +	xfs_filblks_t			fsblocks;
> +	xfs_daddr_t			d;
> +	loff_t				offset;
> +	unsigned int			byte_cnt;
> +	int				n;
> +	int				nmaps = XFS_SYMLINK_MAPS;
> +	int				nr;
> +	int				error;
> +
> +	fsblocks = xfs_symlink_blocks(sc->mp, len);
> +	error = xfs_bmapi_read(sc->ip, 0, fsblocks, mval, &nmaps, 0);
> +	if (error)
> +		return error;
> +
> +	offset = 0;
> +	for (n = 0; n < nmaps; n++) {
> +		d = XFS_FSB_TO_DADDR(sc->mp, mval[n].br_startblock);
> +		byte_cnt = XFS_FSB_TO_B(sc->mp, mval[n].br_blockcount);
> +
> +		error = xfs_trans_read_buf(sc->mp, sc->tp, sc->mp->m_ddev_targp,
> +				d, BTOBB(byte_cnt), 0, &bp, NULL);
> +		if (error)
> +			return error;
> +		bp->b_ops = &xfs_symlink_buf_ops;
> +
> +		byte_cnt = XFS_SYMLINK_BUF_SPACE(sc->mp, byte_cnt);
> +		if (len < byte_cnt)
> +			byte_cnt = len;

can we make this the same as the other functions? i.e.

		byte_cnt = min(byte_cnt, len);

> +
> +		nr = xfs_symlink_hdr_set(sc->mp, sc->ip->i_ino, offset,
> +				byte_cnt, bp);
> +
> +		len -= byte_cnt;
> +		offset += byte_cnt;
> +
> +		xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_SYMLINK_BUF);
> +		xfs_trans_log_buf(sc->tp, bp, 0, nr - 1);
> +		xfs_trans_brelse(sc->tp, bp);

xfs_trans_brelse() is a no-op here because the buffer has been
logged. It can be removed.

> +	}
> +	if (len != 0)
> +		return -EFSCORRUPTED;
> +
> +	return 0;
> +}
> +
> +/* Fix this inline symlink. */
> +STATIC int
> +xfs_repair_symlink_inline(
> +	struct xfs_scrub_context	*sc)
> +{
> +	struct xfs_inode		*ip = sc->ip;
> +	struct xfs_ifork		*ifp;
> +	loff_t				len;
> +	size_t				newlen;
> +
> +	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
> +	len = i_size_read(VFS_I(ip));
> +	xfs_trans_ijoin(sc->tp, ip, 0);
> +
> +	if (ifp->if_u1.if_data) {
> +		newlen = strnlen(ifp->if_u1.if_data, XFS_IFORK_DSIZE(ip));
> +	} else {
> +		/* Zero length symlink becomes a root symlink. */
> +		ifp->if_u1.if_data = kmem_alloc(4, KM_SLEEP);
> +		snprintf(ifp->if_u1.if_data, 4, "/");
> +		newlen = 1;

helper function shared with the fork zapping code?

> +	}
> +
> +	if (len > newlen) {

shouldn't this be 'if (len != newlen) {' ?

> +		i_size_write(VFS_I(ip), newlen);
> +		ip->i_d.di_size = newlen;
> +		xfs_trans_log_inode(sc->tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Repair a remote symlink. */
> +STATIC int
> +xfs_repair_symlink_remote(
> +	struct xfs_scrub_context	*sc)
> +{
> +	struct xfs_inode		*ip = sc->ip;
> +	loff_t				len;
> +	size_t				newlen;
> +	int				error = 0;
> +
> +	len = i_size_read(VFS_I(ip));
> +	xfs_trans_ijoin(sc->tp, ip, 0);
> +
> +	error = xfs_repair_symlink_fix_remotes(sc, len);
> +	if (error)
> +		return error;
> +
> +	/* Roll transaction, release buffers. */
> +	error = xfs_trans_roll_inode(&sc->tp, ip);
> +	if (error)
> +		return error;
> +
> +	/* Size set correctly? */
> +	len = i_size_read(VFS_I(ip));
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +	error = xfs_readlink(ip, sc->buf);
> +	xfs_ilock(ip, XFS_ILOCK_EXCL);

Can we pass a "need_lock" flag to xfs_readlink() rather than
creating a race condition with anything that might be blocked on the
ilock waiting for repair to complete?

> +	if (error)
> +		return error;
> +
> +	/*
> +	 * Figure out the new target length.  We can't handle zero-length
> +	 * symlinks, so make sure that we don't write that out.
> +	 */
> +	newlen = strnlen(sc->buf, XFS_SYMLINK_MAXLEN);
> +	if (newlen == 0) {
> +		*((char *)sc->buf) = '/';
> +		newlen = 1;

We really need to do set the name of the repaired path for zero
length symlinks in only one place. It really seems to me that it
should done in xfs_repair_symlink_rewrite() if newlen is 0, not
here.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

  reply	other threads:[~2018-07-04  5:45 UTC|newest]

Thread overview: 77+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-24 19:23 [PATCH v16 00/21] xfs-4.19: online repair support Darrick J. Wong
2018-06-24 19:23 ` [PATCH 01/21] xfs: don't assume a left rmap when allocating a new rmap Darrick J. Wong
2018-06-27  0:54   ` Dave Chinner
2018-06-28 21:11   ` Allison Henderson
2018-06-29 14:39     ` Darrick J. Wong
2018-06-24 19:23 ` [PATCH 02/21] xfs: add helper to decide if an inode has allocated cow blocks Darrick J. Wong
2018-06-27  1:02   ` Dave Chinner
2018-06-28 21:12   ` Allison Henderson
2018-06-24 19:23 ` [PATCH 03/21] xfs: refactor part of xfs_free_eofblocks Darrick J. Wong
2018-06-28 21:13   ` Allison Henderson
2018-06-24 19:23 ` [PATCH 04/21] xfs: repair the AGF and AGFL Darrick J. Wong
2018-06-27  2:19   ` Dave Chinner
2018-06-27 16:44     ` Allison Henderson
2018-06-27 23:37       ` Dave Chinner
2018-06-29 15:14         ` Darrick J. Wong
2018-06-28 17:25     ` Allison Henderson
2018-06-29 15:08       ` Darrick J. Wong
2018-06-28 21:14   ` Allison Henderson
2018-06-28 23:21     ` Dave Chinner
2018-06-29  1:35       ` Allison Henderson
2018-06-29 14:55         ` Darrick J. Wong
2018-06-24 19:24 ` [PATCH 05/21] xfs: repair the AGI Darrick J. Wong
2018-06-27  2:22   ` Dave Chinner
2018-06-28 21:15   ` Allison Henderson
2018-06-24 19:24 ` [PATCH 06/21] xfs: repair free space btrees Darrick J. Wong
2018-06-27  3:21   ` Dave Chinner
2018-07-04  2:15     ` Darrick J. Wong
2018-07-04  2:25       ` Dave Chinner
2018-06-30 17:36   ` Allison Henderson
2018-06-24 19:24 ` [PATCH 07/21] xfs: repair inode btrees Darrick J. Wong
2018-06-28  0:55   ` Dave Chinner
2018-07-04  2:22     ` Darrick J. Wong
2018-06-30 17:36   ` Allison Henderson
2018-06-30 18:30     ` Darrick J. Wong
2018-07-01  0:45       ` Allison Henderson
2018-06-24 19:24 ` [PATCH 08/21] xfs: defer iput on certain inodes while scrub / repair are running Darrick J. Wong
2018-06-28 23:37   ` Dave Chinner
2018-06-29 14:49     ` Darrick J. Wong
2018-06-24 19:24 ` [PATCH 09/21] xfs: finish our set of inode get/put tracepoints for scrub Darrick J. Wong
2018-06-24 19:24 ` [PATCH 10/21] xfs: introduce online scrub freeze Darrick J. Wong
2018-06-24 19:24 ` [PATCH 11/21] xfs: repair the rmapbt Darrick J. Wong
2018-07-03  5:32   ` Dave Chinner
2018-07-03 23:59     ` Darrick J. Wong
2018-07-04  8:44       ` Carlos Maiolino
2018-07-04 18:40         ` Darrick J. Wong
2018-07-04 23:21       ` Dave Chinner
2018-07-05  3:48         ` Darrick J. Wong
2018-07-05  7:03           ` Dave Chinner
2018-07-06  0:47             ` Darrick J. Wong
2018-07-06  1:08               ` Dave Chinner
2018-06-24 19:24 ` [PATCH 12/21] xfs: repair refcount btrees Darrick J. Wong
2018-07-03  5:50   ` Dave Chinner
2018-07-04  2:23     ` Darrick J. Wong
2018-06-24 19:24 ` [PATCH 13/21] xfs: repair inode records Darrick J. Wong
2018-07-03  6:17   ` Dave Chinner
2018-07-04  0:16     ` Darrick J. Wong
2018-07-04  1:03       ` Dave Chinner
2018-07-04  1:30         ` Darrick J. Wong
2018-06-24 19:24 ` [PATCH 14/21] xfs: zap broken inode forks Darrick J. Wong
2018-07-04  2:07   ` Dave Chinner
2018-07-04  3:26     ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 15/21] xfs: repair inode block maps Darrick J. Wong
2018-07-04  3:00   ` Dave Chinner
2018-07-04  3:41     ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 16/21] xfs: repair damaged symlinks Darrick J. Wong
2018-07-04  5:45   ` Dave Chinner [this message]
2018-07-04 18:45     ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 17/21] xfs: repair extended attributes Darrick J. Wong
2018-07-06  1:03   ` Dave Chinner
2018-07-06  3:10     ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 18/21] xfs: scrub should set preen if attr leaf has holes Darrick J. Wong
2018-06-29  2:52   ` Dave Chinner
2018-06-24 19:25 ` [PATCH 19/21] xfs: repair quotas Darrick J. Wong
2018-07-06  1:50   ` Dave Chinner
2018-07-06  3:16     ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 20/21] xfs: implement live quotacheck as part of quota repair Darrick J. Wong
2018-06-24 19:25 ` [PATCH 21/21] xfs: add online scrub/repair for superblock counters Darrick J. Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180704054533.GO2234@dastard \
    --to=david@fromorbit.com \
    --cc=darrick.wong@oracle.com \
    --cc=linux-xfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).