VM_LOWMEM_ALLOWED_UIDS,
VM_LOWMEM_ALLOWED_PAGES,
VM_LOWMEM_FREE_PAGES,
+ VM_LOWMEM_DENY,
+ VM_LOWMEM_LEVEL1_NOTIFY,
+ VM_LOWMEM_LEVEL2_NOTIFY,
+ VM_LOWMEM_USED_PAGES
};
static long deny_pages;
static unsigned int allowed_uids[LOWMEM_MAX_UIDS];
static unsigned int minuid = 1;
static unsigned int maxuid = 65535;
+static unsigned int deny_percentage;
+static unsigned int l1_notify, l2_notify;
+static long used_pages;
+
+static int
+proc_dointvec_used(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+static int
+proc_dointvec_l1_notify(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+static int
+proc_dointvec_l2_notify(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+static int
+proc_dointvec_deny(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
static ctl_table lowmem_table[] = {
{
.child = NULL,
.proc_handler = &proc_dointvec,
.strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_DENY,
+ .procname = "lowmem_deny_watermark",
+ .data = &deny_percentage,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_deny,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_LEVEL1_NOTIFY,
+ .procname = "lowmem_notify_low",
+ .data = &l1_notify,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_l1_notify,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_LEVEL2_NOTIFY,
+ .procname = "lowmem_notify_high",
+ .data = &l2_notify,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_l2_notify,
+ .strategy = &sysctl_intvec,
+ }, {
+ .ctl_name = VM_LOWMEM_USED_PAGES,
+ .procname = "lowmem_used_pages",
+ .data = &used_pages,
+ .maxlen = sizeof(long),
+ .mode = 0444,
+ .child = NULL,
+ .proc_handler = &proc_dointvec_used,
+ .strategy = &sysctl_intvec,
}, {
.ctl_name = VM_LOWMEM_NOTIFY_LOW_PAGES,
.procname = "lowmem_notify_low_pages",
static int low_watermark_reached, high_watermark_reached;
+static int
+proc_dointvec_l1_notify(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ l1_notify =
+ 100 - (100 * notify_low_pages + allowed_pages / 2) / allowed_pages;
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static int
+proc_dointvec_l2_notify(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ l2_notify =
+ 100 - (100 * notify_high_pages + allowed_pages / 2) / allowed_pages;
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static int
+proc_dointvec_deny(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ deny_percentage =
+ 100 - (100 * deny_pages + allowed_pages / 2) / allowed_pages;
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static int
+proc_dointvec_used(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ if (lowmem_free_pages > 0 && allowed_pages > lowmem_free_pages)
+ used_pages = allowed_pages - lowmem_free_pages;
+ else
+ used_pages = 0;
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
static ssize_t low_watermark_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{
}
}
-static int low_vm_enough_memory(long pages)
+static int low_vm_enough_memory(struct mm_struct *mm, long pages)
{
unsigned long free, allowed;
int cap_sys_admin = 0, notify;
/* We activate ourselves only after both parameters have been
* configured. */
if (deny_pages == 0 || notify_low_pages == 0 || notify_high_pages == 0)
- return __vm_enough_memory(pages, cap_sys_admin);
+ return __vm_enough_memory(mm, pages, cap_sys_admin);
vm_acct_memory(pages);
static struct security_operations lowmem_security_ops = {
/* Use the capability functions for some of the hooks */
- .ptrace = cap_ptrace,
+ .ptrace_may_access = cap_ptrace_may_access,
+ .ptrace_traceme = cap_ptrace_traceme,
.capget = cap_capget,
.capset_check = cap_capset_check,
.capset_set = cap_capset_set,
};
static struct ctl_table_header *lowmem_table_header;
-/* flag to keep track of how we were registered */
-static int secondary;
static struct attribute *lowmem_attrs[] = {
&low_watermark_attr.attr,
/* register ourselves with the security framework */
if (register_security(&lowmem_security_ops)) {
printk(KERN_ERR MY_NAME ": Failure registering with the kernel\n");
- /* try registering with primary module */
- if (mod_reg_security(MY_NAME, &lowmem_security_ops)) {
- printk(KERN_ERR ": Failure registering with the primary"
- "security module.\n");
- return -EINVAL;
- }
- secondary = 1;
+ return -EINVAL;
}
/* initialize the uids vector */
return 0;
}
-static void __exit lowmem_exit(void)
-{
- /* remove ourselves from the security framework */
- if (secondary) {
- if (mod_unreg_security(MY_NAME, &lowmem_security_ops))
- printk(KERN_ERR MY_NAME ": Failure unregistering "
- "with the primary security module.\n");
- } else {
- if (unregister_security(&lowmem_security_ops)) {
- printk(KERN_ERR MY_NAME ": Failure unregistering "
- "with the kernel.\n");
- }
- }
-
- unregister_sysctl_table(lowmem_table_header);
-
- sysfs_remove_group(kernel_kobj, &lowmem_attr_group);
-
- printk(KERN_INFO MY_NAME ": Module removed.\n");
-}
-
module_init(lowmem_init);
-module_exit(lowmem_exit);
MODULE_DESCRIPTION("Low watermark LSM module");
MODULE_LICENSE("GPL");