From patchwork Fri Mar 1 00:43:10 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 15170 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id BEFFF23E1A for ; Fri, 1 Mar 2013 00:44:03 +0000 (UTC) Received: from mail-vc0-f179.google.com (mail-vc0-f179.google.com [209.85.220.179]) by fiordland.canonical.com (Postfix) with ESMTP id 639BFA1935F for ; Fri, 1 Mar 2013 00:44:03 +0000 (UTC) Received: by mail-vc0-f179.google.com with SMTP id k1so1658079vck.10 for ; Thu, 28 Feb 2013 16:44:02 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:x-received:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=weix2x5juI4VuZXf3a17p+WTIHjK9wgdvHctutIKUk0=; b=jsc3/Wnn2yw+N0qFgYwgCEyjVoOk+MkyTbxTaQ/h31XByVBJLnklSwyrIqSmJiVENd nqe8bpIZ/T1pZ7xza5qRdfGK0kNlUGdZfY/e7LvsCKXT96LufaqLKsfDiUat85H6VsdU A2q9p8G0xMdWuMOpnbFfrsSl+4Fi7ZzcsU21IhpT2pqRtaMgokPdZlwswxvzCheN9tBz i4veB8tUshruJPLkvEKgqmkAi24HIWp32chTSS2D/0BUbf8SlfqgUGjQlpbgdG0iOQfm M6irNmgZwJoMxeMdPa6chWp2rdudrKsyrw7l+QhBMwdQry8WD2G3aecrCnl7zkseToqF 29TQ== X-Received: by 10.220.242.73 with SMTP id lh9mr3249453vcb.49.1362098642837; Thu, 28 Feb 2013 16:44:02 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.58.145.101 with SMTP id st5csp653veb; Thu, 28 Feb 2013 16:44:02 -0800 (PST) X-Received: by 10.68.240.33 with SMTP id vx1mr11864435pbc.173.1362098641724; Thu, 28 Feb 2013 16:44:01 -0800 (PST) Received: from mail-da0-f44.google.com (mail-da0-f44.google.com [209.85.210.44]) by mx.google.com with ESMTPS id jy6si10260945pbc.239.2013.02.28.16.44.01 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 28 Feb 2013 16:44:01 -0800 (PST) Received-SPF: neutral (google.com: 209.85.210.44 is neither permitted nor denied by best guess record for domain of john.stultz@linaro.org) client-ip=209.85.210.44; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.210.44 is neither permitted nor denied by best guess record for domain of john.stultz@linaro.org) smtp.mail=john.stultz@linaro.org Received: by mail-da0-f44.google.com with SMTP id z20so1109250dae.17 for ; Thu, 28 Feb 2013 16:44:01 -0800 (PST) X-Received: by 10.68.197.168 with SMTP id iv8mr11735434pbc.114.1362098641337; Thu, 28 Feb 2013 16:44:01 -0800 (PST) Received: from localhost.localdomain (c-24-21-54-107.hsd1.or.comcast.net. [24.21.54.107]) by mx.google.com with ESMTPS id dx17sm10914892pac.17.2013.02.28.16.43.59 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 28 Feb 2013 16:44:00 -0800 (PST) From: John Stultz To: lkml Cc: Erik Gilling , Maarten Lankhorst , Daniel Vetter , Rob Clark , Sumit Semwal , Greg KH , dri-devel@lists.freedesktop.org, Android Kernel Team , John Stultz Subject: [PATCH 14/30] staging: sync: Add internal refcounting to fences Date: Thu, 28 Feb 2013 16:43:10 -0800 Message-Id: <1362098606-26469-15-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1362098606-26469-1-git-send-email-john.stultz@linaro.org> References: <1362098606-26469-1-git-send-email-john.stultz@linaro.org> X-Gm-Message-State: ALoCoQkU6g/I7S26DXjU9aMMlIUXak6gW2i9/FL+t6sXhvict7Fo14tmvLMJfSyXUfumtEp6xygs From: Erik Gilling If a fence is released while a timeline that one of it's pts is on is being signaled, it is possible for that fence to be deleted before it is signaled. This patch adds a refcount for internal references such as signaled pt processing. Cc: Maarten Lankhorst Cc: Erik Gilling Cc: Daniel Vetter Cc: Rob Clark Cc: Sumit Semwal Cc: Greg KH Cc: dri-devel@lists.freedesktop.org Cc: Android Kernel Team Signed-off-by: Erik Gilling Signed-off-by: John Stultz --- drivers/staging/android/sync.c | 54 ++++++++++++++++++++++++++++++++++------ drivers/staging/android/sync.h | 5 ++++ 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index 6cb7c88..7d4e9aa 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -30,6 +30,7 @@ static void sync_fence_signal_pt(struct sync_pt *pt); static int _sync_pt_has_signaled(struct sync_pt *pt); +static void sync_fence_free(struct kref *kref); static LIST_HEAD(sync_timeline_list_head); static DEFINE_SPINLOCK(sync_timeline_list_lock); @@ -113,7 +114,7 @@ static void sync_timeline_remove_pt(struct sync_pt *pt) { struct sync_timeline *obj = pt->parent; unsigned long flags; - bool needs_freeing; + bool needs_freeing = false; spin_lock_irqsave(&obj->active_list_lock, flags); if (!list_empty(&pt->active_list)) @@ -121,8 +122,11 @@ static void sync_timeline_remove_pt(struct sync_pt *pt) spin_unlock_irqrestore(&obj->active_list_lock, flags); spin_lock_irqsave(&obj->child_list_lock, flags); - list_del(&pt->child_list); - needs_freeing = obj->destroyed && list_empty(&obj->child_list_head); + if (!list_empty(&pt->child_list)) { + list_del_init(&pt->child_list); + needs_freeing = obj->destroyed && + list_empty(&obj->child_list_head); + } spin_unlock_irqrestore(&obj->child_list_lock, flags); if (needs_freeing) @@ -141,18 +145,22 @@ void sync_timeline_signal(struct sync_timeline *obj) struct sync_pt *pt = container_of(pos, struct sync_pt, active_list); - if (_sync_pt_has_signaled(pt)) - list_move(pos, &signaled_pts); + if (_sync_pt_has_signaled(pt)) { + list_del_init(pos); + list_add(&pt->signaled_list, &signaled_pts); + kref_get(&pt->fence->kref); + } } spin_unlock_irqrestore(&obj->active_list_lock, flags); list_for_each_safe(pos, n, &signaled_pts) { struct sync_pt *pt = - container_of(pos, struct sync_pt, active_list); + container_of(pos, struct sync_pt, signaled_list); list_del_init(pos); sync_fence_signal_pt(pt); + kref_put(&pt->fence->kref, sync_fence_free); } } EXPORT_SYMBOL(sync_timeline_signal); @@ -253,6 +261,7 @@ static struct sync_fence *sync_fence_alloc(const char *name) if (fence->file == NULL) goto err; + kref_init(&fence->kref); strlcpy(fence->name, name, sizeof(fence->name)); INIT_LIST_HEAD(&fence->pt_list_head); @@ -362,6 +371,16 @@ static int sync_fence_merge_pts(struct sync_fence *dst, struct sync_fence *src) return 0; } +static void sync_fence_detach_pts(struct sync_fence *fence) +{ + struct list_head *pos, *n; + + list_for_each_safe(pos, n, &fence->pt_list_head) { + struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list); + sync_timeline_remove_pt(pt); + } +} + static void sync_fence_free_pts(struct sync_fence *fence) { struct list_head *pos, *n; @@ -565,18 +584,37 @@ int sync_fence_wait(struct sync_fence *fence, long timeout) } EXPORT_SYMBOL(sync_fence_wait); +static void sync_fence_free(struct kref *kref) +{ + struct sync_fence *fence = container_of(kref, struct sync_fence, kref); + + sync_fence_free_pts(fence); + + kfree(fence); +} + static int sync_fence_release(struct inode *inode, struct file *file) { struct sync_fence *fence = file->private_data; unsigned long flags; + /* + * We need to remove all ways to access this fence before droping + * our ref. + * + * start with its membership in the global fence list + */ spin_lock_irqsave(&sync_fence_list_lock, flags); list_del(&fence->sync_fence_list); spin_unlock_irqrestore(&sync_fence_list_lock, flags); - sync_fence_free_pts(fence); + /* + * remove its pts from their parents so that sync_timeline_signal() + * can't reference the fence. + */ + sync_fence_detach_pts(fence); - kfree(fence); + kref_put(&fence->kref, sync_fence_free); return 0; } diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 943f414..00c9bae 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -16,6 +16,7 @@ #include #ifdef __KERNEL__ +#include #include #include #include @@ -109,6 +110,7 @@ struct sync_timeline { * @parent: sync_timeline to which this sync_pt belongs * @child_list: membership in sync_timeline.child_list_head * @active_list: membership in sync_timeline.active_list_head + * @signaled_list: membership in temorary signaled_list on stack * @fence: sync_fence to which the sync_pt belongs * @pt_list: membership in sync_fence.pt_list_head * @status: 1: signaled, 0:active, <0: error @@ -120,6 +122,7 @@ struct sync_pt { struct list_head child_list; struct list_head active_list; + struct list_head signaled_list; struct sync_fence *fence; struct list_head pt_list; @@ -133,6 +136,7 @@ struct sync_pt { /** * struct sync_fence - sync fence * @file: file representing this fence + * @kref: referenace count on fence. * @name: name of sync_fence. Useful for debugging * @pt_list_head: list of sync_pts in ths fence. immutable once fence * is created @@ -145,6 +149,7 @@ struct sync_pt { */ struct sync_fence { struct file *file; + struct kref kref; char name[32]; /* this list is immutable once the fence is created */