@@ -22,6 +22,19 @@ enum {
* Sample value is less than user-specified value
*/
VMEVENT_ATTR_STATE_VALUE_LT = (1UL << 0),
+ /*
+ * Sample value is greater than user-specified value
+ */
+ VMEVENT_ATTR_STATE_VALUE_GT = (1UL << 1),
+ /*
+ * One-shot mode.
+ */
+ VMEVENT_ATTR_STATE_ONE_SHOT = (1UL << 2),
+
+ /* Saved state, used internally by the kernel for one-shot mode. */
+ __VMEVENT_ATTR_STATE_VALUE_WAS_LT = (1UL << 30),
+ /* Saved state, used internally by the kernel for one-shot mode. */
+ __VMEVENT_ATTR_STATE_VALUE_WAS_GT = (1UL << 31),
};
struct vmevent_attr {
@@ -1,5 +1,6 @@
#include <linux/anon_inodes.h>
#include <linux/atomic.h>
+#include <linux/compiler.h>
#include <linux/vmevent.h>
#include <linux/syscalls.h>
#include <linux/timer.h>
@@ -83,16 +84,47 @@ static bool vmevent_match(struct vmevent_watch *watch)
for (i = 0; i < config->counter; i++) {
struct vmevent_attr *attr = &config->attrs[i];
- u64 value;
+ u32 state = attr->state;
+ bool attr_lt = state & VMEVENT_ATTR_STATE_VALUE_LT;
+ bool attr_gt = state & VMEVENT_ATTR_STATE_VALUE_GT;
- if (!attr->state)
+ if (!state)
continue;
- value = vmevent_sample_attr(watch, attr);
-
- if (attr->state & VMEVENT_ATTR_STATE_VALUE_LT) {
- if (value < attr->value)
+ if (attr_lt || attr_gt) {
+ bool one_shot = state & VMEVENT_ATTR_STATE_ONE_SHOT;
+ u32 was_lt_mask = __VMEVENT_ATTR_STATE_VALUE_WAS_LT;
+ u32 was_gt_mask = __VMEVENT_ATTR_STATE_VALUE_WAS_GT;
+ u64 value = vmevent_sample_attr(watch, attr);
+ bool lt = value < attr->value;
+ bool gt = value > attr->value;
+ bool was_lt = state & was_lt_mask;
+ bool was_gt = state & was_gt_mask;
+ bool ret = false;
+
+ if ((lt || gt) && !one_shot)
return true;
+
+ if (attr_lt && lt && was_lt) {
+ return false;
+ } else if (attr_gt && gt && was_gt) {
+ return false;
+ } else if (lt) {
+ state |= was_lt_mask;
+ state &= ~was_gt_mask;
+ if (attr_lt)
+ ret = true;
+ } else if (gt) {
+ state |= was_gt_mask;
+ state &= ~was_lt_mask;
+ if (attr_gt)
+ ret = true;
+ } else {
+ state &= ~was_lt_mask;
+ state &= ~was_gt_mask;
+ }
+ attr->state = state;
+ return ret;
}
}
@@ -33,20 +33,32 @@ int main(int argc, char *argv[])
config = (struct vmevent_config) {
.sample_period_ns = 1000000000L,
- .counter = 4,
+ .counter = 6,
.attrs = {
- [0] = {
+ {
.type = VMEVENT_ATTR_NR_FREE_PAGES,
.state = VMEVENT_ATTR_STATE_VALUE_LT,
.value = phys_pages,
},
- [1] = {
+ {
+ .type = VMEVENT_ATTR_NR_FREE_PAGES,
+ .state = VMEVENT_ATTR_STATE_VALUE_GT,
+ .value = phys_pages,
+ },
+ {
+ .type = VMEVENT_ATTR_NR_FREE_PAGES,
+ .state = VMEVENT_ATTR_STATE_VALUE_LT |
+ VMEVENT_ATTR_STATE_VALUE_GT |
+ VMEVENT_ATTR_STATE_ONE_SHOT,
+ .value = phys_pages / 2,
+ },
+ {
.type = VMEVENT_ATTR_NR_AVAIL_PAGES,
},
- [2] = {
+ {
.type = VMEVENT_ATTR_NR_SWAP_PAGES,
},
- [3] = {
+ {
.type = 0xffff, /* invalid */
},
},
@@ -59,7 +71,7 @@ int main(int argc, char *argv[])
}
for (i = 0; i < 10; i++) {
- char buffer[sizeof(struct vmevent_event) + 4 * sizeof(struct vmevent_attr)];
+ char buffer[sizeof(struct vmevent_event) + config.counter * sizeof(struct vmevent_attr)];
struct vmevent_event *event;
int n = 0;
int idx;