aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/ipc_sysctl.c72
-rw-r--r--ipc/ipcns_notifier.c20
-rw-r--r--ipc/mqueue.c31
-rw-r--r--ipc/sem.c316
-rw-r--r--ipc/shm.c24
-rw-r--r--ipc/util.c61
-rw-r--r--ipc/util.h6
7 files changed, 263 insertions, 267 deletions
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index d3497465cc0a..69bc85978ba0 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -27,15 +27,17 @@ static void *get_ipc(ctl_table *table)
27} 27}
28 28
29/* 29/*
30 * Routine that is called when a tunable has successfully been changed by 30 * Routine that is called when the file "auto_msgmni" has successfully been
31 * hand and it has a callback routine registered on the ipc namespace notifier 31 * written.
32 * chain: we don't want such tunables to be recomputed anymore upon memory 32 * Two values are allowed:
33 * add/remove or ipc namespace creation/removal. 33 * 0: unregister msgmni's callback routine from the ipc namespace notifier
34 * They can come back to a recomputable state by being set to a <0 value. 34 * chain. This means that msgmni won't be recomputed anymore upon memory
35 * add/remove or ipc namespace creation/removal.
36 * 1: register back the callback routine.
35 */ 37 */
36static void tunable_set_callback(int val) 38static void ipc_auto_callback(int val)
37{ 39{
38 if (val >= 0) 40 if (!val)
39 unregister_ipcns_notifier(current->nsproxy->ipc_ns); 41 unregister_ipcns_notifier(current->nsproxy->ipc_ns);
40 else { 42 else {
41 /* 43 /*
@@ -71,7 +73,12 @@ static int proc_ipc_callback_dointvec(ctl_table *table, int write,
71 rc = proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos); 73 rc = proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos);
72 74
73 if (write && !rc && lenp_bef == *lenp) 75 if (write && !rc && lenp_bef == *lenp)
74 tunable_set_callback(*((int *)(ipc_table.data))); 76 /*
77 * Tunable has successfully been changed by hand. Disable its
78 * automatic adjustment. This simply requires unregistering
79 * the notifiers that trigger recalculation.
80 */
81 unregister_ipcns_notifier(current->nsproxy->ipc_ns);
75 82
76 return rc; 83 return rc;
77} 84}
@@ -87,10 +94,39 @@ static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
87 lenp, ppos); 94 lenp, ppos);
88} 95}
89 96
97static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
98 struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos)
99{
100 struct ctl_table ipc_table;
101 size_t lenp_bef = *lenp;
102 int oldval;
103 int rc;
104
105 memcpy(&ipc_table, table, sizeof(ipc_table));
106 ipc_table.data = get_ipc(table);
107 oldval = *((int *)(ipc_table.data));
108
109 rc = proc_dointvec_minmax(&ipc_table, write, filp, buffer, lenp, ppos);
110
111 if (write && !rc && lenp_bef == *lenp) {
112 int newval = *((int *)(ipc_table.data));
113 /*
114 * The file "auto_msgmni" has correctly been set.
115 * React by (un)registering the corresponding tunable, if the
116 * value has changed.
117 */
118 if (newval != oldval)
119 ipc_auto_callback(newval);
120 }
121
122 return rc;
123}
124
90#else 125#else
91#define proc_ipc_doulongvec_minmax NULL 126#define proc_ipc_doulongvec_minmax NULL
92#define proc_ipc_dointvec NULL 127#define proc_ipc_dointvec NULL
93#define proc_ipc_callback_dointvec NULL 128#define proc_ipc_callback_dointvec NULL
129#define proc_ipcauto_dointvec_minmax NULL
94#endif 130#endif
95 131
96#ifdef CONFIG_SYSCTL_SYSCALL 132#ifdef CONFIG_SYSCTL_SYSCALL
@@ -142,14 +178,11 @@ static int sysctl_ipc_registered_data(ctl_table *table, int __user *name,
142 rc = sysctl_ipc_data(table, name, nlen, oldval, oldlenp, newval, 178 rc = sysctl_ipc_data(table, name, nlen, oldval, oldlenp, newval,
143 newlen); 179 newlen);
144 180
145 if (newval && newlen && rc > 0) { 181 if (newval && newlen && rc > 0)
146 /* 182 /*
147 * Tunable has successfully been changed from userland 183 * Tunable has successfully been changed from userland
148 */ 184 */
149 int *data = get_ipc(table); 185 unregister_ipcns_notifier(current->nsproxy->ipc_ns);
150
151 tunable_set_callback(*data);
152 }
153 186
154 return rc; 187 return rc;
155} 188}
@@ -158,6 +191,9 @@ static int sysctl_ipc_registered_data(ctl_table *table, int __user *name,
158#define sysctl_ipc_registered_data NULL 191#define sysctl_ipc_registered_data NULL
159#endif 192#endif
160 193
194static int zero;
195static int one = 1;
196
161static struct ctl_table ipc_kern_table[] = { 197static struct ctl_table ipc_kern_table[] = {
162 { 198 {
163 .ctl_name = KERN_SHMMAX, 199 .ctl_name = KERN_SHMMAX,
@@ -222,6 +258,16 @@ static struct ctl_table ipc_kern_table[] = {
222 .proc_handler = proc_ipc_dointvec, 258 .proc_handler = proc_ipc_dointvec,
223 .strategy = sysctl_ipc_data, 259 .strategy = sysctl_ipc_data,
224 }, 260 },
261 {
262 .ctl_name = CTL_UNNUMBERED,
263 .procname = "auto_msgmni",
264 .data = &init_ipc_ns.auto_msgmni,
265 .maxlen = sizeof(int),
266 .mode = 0644,
267 .proc_handler = proc_ipcauto_dointvec_minmax,
268 .extra1 = &zero,
269 .extra2 = &one,
270 },
225 {} 271 {}
226}; 272};
227 273
diff --git a/ipc/ipcns_notifier.c b/ipc/ipcns_notifier.c
index 70ff09183f7b..b9b31a4f77e1 100644
--- a/ipc/ipcns_notifier.c
+++ b/ipc/ipcns_notifier.c
@@ -55,25 +55,35 @@ static int ipcns_callback(struct notifier_block *self,
55 55
56int register_ipcns_notifier(struct ipc_namespace *ns) 56int register_ipcns_notifier(struct ipc_namespace *ns)
57{ 57{
58 int rc;
59
58 memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb)); 60 memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
59 ns->ipcns_nb.notifier_call = ipcns_callback; 61 ns->ipcns_nb.notifier_call = ipcns_callback;
60 ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI; 62 ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
61 return blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb); 63 rc = blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb);
64 if (!rc)
65 ns->auto_msgmni = 1;
66 return rc;
62} 67}
63 68
64int cond_register_ipcns_notifier(struct ipc_namespace *ns) 69int cond_register_ipcns_notifier(struct ipc_namespace *ns)
65{ 70{
71 int rc;
72
66 memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb)); 73 memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
67 ns->ipcns_nb.notifier_call = ipcns_callback; 74 ns->ipcns_nb.notifier_call = ipcns_callback;
68 ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI; 75 ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
69 return blocking_notifier_chain_cond_register(&ipcns_chain, 76 rc = blocking_notifier_chain_cond_register(&ipcns_chain,
70 &ns->ipcns_nb); 77 &ns->ipcns_nb);
78 if (!rc)
79 ns->auto_msgmni = 1;
80 return rc;
71} 81}
72 82
73int unregister_ipcns_notifier(struct ipc_namespace *ns) 83void unregister_ipcns_notifier(struct ipc_namespace *ns)
74{ 84{
75 return blocking_notifier_chain_unregister(&ipcns_chain, 85 blocking_notifier_chain_unregister(&ipcns_chain, &ns->ipcns_nb);
76 &ns->ipcns_nb); 86 ns->auto_msgmni = 0;
77} 87}
78 88
79int ipcns_notify(unsigned long val) 89int ipcns_notify(unsigned long val)
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index b3b69fd51330..96fb36cd9874 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -207,7 +207,7 @@ static int mqueue_get_sb(struct file_system_type *fs_type,
207 return get_sb_single(fs_type, flags, data, mqueue_fill_super, mnt); 207 return get_sb_single(fs_type, flags, data, mqueue_fill_super, mnt);
208} 208}
209 209
210static void init_once(struct kmem_cache *cachep, void *foo) 210static void init_once(void *foo)
211{ 211{
212 struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo; 212 struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo;
213 213
@@ -314,15 +314,11 @@ static int mqueue_unlink(struct inode *dir, struct dentry *dentry)
314* through std routines) 314* through std routines)
315*/ 315*/
316static ssize_t mqueue_read_file(struct file *filp, char __user *u_data, 316static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
317 size_t count, loff_t * off) 317 size_t count, loff_t *off)
318{ 318{
319 struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode); 319 struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
320 char buffer[FILENT_SIZE]; 320 char buffer[FILENT_SIZE];
321 size_t slen; 321 ssize_t ret;
322 loff_t o;
323
324 if (!count)
325 return 0;
326 322
327 spin_lock(&info->lock); 323 spin_lock(&info->lock);
328 snprintf(buffer, sizeof(buffer), 324 snprintf(buffer, sizeof(buffer),
@@ -335,21 +331,14 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
335 pid_vnr(info->notify_owner)); 331 pid_vnr(info->notify_owner));
336 spin_unlock(&info->lock); 332 spin_unlock(&info->lock);
337 buffer[sizeof(buffer)-1] = '\0'; 333 buffer[sizeof(buffer)-1] = '\0';
338 slen = strlen(buffer)+1;
339
340 o = *off;
341 if (o > slen)
342 return 0;
343
344 if (o + count > slen)
345 count = slen - o;
346 334
347 if (copy_to_user(u_data, buffer + o, count)) 335 ret = simple_read_from_buffer(u_data, count, off, buffer,
348 return -EFAULT; 336 strlen(buffer));
337 if (ret <= 0)
338 return ret;
349 339
350 *off = o + count;
351 filp->f_path.dentry->d_inode->i_atime = filp->f_path.dentry->d_inode->i_ctime = CURRENT_TIME; 340 filp->f_path.dentry->d_inode->i_atime = filp->f_path.dentry->d_inode->i_ctime = CURRENT_TIME;
352 return count; 341 return ret;
353} 342}
354 343
355static int mqueue_flush_file(struct file *filp, fl_owner_t id) 344static int mqueue_flush_file(struct file *filp, fl_owner_t id)
@@ -649,7 +638,7 @@ static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
649 return ERR_PTR(-EINVAL); 638 return ERR_PTR(-EINVAL);
650 } 639 }
651 640
652 if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) { 641 if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) {
653 dput(dentry); 642 dput(dentry);
654 mntput(mqueue_mnt); 643 mntput(mqueue_mnt);
655 return ERR_PTR(-EACCES); 644 return ERR_PTR(-EACCES);
@@ -1054,7 +1043,7 @@ retry:
1054 } 1043 }
1055 1044
1056 timeo = MAX_SCHEDULE_TIMEOUT; 1045 timeo = MAX_SCHEDULE_TIMEOUT;
1057 ret = netlink_attachskb(sock, nc, 0, &timeo, NULL); 1046 ret = netlink_attachskb(sock, nc, &timeo, NULL);
1058 if (ret == 1) 1047 if (ret == 1)
1059 goto retry; 1048 goto retry;
1060 if (ret) { 1049 if (ret) {
diff --git a/ipc/sem.c b/ipc/sem.c
index e9418df5ff3e..bf1bc36cb7ee 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -272,9 +272,8 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
272 ns->used_sems += nsems; 272 ns->used_sems += nsems;
273 273
274 sma->sem_base = (struct sem *) &sma[1]; 274 sma->sem_base = (struct sem *) &sma[1];
275 /* sma->sem_pending = NULL; */ 275 INIT_LIST_HEAD(&sma->sem_pending);
276 sma->sem_pending_last = &sma->sem_pending; 276 INIT_LIST_HEAD(&sma->list_id);
277 /* sma->undo = NULL; */
278 sma->sem_nsems = nsems; 277 sma->sem_nsems = nsems;
279 sma->sem_ctime = get_seconds(); 278 sma->sem_ctime = get_seconds();
280 sem_unlock(sma); 279 sem_unlock(sma);
@@ -331,38 +330,6 @@ asmlinkage long sys_semget(key_t key, int nsems, int semflg)
331 return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); 330 return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
332} 331}
333 332
334/* Manage the doubly linked list sma->sem_pending as a FIFO:
335 * insert new queue elements at the tail sma->sem_pending_last.
336 */
337static inline void append_to_queue (struct sem_array * sma,
338 struct sem_queue * q)
339{
340 *(q->prev = sma->sem_pending_last) = q;
341 *(sma->sem_pending_last = &q->next) = NULL;
342}
343
344static inline void prepend_to_queue (struct sem_array * sma,
345 struct sem_queue * q)
346{
347 q->next = sma->sem_pending;
348 *(q->prev = &sma->sem_pending) = q;
349 if (q->next)
350 q->next->prev = &q->next;
351 else /* sma->sem_pending_last == &sma->sem_pending */
352 sma->sem_pending_last = &q->next;
353}
354
355static inline void remove_from_queue (struct sem_array * sma,
356 struct sem_queue * q)
357{
358 *(q->prev) = q->next;
359 if (q->next)
360 q->next->prev = q->prev;
361 else /* sma->sem_pending_last == &q->next */
362 sma->sem_pending_last = q->prev;
363 q->prev = NULL; /* mark as removed */
364}
365
366/* 333/*
367 * Determine whether a sequence of semaphore operations would succeed 334 * Determine whether a sequence of semaphore operations would succeed
368 * all at once. Return 0 if yes, 1 if need to sleep, else return error code. 335 * all at once. Return 0 if yes, 1 if need to sleep, else return error code.
@@ -438,16 +405,15 @@ static void update_queue (struct sem_array * sma)
438 int error; 405 int error;
439 struct sem_queue * q; 406 struct sem_queue * q;
440 407
441 q = sma->sem_pending; 408 q = list_entry(sma->sem_pending.next, struct sem_queue, list);
442 while(q) { 409 while (&q->list != &sma->sem_pending) {
443 error = try_atomic_semop(sma, q->sops, q->nsops, 410 error = try_atomic_semop(sma, q->sops, q->nsops,
444 q->undo, q->pid); 411 q->undo, q->pid);
445 412
446 /* Does q->sleeper still need to sleep? */ 413 /* Does q->sleeper still need to sleep? */
447 if (error <= 0) { 414 if (error <= 0) {
448 struct sem_queue *n; 415 struct sem_queue *n;
449 remove_from_queue(sma,q); 416
450 q->status = IN_WAKEUP;
451 /* 417 /*
452 * Continue scanning. The next operation 418 * Continue scanning. The next operation
453 * that must be checked depends on the type of the 419 * that must be checked depends on the type of the
@@ -458,11 +424,26 @@ static void update_queue (struct sem_array * sma)
458 * for semaphore values to become 0. 424 * for semaphore values to become 0.
459 * - if the operation didn't modify the array, 425 * - if the operation didn't modify the array,
460 * then just continue. 426 * then just continue.
427 * The order of list_del() and reading ->next
428 * is crucial: In the former case, the list_del()
429 * must be done first [because we might be the
430 * first entry in ->sem_pending], in the latter
431 * case the list_del() must be done last
432 * [because the list is invalid after the list_del()]
461 */ 433 */
462 if (q->alter) 434 if (q->alter) {
463 n = sma->sem_pending; 435 list_del(&q->list);
464 else 436 n = list_entry(sma->sem_pending.next,
465 n = q->next; 437 struct sem_queue, list);
438 } else {
439 n = list_entry(q->list.next, struct sem_queue,
440 list);
441 list_del(&q->list);
442 }
443
444 /* wake up the waiting thread */
445 q->status = IN_WAKEUP;
446
466 wake_up_process(q->sleeper); 447 wake_up_process(q->sleeper);
467 /* hands-off: q will disappear immediately after 448 /* hands-off: q will disappear immediately after
468 * writing q->status. 449 * writing q->status.
@@ -471,7 +452,7 @@ static void update_queue (struct sem_array * sma)
471 q->status = error; 452 q->status = error;
472 q = n; 453 q = n;
473 } else { 454 } else {
474 q = q->next; 455 q = list_entry(q->list.next, struct sem_queue, list);
475 } 456 }
476 } 457 }
477} 458}
@@ -491,7 +472,7 @@ static int count_semncnt (struct sem_array * sma, ushort semnum)
491 struct sem_queue * q; 472 struct sem_queue * q;
492 473
493 semncnt = 0; 474 semncnt = 0;
494 for (q = sma->sem_pending; q; q = q->next) { 475 list_for_each_entry(q, &sma->sem_pending, list) {
495 struct sembuf * sops = q->sops; 476 struct sembuf * sops = q->sops;
496 int nsops = q->nsops; 477 int nsops = q->nsops;
497 int i; 478 int i;
@@ -503,13 +484,14 @@ static int count_semncnt (struct sem_array * sma, ushort semnum)
503 } 484 }
504 return semncnt; 485 return semncnt;
505} 486}
487
506static int count_semzcnt (struct sem_array * sma, ushort semnum) 488static int count_semzcnt (struct sem_array * sma, ushort semnum)
507{ 489{
508 int semzcnt; 490 int semzcnt;
509 struct sem_queue * q; 491 struct sem_queue * q;
510 492
511 semzcnt = 0; 493 semzcnt = 0;
512 for (q = sma->sem_pending; q; q = q->next) { 494 list_for_each_entry(q, &sma->sem_pending, list) {
513 struct sembuf * sops = q->sops; 495 struct sembuf * sops = q->sops;
514 int nsops = q->nsops; 496 int nsops = q->nsops;
515 int i; 497 int i;
@@ -522,35 +504,41 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
522 return semzcnt; 504 return semzcnt;
523} 505}
524 506
507void free_un(struct rcu_head *head)
508{
509 struct sem_undo *un = container_of(head, struct sem_undo, rcu);
510 kfree(un);
511}
512
525/* Free a semaphore set. freeary() is called with sem_ids.rw_mutex locked 513/* Free a semaphore set. freeary() is called with sem_ids.rw_mutex locked
526 * as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex 514 * as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex
527 * remains locked on exit. 515 * remains locked on exit.
528 */ 516 */
529static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) 517static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
530{ 518{
531 struct sem_undo *un; 519 struct sem_undo *un, *tu;
532 struct sem_queue *q; 520 struct sem_queue *q, *tq;
533 struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm); 521 struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
534 522
535 /* Invalidate the existing undo structures for this semaphore set. 523 /* Free the existing undo structures for this semaphore set. */
536 * (They will be freed without any further action in exit_sem() 524 assert_spin_locked(&sma->sem_perm.lock);
537 * or during the next semop.) 525 list_for_each_entry_safe(un, tu, &sma->list_id, list_id) {
538 */ 526 list_del(&un->list_id);
539 for (un = sma->undo; un; un = un->id_next) 527 spin_lock(&un->ulp->lock);
540 un->semid = -1; 528 un->semid = -1;
529 list_del_rcu(&un->list_proc);
530 spin_unlock(&un->ulp->lock);
531 call_rcu(&un->rcu, free_un);
532 }
541 533
542 /* Wake up all pending processes and let them fail with EIDRM. */ 534 /* Wake up all pending processes and let them fail with EIDRM. */
543 q = sma->sem_pending; 535 list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
544 while(q) { 536 list_del(&q->list);
545 struct sem_queue *n; 537
546 /* lazy remove_from_queue: we are killing the whole queue */
547 q->prev = NULL;
548 n = q->next;
549 q->status = IN_WAKEUP; 538 q->status = IN_WAKEUP;
550 wake_up_process(q->sleeper); /* doesn't sleep */ 539 wake_up_process(q->sleeper); /* doesn't sleep */
551 smp_wmb(); 540 smp_wmb();
552 q->status = -EIDRM; /* hands-off q */ 541 q->status = -EIDRM; /* hands-off q */
553 q = n;
554 } 542 }
555 543
556 /* Remove the semaphore set from the IDR */ 544 /* Remove the semaphore set from the IDR */
@@ -763,9 +751,12 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
763 751
764 for (i = 0; i < nsems; i++) 752 for (i = 0; i < nsems; i++)
765 sma->sem_base[i].semval = sem_io[i]; 753 sma->sem_base[i].semval = sem_io[i];
766 for (un = sma->undo; un; un = un->id_next) 754
755 assert_spin_locked(&sma->sem_perm.lock);
756 list_for_each_entry(un, &sma->list_id, list_id) {
767 for (i = 0; i < nsems; i++) 757 for (i = 0; i < nsems; i++)
768 un->semadj[i] = 0; 758 un->semadj[i] = 0;
759 }
769 sma->sem_ctime = get_seconds(); 760 sma->sem_ctime = get_seconds();
770 /* maybe some queued-up processes were waiting for this */ 761 /* maybe some queued-up processes were waiting for this */
771 update_queue(sma); 762 update_queue(sma);
@@ -797,12 +788,15 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
797 { 788 {
798 int val = arg.val; 789 int val = arg.val;
799 struct sem_undo *un; 790 struct sem_undo *un;
791
800 err = -ERANGE; 792 err = -ERANGE;
801 if (val > SEMVMX || val < 0) 793 if (val > SEMVMX || val < 0)
802 goto out_unlock; 794 goto out_unlock;
803 795
804 for (un = sma->undo; un; un = un->id_next) 796 assert_spin_locked(&sma->sem_perm.lock);
797 list_for_each_entry(un, &sma->list_id, list_id)
805 un->semadj[semnum] = 0; 798 un->semadj[semnum] = 0;
799
806 curr->semval = val; 800 curr->semval = val;
807 curr->sempid = task_tgid_vnr(current); 801 curr->sempid = task_tgid_vnr(current);
808 sma->sem_ctime = get_seconds(); 802 sma->sem_ctime = get_seconds();
@@ -952,6 +946,8 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp)
952 return -ENOMEM; 946 return -ENOMEM;
953 spin_lock_init(&undo_list->lock); 947 spin_lock_init(&undo_list->lock);
954 atomic_set(&undo_list->refcnt, 1); 948 atomic_set(&undo_list->refcnt, 1);
949 INIT_LIST_HEAD(&undo_list->list_proc);
950
955 current->sysvsem.undo_list = undo_list; 951 current->sysvsem.undo_list = undo_list;
956 } 952 }
957 *undo_listp = undo_list; 953 *undo_listp = undo_list;
@@ -960,25 +956,27 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp)
960 956
961static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) 957static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid)
962{ 958{
963 struct sem_undo **last, *un; 959 struct sem_undo *walk;
964 960
965 last = &ulp->proc_list; 961 list_for_each_entry_rcu(walk, &ulp->list_proc, list_proc) {
966 un = *last; 962 if (walk->semid == semid)
967 while(un != NULL) { 963 return walk;
968 if(un->semid==semid)
969 break;
970 if(un->semid==-1) {
971 *last=un->proc_next;
972 kfree(un);
973 } else {
974 last=&un->proc_next;
975 }
976 un=*last;
977 } 964 }
978 return un; 965 return NULL;
979} 966}
980 967
981static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid) 968/**
969 * find_alloc_undo - Lookup (and if not present create) undo array
970 * @ns: namespace
971 * @semid: semaphore array id
972 *
973 * The function looks up (and if not present creates) the undo structure.
974 * The size of the undo structure depends on the size of the semaphore
975 * array, thus the alloc path is not that straightforward.
976 * Lifetime-rules: sem_undo is rcu-protected, on success, the function
977 * performs a rcu_read_lock().
978 */
979static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
982{ 980{
983 struct sem_array *sma; 981 struct sem_array *sma;
984 struct sem_undo_list *ulp; 982 struct sem_undo_list *ulp;
@@ -990,13 +988,16 @@ static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid)
990 if (error) 988 if (error)
991 return ERR_PTR(error); 989 return ERR_PTR(error);
992 990
991 rcu_read_lock();
993 spin_lock(&ulp->lock); 992 spin_lock(&ulp->lock);
994 un = lookup_undo(ulp, semid); 993 un = lookup_undo(ulp, semid);
995 spin_unlock(&ulp->lock); 994 spin_unlock(&ulp->lock);
996 if (likely(un!=NULL)) 995 if (likely(un!=NULL))
997 goto out; 996 goto out;
997 rcu_read_unlock();
998 998
999 /* no undo structure around - allocate one. */ 999 /* no undo structure around - allocate one. */
1000 /* step 1: figure out the size of the semaphore array */
1000 sma = sem_lock_check(ns, semid); 1001 sma = sem_lock_check(ns, semid);
1001 if (IS_ERR(sma)) 1002 if (IS_ERR(sma))
1002 return ERR_PTR(PTR_ERR(sma)); 1003 return ERR_PTR(PTR_ERR(sma));
@@ -1004,37 +1005,45 @@ static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid)
1004 nsems = sma->sem_nsems; 1005 nsems = sma->sem_nsems;
1005 sem_getref_and_unlock(sma); 1006 sem_getref_and_unlock(sma);
1006 1007
1008 /* step 2: allocate new undo structure */
1007 new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); 1009 new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
1008 if (!new) { 1010 if (!new) {
1009 sem_putref(sma); 1011 sem_putref(sma);
1010 return ERR_PTR(-ENOMEM); 1012 return ERR_PTR(-ENOMEM);
1011 } 1013 }
1012 new->semadj = (short *) &new[1];
1013 new->semid = semid;
1014 1014
1015 spin_lock(&ulp->lock); 1015 /* step 3: Acquire the lock on semaphore array */
1016 un = lookup_undo(ulp, semid);
1017 if (un) {
1018 spin_unlock(&ulp->lock);
1019 kfree(new);
1020 sem_putref(sma);
1021 goto out;
1022 }
1023 sem_lock_and_putref(sma); 1016 sem_lock_and_putref(sma);
1024 if (sma->sem_perm.deleted) { 1017 if (sma->sem_perm.deleted) {
1025 sem_unlock(sma); 1018 sem_unlock(sma);
1026 spin_unlock(&ulp->lock);
1027 kfree(new); 1019 kfree(new);
1028 un = ERR_PTR(-EIDRM); 1020 un = ERR_PTR(-EIDRM);
1029 goto out; 1021 goto out;
1030 } 1022 }
1031 new->proc_next = ulp->proc_list; 1023 spin_lock(&ulp->lock);
1032 ulp->proc_list = new; 1024
1033 new->id_next = sma->undo; 1025 /*
1034 sma->undo = new; 1026 * step 4: check for races: did someone else allocate the undo struct?
1035 sem_unlock(sma); 1027 */
1028 un = lookup_undo(ulp, semid);
1029 if (un) {
1030 kfree(new);
1031 goto success;
1032 }
1033 /* step 5: initialize & link new undo structure */
1034 new->semadj = (short *) &new[1];
1035 new->ulp = ulp;
1036 new->semid = semid;
1037 assert_spin_locked(&ulp->lock);
1038 list_add_rcu(&new->list_proc, &ulp->list_proc);
1039 assert_spin_locked(&sma->sem_perm.lock);
1040 list_add(&new->list_id, &sma->list_id);
1036 un = new; 1041 un = new;
1042
1043success:
1037 spin_unlock(&ulp->lock); 1044 spin_unlock(&ulp->lock);
1045 rcu_read_lock();
1046 sem_unlock(sma);
1038out: 1047out:
1039 return un; 1048 return un;
1040} 1049}
@@ -1090,9 +1099,8 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
1090 alter = 1; 1099 alter = 1;
1091 } 1100 }
1092 1101
1093retry_undos:
1094 if (undos) { 1102 if (undos) {
1095 un = find_undo(ns, semid); 1103 un = find_alloc_undo(ns, semid);
1096 if (IS_ERR(un)) { 1104 if (IS_ERR(un)) {
1097 error = PTR_ERR(un); 1105 error = PTR_ERR(un);
1098 goto out_free; 1106 goto out_free;
@@ -1102,19 +1110,37 @@ retry_undos:
1102 1110
1103 sma = sem_lock_check(ns, semid); 1111 sma = sem_lock_check(ns, semid);
1104 if (IS_ERR(sma)) { 1112 if (IS_ERR(sma)) {
1113 if (un)
1114 rcu_read_unlock();
1105 error = PTR_ERR(sma); 1115 error = PTR_ERR(sma);
1106 goto out_free; 1116 goto out_free;
1107 } 1117 }
1108 1118
1109 /* 1119 /*
1110 * semid identifiers are not unique - find_undo may have 1120 * semid identifiers are not unique - find_alloc_undo may have
1111 * allocated an undo structure, it was invalidated by an RMID 1121 * allocated an undo structure, it was invalidated by an RMID
1112 * and now a new array with received the same id. Check and retry. 1122 * and now a new array with received the same id. Check and fail.
1123 * This case can be detected checking un->semid. The existance of
1124 * "un" itself is guaranteed by rcu.
1113 */ 1125 */
1114 if (un && un->semid == -1) { 1126 error = -EIDRM;
1115 sem_unlock(sma); 1127 if (un) {
1116 goto retry_undos; 1128 if (un->semid == -1) {
1129 rcu_read_unlock();
1130 goto out_unlock_free;
1131 } else {
1132 /*
1133 * rcu lock can be released, "un" cannot disappear:
1134 * - sem_lock is acquired, thus IPC_RMID is
1135 * impossible.
1136 * - exit_sem is impossible, it always operates on
1137 * current (or a dead task).
1138 */
1139
1140 rcu_read_unlock();
1141 }
1117 } 1142 }
1143
1118 error = -EFBIG; 1144 error = -EFBIG;
1119 if (max >= sma->sem_nsems) 1145 if (max >= sma->sem_nsems)
1120 goto out_unlock_free; 1146 goto out_unlock_free;
@@ -1138,17 +1164,15 @@ retry_undos:
1138 * task into the pending queue and go to sleep. 1164 * task into the pending queue and go to sleep.
1139 */ 1165 */
1140 1166
1141 queue.sma = sma;
1142 queue.sops = sops; 1167 queue.sops = sops;
1143 queue.nsops = nsops; 1168 queue.nsops = nsops;
1144 queue.undo = un; 1169 queue.undo = un;
1145 queue.pid = task_tgid_vnr(current); 1170 queue.pid = task_tgid_vnr(current);
1146 queue.id = semid;
1147 queue.alter = alter; 1171 queue.alter = alter;
1148 if (alter) 1172 if (alter)
1149 append_to_queue(sma ,&queue); 1173 list_add_tail(&queue.list, &sma->sem_pending);
1150 else 1174 else
1151 prepend_to_queue(sma ,&queue); 1175 list_add(&queue.list, &sma->sem_pending);
1152 1176
1153 queue.status = -EINTR; 1177 queue.status = -EINTR;
1154 queue.sleeper = current; 1178 queue.sleeper = current;
@@ -1174,7 +1198,6 @@ retry_undos:
1174 1198
1175 sma = sem_lock(ns, semid); 1199 sma = sem_lock(ns, semid);
1176 if (IS_ERR(sma)) { 1200 if (IS_ERR(sma)) {
1177 BUG_ON(queue.prev != NULL);
1178 error = -EIDRM; 1201 error = -EIDRM;
1179 goto out_free; 1202 goto out_free;
1180 } 1203 }
@@ -1192,7 +1215,7 @@ retry_undos:
1192 */ 1215 */
1193 if (timeout && jiffies_left == 0) 1216 if (timeout && jiffies_left == 0)
1194 error = -EAGAIN; 1217 error = -EAGAIN;
1195 remove_from_queue(sma,&queue); 1218 list_del(&queue.list);
1196 goto out_unlock_free; 1219 goto out_unlock_free;
1197 1220
1198out_unlock_free: 1221out_unlock_free:
@@ -1243,56 +1266,62 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
1243 */ 1266 */
1244void exit_sem(struct task_struct *tsk) 1267void exit_sem(struct task_struct *tsk)
1245{ 1268{
1246 struct sem_undo_list *undo_list; 1269 struct sem_undo_list *ulp;
1247 struct sem_undo *u, **up;
1248 struct ipc_namespace *ns;
1249 1270
1250 undo_list = tsk->sysvsem.undo_list; 1271 ulp = tsk->sysvsem.undo_list;
1251 if (!undo_list) 1272 if (!ulp)
1252 return; 1273 return;
1253 tsk->sysvsem.undo_list = NULL; 1274 tsk->sysvsem.undo_list = NULL;
1254 1275
1255 if (!atomic_dec_and_test(&undo_list->refcnt)) 1276 if (!atomic_dec_and_test(&ulp->refcnt))
1256 return; 1277 return;
1257 1278
1258 ns = tsk->nsproxy->ipc_ns; 1279 for (;;) {
1259 /* There's no need to hold the semundo list lock, as current
1260 * is the last task exiting for this undo list.
1261 */
1262 for (up = &undo_list->proc_list; (u = *up); *up = u->proc_next, kfree(u)) {
1263 struct sem_array *sma; 1280 struct sem_array *sma;
1264 int nsems, i; 1281 struct sem_undo *un;
1265 struct sem_undo *un, **unp;
1266 int semid; 1282 int semid;
1267 1283 int i;
1268 semid = u->semid;
1269 1284
1270 if(semid == -1) 1285 rcu_read_lock();
1271 continue; 1286 un = list_entry(rcu_dereference(ulp->list_proc.next),
1272 sma = sem_lock(ns, semid); 1287 struct sem_undo, list_proc);
1288 if (&un->list_proc == &ulp->list_proc)
1289 semid = -1;
1290 else
1291 semid = un->semid;
1292 rcu_read_unlock();
1293
1294 if (semid == -1)
1295 break;
1296
1297 sma = sem_lock_check(tsk->nsproxy->ipc_ns, un->semid);
1298
1299 /* exit_sem raced with IPC_RMID, nothing to do */
1273 if (IS_ERR(sma)) 1300 if (IS_ERR(sma))
1274 continue; 1301 continue;
1275 1302
1276 if (u->semid == -1) 1303 un = lookup_undo(ulp, semid);
1277 goto next_entry; 1304 if (un == NULL) {
1305 /* exit_sem raced with IPC_RMID+semget() that created
1306 * exactly the same semid. Nothing to do.
1307 */
1308 sem_unlock(sma);
1309 continue;
1310 }
1278 1311
1279 BUG_ON(sem_checkid(sma, u->semid)); 1312 /* remove un from the linked lists */
1313 assert_spin_locked(&sma->sem_perm.lock);
1314 list_del(&un->list_id);
1280 1315
1281 /* remove u from the sma->undo list */ 1316 spin_lock(&ulp->lock);
1282 for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { 1317 list_del_rcu(&un->list_proc);
1283 if (u == un) 1318 spin_unlock(&ulp->lock);
1284 goto found; 1319
1285 } 1320 /* perform adjustments registered in un */
1286 printk ("exit_sem undo list error id=%d\n", u->semid); 1321 for (i = 0; i < sma->sem_nsems; i++) {
1287 goto next_entry;
1288found:
1289 *unp = un->id_next;
1290 /* perform adjustments registered in u */
1291 nsems = sma->sem_nsems;
1292 for (i = 0; i < nsems; i++) {
1293 struct sem * semaphore = &sma->sem_base[i]; 1322 struct sem * semaphore = &sma->sem_base[i];
1294 if (u->semadj[i]) { 1323 if (un->semadj[i]) {
1295 semaphore->semval += u->semadj[i]; 1324 semaphore->semval += un->semadj[i];
1296 /* 1325 /*
1297 * Range checks of the new semaphore value, 1326 * Range checks of the new semaphore value,
1298 * not defined by sus: 1327 * not defined by sus:
@@ -1316,10 +1345,11 @@ found:
1316 sma->sem_otime = get_seconds(); 1345 sma->sem_otime = get_seconds();
1317 /* maybe some queued-up processes were waiting for this */ 1346 /* maybe some queued-up processes were waiting for this */
1318 update_queue(sma); 1347 update_queue(sma);
1319next_entry:
1320 sem_unlock(sma); 1348 sem_unlock(sma);
1349
1350 call_rcu(&un->rcu, free_un);
1321 } 1351 }
1322 kfree(undo_list); 1352 kfree(ulp);
1323} 1353}
1324 1354
1325#ifdef CONFIG_PROC_FS 1355#ifdef CONFIG_PROC_FS
diff --git a/ipc/shm.c b/ipc/shm.c
index 790240cd067f..e77ec698cf40 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -112,23 +112,8 @@ void __init shm_init (void)
112} 112}
113 113
114/* 114/*
115 * shm_lock_(check_)down routines are called in the paths where the rw_mutex
116 * is held to protect access to the idr tree.
117 */
118static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns,
119 int id)
120{
121 struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id);
122
123 if (IS_ERR(ipcp))
124 return (struct shmid_kernel *)ipcp;
125
126 return container_of(ipcp, struct shmid_kernel, shm_perm);
127}
128
129/*
130 * shm_lock_(check_) routines are called in the paths where the rw_mutex 115 * shm_lock_(check_) routines are called in the paths where the rw_mutex
131 * is not held. 116 * is not necessarily held.
132 */ 117 */
133static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) 118static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
134{ 119{
@@ -211,7 +196,7 @@ static void shm_close(struct vm_area_struct *vma)
211 196
212 down_write(&shm_ids(ns).rw_mutex); 197 down_write(&shm_ids(ns).rw_mutex);
213 /* remove from the list of attaches of the shm segment */ 198 /* remove from the list of attaches of the shm segment */
214 shp = shm_lock_down(ns, sfd->id); 199 shp = shm_lock(ns, sfd->id);
215 BUG_ON(IS_ERR(shp)); 200 BUG_ON(IS_ERR(shp));
216 shp->shm_lprid = task_tgid_vnr(current); 201 shp->shm_lprid = task_tgid_vnr(current);
217 shp->shm_dtim = get_seconds(); 202 shp->shm_dtim = get_seconds();
@@ -577,7 +562,8 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
577 562
578 if (is_file_hugepages(shp->shm_file)) { 563 if (is_file_hugepages(shp->shm_file)) {
579 struct address_space *mapping = inode->i_mapping; 564 struct address_space *mapping = inode->i_mapping;
580 *rss += (HPAGE_SIZE/PAGE_SIZE)*mapping->nrpages; 565 struct hstate *h = hstate_file(shp->shm_file);
566 *rss += pages_per_huge_page(h) * mapping->nrpages;
581 } else { 567 } else {
582 struct shmem_inode_info *info = SHMEM_I(inode); 568 struct shmem_inode_info *info = SHMEM_I(inode);
583 spin_lock(&info->lock); 569 spin_lock(&info->lock);
@@ -931,7 +917,7 @@ invalid:
931 917
932out_nattch: 918out_nattch:
933 down_write(&shm_ids(ns).rw_mutex); 919 down_write(&shm_ids(ns).rw_mutex);
934 shp = shm_lock_down(ns, shmid); 920 shp = shm_lock(ns, shmid);
935 BUG_ON(IS_ERR(shp)); 921 BUG_ON(IS_ERR(shp));
936 shp->shm_nattch--; 922 shp->shm_nattch--;
937 if(shp->shm_nattch == 0 && 923 if(shp->shm_nattch == 0 &&
diff --git a/ipc/util.c b/ipc/util.c
index 3339177b336c..49b3ea615dc5 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -688,10 +688,6 @@ void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
688 * Look for an id in the ipc ids idr and lock the associated ipc object. 688 * Look for an id in the ipc ids idr and lock the associated ipc object.
689 * 689 *
690 * The ipc object is locked on exit. 690 * The ipc object is locked on exit.
691 *
692 * This is the routine that should be called when the rw_mutex is not already
693 * held, i.e. idr tree not protected: it protects the idr tree in read mode
694 * during the idr_find().
695 */ 691 */
696 692
697struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) 693struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
@@ -699,18 +695,13 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
699 struct kern_ipc_perm *out; 695 struct kern_ipc_perm *out;
700 int lid = ipcid_to_idx(id); 696 int lid = ipcid_to_idx(id);
701 697
702 down_read(&ids->rw_mutex);
703
704 rcu_read_lock(); 698 rcu_read_lock();
705 out = idr_find(&ids->ipcs_idr, lid); 699 out = idr_find(&ids->ipcs_idr, lid);
706 if (out == NULL) { 700 if (out == NULL) {
707 rcu_read_unlock(); 701 rcu_read_unlock();
708 up_read(&ids->rw_mutex);
709 return ERR_PTR(-EINVAL); 702 return ERR_PTR(-EINVAL);
710 } 703 }
711 704
712 up_read(&ids->rw_mutex);
713
714 spin_lock(&out->lock); 705 spin_lock(&out->lock);
715 706
716 /* ipc_rmid() may have already freed the ID while ipc_lock 707 /* ipc_rmid() may have already freed the ID while ipc_lock
@@ -725,56 +716,6 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
725 return out; 716 return out;
726} 717}
727 718
728/**
729 * ipc_lock_down - Lock an ipc structure with rw_sem held
730 * @ids: IPC identifier set
731 * @id: ipc id to look for
732 *
733 * Look for an id in the ipc ids idr and lock the associated ipc object.
734 *
735 * The ipc object is locked on exit.
736 *
737 * This is the routine that should be called when the rw_mutex is already
738 * held, i.e. idr tree protected.
739 */
740
741struct kern_ipc_perm *ipc_lock_down(struct ipc_ids *ids, int id)
742{
743 struct kern_ipc_perm *out;
744 int lid = ipcid_to_idx(id);
745
746 rcu_read_lock();
747 out = idr_find(&ids->ipcs_idr, lid);
748 if (out == NULL) {
749 rcu_read_unlock();
750 return ERR_PTR(-EINVAL);
751 }
752
753 spin_lock(&out->lock);
754
755 /*
756 * No need to verify that the structure is still valid since the
757 * rw_mutex is held.
758 */
759 return out;
760}
761
762struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, int id)
763{
764 struct kern_ipc_perm *out;
765
766 out = ipc_lock_down(ids, id);
767 if (IS_ERR(out))
768 return out;
769
770 if (ipc_checkid(out, id)) {
771 ipc_unlock(out);
772 return ERR_PTR(-EIDRM);
773 }
774
775 return out;
776}
777
778struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id) 719struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id)
779{ 720{
780 struct kern_ipc_perm *out; 721 struct kern_ipc_perm *out;
@@ -846,7 +787,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
846 int err; 787 int err;
847 788
848 down_write(&ids->rw_mutex); 789 down_write(&ids->rw_mutex);
849 ipcp = ipc_lock_check_down(ids, id); 790 ipcp = ipc_lock_check(ids, id);
850 if (IS_ERR(ipcp)) { 791 if (IS_ERR(ipcp)) {
851 err = PTR_ERR(ipcp); 792 err = PTR_ERR(ipcp);
852 goto out_up; 793 goto out_up;
diff --git a/ipc/util.h b/ipc/util.h
index cdb966aebe07..3646b45a03c9 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -102,11 +102,6 @@ void* ipc_rcu_alloc(int size);
102void ipc_rcu_getref(void *ptr); 102void ipc_rcu_getref(void *ptr);
103void ipc_rcu_putref(void *ptr); 103void ipc_rcu_putref(void *ptr);
104 104
105/*
106 * ipc_lock_down: called with rw_mutex held
107 * ipc_lock: called without that lock held
108 */
109struct kern_ipc_perm *ipc_lock_down(struct ipc_ids *, int);
110struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int); 105struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
111 106
112void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); 107void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
@@ -155,7 +150,6 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm)
155 rcu_read_unlock(); 150 rcu_read_unlock();
156} 151}
157 152
158struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, int id);
159struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id); 153struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id);
160int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, 154int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
161 struct ipc_ops *ops, struct ipc_params *params); 155 struct ipc_ops *ops, struct ipc_params *params);