78
78
#include "zfs_comutil.h"
79
79
80
80
typedef enum zti_modes {
81
- zti_mode_fixed , /* value is # of threads (min 1) */
82
- zti_mode_online_percent , /* value is % of online CPUs */
83
- zti_mode_batch , /* cpu-intensive; value is ignored */
84
- zti_mode_null , /* don't create a taskq */
85
- zti_nmodes
81
+ ZTI_MODE_FIXED , /* value is # of threads (min 1) */
82
+ ZTI_MODE_ONLINE_PERCENT , /* value is % of online CPUs */
83
+ ZTI_MODE_BATCH , /* cpu-intensive; value is ignored */
84
+ ZTI_MODE_NULL , /* don't create a taskq */
85
+ ZTI_NMODES
86
86
} zti_modes_t ;
87
87
88
- #define ZTI_FIX ( n ) { zti_mode_fixed , (n) }
89
- #define ZTI_PCT (n ) { zti_mode_online_percent , (n) }
90
- #define ZTI_BATCH { zti_mode_batch , 0 }
91
- #define ZTI_NULL { zti_mode_null , 0 }
88
+ #define ZTI_P ( n , q ) { ZTI_MODE_FIXED , (n), (q ) }
89
+ #define ZTI_PCT (n ) { ZTI_MODE_ONLINE_PERCENT , (n), 1 }
90
+ #define ZTI_BATCH { ZTI_MODE_BATCH , 0, 1 }
91
+ #define ZTI_NULL { ZTI_MODE_NULL, 0 , 0 }
92
92
93
- #define ZTI_ONE ZTI_FIX(1)
93
+ #define ZTI_N (n ) ZTI_P(n, 1)
94
+ #define ZTI_ONE ZTI_N(1)
94
95
95
96
typedef struct zio_taskq_info {
96
- enum zti_modes zti_mode ;
97
+ zti_modes_t zti_mode ;
97
98
uint_t zti_value ;
99
+ uint_t zti_count ;
98
100
} zio_taskq_info_t ;
99
101
100
102
static const char * const zio_taskq_types [ZIO_TASKQ_TYPES ] = {
101
103
"iss" , "iss_h" , "int" , "int_h"
102
104
};
103
105
104
106
/*
105
- * Define the taskq threads for the following I/O types:
106
- * NULL, READ, WRITE, FREE, CLAIM, and IOCTL
107
+ * This table defines the taskq settings for each ZFS I/O type. When
108
+ * initializing a pool, we use this table to create an appropriately sized
109
+ * taskq. Some operations are low volume and therefore have a small, static
110
+ * number of threads assigned to their taskqs using the ZTI_N(#) or ZTI_ONE
111
+ * macros. Other operations process a large amount of data; the ZTI_BATCH
112
+ * macro causes us to create a taskq oriented for throughput. Some operations
113
+ * are so high frequency and short-lived that the taskq itself can become a a
114
+ * point of lock contention. The ZTI_P(#, #) macro indicates that we need an
115
+ * additional degree of parallelism specified by the number of threads per-
116
+ * taskq and the number of taskqs; when dispatching an event in this case, the
117
+ * particular taskq is chosen at random.
118
+ *
119
+ * The different taskq priorities are to handle the different contexts (issue
120
+ * and interrupt) and then to reserve threads for ZIO_PRIORITY_NOW I/Os that
121
+ * need to be handled with minimum delay.
107
122
*/
108
123
const zio_taskq_info_t zio_taskqs [ZIO_TYPES ][ZIO_TASKQ_TYPES ] = {
109
124
/* ISSUE ISSUE_HIGH INTR INTR_HIGH */
110
- { ZTI_ONE , ZTI_NULL , ZTI_ONE , ZTI_NULL },
111
- { ZTI_FIX (8 ), ZTI_NULL , ZTI_BATCH , ZTI_NULL },
112
- { ZTI_BATCH , ZTI_FIX (5 ), ZTI_FIX (16 ), ZTI_FIX (5 ) },
113
- { ZTI_FIX ( 8 ), ZTI_NULL , ZTI_ONE , ZTI_NULL },
114
- { ZTI_ONE , ZTI_NULL , ZTI_ONE , ZTI_NULL },
115
- { ZTI_ONE , ZTI_NULL , ZTI_ONE , ZTI_NULL },
125
+ { ZTI_ONE , ZTI_NULL , ZTI_ONE , ZTI_NULL }, /* NULL */
126
+ { ZTI_N (8 ), ZTI_NULL , ZTI_BATCH , ZTI_NULL }, /* READ */
127
+ { ZTI_BATCH , ZTI_N (5 ), ZTI_N (16 ), ZTI_N (5 ) }, /* WRITE */
128
+ { ZTI_P ( 4 , 8 ), ZTI_NULL , ZTI_ONE , ZTI_NULL }, /* FREE */
129
+ { ZTI_ONE , ZTI_NULL , ZTI_ONE , ZTI_NULL }, /* CLAIM */
130
+ { ZTI_ONE , ZTI_NULL , ZTI_ONE , ZTI_NULL }, /* IOCTL */
116
131
};
117
132
118
133
static dsl_syncfunc_t spa_sync_version ;
@@ -794,48 +809,121 @@ spa_get_errlists(spa_t *spa, avl_tree_t *last, avl_tree_t *scrub)
794
809
offsetof(spa_error_entry_t , se_avl ));
795
810
}
796
811
797
- static taskq_t *
798
- spa_taskq_create (spa_t * spa , const char * name , enum zti_modes mode ,
799
- uint_t value )
812
+ static void
813
+ spa_taskqs_init (spa_t * spa , zio_type_t t , zio_taskq_type_t q )
800
814
{
801
- uint_t flags = TASKQ_PREPOPULATE ;
815
+ const zio_taskq_info_t * ztip = & zio_taskqs [t ][q ];
816
+ enum zti_modes mode = ztip -> zti_mode ;
817
+ uint_t value = ztip -> zti_value ;
818
+ uint_t count = ztip -> zti_count ;
819
+ spa_taskqs_t * tqs = & spa -> spa_zio_taskq [t ][q ];
820
+ char name [32 ];
821
+ uint_t i , flags = 0 ;
802
822
boolean_t batch = B_FALSE ;
803
823
804
- switch (mode ) {
805
- case zti_mode_null :
806
- return (NULL ); /* no taskq needed */
824
+ if (mode == ZTI_MODE_NULL ) {
825
+ tqs -> stqs_count = 0 ;
826
+ tqs -> stqs_taskq = NULL ;
827
+ return ;
828
+ }
807
829
808
- case zti_mode_fixed :
809
- ASSERT3U (value , >=, 1 );
810
- value = MAX (value , 1 );
811
- break ;
830
+ ASSERT3U (count , > , 0 );
812
831
813
- case zti_mode_batch :
814
- batch = B_TRUE ;
815
- flags |= TASKQ_THREADS_CPU_PCT ;
816
- value = zio_taskq_batch_pct ;
817
- break ;
832
+ tqs -> stqs_count = count ;
833
+ tqs -> stqs_taskq = kmem_alloc (count * sizeof (taskq_t * ), KM_SLEEP );
818
834
819
- case zti_mode_online_percent :
820
- flags |= TASKQ_THREADS_CPU_PCT ;
821
- break ;
835
+ for (i = 0 ; i < count ; i ++ ) {
836
+ taskq_t * tq ;
822
837
823
- default :
824
- panic ("unrecognized mode for %s taskq (%u:%u) in "
825
- "spa_activate()" ,
826
- name , mode , value );
827
- break ;
838
+ switch (mode ) {
839
+ case ZTI_MODE_FIXED :
840
+ ASSERT3U (value , >=, 1 );
841
+ value = MAX (value , 1 );
842
+ break ;
843
+
844
+ case ZTI_MODE_BATCH :
845
+ batch = B_TRUE ;
846
+ flags |= TASKQ_THREADS_CPU_PCT ;
847
+ value = zio_taskq_batch_pct ;
848
+ break ;
849
+
850
+ case ZTI_MODE_ONLINE_PERCENT :
851
+ flags |= TASKQ_THREADS_CPU_PCT ;
852
+ break ;
853
+
854
+ default :
855
+ panic ("unrecognized mode for %s_%s taskq (%u:%u) in "
856
+ "spa_activate()" ,
857
+ zio_type_name [t ], zio_taskq_types [q ], mode , value );
858
+ break ;
859
+ }
860
+
861
+ if (count > 1 ) {
862
+ (void ) snprintf (name , sizeof (name ), "%s_%s_%u" ,
863
+ zio_type_name [t ], zio_taskq_types [q ], i );
864
+ } else {
865
+ (void ) snprintf (name , sizeof (name ), "%s_%s" ,
866
+ zio_type_name [t ], zio_taskq_types [q ]);
867
+ }
868
+
869
+ if (zio_taskq_sysdc && spa -> spa_proc != & p0 ) {
870
+ if (batch )
871
+ flags |= TASKQ_DC_BATCH ;
872
+
873
+ tq = taskq_create_sysdc (name , value , 50 , INT_MAX ,
874
+ spa -> spa_proc , zio_taskq_basedc , flags );
875
+ } else {
876
+ tq = taskq_create_proc (name , value , maxclsyspri , 50 ,
877
+ INT_MAX , spa -> spa_proc , flags );
878
+ }
879
+
880
+ tqs -> stqs_taskq [i ] = tq ;
828
881
}
882
+ }
883
+
884
+ static void
885
+ spa_taskqs_fini (spa_t * spa , zio_type_t t , zio_taskq_type_t q )
886
+ {
887
+ spa_taskqs_t * tqs = & spa -> spa_zio_taskq [t ][q ];
888
+ uint_t i ;
829
889
830
- if (zio_taskq_sysdc && spa -> spa_proc != & p0 ) {
831
- if (batch )
832
- flags |= TASKQ_DC_BATCH ;
890
+ if (tqs -> stqs_taskq == NULL ) {
891
+ ASSERT3U (tqs -> stqs_count , = = , 0 );
892
+ return ;
893
+ }
833
894
834
- return (taskq_create_sysdc (name , value , 50 , INT_MAX ,
835
- spa -> spa_proc , zio_taskq_basedc , flags ));
895
+ for (i = 0 ; i < tqs -> stqs_count ; i ++ ) {
896
+ ASSERT3P (tqs -> stqs_taskq [i ], != , NULL );
897
+ taskq_destroy (tqs -> stqs_taskq [i ]);
836
898
}
837
- return (taskq_create_proc (name , value , maxclsyspri , 50 , INT_MAX ,
838
- spa -> spa_proc , flags ));
899
+
900
+ kmem_free (tqs -> stqs_taskq , tqs -> stqs_count * sizeof (taskq_t * ));
901
+ tqs -> stqs_taskq = NULL ;
902
+ }
903
+
904
+ /*
905
+ * Dispatch a task to the appropriate taskq for the ZFS I/O type and priority.
906
+ * Note that a type may have multiple discrete taskqs to avoid lock contention
907
+ * on the taskq itself. In that case we choose which taskq at random by using
908
+ * the low bits of gethrtime().
909
+ */
910
+ void
911
+ spa_taskq_dispatch_ent (spa_t * spa , zio_type_t t , zio_taskq_type_t q ,
912
+ task_func_t * func , void * arg , uint_t flags , taskq_ent_t * ent )
913
+ {
914
+ spa_taskqs_t * tqs = & spa -> spa_zio_taskq [t ][q ];
915
+ taskq_t * tq ;
916
+
917
+ ASSERT3P (tqs -> stqs_taskq , != , NULL );
918
+ ASSERT3U (tqs -> stqs_count , != , 0 );
919
+
920
+ if (tqs -> stqs_count == 1 ) {
921
+ tq = tqs -> stqs_taskq [0 ];
922
+ } else {
923
+ tq = tqs -> stqs_taskq [gethrtime () % tqs -> stqs_count ];
924
+ }
925
+
926
+ taskq_dispatch_ent (tq , func , arg , flags , ent );
839
927
}
840
928
841
929
static void
@@ -845,16 +933,7 @@ spa_create_zio_taskqs(spa_t *spa)
845
933
846
934
for (t = 0 ; t < ZIO_TYPES ; t ++ ) {
847
935
for (q = 0 ; q < ZIO_TASKQ_TYPES ; q ++ ) {
848
- const zio_taskq_info_t * ztip = & zio_taskqs [t ][q ];
849
- enum zti_modes mode = ztip -> zti_mode ;
850
- uint_t value = ztip -> zti_value ;
851
- char name [32 ];
852
-
853
- (void ) snprintf (name , sizeof (name ),
854
- "%s_%s" , zio_type_name [t ], zio_taskq_types [q ]);
855
-
856
- spa -> spa_zio_taskq [t ][q ] =
857
- spa_taskq_create (spa , name , mode , value );
936
+ spa_taskqs_init (spa , t , q );
858
937
}
859
938
}
860
939
}
@@ -1017,9 +1096,7 @@ spa_deactivate(spa_t *spa)
1017
1096
1018
1097
for (t = 0 ; t < ZIO_TYPES ; t ++ ) {
1019
1098
for (q = 0 ; q < ZIO_TASKQ_TYPES ; q ++ ) {
1020
- if (spa -> spa_zio_taskq [t ][q ] != NULL )
1021
- taskq_destroy (spa -> spa_zio_taskq [t ][q ]);
1022
- spa -> spa_zio_taskq [t ][q ] = NULL ;
1099
+ spa_taskqs_fini (spa , t , q );
1023
1100
}
1024
1101
}
1025
1102
0 commit comments