Root/ipc/ipc_sysctl.c

1/*
2 * Copyright (C) 2007
3 *
4 * Author: Eric Biederman <ebiederm@xmision.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2 of the
9 * License.
10 */
11
12#include <linux/module.h>
13#include <linux/ipc.h>
14#include <linux/nsproxy.h>
15#include <linux/sysctl.h>
16#include <linux/uaccess.h>
17#include <linux/ipc_namespace.h>
18#include <linux/msg.h>
19#include "util.h"
20
21static void *get_ipc(ctl_table *table)
22{
23    char *which = table->data;
24    struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
25    which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
26    return which;
27}
28
29#ifdef CONFIG_PROC_SYSCTL
30static int proc_ipc_dointvec(ctl_table *table, int write,
31    void __user *buffer, size_t *lenp, loff_t *ppos)
32{
33    struct ctl_table ipc_table;
34    memcpy(&ipc_table, table, sizeof(ipc_table));
35    ipc_table.data = get_ipc(table);
36
37    return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
38}
39
40static int proc_ipc_callback_dointvec(ctl_table *table, int write,
41    void __user *buffer, size_t *lenp, loff_t *ppos)
42{
43    struct ctl_table ipc_table;
44    size_t lenp_bef = *lenp;
45    int rc;
46
47    memcpy(&ipc_table, table, sizeof(ipc_table));
48    ipc_table.data = get_ipc(table);
49
50    rc = proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
51
52    if (write && !rc && lenp_bef == *lenp)
53        /*
54         * Tunable has successfully been changed by hand. Disable its
55         * automatic adjustment. This simply requires unregistering
56         * the notifiers that trigger recalculation.
57         */
58        unregister_ipcns_notifier(current->nsproxy->ipc_ns);
59
60    return rc;
61}
62
63static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
64    void __user *buffer, size_t *lenp, loff_t *ppos)
65{
66    struct ctl_table ipc_table;
67    memcpy(&ipc_table, table, sizeof(ipc_table));
68    ipc_table.data = get_ipc(table);
69
70    return proc_doulongvec_minmax(&ipc_table, write, buffer,
71                    lenp, ppos);
72}
73
74/*
75 * Routine that is called when the file "auto_msgmni" has successfully been
76 * written.
77 * Two values are allowed:
78 * 0: unregister msgmni's callback routine from the ipc namespace notifier
79 * chain. This means that msgmni won't be recomputed anymore upon memory
80 * add/remove or ipc namespace creation/removal.
81 * 1: register back the callback routine.
82 */
83static void ipc_auto_callback(int val)
84{
85    if (!val)
86        unregister_ipcns_notifier(current->nsproxy->ipc_ns);
87    else {
88        /*
89         * Re-enable automatic recomputing only if not already
90         * enabled.
91         */
92        recompute_msgmni(current->nsproxy->ipc_ns);
93        cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
94    }
95}
96
97static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
98    void __user *buffer, size_t *lenp, loff_t *ppos)
99{
100    struct ctl_table ipc_table;
101    size_t lenp_bef = *lenp;
102    int oldval;
103    int rc;
104
105    memcpy(&ipc_table, table, sizeof(ipc_table));
106    ipc_table.data = get_ipc(table);
107    oldval = *((int *)(ipc_table.data));
108
109    rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
110
111    if (write && !rc && lenp_bef == *lenp) {
112        int newval = *((int *)(ipc_table.data));
113        /*
114         * The file "auto_msgmni" has correctly been set.
115         * React by (un)registering the corresponding tunable, if the
116         * value has changed.
117         */
118        if (newval != oldval)
119            ipc_auto_callback(newval);
120    }
121
122    return rc;
123}
124
125#else
126#define proc_ipc_doulongvec_minmax NULL
127#define proc_ipc_dointvec NULL
128#define proc_ipc_callback_dointvec NULL
129#define proc_ipcauto_dointvec_minmax NULL
130#endif
131
132static int zero;
133static int one = 1;
134
135static struct ctl_table ipc_kern_table[] = {
136    {
137        .procname = "shmmax",
138        .data = &init_ipc_ns.shm_ctlmax,
139        .maxlen = sizeof (init_ipc_ns.shm_ctlmax),
140        .mode = 0644,
141        .proc_handler = proc_ipc_doulongvec_minmax,
142    },
143    {
144        .procname = "shmall",
145        .data = &init_ipc_ns.shm_ctlall,
146        .maxlen = sizeof (init_ipc_ns.shm_ctlall),
147        .mode = 0644,
148        .proc_handler = proc_ipc_doulongvec_minmax,
149    },
150    {
151        .procname = "shmmni",
152        .data = &init_ipc_ns.shm_ctlmni,
153        .maxlen = sizeof (init_ipc_ns.shm_ctlmni),
154        .mode = 0644,
155        .proc_handler = proc_ipc_dointvec,
156    },
157    {
158        .procname = "msgmax",
159        .data = &init_ipc_ns.msg_ctlmax,
160        .maxlen = sizeof (init_ipc_ns.msg_ctlmax),
161        .mode = 0644,
162        .proc_handler = proc_ipc_dointvec,
163    },
164    {
165        .procname = "msgmni",
166        .data = &init_ipc_ns.msg_ctlmni,
167        .maxlen = sizeof (init_ipc_ns.msg_ctlmni),
168        .mode = 0644,
169        .proc_handler = proc_ipc_callback_dointvec,
170    },
171    {
172        .procname = "msgmnb",
173        .data = &init_ipc_ns.msg_ctlmnb,
174        .maxlen = sizeof (init_ipc_ns.msg_ctlmnb),
175        .mode = 0644,
176        .proc_handler = proc_ipc_dointvec,
177    },
178    {
179        .procname = "sem",
180        .data = &init_ipc_ns.sem_ctls,
181        .maxlen = 4*sizeof (int),
182        .mode = 0644,
183        .proc_handler = proc_ipc_dointvec,
184    },
185    {
186        .procname = "auto_msgmni",
187        .data = &init_ipc_ns.auto_msgmni,
188        .maxlen = sizeof(int),
189        .mode = 0644,
190        .proc_handler = proc_ipcauto_dointvec_minmax,
191        .extra1 = &zero,
192        .extra2 = &one,
193    },
194    {}
195};
196
197static struct ctl_table ipc_root_table[] = {
198    {
199        .procname = "kernel",
200        .mode = 0555,
201        .child = ipc_kern_table,
202    },
203    {}
204};
205
206static int __init ipc_sysctl_init(void)
207{
208    register_sysctl_table(ipc_root_table);
209    return 0;
210}
211
212__initcall(ipc_sysctl_init);
213

Archive Download this file



interactive