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
next prev parent 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).