Commit 03f59566 authored by Stanislav Kinsbursky's avatar Stanislav Kinsbursky Committed by Linus Torvalds

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: default avatarStanislav 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 9afdacda
...@@ -38,6 +38,7 @@ show up in /proc/sys/kernel: ...@@ -38,6 +38,7 @@ show up in /proc/sys/kernel:
- l2cr [ PPC only ] - l2cr [ PPC only ]
- modprobe ==> Documentation/debugging-modules.txt - modprobe ==> Documentation/debugging-modules.txt
- modules_disabled - modules_disabled
- msg_next_id [ sysv ipc ]
- msgmax - msgmax
- msgmnb - msgmnb
- msgmni - msgmni
...@@ -62,7 +63,9 @@ show up in /proc/sys/kernel: ...@@ -62,7 +63,9 @@ show up in /proc/sys/kernel:
- rtsig-max - rtsig-max
- rtsig-nr - rtsig-nr
- sem - sem
- sem_next_id [ sysv ipc ]
- sg-big-buff [ generic SCSI device (sg) ] - sg-big-buff [ generic SCSI device (sg) ]
- shm_next_id [ sysv ipc ]
- shm_rmid_forced - shm_rmid_forced
- shmall - shmall
- shmmax [ sysv ipc ] - shmmax [ sysv ipc ]
...@@ -320,6 +323,22 @@ to false. ...@@ -320,6 +323,22 @@ to false.
============================================================== ==============================================================
msg_next_id, sem_next_id, and shm_next_id:
These three toggles allows to specify desired id for next allocated IPC
object: message, semaphore or shared memory respectively.
By default they are equal to -1, which means generic allocation logic.
Possible values to set are in range {0..INT_MAX}.
Notes:
1) kernel doesn't guarantee, that new object will have desired id. So,
it's up to userspace, how to handle an object with "wrong" id.
2) Toggle with non-default value will be set back to -1 by kernel after
successful IPC object allocation.
==============================================================
nmi_watchdog: nmi_watchdog:
Enables/Disables the NMI watchdog on x86 systems. When the value is Enables/Disables the NMI watchdog on x86 systems. When the value is
......
...@@ -24,6 +24,7 @@ struct ipc_ids { ...@@ -24,6 +24,7 @@ struct ipc_ids {
unsigned short seq_max; unsigned short seq_max;
struct rw_semaphore rw_mutex; struct rw_semaphore rw_mutex;
struct idr ipcs_idr; struct idr ipcs_idr;
int next_id;
}; };
struct ipc_namespace { struct ipc_namespace {
......
...@@ -158,6 +158,9 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write, ...@@ -158,6 +158,9 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
static int zero; static int zero;
static int one = 1; static int one = 1;
#ifdef CONFIG_CHECKPOINT_RESTORE
static int int_max = INT_MAX;
#endif
static struct ctl_table ipc_kern_table[] = { static struct ctl_table ipc_kern_table[] = {
{ {
...@@ -227,6 +230,35 @@ static struct ctl_table ipc_kern_table[] = { ...@@ -227,6 +230,35 @@ static struct ctl_table ipc_kern_table[] = {
.extra1 = &zero, .extra1 = &zero,
.extra2 = &one, .extra2 = &one,
}, },
#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
{} {}
}; };
......
...@@ -122,6 +122,7 @@ void ipc_init_ids(struct ipc_ids *ids) ...@@ -122,6 +122,7 @@ void ipc_init_ids(struct ipc_ids *ids)
ids->in_use = 0; ids->in_use = 0;
ids->seq = 0; ids->seq = 0;
ids->next_id = -1;
{ {
int seq_limit = INT_MAX/SEQ_MULTIPLIER; int seq_limit = INT_MAX/SEQ_MULTIPLIER;
if (seq_limit > USHRT_MAX) if (seq_limit > USHRT_MAX)
...@@ -252,6 +253,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) ...@@ -252,6 +253,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
kuid_t euid; kuid_t euid;
kgid_t egid; kgid_t egid;
int id, err; int id, err;
int next_id = ids->next_id;
if (size > IPCMNI) if (size > IPCMNI)
size = IPCMNI; size = IPCMNI;
...@@ -264,7 +266,8 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) ...@@ -264,7 +266,8 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
rcu_read_lock(); rcu_read_lock();
spin_lock(&new->lock); spin_lock(&new->lock);
err = idr_get_new(&ids->ipcs_idr, new, &id); err = idr_get_new_above(&ids->ipcs_idr, new,
(next_id < 0) ? 0 : ipcid_to_idx(next_id), &id);
if (err) { if (err) {
spin_unlock(&new->lock); spin_unlock(&new->lock);
rcu_read_unlock(); rcu_read_unlock();
...@@ -277,9 +280,14 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) ...@@ -277,9 +280,14 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
new->cuid = new->uid = euid; new->cuid = new->uid = euid;
new->gid = new->cgid = egid; new->gid = new->cgid = egid;
if (next_id < 0) {
new->seq = ids->seq++; new->seq = ids->seq++;
if(ids->seq > ids->seq_max) if (ids->seq > ids->seq_max)
ids->seq = 0; ids->seq = 0;
} else {
new->seq = ipcid_to_seqx(next_id);
ids->next_id = -1;
}
new->id = ipc_buildid(id, new->seq); new->id = ipc_buildid(id, new->seq);
return id; return id;
......
...@@ -92,6 +92,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header, ...@@ -92,6 +92,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
#define IPC_SHM_IDS 2 #define IPC_SHM_IDS 2
#define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER) #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER)
#define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER)
/* must be called with ids->rw_mutex acquired for writing */ /* must be called with ids->rw_mutex acquired for writing */
int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment