@@ -303,67 +303,103 @@ spa_txg_history_init(spa_t *spa)
303303 offsetof(spa_txg_history_t , sth_node ));
304304}
305305
306+ typedef struct {
307+ spa_t * spa ;
308+ int metaclass ;
309+ } freespace_histogram_stat_t ;
310+
306311static void *
307312spa_frag_addr (kstat_t * ksp , loff_t n )
308313{
309- if (n == 0 )
310- return ksp -> ks_private ;
311- return NULL ;
314+ if (n == 0 ) {
315+ freespace_histogram_stat_t * stat = ksp -> ks_private ;
316+ switch (stat -> metaclass ) {
317+ case 0 :
318+ return (spa_normal_class (stat -> spa ));
319+ case 1 :
320+ return (spa_log_class (stat -> spa ));
321+ case 2 :
322+ return (spa_embedded_log_class (stat -> spa ));
323+ case 3 :
324+ return (spa_special_class (stat -> spa ));
325+ case 4 :
326+ return (spa_dedup_class (stat -> spa ));
327+ }
328+ }
329+ return (NULL );
312330}
313331
314332static int
315- spa_frag_data (char * buf , size_t size , void * data ) {
316- spa_t * spa = (spa_t * )data ;
317- size_t offset = 0 ;
318- const char * name = spa_name (spa );
319-
320- metaslab_class_t * mc = spa_normal_class (spa );
321- for (int i = 0 ; i < RANGE_TREE_HISTOGRAM_SIZE ; i ++ ) {
322- if (mc -> mc_histogram [i ] > 0 ) {
323- int res = snprintf (buf + offset , size , "zfs_fragmentation_normal{power=\"%d\",pool=\"%s\"} %llu\n" , i , name , (u_longlong_t )mc -> mc_histogram [i ]);
324- offset += res ;
325- size -= res ;
326- }
327- }
328-
329- metaslab_class_t * smc = spa_special_class (spa );
330- for (int i = 0 ; i < RANGE_TREE_HISTOGRAM_SIZE ; i ++ ) {
331- if (smc -> mc_histogram [i ] > 0 ) {
332- int res = snprintf (buf + offset , size , "zfs_fragmentation_special{power=\"%d\",pool=\"%s\"} %llu\n" , i , name , (u_longlong_t )smc -> mc_histogram [i ]);
333- offset += res ;
334- size -= res ;
335- }
336- }
337- return 0 ;
333+ spa_frag_data (char * buf , size_t size , void * data )
334+ {
335+ metaslab_class_t * mc = data ;
336+ size_t offset = 0 ;
337+ int res ;
338+ // without this, it becomes a data-leak, and un-initialized strings
339+ // can be returned if all buckets are 0
340+ buf [0 ] = 0 ;
341+
342+ for (int i = 0 ; i < RANGE_TREE_HISTOGRAM_SIZE ; i ++ ) {
343+ if (mc -> mc_histogram [i ] > 0 ) {
344+ res = snprintf (buf + offset , size , "%d %llu\n" , i ,
345+ (u_longlong_t )mc -> mc_histogram [i ]);
346+ offset += res ;
347+ size -= res ;
348+ }
349+ }
350+
351+ return (0 );
338352}
339353
340354static void
341355spa_fragmentation_init (spa_t * spa )
342356{
343- char * name ;
344- spa_history_kstat_t * shk = & spa -> spa_stats .fragmentation ;
345- kstat_t * ksp ;
346-
347- name = kmem_asprintf ("zfs/%s" , spa_name (spa ));
348- ksp = kstat_create (name , 0 , "fragmentation" , "misc" , KSTAT_TYPE_RAW , 0 , KSTAT_FLAG_VIRTUAL );
349-
350- shk -> kstat = ksp ;
351- if (ksp ) {
352- ksp -> ks_private = spa ;
353- ksp -> ks_flags |= KSTAT_FLAG_NO_HEADERS ;
354- kstat_set_raw_ops (ksp , NULL , spa_frag_data , spa_frag_addr );
355- kstat_install (ksp );
356- }
357- kmem_strfree (name );
357+ char * dirname ;
358+ const char * statnames [] = {
359+ "fragmentation_normal" ,
360+ "fragmentation_log" ,
361+ "fragmentation_embedded_log" ,
362+ "fragmentation_special" ,
363+ "fragmentation_dedup"
364+ };
365+ for (int i = 0 ; i < 5 ; i ++ ) {
366+ spa_history_kstat_t * shk = & spa -> spa_stats .fragmentation [i ];
367+ kstat_t * ksp ;
368+
369+ dirname = kmem_asprintf ("zfs/%s" , spa_name (spa ));
370+ ksp = kstat_create (dirname , 0 , statnames [i ], "misc" ,
371+ KSTAT_TYPE_RAW , 0 , KSTAT_FLAG_VIRTUAL );
372+ kmem_strfree (dirname );
373+
374+ shk -> kstat = ksp ;
375+ if (ksp ) {
376+ freespace_histogram_stat_t * stat = kmem_zalloc (
377+ sizeof (freespace_histogram_stat_t ), KM_SLEEP );
378+ stat -> spa = spa ;
379+ stat -> metaclass = i ;
380+ ksp -> ks_private = stat ;
381+ ksp -> ks_flags |= KSTAT_FLAG_NO_HEADERS ;
382+ kstat_set_raw_ops (ksp , NULL , spa_frag_data ,
383+ spa_frag_addr );
384+ kstat_install (ksp );
385+ }
386+ }
358387}
359388
360389static void
361390spa_fragmentation_destroy (spa_t * spa )
362391{
363- spa_history_kstat_t * shk = & spa -> spa_stats .fragmentation ;
364- kstat_t * ksp = shk -> kstat ;
365- if (ksp )
366- kstat_delete (ksp );
392+ for (int i = 0 ; i < 5 ; i ++ ) {
393+ spa_history_kstat_t * shk = & spa -> spa_stats .fragmentation [i ];
394+ kstat_t * ksp = shk -> kstat ;
395+ if (ksp ) {
396+ if (ksp -> ks_private ) {
397+ kmem_free (ksp -> ks_private ,
398+ sizeof (freespace_histogram_stat_t ));
399+ }
400+ kstat_delete (ksp );
401+ }
402+ }
367403}
368404
369405static void
0 commit comments