@@ -70,6 +70,9 @@ xchk_dirtree_buf_cleanup(
70
70
struct xchk_dirtree * dl = buf ;
71
71
struct xchk_dirpath * path , * n ;
72
72
73
+ if (dl -> scan_ino != NULLFSINO )
74
+ xfs_dir_hook_del (dl -> sc -> mp , & dl -> dhook );
75
+
73
76
xchk_dirtree_for_each_path_safe (dl , path , n ) {
74
77
list_del_init (& path -> list );
75
78
xino_bitmap_destroy (& path -> seen_inodes );
@@ -90,13 +93,17 @@ xchk_setup_dirtree(
90
93
char * descr ;
91
94
int error ;
92
95
96
+ xchk_fsgates_enable (sc , XCHK_FSGATES_DIRENTS );
97
+
93
98
dl = kvzalloc (sizeof (struct xchk_dirtree ), XCHK_GFP_FLAGS );
94
99
if (!dl )
95
100
return - ENOMEM ;
96
101
dl -> sc = sc ;
97
102
dl -> xname .name = dl -> namebuf ;
103
+ dl -> hook_xname .name = dl -> hook_namebuf ;
98
104
INIT_LIST_HEAD (& dl -> path_list );
99
105
dl -> root_ino = NULLFSINO ;
106
+ dl -> scan_ino = NULLFSINO ;
100
107
101
108
mutex_init (& dl -> lock );
102
109
@@ -558,6 +565,133 @@ xchk_dirpath_walk_upwards(
558
565
return error ;
559
566
}
560
567
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
+
561
695
/* Delete all the collected path information. */
562
696
STATIC void
563
697
xchk_dirtree_reset (
@@ -673,6 +807,8 @@ xchk_dirtree_find_paths_to_root(
673
807
}
674
808
if (error )
675
809
return error ;
810
+ if (dl -> aborted )
811
+ return 0 ;
676
812
}
677
813
} while (dl -> stale );
678
814
@@ -744,11 +880,28 @@ xchk_dirtree(
744
880
745
881
ASSERT (xfs_has_parent (sc -> mp ));
746
882
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
+ */
748
888
dl -> root_ino = sc -> mp -> m_rootip -> i_ino ;
889
+ dl -> scan_ino = sc -> ip -> i_ino ;
749
890
750
891
trace_xchk_dirtree_start (sc -> ip , sc -> sm , 0 );
751
892
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
+
752
905
mutex_lock (& dl -> lock );
753
906
754
907
/* Trace each parent pointer's path to the root. */
@@ -775,6 +928,10 @@ xchk_dirtree(
775
928
}
776
929
if (error )
777
930
goto out_scanlock ;
931
+ if (dl -> aborted ) {
932
+ xchk_set_incomplete (sc );
933
+ goto out_scanlock ;
934
+ }
778
935
779
936
/* Assess what we found in our path evaluation. */
780
937
xchk_dirtree_evaluate (dl , & oc );
@@ -790,6 +947,7 @@ xchk_dirtree(
790
947
791
948
out_scanlock :
792
949
mutex_unlock (& dl -> lock );
950
+ out :
793
951
trace_xchk_dirtree_done (sc -> ip , sc -> sm , error );
794
952
return error ;
795
953
}
0 commit comments