|
22 | 22 | #include "xfs_exchmaps.h"
|
23 | 23 | #include "xfs_defer.h"
|
24 | 24 | #include "xfs_symlink_remote.h"
|
| 25 | +#include "xfs_metafile.h" |
25 | 26 | #include "scrub/scrub.h"
|
26 | 27 | #include "scrub/common.h"
|
27 | 28 | #include "scrub/repair.h"
|
@@ -182,6 +183,101 @@ xrep_tempfile_create(
|
182 | 183 | return error;
|
183 | 184 | }
|
184 | 185 |
|
| 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 | + |
185 | 281 | /* Take IOLOCK_EXCL on the temporary file, maybe. */
|
186 | 282 | bool
|
187 | 283 | xrep_tempfile_iolock_nowait(
|
@@ -290,6 +386,7 @@ xrep_tempfile_rele(
|
290 | 386 | sc->temp_ilock_flags = 0;
|
291 | 387 | }
|
292 | 388 |
|
| 389 | + xrep_tempfile_remove_metadir(sc); |
293 | 390 | xchk_irele(sc, sc->tempip);
|
294 | 391 | sc->tempip = NULL;
|
295 | 392 | }
|
|
0 commit comments