diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2009-11-25 20:54:20 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2009-11-25 20:54:20 +1100 |
commit | dbaeb7ac13814497f69f76aeed54ea68b75a3361 (patch) | |
tree | 10281b4a8f0013fb2ccd97dede967875de417ba2 /fs/proc | |
parent | 8d995deca7558b565ac7d5e14ce14af87e2f1ab0 (diff) | |
parent | eba9d1652b21f62e22b7a8edfc6c492676fbeb76 (diff) |
Merge remote branch 'limits/writable_limits'
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 78 |
1 files changed, 76 insertions, 2 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index af643b5aefe8..c6589fb4d071 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -128,6 +128,8 @@ struct pid_entry { NULL, &proc_single_file_operations, \ { .proc_show = show } ) +static ssize_t proc_info_read(struct file * file, char __user * buf, + size_t count, loff_t *ppos); /* * Count the number of hardlinks for the pid_entry table, excluding the . * and .. links. @@ -521,6 +523,74 @@ static int proc_pid_limits(struct task_struct *task, char *buffer) return count; } +static ssize_t limits_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); + char str[32 + 1 + 16 + 1 + 16 + 1], *delim, *next; + struct rlimit new_rlimit; + unsigned int i; + int ret; + + if (!task) { + count = -ESRCH; + goto out; + } + if (copy_from_user(str, buf, min(count, sizeof(str) - 1))) { + count = -EFAULT; + goto put_task; + } + + str[min(count, sizeof(str) - 1)] = 0; + + delim = strchr(str, '='); + if (!delim) { + count = -EINVAL; + goto put_task; + } + *delim++ = 0; /* for easy 'str' usage */ + new_rlimit.rlim_cur = simple_strtoul(delim, &next, 0); + if (*next != ':') { + if (strncmp(delim, "unlimited:", 10)) { + count = -EINVAL; + goto put_task; + } + new_rlimit.rlim_cur = RLIM_INFINITY; + next = delim + 9; /* move to ':' */ + } + delim = next + 1; + new_rlimit.rlim_max = simple_strtoul(delim, &next, 0); + if (*next != 0) { + if (strcmp(delim, "unlimited")) { + count = -EINVAL; + goto put_task; + } + new_rlimit.rlim_max = RLIM_INFINITY; + } + + for (i = 0; i < RLIM_NLIMITS; i++) + if (!strcmp(str, lnames[i].name)) + break; + if (i >= RLIM_NLIMITS) { + count = -EINVAL; + goto put_task; + } + + ret = do_setrlimit(task, i, &new_rlimit); + if (ret) + count = ret; + +put_task: + put_task_struct(task); +out: + return count; +} + +static const struct file_operations proc_pid_limits_operations = { + .read = proc_info_read, + .write = limits_write, +}; + #ifdef CONFIG_HAVE_ARCH_TRACEHOOK static int proc_pid_syscall(struct task_struct *task, char *buffer) { @@ -2500,7 +2570,9 @@ static const struct pid_entry tgid_base_stuff[] = { INF("auxv", S_IRUSR, proc_pid_auxv), ONE("status", S_IRUGO, proc_pid_status), ONE("personality", S_IRUSR, proc_pid_personality), - INF("limits", S_IRUSR, proc_pid_limits), + NOD("limits", S_IFREG|S_IRUSR|S_IWUSR, NULL, + &proc_pid_limits_operations, + { .proc_read = proc_pid_limits }), #ifdef CONFIG_SCHED_DEBUG REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), #endif @@ -2834,7 +2906,9 @@ static const struct pid_entry tid_base_stuff[] = { INF("auxv", S_IRUSR, proc_pid_auxv), ONE("status", S_IRUGO, proc_pid_status), ONE("personality", S_IRUSR, proc_pid_personality), - INF("limits", S_IRUSR, proc_pid_limits), + NOD("limits", S_IFREG|S_IRUSR|S_IWUSR, NULL, + &proc_pid_limits_operations, + { .proc_read = proc_pid_limits }), #ifdef CONFIG_SCHED_DEBUG REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), #endif |