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