--- mm/vmstat.c | 69 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 31 deletions(-) Index: linux-2.6/mm/vmstat.c =================================================================== --- linux-2.6.orig/mm/vmstat.c 2007-11-08 20:19:59.013637624 -0800 +++ linux-2.6/mm/vmstat.c 2007-11-08 20:25:40.018137624 -0800 @@ -211,6 +211,33 @@ EXPORT_SYMBOL(mod_zone_page_state); * in between and therefore the atomicity vs. interrupt cannot be exploited * in a useful way here. */ +static s8 inc_diff(s8 *p) +{ + __asm__ __volatile__( + "incb %0;" + : "=m" (p) + : "m" (p)); + return *p; +} + +static s8 dec_diff(s8 *p) +{ + __asm__ __volatile__( + "decb %0;" + : "=m" (p) + : "m" (p)); + return *p; +} + +static inline void sync_diff(struct zone *zone, s8 *p, + int i, int offset) +{ + /* + * xchg_local() would be useful here but that does not exist. + */ + zone_page_state_add(xchg(p, offset) - offset, zone, i); +} + void __inc_zone_state(struct zone *zone, enum zone_stat_item item) { struct per_cpu_pageset *pcp = THIS_CPU(zone->pageset); @@ -218,15 +245,10 @@ void __inc_zone_state(struct zone *zone, s8 new; s8 t = pcp->stat_threshold; - new = *p + 1; + new = inc_diff(p); - if (unlikely(new > t)) { - int overstep = t / 2; - - zone_page_state_add(new + overstep, zone, item); - new = -overstep; - } - *p = new; + if (unlikely(new > t)) + sync_diff(zone, p, item, t / 2); } void __inc_zone_page_state(struct page *page, enum zone_stat_item item) @@ -242,15 +264,10 @@ void __dec_zone_state(struct zone *zone, s8 new; s8 t = -pcp->stat_threshold; - new = *p - 1; + new = dec_diff(p); - if (unlikely(new < t)) { - int overstep = t / 2; - - zone_page_state_add(new + overstep, zone, item); - new = -overstep; - } - *p = new; + if (unlikely(new < t)) + sync_diff(zone, p, item, t / 2); } void __dec_zone_page_state(struct page *page, enum zone_stat_item item) @@ -261,32 +278,22 @@ EXPORT_SYMBOL(__dec_zone_page_state); void inc_zone_state(struct zone *zone, enum zone_stat_item item) { - unsigned long flags; - - local_irq_save(flags); + preempt_disable(); __inc_zone_state(zone, item); - local_irq_restore(flags); + preempt_enable(); } void inc_zone_page_state(struct page *page, enum zone_stat_item item) { - unsigned long flags; - struct zone *zone; - - zone = page_zone(page); - local_irq_save(flags); - __inc_zone_state(zone, item); - local_irq_restore(flags); + inc_zone_state(page_zone(page), item); } EXPORT_SYMBOL(inc_zone_page_state); void dec_zone_page_state(struct page *page, enum zone_stat_item item) { - unsigned long flags; - - local_irq_save(flags); + preempt_disable(); __dec_zone_page_state(page, item); - local_irq_restore(flags); + preempt_enable(); } EXPORT_SYMBOL(dec_zone_page_state);