diff options
author | Stanislav Kinsbursky <skinsbursky@parallels.com> | 2013-01-04 18:34:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-01-04 19:11:45 -0500 |
commit | 03f595668017f1a1fb971c02fc37140bc6e7bb1c (patch) | |
tree | 3aa5c4b32b5fd396f0d74679548de8c09ca195a1 | |
parent | 9afdacda0252fc1ddb7907728e878518edbcdfce (diff) |
ipc: add sysctl to specify desired next object id
Add 3 new variables and sysctls to tune them (by one "next_id" variable
for messages, semaphores and shared memory respectively). This variable
can be used to set desired id for next allocated IPC object. By default
it's equal to -1 and old behaviour is preserved. If this variable is
non-negative, then desired idr will be extracted from it and used as a
start value to search for free IDR slot.
Notes:
1) this patch doesn't guarantee that the new object will have desired
id. So it's up to user space how to handle new object with wrong id.
2) After a sucessful id allocation attempt, "next_id" will be set back
to -1 (if it was non-negative).
[akpm@linux-foundation.org: checkpatch fixes]
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
Cc: Serge Hallyn <serge.hallyn@canonical.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Pavel Emelyanov <xemul@parallels.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | Documentation/sysctl/kernel.txt | 19 | ||||
-rw-r--r-- | include/linux/ipc_namespace.h | 1 | ||||
-rw-r--r-- | ipc/ipc_sysctl.c | 32 | ||||
-rw-r--r-- | ipc/util.c | 16 | ||||
-rw-r--r-- | ipc/util.h | 1 |
5 files changed, 65 insertions, 4 deletions
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 2907ba6c3607..51b953a1b149 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt | |||
@@ -38,6 +38,7 @@ show up in /proc/sys/kernel: | |||
38 | - l2cr [ PPC only ] | 38 | - l2cr [ PPC only ] |
39 | - modprobe ==> Documentation/debugging-modules.txt | 39 | - modprobe ==> Documentation/debugging-modules.txt |
40 | - modules_disabled | 40 | - modules_disabled |
41 | - msg_next_id [ sysv ipc ] | ||
41 | - msgmax | 42 | - msgmax |
42 | - msgmnb | 43 | - msgmnb |
43 | - msgmni | 44 | - msgmni |
@@ -62,7 +63,9 @@ show up in /proc/sys/kernel: | |||
62 | - rtsig-max | 63 | - rtsig-max |
63 | - rtsig-nr | 64 | - rtsig-nr |
64 | - sem | 65 | - sem |
66 | - sem_next_id [ sysv ipc ] | ||
65 | - sg-big-buff [ generic SCSI device (sg) ] | 67 | - sg-big-buff [ generic SCSI device (sg) ] |
68 | - shm_next_id [ sysv ipc ] | ||
66 | - shm_rmid_forced | 69 | - shm_rmid_forced |
67 | - shmall | 70 | - shmall |
68 | - shmmax [ sysv ipc ] | 71 | - shmmax [ sysv ipc ] |
@@ -320,6 +323,22 @@ to false. | |||
320 | 323 | ||
321 | ============================================================== | 324 | ============================================================== |
322 | 325 | ||
326 | msg_next_id, sem_next_id, and shm_next_id: | ||
327 | |||
328 | These three toggles allows to specify desired id for next allocated IPC | ||
329 | object: message, semaphore or shared memory respectively. | ||
330 | |||
331 | By default they are equal to -1, which means generic allocation logic. | ||
332 | Possible values to set are in range {0..INT_MAX}. | ||
333 | |||
334 | Notes: | ||
335 | 1) kernel doesn't guarantee, that new object will have desired id. So, | ||
336 | it's up to userspace, how to handle an object with "wrong" id. | ||
337 | 2) Toggle with non-default value will be set back to -1 by kernel after | ||
338 | successful IPC object allocation. | ||
339 | |||
340 | ============================================================== | ||
341 | |||
323 | nmi_watchdog: | 342 | nmi_watchdog: |
324 | 343 | ||
325 | Enables/Disables the NMI watchdog on x86 systems. When the value is | 344 | Enables/Disables the NMI watchdog on x86 systems. When the value is |
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h index fe771978e877..ae221a7b5092 100644 --- a/include/linux/ipc_namespace.h +++ b/include/linux/ipc_namespace.h | |||
@@ -24,6 +24,7 @@ struct ipc_ids { | |||
24 | unsigned short seq_max; | 24 | unsigned short seq_max; |
25 | struct rw_semaphore rw_mutex; | 25 | struct rw_semaphore rw_mutex; |
26 | struct idr ipcs_idr; | 26 | struct idr ipcs_idr; |
27 | int next_id; | ||
27 | }; | 28 | }; |
28 | 29 | ||
29 | struct ipc_namespace { | 30 | struct ipc_namespace { |
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index 00fba2bab87d..130dfece27ac 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c | |||
@@ -158,6 +158,9 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write, | |||
158 | 158 | ||
159 | static int zero; | 159 | static int zero; |
160 | static int one = 1; | 160 | static int one = 1; |
161 | #ifdef CONFIG_CHECKPOINT_RESTORE | ||
162 | static int int_max = INT_MAX; | ||
163 | #endif | ||
161 | 164 | ||
162 | static struct ctl_table ipc_kern_table[] = { | 165 | static struct ctl_table ipc_kern_table[] = { |
163 | { | 166 | { |
@@ -227,6 +230,35 @@ static struct ctl_table ipc_kern_table[] = { | |||
227 | .extra1 = &zero, | 230 | .extra1 = &zero, |
228 | .extra2 = &one, | 231 | .extra2 = &one, |
229 | }, | 232 | }, |
233 | #ifdef CONFIG_CHECKPOINT_RESTORE | ||
234 | { | ||
235 | .procname = "sem_next_id", | ||
236 | .data = &init_ipc_ns.ids[IPC_SEM_IDS].next_id, | ||
237 | .maxlen = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id), | ||
238 | .mode = 0644, | ||
239 | .proc_handler = proc_ipc_dointvec_minmax, | ||
240 | .extra1 = &zero, | ||
241 | .extra2 = &int_max, | ||
242 | }, | ||
243 | { | ||
244 | .procname = "msg_next_id", | ||
245 | .data = &init_ipc_ns.ids[IPC_MSG_IDS].next_id, | ||
246 | .maxlen = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id), | ||
247 | .mode = 0644, | ||
248 | .proc_handler = proc_ipc_dointvec_minmax, | ||
249 | .extra1 = &zero, | ||
250 | .extra2 = &int_max, | ||
251 | }, | ||
252 | { | ||
253 | .procname = "shm_next_id", | ||
254 | .data = &init_ipc_ns.ids[IPC_SHM_IDS].next_id, | ||
255 | .maxlen = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id), | ||
256 | .mode = 0644, | ||
257 | .proc_handler = proc_ipc_dointvec_minmax, | ||
258 | .extra1 = &zero, | ||
259 | .extra2 = &int_max, | ||
260 | }, | ||
261 | #endif | ||
230 | {} | 262 | {} |
231 | }; | 263 | }; |
232 | 264 | ||
diff --git a/ipc/util.c b/ipc/util.c index 72fd0785ac94..74e1d9c7a98a 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -122,6 +122,7 @@ void ipc_init_ids(struct ipc_ids *ids) | |||
122 | 122 | ||
123 | ids->in_use = 0; | 123 | ids->in_use = 0; |
124 | ids->seq = 0; | 124 | ids->seq = 0; |
125 | ids->next_id = -1; | ||
125 | { | 126 | { |
126 | int seq_limit = INT_MAX/SEQ_MULTIPLIER; | 127 | int seq_limit = INT_MAX/SEQ_MULTIPLIER; |
127 | if (seq_limit > USHRT_MAX) | 128 | if (seq_limit > USHRT_MAX) |
@@ -252,6 +253,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
252 | kuid_t euid; | 253 | kuid_t euid; |
253 | kgid_t egid; | 254 | kgid_t egid; |
254 | int id, err; | 255 | int id, err; |
256 | int next_id = ids->next_id; | ||
255 | 257 | ||
256 | if (size > IPCMNI) | 258 | if (size > IPCMNI) |
257 | size = IPCMNI; | 259 | size = IPCMNI; |
@@ -264,7 +266,8 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
264 | rcu_read_lock(); | 266 | rcu_read_lock(); |
265 | spin_lock(&new->lock); | 267 | spin_lock(&new->lock); |
266 | 268 | ||
267 | err = idr_get_new(&ids->ipcs_idr, new, &id); | 269 | err = idr_get_new_above(&ids->ipcs_idr, new, |
270 | (next_id < 0) ? 0 : ipcid_to_idx(next_id), &id); | ||
268 | if (err) { | 271 | if (err) { |
269 | spin_unlock(&new->lock); | 272 | spin_unlock(&new->lock); |
270 | rcu_read_unlock(); | 273 | rcu_read_unlock(); |
@@ -277,9 +280,14 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
277 | new->cuid = new->uid = euid; | 280 | new->cuid = new->uid = euid; |
278 | new->gid = new->cgid = egid; | 281 | new->gid = new->cgid = egid; |
279 | 282 | ||
280 | new->seq = ids->seq++; | 283 | if (next_id < 0) { |
281 | if(ids->seq > ids->seq_max) | 284 | new->seq = ids->seq++; |
282 | ids->seq = 0; | 285 | if (ids->seq > ids->seq_max) |
286 | ids->seq = 0; | ||
287 | } else { | ||
288 | new->seq = ipcid_to_seqx(next_id); | ||
289 | ids->next_id = -1; | ||
290 | } | ||
283 | 291 | ||
284 | new->id = ipc_buildid(id, new->seq); | 292 | new->id = ipc_buildid(id, new->seq); |
285 | return id; | 293 | return id; |
diff --git a/ipc/util.h b/ipc/util.h index c8fe2f7631e9..a61e0ca2bffd 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
@@ -92,6 +92,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header, | |||
92 | #define IPC_SHM_IDS 2 | 92 | #define IPC_SHM_IDS 2 |
93 | 93 | ||
94 | #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) | 94 | #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) |
95 | #define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER) | ||
95 | 96 | ||
96 | /* must be called with ids->rw_mutex acquired for writing */ | 97 | /* must be called with ids->rw_mutex acquired for writing */ |
97 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); | 98 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); |