aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorStanislav Kinsbursky <skinsbursky@parallels.com>2013-01-04 18:34:50 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-01-04 19:11:45 -0500
commit03f595668017f1a1fb971c02fc37140bc6e7bb1c (patch)
tree3aa5c4b32b5fd396f0d74679548de8c09ca195a1 /ipc
parent9afdacda0252fc1ddb7907728e878518edbcdfce (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>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/ipc_sysctl.c32
-rw-r--r--ipc/util.c16
-rw-r--r--ipc/util.h1
3 files changed, 45 insertions, 4 deletions
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
159static int zero; 159static int zero;
160static int one = 1; 160static int one = 1;
161#ifdef CONFIG_CHECKPOINT_RESTORE
162static int int_max = INT_MAX;
163#endif
161 164
162static struct ctl_table ipc_kern_table[] = { 165static 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 */
97int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); 98int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);