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 /ipc | |
| 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>
Diffstat (limited to 'ipc')
| -rw-r--r-- | ipc/ipc_sysctl.c | 32 | ||||
| -rw-r--r-- | ipc/util.c | 16 | ||||
| -rw-r--r-- | ipc/util.h | 1 |
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 | ||
| 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); |
