mm: count reclaimable pages per BDI
[safe/jmp/linux-2.6] / include / linux / backing-dev.h
index 7011d62..bfae09d 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _LINUX_BACKING_DEV_H
 #define _LINUX_BACKING_DEV_H
 
+#include <linux/percpu_counter.h>
+#include <linux/log2.h>
 #include <asm/atomic.h>
 
 struct page;
@@ -24,6 +26,13 @@ enum bdi_state {
 
 typedef int (congested_fn)(void *, int);
 
+enum bdi_stat_item {
+       BDI_RECLAIMABLE,
+       NR_BDI_STAT_ITEMS
+};
+
+#define BDI_STAT_BATCH (8*(1+ilog2(nr_cpu_ids)))
+
 struct backing_dev_info {
        unsigned long ra_pages; /* max readahead in PAGE_CACHE_SIZE units */
        unsigned long state;    /* Always use atomic bitops on this */
@@ -32,8 +41,87 @@ struct backing_dev_info {
        void *congested_data;   /* Pointer to aux data for congested func */
        void (*unplug_io_fn)(struct backing_dev_info *, struct page *);
        void *unplug_io_data;
+
+       struct percpu_counter bdi_stat[NR_BDI_STAT_ITEMS];
 };
 
+int bdi_init(struct backing_dev_info *bdi);
+void bdi_destroy(struct backing_dev_info *bdi);
+
+static inline void __add_bdi_stat(struct backing_dev_info *bdi,
+               enum bdi_stat_item item, s64 amount)
+{
+       __percpu_counter_add(&bdi->bdi_stat[item], amount, BDI_STAT_BATCH);
+}
+
+static inline void __inc_bdi_stat(struct backing_dev_info *bdi,
+               enum bdi_stat_item item)
+{
+       __add_bdi_stat(bdi, item, 1);
+}
+
+static inline void inc_bdi_stat(struct backing_dev_info *bdi,
+               enum bdi_stat_item item)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __inc_bdi_stat(bdi, item);
+       local_irq_restore(flags);
+}
+
+static inline void __dec_bdi_stat(struct backing_dev_info *bdi,
+               enum bdi_stat_item item)
+{
+       __add_bdi_stat(bdi, item, -1);
+}
+
+static inline void dec_bdi_stat(struct backing_dev_info *bdi,
+               enum bdi_stat_item item)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __dec_bdi_stat(bdi, item);
+       local_irq_restore(flags);
+}
+
+static inline s64 bdi_stat(struct backing_dev_info *bdi,
+               enum bdi_stat_item item)
+{
+       return percpu_counter_read_positive(&bdi->bdi_stat[item]);
+}
+
+static inline s64 __bdi_stat_sum(struct backing_dev_info *bdi,
+               enum bdi_stat_item item)
+{
+       return percpu_counter_sum_positive(&bdi->bdi_stat[item]);
+}
+
+static inline s64 bdi_stat_sum(struct backing_dev_info *bdi,
+               enum bdi_stat_item item)
+{
+       s64 sum;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       sum = __bdi_stat_sum(bdi, item);
+       local_irq_restore(flags);
+
+       return sum;
+}
+
+/*
+ * maximal error of a stat counter.
+ */
+static inline unsigned long bdi_stat_error(struct backing_dev_info *bdi)
+{
+#ifdef CONFIG_SMP
+       return nr_cpu_ids * BDI_STAT_BATCH;
+#else
+       return 1;
+#endif
+}
 
 /*
  * Flags in backing_dev_info::capability
@@ -93,7 +181,6 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi)
 void clear_bdi_congested(struct backing_dev_info *bdi, int rw);
 void set_bdi_congested(struct backing_dev_info *bdi, int rw);
 long congestion_wait(int rw, long timeout);
-void congestion_end(int rw);
 
 #define bdi_cap_writeback_dirty(bdi) \
        (!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK))