~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/xfs/scrub/orphanage.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Copyright (c) 2021-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_log_format.h"
 13 #include "xfs_trans.h"
 14 #include "xfs_inode.h"
 15 #include "xfs_ialloc.h"
 16 #include "xfs_quota.h"
 17 #include "xfs_trans_space.h"
 18 #include "xfs_dir2.h"
 19 #include "xfs_icache.h"
 20 #include "xfs_bmap.h"
 21 #include "xfs_bmap_btree.h"
 22 #include "xfs_parent.h"
 23 #include "xfs_attr_sf.h"
 24 #include "scrub/scrub.h"
 25 #include "scrub/common.h"
 26 #include "scrub/repair.h"
 27 #include "scrub/trace.h"
 28 #include "scrub/orphanage.h"
 29 #include "scrub/readdir.h"
 30 
 31 #include <linux/namei.h>
 32 
 33 /*
 34  * The Orphanage
 35  * =============
 36  *
 37  * If the directory tree is damaged, children of that directory become
 38  * inaccessible via that file path.  If a child has no other parents, the file
 39  * is said to be orphaned.  xfs_repair fixes this situation by creating a
 40  * orphanage directory (specifically, /lost+found) and creating a directory
 41  * entry pointing to the orphaned file.
 42  *
 43  * Online repair follows this tactic by creating a root-owned /lost+found
 44  * directory if one does not exist.  If an orphan is found, it will move that
 45  * files into orphanage.
 46  */
 47 
 48 /* Make the orphanage owned by root. */
 49 STATIC int
 50 xrep_chown_orphanage(
 51         struct xfs_scrub        *sc,
 52         struct xfs_inode        *dp)
 53 {
 54         struct xfs_trans        *tp;
 55         struct xfs_mount        *mp = sc->mp;
 56         struct xfs_dquot        *udqp = NULL, *gdqp = NULL, *pdqp = NULL;
 57         struct xfs_dquot        *oldu = NULL, *oldg = NULL, *oldp = NULL;
 58         struct inode            *inode = VFS_I(dp);
 59         int                     error;
 60 
 61         error = xfs_qm_vop_dqalloc(dp, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0,
 62                         XFS_QMOPT_QUOTALL, &udqp, &gdqp, &pdqp);
 63         if (error)
 64                 return error;
 65 
 66         error = xfs_trans_alloc_ichange(dp, udqp, gdqp, pdqp, true, &tp);
 67         if (error)
 68                 goto out_dqrele;
 69 
 70         /*
 71          * Always clear setuid/setgid/sticky on the orphanage since we don't
 72          * normally want that functionality on this directory and xfs_repair
 73          * doesn't create it this way either.  Leave the other access bits
 74          * unchanged.
 75          */
 76         inode->i_mode &= ~(S_ISUID | S_ISGID | S_ISVTX);
 77 
 78         /*
 79          * Change the ownerships and register quota modifications
 80          * in the transaction.
 81          */
 82         if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID)) {
 83                 if (XFS_IS_UQUOTA_ON(mp))
 84                         oldu = xfs_qm_vop_chown(tp, dp, &dp->i_udquot, udqp);
 85                 inode->i_uid = GLOBAL_ROOT_UID;
 86         }
 87         if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID)) {
 88                 if (XFS_IS_GQUOTA_ON(mp))
 89                         oldg = xfs_qm_vop_chown(tp, dp, &dp->i_gdquot, gdqp);
 90                 inode->i_gid = GLOBAL_ROOT_GID;
 91         }
 92         if (dp->i_projid != 0) {
 93                 if (XFS_IS_PQUOTA_ON(mp))
 94                         oldp = xfs_qm_vop_chown(tp, dp, &dp->i_pdquot, pdqp);
 95                 dp->i_projid = 0;
 96         }
 97 
 98         dp->i_diflags &= ~(XFS_DIFLAG_REALTIME | XFS_DIFLAG_RTINHERIT);
 99         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
100 
101         XFS_STATS_INC(mp, xs_ig_attrchg);
102 
103         if (xfs_has_wsync(mp))
104                 xfs_trans_set_sync(tp);
105         error = xfs_trans_commit(tp);
106 
107         xfs_qm_dqrele(oldu);
108         xfs_qm_dqrele(oldg);
109         xfs_qm_dqrele(oldp);
110 
111 out_dqrele:
112         xfs_qm_dqrele(udqp);
113         xfs_qm_dqrele(gdqp);
114         xfs_qm_dqrele(pdqp);
115         return error;
116 }
117 
118 #define ORPHANAGE       "lost+found"
119 
120 /* Create the orphanage directory, and set sc->orphanage to it. */
121 int
122 xrep_orphanage_create(
123         struct xfs_scrub        *sc)
124 {
125         struct xfs_mount        *mp = sc->mp;
126         struct dentry           *root_dentry, *orphanage_dentry;
127         struct inode            *root_inode = VFS_I(sc->mp->m_rootip);
128         struct inode            *orphanage_inode;
129         int                     error;
130 
131         if (xfs_is_shutdown(mp))
132                 return -EIO;
133         if (xfs_is_readonly(mp)) {
134                 sc->orphanage = NULL;
135                 return 0;
136         }
137 
138         ASSERT(sc->tp == NULL);
139         ASSERT(sc->orphanage == NULL);
140 
141         /* Find the dentry for the root directory... */
142         root_dentry = d_find_alias(root_inode);
143         if (!root_dentry) {
144                 error = -EFSCORRUPTED;
145                 goto out;
146         }
147 
148         /* ...which is a directory, right? */
149         if (!d_is_dir(root_dentry)) {
150                 error = -EFSCORRUPTED;
151                 goto out_dput_root;
152         }
153 
154         /* Try to find the orphanage directory. */
155         inode_lock_nested(root_inode, I_MUTEX_PARENT);
156         orphanage_dentry = lookup_one_len(ORPHANAGE, root_dentry,
157                         strlen(ORPHANAGE));
158         if (IS_ERR(orphanage_dentry)) {
159                 error = PTR_ERR(orphanage_dentry);
160                 goto out_unlock_root;
161         }
162 
163         /*
164          * Nothing found?  Call mkdir to create the orphanage.  Create the
165          * directory without other-user access because we're live and someone
166          * could have been relying partly on minimal access to a parent
167          * directory to control access to a file we put in here.
168          */
169         if (d_really_is_negative(orphanage_dentry)) {
170                 error = vfs_mkdir(&nop_mnt_idmap, root_inode, orphanage_dentry,
171                                 0750);
172                 if (error)
173                         goto out_dput_orphanage;
174         }
175 
176         /* Not a directory? Bail out. */
177         if (!d_is_dir(orphanage_dentry)) {
178                 error = -ENOTDIR;
179                 goto out_dput_orphanage;
180         }
181 
182         /*
183          * Grab a reference to the orphanage.  This /should/ succeed since
184          * we hold the root directory locked and therefore nobody can delete
185          * the orphanage.
186          */
187         orphanage_inode = igrab(d_inode(orphanage_dentry));
188         if (!orphanage_inode) {
189                 error = -ENOENT;
190                 goto out_dput_orphanage;
191         }
192 
193         /* Make sure the orphanage is owned by root. */
194         error = xrep_chown_orphanage(sc, XFS_I(orphanage_inode));
195         if (error)
196                 goto out_dput_orphanage;
197 
198         /* Stash the reference for later and bail out. */
199         sc->orphanage = XFS_I(orphanage_inode);
200         sc->orphanage_ilock_flags = 0;
201 
202 out_dput_orphanage:
203         dput(orphanage_dentry);
204 out_unlock_root:
205         inode_unlock(VFS_I(sc->mp->m_rootip));
206 out_dput_root:
207         dput(root_dentry);
208 out:
209         return error;
210 }
211 
212 void
213 xrep_orphanage_ilock(
214         struct xfs_scrub        *sc,
215         unsigned int            ilock_flags)
216 {
217         sc->orphanage_ilock_flags |= ilock_flags;
218         xfs_ilock(sc->orphanage, ilock_flags);
219 }
220 
221 bool
222 xrep_orphanage_ilock_nowait(
223         struct xfs_scrub        *sc,
224         unsigned int            ilock_flags)
225 {
226         if (xfs_ilock_nowait(sc->orphanage, ilock_flags)) {
227                 sc->orphanage_ilock_flags |= ilock_flags;
228                 return true;
229         }
230 
231         return false;
232 }
233 
234 void
235 xrep_orphanage_iunlock(
236         struct xfs_scrub        *sc,
237         unsigned int            ilock_flags)
238 {
239         xfs_iunlock(sc->orphanage, ilock_flags);
240         sc->orphanage_ilock_flags &= ~ilock_flags;
241 }
242 
243 /* Grab the IOLOCK of the orphanage and sc->ip. */
244 int
245 xrep_orphanage_iolock_two(
246         struct xfs_scrub        *sc)
247 {
248         int                     error = 0;
249 
250         while (true) {
251                 if (xchk_should_terminate(sc, &error))
252                         return error;
253 
254                 /*
255                  * Normal XFS takes the IOLOCK before grabbing a transaction.
256                  * Scrub holds a transaction, which means that we can't block
257                  * on either IOLOCK.
258                  */
259                 if (xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL)) {
260                         if (xchk_ilock_nowait(sc, XFS_IOLOCK_EXCL))
261                                 break;
262                         xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
263                 }
264                 delay(1);
265         }
266 
267         return 0;
268 }
269 
270 /* Release the orphanage. */
271 void
272 xrep_orphanage_rele(
273         struct xfs_scrub        *sc)
274 {
275         if (!sc->orphanage)
276                 return;
277 
278         if (sc->orphanage_ilock_flags)
279                 xfs_iunlock(sc->orphanage, sc->orphanage_ilock_flags);
280 
281         xchk_irele(sc, sc->orphanage);
282         sc->orphanage = NULL;
283 }
284 
285 /* Adoption moves a file into /lost+found */
286 
287 /* Can the orphanage adopt @sc->ip? */
288 bool
289 xrep_orphanage_can_adopt(
290         struct xfs_scrub        *sc)
291 {
292         ASSERT(sc->ip != NULL);
293 
294         if (!sc->orphanage)
295                 return false;
296         if (sc->ip == sc->orphanage)
297                 return false;
298         if (xfs_internal_inum(sc->mp, sc->ip->i_ino))
299                 return false;
300         return true;
301 }
302 
303 /*
304  * Create a new transaction to send a child to the orphanage.
305  *
306  * Allocate a new transaction with sufficient disk space to handle the
307  * adoption, take ILOCK_EXCL of the orphanage and sc->ip, joins them to the
308  * transaction, and reserve quota to reparent the latter.  Caller must hold the
309  * IOLOCK of the orphanage and sc->ip.
310  */
311 int
312 xrep_adoption_trans_alloc(
313         struct xfs_scrub        *sc,
314         struct xrep_adoption    *adopt)
315 {
316         struct xfs_mount        *mp = sc->mp;
317         unsigned int            child_blkres = 0;
318         int                     error;
319 
320         ASSERT(sc->tp == NULL);
321         ASSERT(sc->ip != NULL);
322         ASSERT(sc->orphanage != NULL);
323         ASSERT(sc->ilock_flags & XFS_IOLOCK_EXCL);
324         ASSERT(sc->orphanage_ilock_flags & XFS_IOLOCK_EXCL);
325         ASSERT(!(sc->ilock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)));
326         ASSERT(!(sc->orphanage_ilock_flags &
327                                 (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)));
328 
329         /* Compute the worst case space reservation that we need. */
330         adopt->sc = sc;
331         adopt->orphanage_blkres = xfs_link_space_res(mp, MAXNAMELEN);
332         if (S_ISDIR(VFS_I(sc->ip)->i_mode))
333                 child_blkres = xfs_rename_space_res(mp, 0, false,
334                                                     xfs_name_dotdot.len, false);
335         if (xfs_has_parent(mp))
336                 child_blkres += XFS_ADDAFORK_SPACE_RES(mp);
337         adopt->child_blkres = child_blkres;
338 
339         /*
340          * Allocate a transaction to link the child into the parent, along with
341          * enough disk space to handle expansion of both the orphanage and the
342          * dotdot entry of a child directory.
343          */
344         error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link,
345                         adopt->orphanage_blkres + adopt->child_blkres, 0, 0,
346                         &sc->tp);
347         if (error)
348                 return error;
349 
350         xfs_lock_two_inodes(sc->orphanage, XFS_ILOCK_EXCL,
351                             sc->ip, XFS_ILOCK_EXCL);
352         sc->ilock_flags |= XFS_ILOCK_EXCL;
353         sc->orphanage_ilock_flags |= XFS_ILOCK_EXCL;
354 
355         xfs_trans_ijoin(sc->tp, sc->orphanage, 0);
356         xfs_trans_ijoin(sc->tp, sc->ip, 0);
357 
358         /*
359          * Reserve enough quota in the orphan directory to add the new name.
360          * Normally the orphanage should have user/group/project ids of zero
361          * and hence is not subject to quota enforcement, but we're allowed to
362          * exceed quota to reattach disconnected parts of the directory tree.
363          */
364         error = xfs_trans_reserve_quota_nblks(sc->tp, sc->orphanage,
365                         adopt->orphanage_blkres, 0, true);
366         if (error)
367                 goto out_cancel;
368 
369         /*
370          * Reserve enough quota in the child directory to change dotdot.
371          * Here we're also allowed to exceed file quota to repair inconsistent
372          * metadata.
373          */
374         if (adopt->child_blkres) {
375                 error = xfs_trans_reserve_quota_nblks(sc->tp, sc->ip,
376                                 adopt->child_blkres, 0, true);
377                 if (error)
378                         goto out_cancel;
379         }
380 
381         return 0;
382 out_cancel:
383         xchk_trans_cancel(sc);
384         xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
385         xchk_iunlock(sc, XFS_ILOCK_EXCL);
386         return error;
387 }
388 
389 /*
390  * Compute the xfs_name for the directory entry that we're adding to the
391  * orphanage.  Caller must hold ILOCKs of sc->ip and the orphanage and must not
392  * reuse namebuf until the adoption completes or is dissolved.
393  */
394 int
395 xrep_adoption_compute_name(
396         struct xrep_adoption    *adopt,
397         struct xfs_name         *xname)
398 {
399         struct xfs_scrub        *sc = adopt->sc;
400         char                    *namebuf = (void *)xname->name;
401         xfs_ino_t               ino;
402         unsigned int            incr = 0;
403         int                     error = 0;
404 
405         adopt->xname = xname;
406         xname->len = snprintf(namebuf, MAXNAMELEN, "%llu", sc->ip->i_ino);
407         xname->type = xfs_mode_to_ftype(VFS_I(sc->ip)->i_mode);
408 
409         /* Make sure the filename is unique in the lost+found. */
410         error = xchk_dir_lookup(sc, sc->orphanage, xname, &ino);
411         while (error == 0 && incr < 10000) {
412                 xname->len = snprintf(namebuf, MAXNAMELEN, "%llu.%u",
413                                 sc->ip->i_ino, ++incr);
414                 error = xchk_dir_lookup(sc, sc->orphanage, xname, &ino);
415         }
416         if (error == 0) {
417                 /* We already have 10,000 entries in the orphanage? */
418                 return -EFSCORRUPTED;
419         }
420 
421         if (error != -ENOENT)
422                 return error;
423         return 0;
424 }
425 
426 /*
427  * Make sure the dcache does not have a positive dentry for the name we've
428  * chosen.  The caller should have checked with the ondisk directory, so any
429  * discrepancy is a sign that something is seriously wrong.
430  */
431 static int
432 xrep_adoption_check_dcache(
433         struct xrep_adoption    *adopt)
434 {
435         struct qstr             qname = QSTR_INIT(adopt->xname->name,
436                                                   adopt->xname->len);
437         struct xfs_scrub        *sc = adopt->sc;
438         struct dentry           *d_orphanage, *d_child;
439         int                     error = 0;
440 
441         d_orphanage = d_find_alias(VFS_I(sc->orphanage));
442         if (!d_orphanage)
443                 return 0;
444 
445         d_child = d_hash_and_lookup(d_orphanage, &qname);
446         if (d_child) {
447                 trace_xrep_adoption_check_child(sc->mp, d_child);
448 
449                 if (d_is_positive(d_child)) {
450                         ASSERT(d_is_negative(d_child));
451                         error = -EFSCORRUPTED;
452                 }
453 
454                 dput(d_child);
455         }
456 
457         dput(d_orphanage);
458         return error;
459 }
460 
461 /*
462  * Invalidate all dentries for the name that was added to the orphanage
463  * directory, and all dentries pointing to the child inode that was moved.
464  *
465  * There should not be any positive entries for the name, since we've
466  * maintained our lock on the orphanage directory.
467  */
468 static void
469 xrep_adoption_zap_dcache(
470         struct xrep_adoption    *adopt)
471 {
472         struct qstr             qname = QSTR_INIT(adopt->xname->name,
473                                                   adopt->xname->len);
474         struct xfs_scrub        *sc = adopt->sc;
475         struct dentry           *d_orphanage, *d_child;
476 
477         /* Invalidate all dentries for the adoption name */
478         d_orphanage = d_find_alias(VFS_I(sc->orphanage));
479         if (!d_orphanage)
480                 return;
481 
482         d_child = d_hash_and_lookup(d_orphanage, &qname);
483         while (d_child != NULL) {
484                 trace_xrep_adoption_invalidate_child(sc->mp, d_child);
485 
486                 ASSERT(d_is_negative(d_child));
487                 d_invalidate(d_child);
488                 dput(d_child);
489                 d_child = d_lookup(d_orphanage, &qname);
490         }
491 
492         dput(d_orphanage);
493 
494         /* Invalidate all the dentries pointing down to this file. */
495         while ((d_child = d_find_alias(VFS_I(sc->ip))) != NULL) {
496                 trace_xrep_adoption_invalidate_child(sc->mp, d_child);
497 
498                 d_invalidate(d_child);
499                 dput(d_child);
500         }
501 }
502 
503 /*
504  * If we have to add an attr fork ahead of a parent pointer update, how much
505  * space should we ask for?
506  */
507 static inline int
508 xrep_adoption_attr_sizeof(
509         const struct xrep_adoption      *adopt)
510 {
511         return sizeof(struct xfs_attr_sf_hdr) +
512                 xfs_attr_sf_entsize_byname(sizeof(struct xfs_parent_rec),
513                                            adopt->xname->len);
514 }
515 
516 /*
517  * Move the current file to the orphanage under the computed name.
518  *
519  * Returns with a dirty transaction so that the caller can handle any other
520  * work, such as fixing up unlinked lists or resetting link counts.
521  */
522 int
523 xrep_adoption_move(
524         struct xrep_adoption    *adopt)
525 {
526         struct xfs_scrub        *sc = adopt->sc;
527         bool                    isdir = S_ISDIR(VFS_I(sc->ip)->i_mode);
528         int                     error;
529 
530         trace_xrep_adoption_reparent(sc->orphanage, adopt->xname,
531                         sc->ip->i_ino);
532 
533         error = xrep_adoption_check_dcache(adopt);
534         if (error)
535                 return error;
536 
537         /*
538          * If this filesystem has parent pointers, ensure that the file being
539          * moved to the orphanage has an attribute fork.  This is required
540          * because the parent pointer code does not itself add attr forks.
541          */
542         if (!xfs_inode_has_attr_fork(sc->ip) && xfs_has_parent(sc->mp)) {
543                 int sf_size = xrep_adoption_attr_sizeof(adopt);
544 
545                 error = xfs_bmap_add_attrfork(sc->tp, sc->ip, sf_size, true);
546                 if (error)
547                         return error;
548         }
549 
550         /* Create the new name in the orphanage. */
551         error = xfs_dir_createname(sc->tp, sc->orphanage, adopt->xname,
552                         sc->ip->i_ino, adopt->orphanage_blkres);
553         if (error)
554                 return error;
555 
556         /*
557          * Bump the link count of the orphanage if we just added a
558          * subdirectory, and update its timestamps.
559          */
560         xfs_trans_ichgtime(sc->tp, sc->orphanage,
561                         XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
562         if (isdir)
563                 xfs_bumplink(sc->tp, sc->orphanage);
564         xfs_trans_log_inode(sc->tp, sc->orphanage, XFS_ILOG_CORE);
565 
566         /* Bump the link count of the child. */
567         if (adopt->bump_child_nlink) {
568                 xfs_bumplink(sc->tp, sc->ip);
569                 xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
570         }
571 
572         /* Replace the dotdot entry if the child is a subdirectory. */
573         if (isdir) {
574                 error = xfs_dir_replace(sc->tp, sc->ip, &xfs_name_dotdot,
575                                 sc->orphanage->i_ino, adopt->child_blkres);
576                 if (error)
577                         return error;
578         }
579 
580         /* Add a parent pointer from the file back to the lost+found. */
581         if (xfs_has_parent(sc->mp)) {
582                 error = xfs_parent_addname(sc->tp, &adopt->ppargs,
583                                 sc->orphanage, adopt->xname, sc->ip);
584                 if (error)
585                         return error;
586         }
587 
588         /*
589          * Notify dirent hooks that we moved the file to /lost+found, and
590          * finish all the deferred work so that we know the adoption is fully
591          * recorded in the log.
592          */
593         xfs_dir_update_hook(sc->orphanage, sc->ip, 1, adopt->xname);
594 
595         /* Remove negative dentries from the lost+found's dcache */
596         xrep_adoption_zap_dcache(adopt);
597         return 0;
598 }
599 
600 /*
601  * Roll to a clean scrub transaction so that we can release the orphanage,
602  * even if xrep_adoption_move was not called.
603  *
604  * Commits all the work and deferred ops attached to an adoption request and
605  * rolls to a clean scrub transaction.  On success, returns 0 with the scrub
606  * context holding a clean transaction with no inodes joined.  On failure,
607  * returns negative errno with no scrub transaction.  All inode locks are
608  * still held after this function returns.
609  */
610 int
611 xrep_adoption_trans_roll(
612         struct xrep_adoption    *adopt)
613 {
614         struct xfs_scrub        *sc = adopt->sc;
615         int                     error;
616 
617         trace_xrep_adoption_trans_roll(sc->orphanage, sc->ip,
618                         !!(sc->tp->t_flags & XFS_TRANS_DIRTY));
619 
620         /* Finish all the deferred ops to commit all repairs. */
621         error = xrep_defer_finish(sc);
622         if (error)
623                 return error;
624 
625         /* Roll the transaction once more to detach the inodes. */
626         return xfs_trans_roll(&sc->tp);
627 }
628 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php