Add High/Low watermark support to res_counter.

This adds high/low watermark support to res_counter.

Adds new member hwmark, lwmark, wmark_state to res_counter struct.

Users of res_counter must keep lwmark <= hwmark <= limit.
(set params as lwmark == hwmark == limit will disable this feature.)

wmark_state is added to read wmark status without lock.

Codes will be like this. (check status after charge.)

        if (res_counter_charge(cnt...)) { <----(need lock)
                .....
        }
        if (res_counter_above_hwmark(cnt)) <---- (no lock)
                trigger background jobs...

If I have to check under lock, please teach me.

counter->hwmark and counter->lwmark is not automatically adjusted
when limit is changed. So, users must change lwmark, hwmark before
changing limit.

Changelog
  * made variable names shorter.
  * adjusted to 2.6.24-mm1

Signed-off-by: KAMEZAWA Hiroyuki <[EMAIL PROTECTED]>

 include/linux/res_counter.h |   30 ++++++++++++++++++++++++
 kernel/res_counter.c        |   53 +++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 78 insertions(+), 5 deletions(-)

Index: linux-2.6.24-mm1/include/linux/res_counter.h
===================================================================
--- linux-2.6.24-mm1.orig/include/linux/res_counter.h
+++ linux-2.6.24-mm1/include/linux/res_counter.h
@@ -19,6 +19,16 @@
  * the helpers described beyond
  */
 
+/*
+ * Watermark status.
+ */
+
+enum watermark_state {
+       RES_WMARK_BELOW_LOW = 0,        /* usage < low <= high <= max */
+       RES_WMARK_ABOVE_LOW,    /* low <= usage < high <= max */
+       RES_WMARK_ABOVE_HIGH,   /* low <= high <= usage <= max */
+};
+
 struct res_counter {
        /*
         * the current resource consumption level
@@ -33,10 +43,18 @@ struct res_counter {
         */
        unsigned long long failcnt;
        /*
+        * for supporting High/Low watermak
+        * Must keep low <= high <= limit.
+        */
+       unsigned long long hwmark;
+       unsigned long long lwmark;
+       enum watermark_state wmark_state; /* changed at charge/uncharge */
+       /*
         * the lock to protect all of the above.
         * the routines below consider this to be IRQ-safe
         */
        spinlock_t lock;
+
 };
 
 /*
@@ -66,6 +84,8 @@ enum {
        RES_USAGE,
        RES_LIMIT,
        RES_FAILCNT,
+       RES_HWMARK,
+       RES_LWMARK,
 };
 
 /*
@@ -124,4 +144,14 @@ static inline bool res_counter_check_und
        return ret;
 }
 
+static inline bool res_counter_below_lwmark(struct res_counter *cnt)
+{
+       smp_rmb();
+       return (cnt->wmark_state == RES_WMARK_BELOW_LOW);
+}
+static inline bool res_counter_above_hwmark(struct res_counter *cnt)
+{
+       smp_rmb();
+       return (cnt->wmark_state == RES_WMARK_ABOVE_HIGH);
+}
 #endif
Index: linux-2.6.24-mm1/kernel/res_counter.c
===================================================================
--- linux-2.6.24-mm1.orig/kernel/res_counter.c
+++ linux-2.6.24-mm1/kernel/res_counter.c
@@ -17,16 +17,29 @@ void res_counter_init(struct res_counter
 {
        spin_lock_init(&counter->lock);
        counter->limit = (unsigned long long)LLONG_MAX;
+       counter->lwmark = (unsigned long long)LLONG_MAX;
+       counter->hwmark = (unsigned long long)LLONG_MAX;
+       counter->wmark_state = RES_WMARK_BELOW_LOW;
 }
 
 int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
 {
-       if (counter->usage + val > counter->limit) {
+       unsigned long long newval = counter->usage + val;
+       if (newval > counter->limit) {
                counter->failcnt++;
                return -ENOMEM;
        }
 
-       counter->usage += val;
+        if (newval > counter->hwmark) {
+               counter->wmark_state = RES_WMARK_ABOVE_HIGH;
+               smp_wmb();
+       } else if (newval > counter->lwmark) {
+               counter->wmark_state = RES_WMARK_ABOVE_LOW;
+               smp_wmb();
+       }
+
+       counter->usage = newval;
+
        return 0;
 }
 
@@ -43,10 +56,18 @@ int res_counter_charge(struct res_counte
 
 void res_counter_uncharge_locked(struct res_counter *counter, unsigned long 
val)
 {
+       unsigned long long newval = counter->usage - val;
        if (WARN_ON(counter->usage < val))
-               val = counter->usage;
+               newval = 0;
 
-       counter->usage -= val;
+       if (newval < counter->lwmark) {
+               counter->wmark_state = RES_WMARK_BELOW_LOW;
+               smp_wmb();
+       } else if (newval < counter->hwmark) {
+               counter->wmark_state = RES_WMARK_ABOVE_LOW;
+               smp_wmb();
+       }
+       counter->usage = newval;
 }
 
 void res_counter_uncharge(struct res_counter *counter, unsigned long val)
@@ -69,6 +90,10 @@ res_counter_member(struct res_counter *c
                return &counter->limit;
        case RES_FAILCNT:
                return &counter->failcnt;
+       case RES_HWMARK:
+               return &counter->hwmark;
+       case RES_LWMARK:
+               return &counter->lwmark;
        };
 
        BUG();
@@ -123,10 +148,28 @@ ssize_t res_counter_write(struct res_cou
                        goto out_free;
        }
        spin_lock_irqsave(&counter->lock, flags);
+       switch (member) {
+               case RES_LIMIT:
+                       if (counter->hwmark > tmp)
+                               goto unlock_free;
+                       break;
+               case RES_HWMARK:
+                       if (tmp < counter->lwmark ||
+                           tmp > counter->limit)
+                               goto unlock_free;
+                       break;
+               case RES_LWMARK:
+                       if (tmp > counter->hwmark)
+                               goto unlock_free;
+                       break;
+               default:
+                       break;
+       }
        val = res_counter_member(counter, member);
        *val = tmp;
-       spin_unlock_irqrestore(&counter->lock, flags);
        ret = nbytes;
+unlock_free:
+       spin_unlock_irqrestore(&counter->lock, flags);
 out_free:
        kfree(buf);
 out:

_______________________________________________
Containers mailing list
[EMAIL PROTECTED]
https://lists.linux-foundation.org/mailman/listinfo/containers

_______________________________________________
Devel mailing list
Devel@openvz.org
https://openvz.org/mailman/listinfo/devel

Reply via email to