From: "Darrick J. Wong" <darrick.wong@oracle.com>
To: Dave Chinner <david@fromorbit.com>
Cc: linux-xfs@vger.kernel.org
Subject: Re: [PATCH 16/21] xfs: repair damaged symlinks
Date: Wed, 4 Jul 2018 11:45:29 -0700 [thread overview]
Message-ID: <20180704184529.GG32415@magnolia> (raw)
In-Reply-To: <20180704054533.GO2234@dastard>
On Wed, Jul 04, 2018 at 03:45:33PM +1000, Dave Chinner wrote:
> 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?
Yeah, helpers clearly needed somewhere.
> > +
> > + /* 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.
Ok.
> > +
> > + /* 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?
Ok.
> > +
> > + 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);
<nod>
> > +
> > + 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.
<nod>
> > + }
> > + 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?
Yes.
> > + }
> > +
> > + if (len > newlen) {
>
> shouldn't this be 'if (len != newlen) {' ?
Yes.
> > + 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?
LOL, there already is a locked version of that, which I added two years
ago in preparation for online symlink scrub. Will switch to
xfs_readlink_bmap_ilocked.
> > + 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.
Agreed, will work on that.
--D
> Cheers,
>
> Dave.
> --
> Dave Chinner
> david@fromorbit.com
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2018-07-04 18: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
2018-07-04 18:45 ` Darrick J. Wong [this message]
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=20180704184529.GG32415@magnolia \
--to=darrick.wong@oracle.com \
--cc=david@fromorbit.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).