Skip to content

Commit 9dc31ac

Browse files
author
Darrick J. Wong
committed
xfs: move repair temporary files to the metadata directory tree
Due to resource acquisition rules, we have to create the ondisk temporary files used to stage a filesystem repair before we can acquire a reference to the inode that we actually want to repair. Therefore, we do not know at tempfile creation time whether the tempfile will belong to the regular directory tree or the metadata directory tree. This distinction becomes important when the swapext code tries to figure out the quota accounting of the two files whose mappings are being swapped. The swapext code assumes that accounting updates are required for a file if dqattach attaches dquots. Metadir files are never accounted in quota, which means that swapext must not update the quota accounting when swapping in a repaired directory/xattr/rtbitmap structure. Prior to the swapext call, therefore, both files must be marked as METADIR for dqattach so that dqattach will ignore them. Add support for a repair tempfile to be switched to the metadir tree and switched back before being released so that ifree will just free the file. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent dcde94b commit 9dc31ac

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

fs/xfs/scrub/common.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "scrub/trace.h"
4040
#include "scrub/repair.h"
4141
#include "scrub/health.h"
42+
#include "scrub/tempfile.h"
4243

4344
/* Common code for the metadata scrubbers. */
4445

@@ -1090,6 +1091,10 @@ xchk_setup_inode_contents(
10901091
if (error)
10911092
return error;
10921093

1094+
error = xrep_tempfile_adjust_directory_tree(sc);
1095+
if (error)
1096+
return error;
1097+
10931098
/* Lock the inode so the VFS cannot touch this file. */
10941099
xchk_ilock(sc, XFS_IOLOCK_EXCL);
10951100

fs/xfs/scrub/tempfile.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "xfs_exchmaps.h"
2323
#include "xfs_defer.h"
2424
#include "xfs_symlink_remote.h"
25+
#include "xfs_metafile.h"
2526
#include "scrub/scrub.h"
2627
#include "scrub/common.h"
2728
#include "scrub/repair.h"
@@ -182,6 +183,101 @@ xrep_tempfile_create(
182183
return error;
183184
}
184185

186+
/*
187+
* Temporary files have to be created before we even know which inode we're
188+
* going to scrub, so we assume that they will be part of the regular directory
189+
* tree. If it turns out that we're actually scrubbing a file from the
190+
* metadata directory tree, we have to subtract the temp file from the root
191+
* dquots and detach the dquots.
192+
*/
193+
int
194+
xrep_tempfile_adjust_directory_tree(
195+
struct xfs_scrub *sc)
196+
{
197+
int error;
198+
199+
if (!sc->tempip)
200+
return 0;
201+
202+
ASSERT(sc->tp == NULL);
203+
ASSERT(!xfs_is_metadir_inode(sc->tempip));
204+
205+
if (!sc->ip || !xfs_is_metadir_inode(sc->ip))
206+
return 0;
207+
208+
xfs_ilock(sc->tempip, XFS_IOLOCK_EXCL);
209+
sc->temp_ilock_flags |= XFS_IOLOCK_EXCL;
210+
211+
error = xchk_trans_alloc(sc, 0);
212+
if (error)
213+
goto out_iolock;
214+
215+
xrep_tempfile_ilock(sc);
216+
xfs_trans_ijoin(sc->tp, sc->tempip, 0);
217+
218+
/* Metadir files are not accounted in quota, so drop icount */
219+
xfs_trans_mod_dquot_byino(sc->tp, sc->tempip, XFS_TRANS_DQ_ICOUNT, -1L);
220+
xfs_metafile_set_iflag(sc->tp, sc->tempip, XFS_METAFILE_UNKNOWN);
221+
222+
error = xrep_trans_commit(sc);
223+
if (error)
224+
goto out_ilock;
225+
226+
xfs_qm_dqdetach(sc->tempip);
227+
out_ilock:
228+
xrep_tempfile_iunlock(sc);
229+
out_iolock:
230+
xrep_tempfile_iounlock(sc);
231+
return error;
232+
}
233+
234+
/*
235+
* Remove this temporary file from the metadata directory tree so that it can
236+
* be inactivated the normal way.
237+
*/
238+
STATIC int
239+
xrep_tempfile_remove_metadir(
240+
struct xfs_scrub *sc)
241+
{
242+
int error;
243+
244+
if (!sc->tempip || !xfs_is_metadir_inode(sc->tempip))
245+
return 0;
246+
247+
ASSERT(sc->tp == NULL);
248+
249+
xfs_ilock(sc->tempip, XFS_IOLOCK_EXCL);
250+
sc->temp_ilock_flags |= XFS_IOLOCK_EXCL;
251+
252+
error = xchk_trans_alloc(sc, 0);
253+
if (error)
254+
goto out_iolock;
255+
256+
xrep_tempfile_ilock(sc);
257+
xfs_trans_ijoin(sc->tp, sc->tempip, 0);
258+
259+
xfs_metafile_clear_iflag(sc->tp, sc->tempip);
260+
261+
/* Non-metadir files are accounted in quota, so bump bcount/icount */
262+
error = xfs_qm_dqattach_locked(sc->tempip, false);
263+
if (error)
264+
goto out_cancel;
265+
266+
xfs_trans_mod_dquot_byino(sc->tp, sc->tempip, XFS_TRANS_DQ_ICOUNT, 1L);
267+
xfs_trans_mod_dquot_byino(sc->tp, sc->tempip, XFS_TRANS_DQ_BCOUNT,
268+
sc->tempip->i_nblocks);
269+
error = xrep_trans_commit(sc);
270+
goto out_ilock;
271+
272+
out_cancel:
273+
xchk_trans_cancel(sc);
274+
out_ilock:
275+
xrep_tempfile_iunlock(sc);
276+
out_iolock:
277+
xrep_tempfile_iounlock(sc);
278+
return error;
279+
}
280+
185281
/* Take IOLOCK_EXCL on the temporary file, maybe. */
186282
bool
187283
xrep_tempfile_iolock_nowait(
@@ -290,6 +386,7 @@ xrep_tempfile_rele(
290386
sc->temp_ilock_flags = 0;
291387
}
292388

389+
xrep_tempfile_remove_metadir(sc);
293390
xchk_irele(sc, sc->tempip);
294391
sc->tempip = NULL;
295392
}

fs/xfs/scrub/tempfile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
int xrep_tempfile_create(struct xfs_scrub *sc, uint16_t mode);
1111
void xrep_tempfile_rele(struct xfs_scrub *sc);
1212

13+
int xrep_tempfile_adjust_directory_tree(struct xfs_scrub *sc);
14+
1315
bool xrep_tempfile_iolock_nowait(struct xfs_scrub *sc);
1416
int xrep_tempfile_iolock_polled(struct xfs_scrub *sc);
1517
void xrep_tempfile_iounlock(struct xfs_scrub *sc);
@@ -42,6 +44,7 @@ static inline void xrep_tempfile_iolock_both(struct xfs_scrub *sc)
4244
xchk_ilock(sc, XFS_IOLOCK_EXCL);
4345
}
4446
# define xrep_is_tempfile(ip) (false)
47+
# define xrep_tempfile_adjust_directory_tree(sc) (0)
4548
# define xrep_tempfile_rele(sc)
4649
#endif /* CONFIG_XFS_ONLINE_REPAIR */
4750

0 commit comments

Comments
 (0)