xfs: implement live updates for directory repairs
[linux-2.6-block.git] / fs / xfs / scrub / findparent.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2020-2024 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <djwong@kernel.org>
5  */
6 #include "xfs.h"
7 #include "xfs_fs.h"
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_trans_resv.h"
11 #include "xfs_mount.h"
12 #include "xfs_defer.h"
13 #include "xfs_bit.h"
14 #include "xfs_log_format.h"
15 #include "xfs_trans.h"
16 #include "xfs_sb.h"
17 #include "xfs_inode.h"
18 #include "xfs_icache.h"
19 #include "xfs_da_format.h"
20 #include "xfs_da_btree.h"
21 #include "xfs_dir2.h"
22 #include "xfs_bmap_btree.h"
23 #include "xfs_dir2_priv.h"
24 #include "xfs_trans_space.h"
25 #include "xfs_health.h"
26 #include "xfs_exchmaps.h"
27 #include "scrub/xfs_scrub.h"
28 #include "scrub/scrub.h"
29 #include "scrub/common.h"
30 #include "scrub/trace.h"
31 #include "scrub/repair.h"
32 #include "scrub/iscan.h"
33 #include "scrub/findparent.h"
34 #include "scrub/readdir.h"
35 #include "scrub/tempfile.h"
36
37 /*
38  * Finding the Parent of a Directory
39  * =================================
40  *
41  * Directories have parent pointers, in the sense that each directory contains
42  * a dotdot entry that points to the single allowed parent.  The brute force
43  * way to find the parent of a given directory is to scan every directory in
44  * the filesystem looking for a child dirent that references this directory.
45  *
46  * This module wraps the process of scanning the directory tree.  It requires
47  * that @sc->ip is the directory whose parent we want to find, and that the
48  * caller hold only the IOLOCK on that directory.  The scan itself needs to
49  * take the ILOCK of each directory visited.
50  *
51  * Because we cannot hold @sc->ip's ILOCK during a scan of the whole fs, it is
52  * necessary to use dirent hook to update the parent scan results.  Callers
53  * must not read the scan results without re-taking @sc->ip's ILOCK.
54  *
55  * There are a few shortcuts that we can take to avoid scanning the entire
56  * filesystem, such as noticing directory tree roots and querying the dentry
57  * cache for parent information.
58  */
59
60 struct xrep_findparent_info {
61         /* The directory currently being scanned. */
62         struct xfs_inode        *dp;
63
64         /*
65          * Scrub context.  We're looking for a @dp containing a directory
66          * entry pointing to sc->ip->i_ino.
67          */
68         struct xfs_scrub        *sc;
69
70         /* Optional scan information for a xrep_findparent_scan call. */
71         struct xrep_parent_scan_info *parent_scan;
72
73         /*
74          * Parent that we've found for sc->ip.  If we're scanning the entire
75          * directory tree, we need this to ensure that we only find /one/
76          * parent directory.
77          */
78         xfs_ino_t               found_parent;
79
80         /*
81          * This is set to true if @found_parent was not observed directly from
82          * the directory scan but by noticing a change in dotdot entries after
83          * cycling the sc->ip IOLOCK.
84          */
85         bool                    parent_tentative;
86 };
87
88 /*
89  * If this directory entry points to the scrub target inode, then the directory
90  * we're scanning is the parent of the scrub target inode.
91  */
92 STATIC int
93 xrep_findparent_dirent(
94         struct xfs_scrub                *sc,
95         struct xfs_inode                *dp,
96         xfs_dir2_dataptr_t              dapos,
97         const struct xfs_name           *name,
98         xfs_ino_t                       ino,
99         void                            *priv)
100 {
101         struct xrep_findparent_info     *fpi = priv;
102         int                             error = 0;
103
104         if (xchk_should_terminate(fpi->sc, &error))
105                 return error;
106
107         if (ino != fpi->sc->ip->i_ino)
108                 return 0;
109
110         /* Ignore garbage directory entry names. */
111         if (name->len == 0 || !xfs_dir2_namecheck(name->name, name->len))
112                 return -EFSCORRUPTED;
113
114         /*
115          * Ignore dotdot and dot entries -- we're looking for parent -> child
116          * links only.
117          */
118         if (name->name[0] == '.' && (name->len == 1 ||
119                                      (name->len == 2 && name->name[1] == '.')))
120                 return 0;
121
122         /* Uhoh, more than one parent for a dir? */
123         if (fpi->found_parent != NULLFSINO &&
124             !(fpi->parent_tentative && fpi->found_parent == fpi->dp->i_ino)) {
125                 trace_xrep_findparent_dirent(fpi->sc->ip, 0);
126                 return -EFSCORRUPTED;
127         }
128
129         /* We found a potential parent; remember this. */
130         trace_xrep_findparent_dirent(fpi->sc->ip, fpi->dp->i_ino);
131         fpi->found_parent = fpi->dp->i_ino;
132         fpi->parent_tentative = false;
133
134         if (fpi->parent_scan)
135                 xrep_findparent_scan_found(fpi->parent_scan, fpi->dp->i_ino);
136
137         return 0;
138 }
139
140 /*
141  * If this is a directory, walk the dirents looking for any that point to the
142  * scrub target inode.
143  */
144 STATIC int
145 xrep_findparent_walk_directory(
146         struct xrep_findparent_info     *fpi)
147 {
148         struct xfs_scrub                *sc = fpi->sc;
149         struct xfs_inode                *dp = fpi->dp;
150         unsigned int                    lock_mode;
151         int                             error = 0;
152
153         /*
154          * The inode being scanned cannot be its own parent, nor can any
155          * temporary directory we created to stage this repair.
156          */
157         if (dp == sc->ip || dp == sc->tempip)
158                 return 0;
159
160         /*
161          * Similarly, temporary files created to stage a repair cannot be the
162          * parent of this inode.
163          */
164         if (xrep_is_tempfile(dp))
165                 return 0;
166
167         /*
168          * Scan the directory to see if there it contains an entry pointing to
169          * the directory that we are repairing.
170          */
171         lock_mode = xfs_ilock_data_map_shared(dp);
172
173         /*
174          * If this directory is known to be sick, we cannot scan it reliably
175          * and must abort.
176          */
177         if (xfs_inode_has_sickness(dp, XFS_SICK_INO_CORE |
178                                        XFS_SICK_INO_BMBTD |
179                                        XFS_SICK_INO_DIR)) {
180                 error = -EFSCORRUPTED;
181                 goto out_unlock;
182         }
183
184         /*
185          * We cannot complete our parent pointer scan if a directory looks as
186          * though it has been zapped by the inode record repair code.
187          */
188         if (xchk_dir_looks_zapped(dp)) {
189                 error = -EBUSY;
190                 goto out_unlock;
191         }
192
193         error = xchk_dir_walk(sc, dp, xrep_findparent_dirent, fpi);
194         if (error)
195                 goto out_unlock;
196
197 out_unlock:
198         xfs_iunlock(dp, lock_mode);
199         return error;
200 }
201
202 /*
203  * Update this directory's dotdot pointer based on ongoing dirent updates.
204  */
205 STATIC int
206 xrep_findparent_live_update(
207         struct notifier_block           *nb,
208         unsigned long                   action,
209         void                            *data)
210 {
211         struct xfs_dir_update_params    *p = data;
212         struct xrep_parent_scan_info    *pscan;
213         struct xfs_scrub                *sc;
214
215         pscan = container_of(nb, struct xrep_parent_scan_info,
216                         dhook.dirent_hook.nb);
217         sc = pscan->sc;
218
219         /*
220          * If @p->ip is the subdirectory that we're interested in and we've
221          * already scanned @p->dp, update the dotdot target inumber to the
222          * parent inode.
223          */
224         if (p->ip->i_ino == sc->ip->i_ino &&
225             xchk_iscan_want_live_update(&pscan->iscan, p->dp->i_ino)) {
226                 if (p->delta > 0) {
227                         xrep_findparent_scan_found(pscan, p->dp->i_ino);
228                 } else {
229                         xrep_findparent_scan_found(pscan, NULLFSINO);
230                 }
231         }
232
233         return NOTIFY_DONE;
234 }
235
236 /*
237  * Set up a scan to find the parent of a directory.  The provided dirent hook
238  * will be called when there is a dotdot update for the inode being repaired.
239  */
240 int
241 __xrep_findparent_scan_start(
242         struct xfs_scrub                *sc,
243         struct xrep_parent_scan_info    *pscan,
244         notifier_fn_t                   custom_fn)
245 {
246         int                             error;
247
248         if (!(sc->flags & XCHK_FSGATES_DIRENTS)) {
249                 ASSERT(sc->flags & XCHK_FSGATES_DIRENTS);
250                 return -EINVAL;
251         }
252
253         pscan->sc = sc;
254         pscan->parent_ino = NULLFSINO;
255
256         mutex_init(&pscan->lock);
257
258         xchk_iscan_start(sc, 30000, 100, &pscan->iscan);
259
260         /*
261          * Hook into the dirent update code.  The hook only operates on inodes
262          * that were already scanned, and the scanner thread takes each inode's
263          * ILOCK, which means that any in-progress inode updates will finish
264          * before we can scan the inode.
265          */
266         if (custom_fn)
267                 xfs_dir_hook_setup(&pscan->dhook, custom_fn);
268         else
269                 xfs_dir_hook_setup(&pscan->dhook, xrep_findparent_live_update);
270         error = xfs_dir_hook_add(sc->mp, &pscan->dhook);
271         if (error)
272                 goto out_iscan;
273
274         return 0;
275 out_iscan:
276         xchk_iscan_teardown(&pscan->iscan);
277         mutex_destroy(&pscan->lock);
278         return error;
279 }
280
281 /*
282  * Scan the entire filesystem looking for a parent inode for the inode being
283  * scrubbed.  @sc->ip must not be the root of a directory tree.  Callers must
284  * not hold a dirty transaction or any lock that would interfere with taking
285  * an ILOCK.
286  *
287  * Returns 0 with @pscan->parent_ino set to the parent that we found.
288  * Returns 0 with @pscan->parent_ino set to NULLFSINO if we found no parents.
289  * Returns the usual negative errno if something else happened.
290  */
291 int
292 xrep_findparent_scan(
293         struct xrep_parent_scan_info    *pscan)
294 {
295         struct xrep_findparent_info     fpi = {
296                 .sc                     = pscan->sc,
297                 .found_parent           = NULLFSINO,
298                 .parent_scan            = pscan,
299         };
300         struct xfs_scrub                *sc = pscan->sc;
301         int                             ret;
302
303         ASSERT(S_ISDIR(VFS_IC(sc->ip)->i_mode));
304
305         while ((ret = xchk_iscan_iter(&pscan->iscan, &fpi.dp)) == 1) {
306                 if (S_ISDIR(VFS_I(fpi.dp)->i_mode))
307                         ret = xrep_findparent_walk_directory(&fpi);
308                 else
309                         ret = 0;
310                 xchk_iscan_mark_visited(&pscan->iscan, fpi.dp);
311                 xchk_irele(sc, fpi.dp);
312                 if (ret)
313                         break;
314
315                 if (xchk_should_terminate(sc, &ret))
316                         break;
317         }
318         xchk_iscan_iter_finish(&pscan->iscan);
319
320         return ret;
321 }
322
323 /* Tear down a parent scan. */
324 void
325 xrep_findparent_scan_teardown(
326         struct xrep_parent_scan_info    *pscan)
327 {
328         xfs_dir_hook_del(pscan->sc->mp, &pscan->dhook);
329         xchk_iscan_teardown(&pscan->iscan);
330         mutex_destroy(&pscan->lock);
331 }
332
333 /* Finish a parent scan early. */
334 void
335 xrep_findparent_scan_finish_early(
336         struct xrep_parent_scan_info    *pscan,
337         xfs_ino_t                       ino)
338 {
339         xrep_findparent_scan_found(pscan, ino);
340         xchk_iscan_finish_early(&pscan->iscan);
341 }
342
343 /*
344  * Confirm that the directory @parent_ino actually contains a directory entry
345  * pointing to the child @sc->ip->ino.  This function returns one of several
346  * ways:
347  *
348  * Returns 0 with @parent_ino unchanged if the parent was confirmed.
349  * Returns 0 with @parent_ino set to NULLFSINO if the parent was not valid.
350  * Returns the usual negative errno if something else happened.
351  */
352 int
353 xrep_findparent_confirm(
354         struct xfs_scrub        *sc,
355         xfs_ino_t               *parent_ino)
356 {
357         struct xrep_findparent_info fpi = {
358                 .sc             = sc,
359                 .found_parent   = NULLFSINO,
360         };
361         int                     error;
362
363         /*
364          * The root directory always points to itself.  Unlinked dirs can point
365          * anywhere, so we point them at the root dir too.
366          */
367         if (sc->ip == sc->mp->m_rootip || VFS_I(sc->ip)->i_nlink == 0) {
368                 *parent_ino = sc->mp->m_sb.sb_rootino;
369                 return 0;
370         }
371
372         /* Reject garbage parent inode numbers and self-referential parents. */
373         if (*parent_ino == NULLFSINO)
374                return 0;
375         if (!xfs_verify_dir_ino(sc->mp, *parent_ino) ||
376             *parent_ino == sc->ip->i_ino) {
377                 *parent_ino = NULLFSINO;
378                 return 0;
379         }
380
381         error = xchk_iget(sc, *parent_ino, &fpi.dp);
382         if (error)
383                 return error;
384
385         if (!S_ISDIR(VFS_I(fpi.dp)->i_mode)) {
386                 *parent_ino = NULLFSINO;
387                 goto out_rele;
388         }
389
390         error = xrep_findparent_walk_directory(&fpi);
391         if (error)
392                 goto out_rele;
393
394         *parent_ino = fpi.found_parent;
395 out_rele:
396         xchk_irele(sc, fpi.dp);
397         return error;
398 }
399
400 /*
401  * If we're the root of a directory tree, we are our own parent.  If we're an
402  * unlinked directory, the parent /won't/ have a link to us.  Set the parent
403  * directory to the root for both cases.  Returns NULLFSINO if we don't know
404  * what to do.
405  */
406 xfs_ino_t
407 xrep_findparent_self_reference(
408         struct xfs_scrub        *sc)
409 {
410         if (sc->ip->i_ino == sc->mp->m_sb.sb_rootino)
411                 return sc->mp->m_sb.sb_rootino;
412
413         if (VFS_I(sc->ip)->i_nlink == 0)
414                 return sc->mp->m_sb.sb_rootino;
415
416         return NULLFSINO;
417 }
418
419 /* Check the dentry cache to see if knows of a parent for the scrub target. */
420 xfs_ino_t
421 xrep_findparent_from_dcache(
422         struct xfs_scrub        *sc)
423 {
424         struct inode            *pip = NULL;
425         struct dentry           *dentry, *parent;
426         xfs_ino_t               ret = NULLFSINO;
427
428         dentry = d_find_alias(VFS_I(sc->ip));
429         if (!dentry)
430                 goto out;
431
432         parent = dget_parent(dentry);
433         if (!parent)
434                 goto out_dput;
435
436         ASSERT(parent->d_sb == sc->ip->i_mount->m_super);
437
438         pip = igrab(d_inode(parent));
439         dput(parent);
440
441         if (S_ISDIR(pip->i_mode)) {
442                 trace_xrep_findparent_from_dcache(sc->ip, XFS_I(pip)->i_ino);
443                 ret = XFS_I(pip)->i_ino;
444         }
445
446         xchk_irele(sc, XFS_I(pip));
447
448 out_dput:
449         dput(dentry);
450 out:
451         return ret;
452 }