summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cgroup.c1
-rw-r--r--kernel/exec_domain.c1
-rw-r--r--kernel/exit.c32
-rw-r--r--kernel/fork.c22
-rw-r--r--kernel/sysctl.c168
-rw-r--r--kernel/trace/trace.c1
-rw-r--r--kernel/tsacct.c8
7 files changed, 162 insertions, 71 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 89bd6fb7894..657f8f8d93a 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -45,6 +45,7 @@
#include <linux/delayacct.h>
#include <linux/cgroupstats.h>
#include <linux/hash.h>
+#include <linux/namei.h>
#include <asm/atomic.h>
diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c
index c1ef192aa65..0d407e88673 100644
--- a/kernel/exec_domain.c
+++ b/kernel/exec_domain.c
@@ -168,7 +168,6 @@ __set_personality(u_long personality)
current->personality = personality;
oep = current_thread_info()->exec_domain;
current_thread_info()->exec_domain = ep;
- set_fs_altroot();
module_put(oep->module);
return 0;
diff --git a/kernel/exit.c b/kernel/exit.c
index 6cdf60712bd..eb4d6470d1d 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -121,18 +121,7 @@ static void __exit_signal(struct task_struct *tsk)
sig->nivcsw += tsk->nivcsw;
sig->inblock += task_io_get_inblock(tsk);
sig->oublock += task_io_get_oublock(tsk);
-#ifdef CONFIG_TASK_XACCT
- sig->rchar += tsk->rchar;
- sig->wchar += tsk->wchar;
- sig->syscr += tsk->syscr;
- sig->syscw += tsk->syscw;
-#endif /* CONFIG_TASK_XACCT */
-#ifdef CONFIG_TASK_IO_ACCOUNTING
- sig->ioac.read_bytes += tsk->ioac.read_bytes;
- sig->ioac.write_bytes += tsk->ioac.write_bytes;
- sig->ioac.cancelled_write_bytes +=
- tsk->ioac.cancelled_write_bytes;
-#endif /* CONFIG_TASK_IO_ACCOUNTING */
+ task_io_accounting_add(&sig->ioac, &tsk->ioac);
sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
sig = NULL; /* Marker for below. */
}
@@ -565,8 +554,6 @@ void put_fs_struct(struct fs_struct *fs)
if (atomic_dec_and_test(&fs->count)) {
path_put(&fs->root);
path_put(&fs->pwd);
- if (fs->altroot.dentry)
- path_put(&fs->altroot);
kmem_cache_free(fs_cachep, fs);
}
}
@@ -1365,21 +1352,8 @@ static int wait_task_zombie(struct task_struct *p, int options,
psig->coublock +=
task_io_get_oublock(p) +
sig->oublock + sig->coublock;
-#ifdef CONFIG_TASK_XACCT
- psig->rchar += p->rchar + sig->rchar;
- psig->wchar += p->wchar + sig->wchar;
- psig->syscr += p->syscr + sig->syscr;
- psig->syscw += p->syscw + sig->syscw;
-#endif /* CONFIG_TASK_XACCT */
-#ifdef CONFIG_TASK_IO_ACCOUNTING
- psig->ioac.read_bytes +=
- p->ioac.read_bytes + sig->ioac.read_bytes;
- psig->ioac.write_bytes +=
- p->ioac.write_bytes + sig->ioac.write_bytes;
- psig->ioac.cancelled_write_bytes +=
- p->ioac.cancelled_write_bytes +
- sig->ioac.cancelled_write_bytes;
-#endif /* CONFIG_TASK_IO_ACCOUNTING */
+ task_io_accounting_add(&psig->ioac, &p->ioac);
+ task_io_accounting_add(&psig->ioac, &sig->ioac);
spin_unlock_irq(&p->parent->sighand->siglock);
}
diff --git a/kernel/fork.c b/kernel/fork.c
index abb3ed6298f..8214ba7c8bb 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -657,13 +657,6 @@ static struct fs_struct *__copy_fs_struct(struct fs_struct *old)
path_get(&old->root);
fs->pwd = old->pwd;
path_get(&old->pwd);
- if (old->altroot.dentry) {
- fs->altroot = old->altroot;
- path_get(&old->altroot);
- } else {
- fs->altroot.mnt = NULL;
- fs->altroot.dentry = NULL;
- }
read_unlock(&old->lock);
}
return fs;
@@ -813,12 +806,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
-#ifdef CONFIG_TASK_XACCT
- sig->rchar = sig->wchar = sig->syscr = sig->syscw = 0;
-#endif
-#ifdef CONFIG_TASK_IO_ACCOUNTING
- memset(&sig->ioac, 0, sizeof(sig->ioac));
-#endif
+ task_io_accounting_init(&sig->ioac);
sig->sum_sched_runtime = 0;
INIT_LIST_HEAD(&sig->cpu_timers[0]);
INIT_LIST_HEAD(&sig->cpu_timers[1]);
@@ -1001,13 +989,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->last_switch_timestamp = 0;
#endif
-#ifdef CONFIG_TASK_XACCT
- p->rchar = 0; /* I/O counter: bytes read */
- p->wchar = 0; /* I/O counter: bytes written */
- p->syscr = 0; /* I/O counter: read syscalls */
- p->syscw = 0; /* I/O counter: write syscalls */
-#endif
- task_io_accounting_init(p);
+ task_io_accounting_init(&p->ioac);
acct_clear_integrals(p);
p->it_virt_expires = cputime_zero;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 35a50db9b6c..fe471334727 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -160,12 +160,13 @@ static struct ctl_table root_table[];
static struct ctl_table_root sysctl_table_root;
static struct ctl_table_header root_table_header = {
.ctl_table = root_table,
- .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.header_list),
+ .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),
.root = &sysctl_table_root,
+ .set = &sysctl_table_root.default_set,
};
static struct ctl_table_root sysctl_table_root = {
.root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
- .header_list = LIST_HEAD_INIT(root_table_header.ctl_entry),
+ .default_set.list = LIST_HEAD_INIT(root_table_header.ctl_entry),
};
static struct ctl_table kern_table[];
@@ -1386,6 +1387,9 @@ static void start_unregistering(struct ctl_table_header *p)
spin_unlock(&sysctl_lock);
wait_for_completion(&wait);
spin_lock(&sysctl_lock);
+ } else {
+ /* anything non-NULL; we'll never dereference it */
+ p->unregistering = ERR_PTR(-EINVAL);
}
/*
* do not remove from the list until nobody holds it; walking the
@@ -1394,6 +1398,32 @@ static void start_unregistering(struct ctl_table_header *p)
list_del_init(&p->ctl_entry);
}
+void sysctl_head_get(struct ctl_table_header *head)
+{
+ spin_lock(&sysctl_lock);
+ head->count++;
+ spin_unlock(&sysctl_lock);
+}
+
+void sysctl_head_put(struct ctl_table_header *head)
+{
+ spin_lock(&sysctl_lock);
+ if (!--head->count)
+ kfree(head);
+ spin_unlock(&sysctl_lock);
+}
+
+struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
+{
+ if (!head)
+ BUG();
+ spin_lock(&sysctl_lock);
+ if (!use_table(head))
+ head = ERR_PTR(-ENOENT);
+ spin_unlock(&sysctl_lock);
+ return head;
+}
+
void sysctl_head_finish(struct ctl_table_header *head)
{
if (!head)
@@ -1403,14 +1433,20 @@ void sysctl_head_finish(struct ctl_table_header *head)
spin_unlock(&sysctl_lock);
}
+static struct ctl_table_set *
+lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
+{
+ struct ctl_table_set *set = &root->default_set;
+ if (root->lookup)
+ set = root->lookup(root, namespaces);
+ return set;
+}
+
static struct list_head *
lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
{
- struct list_head *header_list;
- header_list = &root->header_list;
- if (root->lookup)
- header_list = root->lookup(root, namespaces);
- return header_list;
+ struct ctl_table_set *set = lookup_header_set(root, namespaces);
+ return &set->list;
}
struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
@@ -1480,9 +1516,9 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
int op = 0, rc;
if (oldval)
- op |= 004;
+ op |= MAY_READ;
if (newval)
- op |= 002;
+ op |= MAY_WRITE;
if (sysctl_perm(root, table, op))
return -EPERM;
@@ -1524,7 +1560,7 @@ repeat:
if (n == table->ctl_name) {
int error;
if (table->child) {
- if (sysctl_perm(root, table, 001))
+ if (sysctl_perm(root, table, MAY_EXEC))
return -EPERM;
name++;
nlen--;
@@ -1599,7 +1635,7 @@ static int test_perm(int mode, int op)
mode >>= 6;
else if (in_egroup_p(0))
mode >>= 3;
- if ((mode & op & 0007) == op)
+ if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
return 0;
return -EACCES;
}
@@ -1609,7 +1645,7 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
int error;
int mode;
- error = security_sysctl(table, op);
+ error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC));
if (error)
return error;
@@ -1644,6 +1680,54 @@ static __init int sysctl_init(void)
core_initcall(sysctl_init);
+static struct ctl_table *is_branch_in(struct ctl_table *branch,
+ struct ctl_table *table)
+{
+ struct ctl_table *p;
+ const char *s = branch->procname;
+
+ /* branch should have named subdirectory as its first element */
+ if (!s || !branch->child)
+ return NULL;
+
+ /* ... and nothing else */
+ if (branch[1].procname || branch[1].ctl_name)
+ return NULL;
+
+ /* table should contain subdirectory with the same name */
+ for (p = table; p->procname || p->ctl_name; p++) {
+ if (!p->child)
+ continue;
+ if (p->procname && strcmp(p->procname, s) == 0)
+ return p;
+ }
+ return NULL;
+}
+
+/* see if attaching q to p would be an improvement */
+static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q)
+{
+ struct ctl_table *to = p->ctl_table, *by = q->ctl_table;
+ struct ctl_table *next;
+ int is_better = 0;
+ int not_in_parent = !p->attached_by;
+
+ while ((next = is_branch_in(by, to)) != NULL) {
+ if (by == q->attached_by)
+ is_better = 1;
+ if (to == p->attached_by)
+ not_in_parent = 1;
+ by = by->child;
+ to = next->child;
+ }
+
+ if (is_better && not_in_parent) {
+ q->attached_by = by;
+ q->attached_to = to;
+ q->parent = p;
+ }
+}
+
/**
* __register_sysctl_paths - register a sysctl hierarchy
* @root: List of sysctl headers to register on
@@ -1720,10 +1804,10 @@ struct ctl_table_header *__register_sysctl_paths(
struct nsproxy *namespaces,
const struct ctl_path *path, struct ctl_table *table)
{
- struct list_head *header_list;
struct ctl_table_header *header;
struct ctl_table *new, **prevp;
unsigned int n, npath;
+ struct ctl_table_set *set;
/* Count the path components */
for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath)
@@ -1765,6 +1849,7 @@ struct ctl_table_header *__register_sysctl_paths(
header->unregistering = NULL;
header->root = root;
sysctl_set_parent(NULL, header->ctl_table);
+ header->count = 1;
#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
if (sysctl_check_table(namespaces, header->ctl_table)) {
kfree(header);
@@ -1772,8 +1857,20 @@ struct ctl_table_header *__register_sysctl_paths(
}
#endif
spin_lock(&sysctl_lock);
- header_list = lookup_header_list(root, namespaces);
- list_add_tail(&header->ctl_entry, header_list);
+ header->set = lookup_header_set(root, namespaces);
+ header->attached_by = header->ctl_table;
+ header->attached_to = root_table;
+ header->parent = &root_table_header;
+ for (set = header->set; set; set = set->parent) {
+ struct ctl_table_header *p;
+ list_for_each_entry(p, &set->list, ctl_entry) {
+ if (p->unregistering)
+ continue;
+ try_attach(p, header);
+ }
+ }
+ header->parent->count++;
+ list_add_tail(&header->ctl_entry, &header->set->list);
spin_unlock(&sysctl_lock);
return header;
@@ -1828,8 +1925,37 @@ void unregister_sysctl_table(struct ctl_table_header * header)
spin_lock(&sysctl_lock);
start_unregistering(header);
+ if (!--header->parent->count) {
+ WARN_ON(1);
+ kfree(header->parent);
+ }
+ if (!--header->count)
+ kfree(header);
spin_unlock(&sysctl_lock);
- kfree(header);
+}
+
+int sysctl_is_seen(struct ctl_table_header *p)
+{
+ struct ctl_table_set *set = p->set;
+ int res;
+ spin_lock(&sysctl_lock);
+ if (p->unregistering)
+ res = 0;
+ else if (!set->is_seen)
+ res = 1;
+ else
+ res = set->is_seen(set);
+ spin_unlock(&sysctl_lock);
+ return res;
+}
+
+void setup_sysctl_set(struct ctl_table_set *p,
+ struct ctl_table_set *parent,
+ int (*is_seen)(struct ctl_table_set *))
+{
+ INIT_LIST_HEAD(&p->list);
+ p->parent = parent ? parent : &sysctl_table_root.default_set;
+ p->is_seen = is_seen;
}
#else /* !CONFIG_SYSCTL */
@@ -1848,6 +1974,16 @@ void unregister_sysctl_table(struct ctl_table_header * table)
{
}
+void setup_sysctl_set(struct ctl_table_set *p,
+ struct ctl_table_set *parent,
+ int (*is_seen)(struct ctl_table_set *))
+{
+}
+
+void sysctl_head_put(struct ctl_table_header *head)
+{
+}
+
#endif /* CONFIG_SYSCTL */
/*
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index fc20e09a6cb..8f3fb3db61c 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1183,7 +1183,6 @@ static void *find_next_entry_inc(struct trace_iterator *iter)
static void *s_next(struct seq_file *m, void *v, loff_t *pos)
{
struct trace_iterator *iter = m->private;
- void *last_ent = iter->ent;
int i = (int)*pos;
void *ent;
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index 3da47ccdc5e..8ebcd8532df 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -94,10 +94,10 @@ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
stats->hiwater_vm = mm->hiwater_vm * PAGE_SIZE / KB;
mmput(mm);
}
- stats->read_char = p->rchar;
- stats->write_char = p->wchar;
- stats->read_syscalls = p->syscr;
- stats->write_syscalls = p->syscw;
+ stats->read_char = p->ioac.rchar;
+ stats->write_char = p->ioac.wchar;
+ stats->read_syscalls = p->ioac.syscr;
+ stats->write_syscalls = p->ioac.syscw;
#ifdef CONFIG_TASK_IO_ACCOUNTING
stats->read_bytes = p->ioac.read_bytes;
stats->write_bytes = p->ioac.write_bytes;