All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Darrick J. Wong" <darrick.wong@oracle.com>
To: darrick.wong@oracle.com
Cc: linux-xfs@vger.kernel.org
Subject: [PATCH 2/5] xfs: create temporary files and directories for online repair
Date: Tue, 28 Apr 2020 19:46:26 -0700	[thread overview]
Message-ID: <158812838655.169849.13868470966237126958.stgit@magnolia> (raw)
In-Reply-To: <158812837421.169849.625434931406278072.stgit@magnolia>

From: Darrick J. Wong <darrick.wong@oracle.com>

Teach the online repair code how to create temporary files or
directories.  These temporary files can be used to stage reconstructed
information until we're ready to perform an atomic extent swap to commit
the new metadata.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/scrub/repair.c |  122 +++++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/scrub/repair.h |    1 
 fs/xfs/scrub/scrub.c  |    6 ++
 fs/xfs/scrub/scrub.h  |    3 +
 4 files changed, 132 insertions(+)


diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index c134804bc5a1..0ec483d511cd 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -31,6 +31,9 @@
 #include "xfs_attr.h"
 #include "xfs_reflink.h"
 #include "xfs_health.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_trans_space.h"
+#include "xfs_dir2.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
@@ -1502,6 +1505,125 @@ xrep_metadata_inode_forks(
 	return error;
 }
 
+/* Create a temporary file or directory. */
+int
+xrep_create_tempfile(
+	struct xfs_scrub	*sc,
+	uint16_t		mode)
+{
+	struct xfs_ialloc_args	args = {
+		.pip		= sc->mp->m_rootip,
+		.nlink		= 0,
+		.mode		= mode,
+	};
+	struct xfs_mount	*mp = sc->mp;
+	struct xfs_trans	*tp = NULL;
+	struct xfs_dquot	*udqp = NULL;
+	struct xfs_dquot	*gdqp = NULL;
+	struct xfs_dquot	*pdqp = NULL;
+	struct xfs_trans_res	*tres;
+	unsigned int		resblks;
+	bool			is_dir = S_ISDIR(mode);
+	int			error;
+
+	ASSERT(sc->tp == NULL);
+	ASSERT(sc->tempip == NULL);
+
+	if (XFS_FORCED_SHUTDOWN(mp))
+		return -EIO;
+
+	/*
+	 * Make sure that we have allocated dquot(s) on disk.  The temporary
+	 * inode should be completely root owned, but we'll still go through
+	 * the motions to keep the quota accounting accurate.
+	 */
+	error = xfs_qm_vop_dqalloc(sc->mp->m_rootip, args.uid, args.gid,
+			args.prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+			&udqp, &gdqp, &pdqp);
+	if (error)
+		return error;
+
+	if (is_dir) {
+		resblks = XFS_MKDIR_SPACE_RES(mp, 0);
+		tres = &M_RES(mp)->tr_mkdir;
+	} else {
+		resblks = XFS_IALLOC_SPACE_RES(mp);
+		tres = &M_RES(mp)->tr_create_tmpfile;
+	}
+
+	error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
+	if (error)
+		goto out_release_inode;
+
+	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, pdqp, resblks,
+			1, 0);
+	if (error)
+		goto out_trans_cancel;
+
+	/* Allocate inode, set up directory. */
+	error = xfs_dir_ialloc(&tp, &args, &sc->tempip);
+	if (error)
+		goto out_trans_cancel;
+
+	if (is_dir) {
+		error = xfs_dir_init(tp, sc->tempip, sc->mp->m_rootip);
+		if (error)
+			goto out_trans_cancel;
+	}
+
+	/*
+	 * Attach the dquot(s) to the inodes and modify them incore.
+	 * These ids of the inode couldn't have changed since the new
+	 * inode has been locked ever since it was created.
+	 */
+	xfs_qm_vop_create_dqattach(tp, sc->tempip, udqp, gdqp, pdqp);
+
+	/*
+	 * Put our temp file on the unlinked list so it's purged automatically.
+	 * Anything being reconstructed using this file must be atomically
+	 * swapped with the original file because the contents here will be
+	 * purged when the inode is dropped or log recovery cleans out the
+	 * unlinked list.
+	 */
+	error = xfs_iunlink(tp, sc->tempip);
+	if (error)
+		goto out_trans_cancel;
+
+	error = xfs_trans_commit(tp);
+	if (error)
+		goto out_release_inode;
+
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
+	xfs_qm_dqrele(pdqp);
+
+	/* Finish setting up the incore / vfs context. */
+	xfs_setup_iops(sc->tempip);
+	xfs_finish_inode_setup(sc->tempip);
+
+	sc->temp_ilock_flags = 0;
+	return error;
+
+out_trans_cancel:
+	xfs_trans_cancel(tp);
+out_release_inode:
+	/*
+	 * Wait until after the current transaction is aborted to finish the
+	 * setup of the inode and release the inode.  This prevents recursive
+	 * transactions and deadlocks from xfs_inactive.
+	 */
+	if (sc->tempip) {
+		xfs_finish_inode_setup(sc->tempip);
+		xfs_irele(sc->tempip);
+	}
+
+	xfs_qm_dqrele(udqp);
+	xfs_qm_dqrele(gdqp);
+	xfs_qm_dqrele(pdqp);
+
+	return error;
+}
+
 /*
  * Make sure that the given range of the data fork of the metadata file being
  * checked is mapped to written blocks.  The caller must ensure that the inode
diff --git a/fs/xfs/scrub/repair.h b/fs/xfs/scrub/repair.h
index 9388b3ce1cb8..299d39360c11 100644
--- a/fs/xfs/scrub/repair.h
+++ b/fs/xfs/scrub/repair.h
@@ -32,6 +32,7 @@ int xrep_alloc_ag_block(struct xfs_scrub *sc,
 int xrep_init_btblock(struct xfs_scrub *sc, xfs_fsblock_t fsb,
 		struct xfs_buf **bpp, xfs_btnum_t btnum,
 		const struct xfs_buf_ops *ops);
+int xrep_create_tempfile(struct xfs_scrub *sc, uint16_t mode);
 int xrep_fallocate(struct xfs_scrub *sc, xfs_fileoff_t off, xfs_filblks_t len);
 
 typedef int (*xrep_setfile_getbuf_fn)(struct xfs_scrub *sc,
diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c
index a2911a01cf68..a6f5b5c21f3f 100644
--- a/fs/xfs/scrub/scrub.c
+++ b/fs/xfs/scrub/scrub.c
@@ -194,6 +194,12 @@ xchk_teardown(
 		kmem_free(sc->buf);
 		sc->buf = NULL;
 	}
+	if (sc->tempip) {
+		if (sc->temp_ilock_flags)
+			xfs_iunlock(sc->tempip, sc->temp_ilock_flags);
+		xfs_irele(sc->tempip);
+		sc->tempip = NULL;
+	}
 	return error;
 }
 
diff --git a/fs/xfs/scrub/scrub.h b/fs/xfs/scrub/scrub.h
index b8d582808cd3..798942bd7eaf 100644
--- a/fs/xfs/scrub/scrub.h
+++ b/fs/xfs/scrub/scrub.h
@@ -72,6 +72,9 @@ struct xfs_scrub {
 	struct file			*xfile;
 	uint				ilock_flags;
 
+	struct xfs_inode		*tempip;
+	uint				temp_ilock_flags;
+
 	/* See the XCHK/XREP state flags below. */
 	unsigned int			flags;
 


  parent reply	other threads:[~2020-04-29  2:46 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-29  2:46 [PATCH RFCRAP 0/5] xfs: atomic file metadata repairs Darrick J. Wong
2020-04-29  2:46 ` [PATCH 1/5] xfs: parent repair should try the dcache first Darrick J. Wong
2020-04-29  2:46 ` Darrick J. Wong [this message]
2020-04-29  2:46 ` [PATCH 3/5] xfs: use atomic extent swapping to repair rt metadata Darrick J. Wong
2020-04-29  2:46 ` [PATCH 4/5] xfs: use atomic extent swapping to repair extended attributes Darrick J. Wong
2020-04-29  2:46 ` [PATCH 5/5] xfs: use atomic extent swapping to repair directories 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=158812838655.169849.13868470966237126958.stgit@magnolia \
    --to=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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.