forked from mirrors/linux
		
	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>
This commit is contained in:
		
							parent
							
								
									9afdacda02
								
							
						
					
					
						commit
						03f5956680
					
				
					 5 changed files with 65 additions and 4 deletions
				
			
		|  | @ -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: | ||||||
| - 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. | ||||||
| 
 | 
 | ||||||
| ============================================================== | ============================================================== | ||||||
| 
 | 
 | ||||||
|  | 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 { | ||||||
| 	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, | ||||||
| 
 | 
 | ||||||
| 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[] = { | ||||||
| 		.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 | ||||||
| 	{} | 	{} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								ipc/util.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								ipc/util.c
									
									
									
									
									
								
							|  | @ -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) | ||||||
| 	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) | ||||||
| 	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) | ||||||
| 	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, | ||||||
| #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); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Stanislav Kinsbursky
						Stanislav Kinsbursky