82
82
83
83
/*
84
84
* There are three quota SMP locks. dq_list_lock protects all lists with quotas
85
- * and quota formats, dqstats structure containing statistics about the lists
85
+ * and quota formats.
86
86
* dq_data_lock protects data from dq_dqb and also mem_dqinfo structures and
87
87
* also guards consistency of dquot->dq_dqb with inode->i_blocks, i_bytes.
88
88
* i_blocks and i_bytes updates itself are guarded by i_lock acquired directly
@@ -228,6 +228,10 @@ static struct hlist_head *dquot_hash;
228
228
229
229
struct dqstats dqstats ;
230
230
EXPORT_SYMBOL (dqstats );
231
+ #ifdef CONFIG_SMP
232
+ struct dqstats * dqstats_pcpu ;
233
+ EXPORT_SYMBOL (dqstats_pcpu );
234
+ #endif
231
235
232
236
static qsize_t inode_get_rsv_space (struct inode * inode );
233
237
static void __dquot_initialize (struct inode * inode , int type );
@@ -275,28 +279,28 @@ static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
275
279
static inline void put_dquot_last (struct dquot * dquot )
276
280
{
277
281
list_add_tail (& dquot -> dq_free , & free_dquots );
278
- dqstats . free_dquots ++ ;
282
+ dqstats_inc ( DQST_FREE_DQUOTS ) ;
279
283
}
280
284
281
285
static inline void remove_free_dquot (struct dquot * dquot )
282
286
{
283
287
if (list_empty (& dquot -> dq_free ))
284
288
return ;
285
289
list_del_init (& dquot -> dq_free );
286
- dqstats . free_dquots -- ;
290
+ dqstats_dec ( DQST_FREE_DQUOTS ) ;
287
291
}
288
292
289
293
static inline void put_inuse (struct dquot * dquot )
290
294
{
291
295
/* We add to the back of inuse list so we don't have to restart
292
296
* when traversing this list and we block */
293
297
list_add_tail (& dquot -> dq_inuse , & inuse_list );
294
- dqstats . allocated_dquots ++ ;
298
+ dqstats_inc ( DQST_ALLOC_DQUOTS ) ;
295
299
}
296
300
297
301
static inline void remove_inuse (struct dquot * dquot )
298
302
{
299
- dqstats . allocated_dquots -- ;
303
+ dqstats_dec ( DQST_ALLOC_DQUOTS ) ;
300
304
list_del (& dquot -> dq_inuse );
301
305
}
302
306
/*
@@ -561,8 +565,8 @@ int dquot_scan_active(struct super_block *sb,
561
565
continue ;
562
566
/* Now we have active dquot so we can just increase use count */
563
567
atomic_inc (& dquot -> dq_count );
564
- dqstats .lookups ++ ;
565
568
spin_unlock (& dq_list_lock );
569
+ dqstats_inc (DQST_LOOKUPS );
566
570
dqput (old_dquot );
567
571
old_dquot = dquot ;
568
572
ret = fn (dquot , priv );
@@ -607,8 +611,8 @@ int vfs_quota_sync(struct super_block *sb, int type, int wait)
607
611
* holding reference so we can safely just increase
608
612
* use count */
609
613
atomic_inc (& dquot -> dq_count );
610
- dqstats .lookups ++ ;
611
614
spin_unlock (& dq_list_lock );
615
+ dqstats_inc (DQST_LOOKUPS );
612
616
sb -> dq_op -> write_dquot (dquot );
613
617
dqput (dquot );
614
618
spin_lock (& dq_list_lock );
@@ -620,9 +624,7 @@ int vfs_quota_sync(struct super_block *sb, int type, int wait)
620
624
if ((cnt == type || type == -1 ) && sb_has_quota_active (sb , cnt )
621
625
&& info_dirty (& dqopt -> info [cnt ]))
622
626
sb -> dq_op -> write_info (sb , cnt );
623
- spin_lock (& dq_list_lock );
624
- dqstats .syncs ++ ;
625
- spin_unlock (& dq_list_lock );
627
+ dqstats_inc (DQST_SYNCS );
626
628
mutex_unlock (& dqopt -> dqonoff_mutex );
627
629
628
630
if (!wait || (sb_dqopt (sb )-> flags & DQUOT_QUOTA_SYS_FILE ))
@@ -674,6 +676,22 @@ static void prune_dqcache(int count)
674
676
}
675
677
}
676
678
679
+ static int dqstats_read (unsigned int type )
680
+ {
681
+ int count = 0 ;
682
+ #ifdef CONFIG_SMP
683
+ int cpu ;
684
+ for_each_possible_cpu (cpu )
685
+ count += per_cpu_ptr (dqstats_pcpu , cpu )-> stat [type ];
686
+ /* Statistics reading is racy, but absolute accuracy isn't required */
687
+ if (count < 0 )
688
+ count = 0 ;
689
+ #else
690
+ count = dqstats .stat [type ];
691
+ #endif
692
+ return count ;
693
+ }
694
+
677
695
/*
678
696
* This is called from kswapd when we think we need some
679
697
* more memory
@@ -686,7 +704,7 @@ static int shrink_dqcache_memory(int nr, gfp_t gfp_mask)
686
704
prune_dqcache (nr );
687
705
spin_unlock (& dq_list_lock );
688
706
}
689
- return (dqstats . free_dquots / 100 ) * sysctl_vfs_cache_pressure ;
707
+ return (dqstats_read ( DQST_FREE_DQUOTS )/ 100 ) * sysctl_vfs_cache_pressure ;
690
708
}
691
709
692
710
static struct shrinker dqcache_shrinker = {
@@ -714,10 +732,7 @@ void dqput(struct dquot *dquot)
714
732
BUG ();
715
733
}
716
734
#endif
717
-
718
- spin_lock (& dq_list_lock );
719
- dqstats .drops ++ ;
720
- spin_unlock (& dq_list_lock );
735
+ dqstats_inc (DQST_DROPS );
721
736
we_slept :
722
737
spin_lock (& dq_list_lock );
723
738
if (atomic_read (& dquot -> dq_count ) > 1 ) {
@@ -834,15 +849,15 @@ struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
834
849
put_inuse (dquot );
835
850
/* hash it first so it can be found */
836
851
insert_dquot_hash (dquot );
837
- dqstats .lookups ++ ;
838
852
spin_unlock (& dq_list_lock );
853
+ dqstats_inc (DQST_LOOKUPS );
839
854
} else {
840
855
if (!atomic_read (& dquot -> dq_count ))
841
856
remove_free_dquot (dquot );
842
857
atomic_inc (& dquot -> dq_count );
843
- dqstats .cache_hits ++ ;
844
- dqstats .lookups ++ ;
845
858
spin_unlock (& dq_list_lock );
859
+ dqstats_inc (DQST_CACHE_HITS );
860
+ dqstats_inc (DQST_LOOKUPS );
846
861
}
847
862
/* Wait for dq_lock - after this we know that either dquot_release() is
848
863
* already finished or it will be canceled due to dq_count > 1 test */
@@ -2476,62 +2491,74 @@ const struct quotactl_ops vfs_quotactl_ops = {
2476
2491
.set_dqblk = vfs_set_dqblk
2477
2492
};
2478
2493
2494
+
2495
+ static int do_proc_dqstats (struct ctl_table * table , int write ,
2496
+ void __user * buffer , size_t * lenp , loff_t * ppos )
2497
+ {
2498
+ #ifdef CONFIG_SMP
2499
+ /* Update global table */
2500
+ unsigned int type = (int * )table -> data - dqstats .stat ;
2501
+ dqstats .stat [type ] = dqstats_read (type );
2502
+ #endif
2503
+ return proc_dointvec (table , write , buffer , lenp , ppos );
2504
+ }
2505
+
2479
2506
static ctl_table fs_dqstats_table [] = {
2480
2507
{
2481
2508
.procname = "lookups" ,
2482
- .data = & dqstats .lookups ,
2509
+ .data = & dqstats .stat [ DQST_LOOKUPS ] ,
2483
2510
.maxlen = sizeof (int ),
2484
2511
.mode = 0444 ,
2485
- .proc_handler = proc_dointvec ,
2512
+ .proc_handler = do_proc_dqstats ,
2486
2513
},
2487
2514
{
2488
2515
.procname = "drops" ,
2489
- .data = & dqstats .drops ,
2516
+ .data = & dqstats .stat [ DQST_DROPS ] ,
2490
2517
.maxlen = sizeof (int ),
2491
2518
.mode = 0444 ,
2492
- .proc_handler = proc_dointvec ,
2519
+ .proc_handler = do_proc_dqstats ,
2493
2520
},
2494
2521
{
2495
2522
.procname = "reads" ,
2496
- .data = & dqstats .reads ,
2523
+ .data = & dqstats .stat [ DQST_READS ] ,
2497
2524
.maxlen = sizeof (int ),
2498
2525
.mode = 0444 ,
2499
- .proc_handler = proc_dointvec ,
2526
+ .proc_handler = do_proc_dqstats ,
2500
2527
},
2501
2528
{
2502
2529
.procname = "writes" ,
2503
- .data = & dqstats .writes ,
2530
+ .data = & dqstats .stat [ DQST_WRITES ] ,
2504
2531
.maxlen = sizeof (int ),
2505
2532
.mode = 0444 ,
2506
- .proc_handler = proc_dointvec ,
2533
+ .proc_handler = do_proc_dqstats ,
2507
2534
},
2508
2535
{
2509
2536
.procname = "cache_hits" ,
2510
- .data = & dqstats .cache_hits ,
2537
+ .data = & dqstats .stat [ DQST_CACHE_HITS ] ,
2511
2538
.maxlen = sizeof (int ),
2512
2539
.mode = 0444 ,
2513
- .proc_handler = proc_dointvec ,
2540
+ .proc_handler = do_proc_dqstats ,
2514
2541
},
2515
2542
{
2516
2543
.procname = "allocated_dquots" ,
2517
- .data = & dqstats .allocated_dquots ,
2544
+ .data = & dqstats .stat [ DQST_ALLOC_DQUOTS ] ,
2518
2545
.maxlen = sizeof (int ),
2519
2546
.mode = 0444 ,
2520
- .proc_handler = proc_dointvec ,
2547
+ .proc_handler = do_proc_dqstats ,
2521
2548
},
2522
2549
{
2523
2550
.procname = "free_dquots" ,
2524
- .data = & dqstats .free_dquots ,
2551
+ .data = & dqstats .stat [ DQST_FREE_DQUOTS ] ,
2525
2552
.maxlen = sizeof (int ),
2526
2553
.mode = 0444 ,
2527
- .proc_handler = proc_dointvec ,
2554
+ .proc_handler = do_proc_dqstats ,
2528
2555
},
2529
2556
{
2530
2557
.procname = "syncs" ,
2531
- .data = & dqstats .syncs ,
2558
+ .data = & dqstats .stat [ DQST_SYNCS ] ,
2532
2559
.maxlen = sizeof (int ),
2533
2560
.mode = 0444 ,
2534
- .proc_handler = proc_dointvec ,
2561
+ .proc_handler = do_proc_dqstats ,
2535
2562
},
2536
2563
#ifdef CONFIG_PRINT_QUOTA_WARNING
2537
2564
{
@@ -2583,6 +2610,13 @@ static int __init dquot_init(void)
2583
2610
if (!dquot_hash )
2584
2611
panic ("Cannot create dquot hash table" );
2585
2612
2613
+ #ifdef CONFIG_SMP
2614
+ dqstats_pcpu = alloc_percpu (struct dqstats );
2615
+ if (!dqstats_pcpu )
2616
+ panic ("Cannot create dquot stats table" );
2617
+ #endif
2618
+ memset (& dqstats , 0 , sizeof (struct dqstats ));
2619
+
2586
2620
/* Find power-of-two hlist_heads which can fit into allocation */
2587
2621
nr_hash = (1UL << order ) * PAGE_SIZE / sizeof (struct hlist_head );
2588
2622
dq_hash_bits = 0 ;
0 commit comments