aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/backing-dev.h85
-rw-r--r--mm/backing-dev.c27
2 files changed, 109 insertions, 3 deletions
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 8f56634f537a..f7677ff80cc5 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -8,6 +8,8 @@
8#ifndef _LINUX_BACKING_DEV_H 8#ifndef _LINUX_BACKING_DEV_H
9#define _LINUX_BACKING_DEV_H 9#define _LINUX_BACKING_DEV_H
10 10
11#include <linux/percpu_counter.h>
12#include <linux/log2.h>
11#include <asm/atomic.h> 13#include <asm/atomic.h>
12 14
13struct page; 15struct page;
@@ -24,6 +26,12 @@ enum bdi_state {
24 26
25typedef int (congested_fn)(void *, int); 27typedef int (congested_fn)(void *, int);
26 28
29enum bdi_stat_item {
30 NR_BDI_STAT_ITEMS
31};
32
33#define BDI_STAT_BATCH (8*(1+ilog2(nr_cpu_ids)))
34
27struct backing_dev_info { 35struct backing_dev_info {
28 unsigned long ra_pages; /* max readahead in PAGE_CACHE_SIZE units */ 36 unsigned long ra_pages; /* max readahead in PAGE_CACHE_SIZE units */
29 unsigned long state; /* Always use atomic bitops on this */ 37 unsigned long state; /* Always use atomic bitops on this */
@@ -32,15 +40,86 @@ struct backing_dev_info {
32 void *congested_data; /* Pointer to aux data for congested func */ 40 void *congested_data; /* Pointer to aux data for congested func */
33 void (*unplug_io_fn)(struct backing_dev_info *, struct page *); 41 void (*unplug_io_fn)(struct backing_dev_info *, struct page *);
34 void *unplug_io_data; 42 void *unplug_io_data;
43
44 struct percpu_counter bdi_stat[NR_BDI_STAT_ITEMS];
35}; 45};
36 46
37static inline int bdi_init(struct backing_dev_info *bdi) 47int bdi_init(struct backing_dev_info *bdi);
48void bdi_destroy(struct backing_dev_info *bdi);
49
50static inline void __add_bdi_stat(struct backing_dev_info *bdi,
51 enum bdi_stat_item item, s64 amount)
38{ 52{
39 return 0; 53 __percpu_counter_add(&bdi->bdi_stat[item], amount, BDI_STAT_BATCH);
40} 54}
41 55
42static inline void bdi_destroy(struct backing_dev_info *bdi) 56static inline void __inc_bdi_stat(struct backing_dev_info *bdi,
57 enum bdi_stat_item item)
43{ 58{
59 __add_bdi_stat(bdi, item, 1);
60}
61
62static inline void inc_bdi_stat(struct backing_dev_info *bdi,
63 enum bdi_stat_item item)
64{
65 unsigned long flags;
66
67 local_irq_save(flags);
68 __inc_bdi_stat(bdi, item);
69 local_irq_restore(flags);
70}
71
72static inline void __dec_bdi_stat(struct backing_dev_info *bdi,
73 enum bdi_stat_item item)
74{
75 __add_bdi_stat(bdi, item, -1);
76}
77
78static inline void dec_bdi_stat(struct backing_dev_info *bdi,
79 enum bdi_stat_item item)
80{
81 unsigned long flags;
82
83 local_irq_save(flags);
84 __dec_bdi_stat(bdi, item);
85 local_irq_restore(flags);
86}
87
88static inline s64 bdi_stat(struct backing_dev_info *bdi,
89 enum bdi_stat_item item)
90{
91 return percpu_counter_read_positive(&bdi->bdi_stat[item]);
92}
93
94static inline s64 __bdi_stat_sum(struct backing_dev_info *bdi,
95 enum bdi_stat_item item)
96{
97 return percpu_counter_sum_positive(&bdi->bdi_stat[item]);
98}
99
100static inline s64 bdi_stat_sum(struct backing_dev_info *bdi,
101 enum bdi_stat_item item)
102{
103 s64 sum;
104 unsigned long flags;
105
106 local_irq_save(flags);
107 sum = __bdi_stat_sum(bdi, item);
108 local_irq_restore(flags);
109
110 return sum;
111}
112
113/*
114 * maximal error of a stat counter.
115 */
116static inline unsigned long bdi_stat_error(struct backing_dev_info *bdi)
117{
118#ifdef CONFIG_SMP
119 return nr_cpu_ids * BDI_STAT_BATCH;
120#else
121 return 1;
122#endif
44} 123}
45 124
46/* 125/*
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 841901a95595..a47065e084a4 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -5,6 +5,33 @@
5#include <linux/sched.h> 5#include <linux/sched.h>
6#include <linux/module.h> 6#include <linux/module.h>
7 7
8int bdi_init(struct backing_dev_info *bdi)
9{
10 int i, j;
11 int err;
12
13 for (i = 0; i < NR_BDI_STAT_ITEMS; i++) {
14 err = percpu_counter_init_irq(&bdi->bdi_stat[i], 0);
15 if (err) {
16 for (j = 0; j < i; j++)
17 percpu_counter_destroy(&bdi->bdi_stat[i]);
18 break;
19 }
20 }
21
22 return err;
23}
24EXPORT_SYMBOL(bdi_init);
25
26void bdi_destroy(struct backing_dev_info *bdi)
27{
28 int i;
29
30 for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
31 percpu_counter_destroy(&bdi->bdi_stat[i]);
32}
33EXPORT_SYMBOL(bdi_destroy);
34
8static wait_queue_head_t congestion_wqh[2] = { 35static wait_queue_head_t congestion_wqh[2] = {
9 __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]), 36 __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
10 __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1]) 37 __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])