@@ -70,6 +70,9 @@ xchk_dirtree_buf_cleanup(
7070 struct xchk_dirtree * dl = buf ;
7171 struct xchk_dirpath * path , * n ;
7272
73+ if (dl -> scan_ino != NULLFSINO )
74+ xfs_dir_hook_del (dl -> sc -> mp , & dl -> dhook );
75+
7376 xchk_dirtree_for_each_path_safe (dl , path , n ) {
7477 list_del_init (& path -> list );
7578 xino_bitmap_destroy (& path -> seen_inodes );
@@ -90,13 +93,17 @@ xchk_setup_dirtree(
9093 char * descr ;
9194 int error ;
9295
96+ xchk_fsgates_enable (sc , XCHK_FSGATES_DIRENTS );
97+
9398 dl = kvzalloc (sizeof (struct xchk_dirtree ), XCHK_GFP_FLAGS );
9499 if (!dl )
95100 return - ENOMEM ;
96101 dl -> sc = sc ;
97102 dl -> xname .name = dl -> namebuf ;
103+ dl -> hook_xname .name = dl -> hook_namebuf ;
98104 INIT_LIST_HEAD (& dl -> path_list );
99105 dl -> root_ino = NULLFSINO ;
106+ dl -> scan_ino = NULLFSINO ;
100107
101108 mutex_init (& dl -> lock );
102109
@@ -558,6 +565,133 @@ xchk_dirpath_walk_upwards(
558565 return error ;
559566}
560567
568+ /*
569+ * Decide if this path step has been touched by this live update. Returns
570+ * 1 for yes, 0 for no, or a negative errno.
571+ */
572+ STATIC int
573+ xchk_dirpath_step_is_stale (
574+ struct xchk_dirtree * dl ,
575+ struct xchk_dirpath * path ,
576+ unsigned int step_nr ,
577+ xfarray_idx_t step_idx ,
578+ struct xfs_dir_update_params * p ,
579+ xfs_ino_t * cursor )
580+ {
581+ struct xchk_dirpath_step step ;
582+ xfs_ino_t child_ino = * cursor ;
583+ int error ;
584+
585+ error = xfarray_load (dl -> path_steps , step_idx , & step );
586+ if (error )
587+ return error ;
588+ * cursor = be64_to_cpu (step .pptr_rec .p_ino );
589+
590+ /*
591+ * If the parent and child being updated are not the ones mentioned in
592+ * this path step, the scan data is still ok.
593+ */
594+ if (p -> ip -> i_ino != child_ino || p -> dp -> i_ino != * cursor )
595+ return 0 ;
596+
597+ /*
598+ * If the dirent name lengths or byte sequences are different, the scan
599+ * data is still ok.
600+ */
601+ if (p -> name -> len != step .name_len )
602+ return 0 ;
603+
604+ error = xfblob_loadname (dl -> path_names , step .name_cookie ,
605+ & dl -> hook_xname , step .name_len );
606+ if (error )
607+ return error ;
608+
609+ if (memcmp (dl -> hook_xname .name , p -> name -> name , p -> name -> len ) != 0 )
610+ return 0 ;
611+
612+ /* Exact match, scan data is out of date. */
613+ trace_xchk_dirpath_changed (dl -> sc , path -> path_nr , step_nr , p -> dp ,
614+ p -> ip , p -> name );
615+ return 1 ;
616+ }
617+
618+ /*
619+ * Decide if this path has been touched by this live update. Returns 1 for
620+ * yes, 0 for no, or a negative errno.
621+ */
622+ STATIC int
623+ xchk_dirpath_is_stale (
624+ struct xchk_dirtree * dl ,
625+ struct xchk_dirpath * path ,
626+ struct xfs_dir_update_params * p )
627+ {
628+ xfs_ino_t cursor = dl -> scan_ino ;
629+ xfarray_idx_t idx = path -> first_step ;
630+ unsigned int i ;
631+ int ret ;
632+
633+ /*
634+ * The child being updated has not been seen by this path at all; this
635+ * path cannot be stale.
636+ */
637+ if (!xino_bitmap_test (& path -> seen_inodes , p -> ip -> i_ino ))
638+ return 0 ;
639+
640+ ret = xchk_dirpath_step_is_stale (dl , path , 0 , idx , p , & cursor );
641+ if (ret != 0 )
642+ return ret ;
643+
644+ for (i = 1 , idx = path -> second_step ; i < path -> nr_steps ; i ++ , idx ++ ) {
645+ ret = xchk_dirpath_step_is_stale (dl , path , i , idx , p , & cursor );
646+ if (ret != 0 )
647+ return ret ;
648+ }
649+
650+ return 0 ;
651+ }
652+
653+ /*
654+ * Decide if a directory update from the regular filesystem touches any of the
655+ * paths we've scanned, and invalidate the scan data if true.
656+ */
657+ STATIC int
658+ xchk_dirtree_live_update (
659+ struct notifier_block * nb ,
660+ unsigned long action ,
661+ void * data )
662+ {
663+ struct xfs_dir_update_params * p = data ;
664+ struct xchk_dirtree * dl ;
665+ struct xchk_dirpath * path ;
666+ int ret ;
667+
668+ dl = container_of (nb , struct xchk_dirtree , dhook .dirent_hook .nb );
669+
670+ trace_xchk_dirtree_live_update (dl -> sc , p -> dp , action , p -> ip , p -> delta ,
671+ p -> name );
672+
673+ mutex_lock (& dl -> lock );
674+
675+ if (dl -> stale || dl -> aborted )
676+ goto out_unlock ;
677+
678+ xchk_dirtree_for_each_path (dl , path ) {
679+ ret = xchk_dirpath_is_stale (dl , path , p );
680+ if (ret < 0 ) {
681+ dl -> aborted = true;
682+ break ;
683+ }
684+ if (ret == 1 ) {
685+ dl -> stale = true;
686+ break ;
687+ }
688+ }
689+
690+ out_unlock :
691+ mutex_unlock (& dl -> lock );
692+ return NOTIFY_DONE ;
693+ }
694+
561695/* Delete all the collected path information. */
562696STATIC void
563697xchk_dirtree_reset (
@@ -673,6 +807,8 @@ xchk_dirtree_find_paths_to_root(
673807 }
674808 if (error )
675809 return error ;
810+ if (dl -> aborted )
811+ return 0 ;
676812 }
677813 } while (dl -> stale );
678814
@@ -744,11 +880,28 @@ xchk_dirtree(
744880
745881 ASSERT (xfs_has_parent (sc -> mp ));
746882
747- /* Find the root of the directory tree. */
883+ /*
884+ * Find the root of the directory tree. Remember which directory to
885+ * scan, because the hook doesn't detach until after sc->ip gets
886+ * released during teardown.
887+ */
748888 dl -> root_ino = sc -> mp -> m_rootip -> i_ino ;
889+ dl -> scan_ino = sc -> ip -> i_ino ;
749890
750891 trace_xchk_dirtree_start (sc -> ip , sc -> sm , 0 );
751892
893+ /*
894+ * Hook into the directory entry code so that we can capture updates to
895+ * paths that we have already scanned. The scanner thread takes each
896+ * directory's ILOCK, which means that any in-progress directory update
897+ * will finish before we can scan the directory.
898+ */
899+ ASSERT (sc -> flags & XCHK_FSGATES_DIRENTS );
900+ xfs_dir_hook_setup (& dl -> dhook , xchk_dirtree_live_update );
901+ error = xfs_dir_hook_add (sc -> mp , & dl -> dhook );
902+ if (error )
903+ goto out ;
904+
752905 mutex_lock (& dl -> lock );
753906
754907 /* Trace each parent pointer's path to the root. */
@@ -775,6 +928,10 @@ xchk_dirtree(
775928 }
776929 if (error )
777930 goto out_scanlock ;
931+ if (dl -> aborted ) {
932+ xchk_set_incomplete (sc );
933+ goto out_scanlock ;
934+ }
778935
779936 /* Assess what we found in our path evaluation. */
780937 xchk_dirtree_evaluate (dl , & oc );
@@ -790,6 +947,7 @@ xchk_dirtree(
790947
791948out_scanlock :
792949 mutex_unlock (& dl -> lock );
950+ out :
793951 trace_xchk_dirtree_done (sc -> ip , sc -> sm , error );
794952 return error ;
795953}
0 commit comments