aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/util.c')
-rw-r--r--ipc/util.c59
1 files changed, 33 insertions, 26 deletions
diff --git a/ipc/util.c b/ipc/util.c
index e829da9ed01f..7684f41bce76 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -17,12 +17,27 @@
17 * Pavel Emelianov <xemul@openvz.org> 17 * Pavel Emelianov <xemul@openvz.org>
18 * 18 *
19 * General sysv ipc locking scheme: 19 * General sysv ipc locking scheme:
20 * when doing ipc id lookups, take the ids->rwsem 20 * rcu_read_lock()
21 * rcu_read_lock() 21 * obtain the ipc object (kern_ipc_perm) by looking up the id in an idr
22 * obtain the ipc object (kern_ipc_perm) 22 * tree.
23 * perform security, capabilities, auditing and permission checks, etc. 23 * - perform initial checks (capabilities, auditing and permission,
24 * acquire the ipc lock (kern_ipc_perm.lock) throught ipc_lock_object() 24 * etc).
25 * perform data updates (ie: SET, RMID, LOCK/UNLOCK commands) 25 * - perform read-only operations, such as STAT, INFO commands.
26 * acquire the ipc lock (kern_ipc_perm.lock) through
27 * ipc_lock_object()
28 * - perform data updates, such as SET, RMID commands and
29 * mechanism-specific operations (semop/semtimedop,
30 * msgsnd/msgrcv, shmat/shmdt).
31 * drop the ipc lock, through ipc_unlock_object().
32 * rcu_read_unlock()
33 *
34 * The ids->rwsem must be taken when:
35 * - creating, removing and iterating the existing entries in ipc
36 * identifier sets.
37 * - iterating through files under /proc/sysvipc/
38 *
39 * Note that sems have a special fast path that avoids kern_ipc_perm.lock -
40 * see sem_lock().
26 */ 41 */
27 42
28#include <linux/mm.h> 43#include <linux/mm.h>
@@ -474,11 +489,6 @@ void ipc_free(void* ptr, int size)
474 kfree(ptr); 489 kfree(ptr);
475} 490}
476 491
477struct ipc_rcu {
478 struct rcu_head rcu;
479 atomic_t refcount;
480} ____cacheline_aligned_in_smp;
481
482/** 492/**
483 * ipc_rcu_alloc - allocate ipc and rcu space 493 * ipc_rcu_alloc - allocate ipc and rcu space
484 * @size: size desired 494 * @size: size desired
@@ -505,27 +515,24 @@ int ipc_rcu_getref(void *ptr)
505 return atomic_inc_not_zero(&p->refcount); 515 return atomic_inc_not_zero(&p->refcount);
506} 516}
507 517
508/** 518void ipc_rcu_putref(void *ptr, void (*func)(struct rcu_head *head))
509 * ipc_schedule_free - free ipc + rcu space
510 * @head: RCU callback structure for queued work
511 */
512static void ipc_schedule_free(struct rcu_head *head)
513{
514 vfree(container_of(head, struct ipc_rcu, rcu));
515}
516
517void ipc_rcu_putref(void *ptr)
518{ 519{
519 struct ipc_rcu *p = ((struct ipc_rcu *)ptr) - 1; 520 struct ipc_rcu *p = ((struct ipc_rcu *)ptr) - 1;
520 521
521 if (!atomic_dec_and_test(&p->refcount)) 522 if (!atomic_dec_and_test(&p->refcount))
522 return; 523 return;
523 524
524 if (is_vmalloc_addr(ptr)) { 525 call_rcu(&p->rcu, func);
525 call_rcu(&p->rcu, ipc_schedule_free); 526}
526 } else { 527
527 kfree_rcu(p, rcu); 528void ipc_rcu_free(struct rcu_head *head)
528 } 529{
530 struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
531
532 if (is_vmalloc_addr(p))
533 vfree(p);
534 else
535 kfree(p);
529} 536}
530 537
531/** 538/**