@@ -303,67 +303,88 @@ 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 ;
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+ }
311329 return NULL ;
312330}
313331
314332static int
315333spa_frag_data (char * buf , size_t size , void * data ) {
316- spa_t * spa = ( spa_t * ) data ;
334+ metaslab_class_t * mc = data ;
317335 size_t offset = 0 ;
318- const char * name = spa_name (spa );
336+ int res ;
337+ // without this, it becomes a data-leak, and un-initialized strings can be returned if all buckets are 0
338+ buf [0 ] = 0 ;
319339
320- metaslab_class_t * mc = spa_normal_class (spa );
321340 for (int i = 0 ; i < RANGE_TREE_HISTOGRAM_SIZE ; i ++ ) {
322341 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 ]);
342+ res = snprintf (buf + offset , size , "%d %llu\n" , i , (u_longlong_t )mc -> mc_histogram [i ]);
324343 offset += res ;
325344 size -= res ;
326345 }
327346 }
328347
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- }
337348 return 0 ;
338349}
339350
340351static void
341352spa_fragmentation_init (spa_t * spa )
342353{
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 );
354+ char * dirname ;
355+ const char * statnames [] = { "fragmentation_normal" , "fragmentation_log" , "fragmentation_embedded_log" , "fragmentation_special" , "fragmentation_dedup" };
356+ for (int i = 0 ; i < 5 ; i ++ ) {
357+ spa_history_kstat_t * shk = & spa -> spa_stats .fragmentation [i ];
358+ kstat_t * ksp ;
359+
360+ dirname = kmem_asprintf ("zfs/%s" , spa_name (spa ));
361+ ksp = kstat_create (dirname , 0 , statnames [i ], "misc" , KSTAT_TYPE_RAW , 0 , KSTAT_FLAG_VIRTUAL );
362+ kmem_strfree (dirname );
363+
364+ shk -> kstat = ksp ;
365+ if (ksp ) {
366+ freespace_histogram_stat_t * stat = kmem_zalloc (sizeof (freespace_histogram_stat_t ), KM_SLEEP );
367+ stat -> spa = spa ;
368+ stat -> metaclass = i ;
369+ ksp -> ks_private = stat ;
370+ ksp -> ks_flags |= KSTAT_FLAG_NO_HEADERS ;
371+ kstat_set_raw_ops (ksp , NULL , spa_frag_data , spa_frag_addr );
372+ kstat_install (ksp );
373+ }
356374 }
357- kmem_strfree (name );
358375}
359376
360377static void
361378spa_fragmentation_destroy (spa_t * spa )
362379{
363- spa_history_kstat_t * shk = & spa -> spa_stats .fragmentation ;
364- kstat_t * ksp = shk -> kstat ;
365- if (ksp )
366- kstat_delete (ksp );
380+ for (int i = 0 ; i < 5 ; i ++ ) {
381+ spa_history_kstat_t * shk = & spa -> spa_stats .fragmentation [i ];
382+ kstat_t * ksp = shk -> kstat ;
383+ if (ksp ) {
384+ if (ksp -> ks_private ) kmem_free (ksp -> ks_private , sizeof (freespace_histogram_stat_t ));
385+ kstat_delete (ksp );
386+ }
387+ }
367388}
368389
369390static void
0 commit comments