aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorDavidlohr Bueso <davidlohr.bueso@hp.com>2013-04-30 22:15:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-01 11:12:57 -0400
commit4d2bff5eb86e8d7b4a20934cccb93bdeebed3558 (patch)
tree3667eec32ddcf8686335f64db553613c319f0625 /ipc
parent7bb4deff61bdab3338534841cb6d0508314a41d6 (diff)
ipc: introduce obtaining a lockless ipc object
Through ipc_lock() and therefore ipc_lock_check() we currently return the locked ipc object. This is not necessary for all situations and can, therefore, cause unnecessary ipc lock contention. Introduce analogous ipc_obtain_object() and ipc_obtain_object_check() functions that only lookup and return the ipc object. Both these functions must be called within the RCU read critical section. [akpm@linux-foundation.org: propagate the ipc_obtain_object() errno from ipc_lock()] Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com> Signed-off-by: Rik van Riel <riel@redhat.com> Reviewed-by: Chegu Vinod <chegu_vinod@hp.com> Acked-by: Michel Lespinasse <walken@google.com> Cc: Emmanuel Benisty <benisty.e@gmail.com> Cc: Jason Low <jason.low2@hp.com> Cc: Peter Hurley <peter@hurleysoftware.com> Cc: Stanislav Kinsbursky <skinsbursky@parallels.com> Tested-by: Sedat Dilek <sedat.dilek@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/util.c71
-rw-r--r--ipc/util.h2
2 files changed, 59 insertions, 14 deletions
diff --git a/ipc/util.c b/ipc/util.c
index 03eadd8fb0fd..813804ebdeba 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -669,38 +669,81 @@ void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
669} 669}
670 670
671/** 671/**
672 * ipc_obtain_object
673 * @ids: ipc identifier set
674 * @id: ipc id to look for
675 *
676 * Look for an id in the ipc ids idr and return associated ipc object.
677 *
678 * Call inside the RCU critical section.
679 * The ipc object is *not* locked on exit.
680 */
681struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id)
682{
683 struct kern_ipc_perm *out;
684 int lid = ipcid_to_idx(id);
685
686 out = idr_find(&ids->ipcs_idr, lid);
687 if (!out)
688 return ERR_PTR(-EINVAL);
689
690 return out;
691}
692
693/**
672 * ipc_lock - Lock an ipc structure without rw_mutex held 694 * ipc_lock - Lock an ipc structure without rw_mutex held
673 * @ids: IPC identifier set 695 * @ids: IPC identifier set
674 * @id: ipc id to look for 696 * @id: ipc id to look for
675 * 697 *
676 * Look for an id in the ipc ids idr and lock the associated ipc object. 698 * Look for an id in the ipc ids idr and lock the associated ipc object.
677 * 699 *
678 * The ipc object is locked on exit. 700 * The ipc object is locked on successful exit.
679 */ 701 */
680
681struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id) 702struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
682{ 703{
683 struct kern_ipc_perm *out; 704 struct kern_ipc_perm *out;
684 int lid = ipcid_to_idx(id);
685 705
686 rcu_read_lock(); 706 rcu_read_lock();
687 out = idr_find(&ids->ipcs_idr, lid); 707 out = ipc_obtain_object(ids, id);
688 if (out == NULL) { 708 if (IS_ERR(out))
689 rcu_read_unlock(); 709 goto err1;
690 return ERR_PTR(-EINVAL);
691 }
692 710
693 spin_lock(&out->lock); 711 spin_lock(&out->lock);
694 712
695 /* ipc_rmid() may have already freed the ID while ipc_lock 713 /* ipc_rmid() may have already freed the ID while ipc_lock
696 * was spinning: here verify that the structure is still valid 714 * was spinning: here verify that the structure is still valid
697 */ 715 */
698 if (out->deleted) { 716 if (!out->deleted)
699 spin_unlock(&out->lock); 717 return out;
700 rcu_read_unlock();
701 return ERR_PTR(-EINVAL);
702 }
703 718
719 spin_unlock(&out->lock);
720 out = ERR_PTR(-EINVAL);
721err1:
722 rcu_read_unlock();
723 return out;
724}
725
726/**
727 * ipc_obtain_object_check
728 * @ids: ipc identifier set
729 * @id: ipc id to look for
730 *
731 * Similar to ipc_obtain_object() but also checks
732 * the ipc object reference counter.
733 *
734 * Call inside the RCU critical section.
735 * The ipc object is *not* locked on exit.
736 */
737struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id)
738{
739 struct kern_ipc_perm *out = ipc_obtain_object(ids, id);
740
741 if (IS_ERR(out))
742 goto out;
743
744 if (ipc_checkid(out, id))
745 return ERR_PTR(-EIDRM);
746out:
704 return out; 747 return out;
705} 748}
706 749
diff --git a/ipc/util.h b/ipc/util.h
index ac1480a4efd1..bfc8d4ea6e46 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -123,6 +123,7 @@ void ipc_rcu_getref(void *ptr);
123void ipc_rcu_putref(void *ptr); 123void ipc_rcu_putref(void *ptr);
124 124
125struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int); 125struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
126struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id);
126 127
127void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); 128void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
128void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); 129void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
@@ -168,6 +169,7 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm)
168} 169}
169 170
170struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id); 171struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id);
172struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id);
171int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, 173int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
172 struct ipc_ops *ops, struct ipc_params *params); 174 struct ipc_ops *ops, struct ipc_params *params);
173void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, 175void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,