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