From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752060AbcBLRKK (ORCPT ); Fri, 12 Feb 2016 12:10:10 -0500 Received: from mga14.intel.com ([192.55.52.115]:52158 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751003AbcBLRKI (ORCPT ); Fri, 12 Feb 2016 12:10:08 -0500 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.22,436,1449561600"; d="scan'208";a="901632423" From: Alexander Shishkin To: Greg KH Cc: Mathieu Poirier , Chunyan Zhang , laurent.fert@intel.com, yann.fouassier@intel.com, linux-kernel@vger.kernel.org, Alexander Shishkin Subject: [QUEUED v20160212 15/19] stm class: Guard output assignment against concurrency Date: Fri, 12 Feb 2016 19:00:31 +0200 Message-Id: <1455296435-17362-16-git-send-email-alexander.shishkin@linux.intel.com> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1455296435-17362-1-git-send-email-alexander.shishkin@linux.intel.com> References: <1455296435-17362-1-git-send-email-alexander.shishkin@linux.intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org It is possible to concurrently assign the same output (a character device writer or an stm_source device) to different stm devices, which sets off a strategically placed warning in stm_output_assign(). To avoid this, use a spinlock to serialize (un)assignments between outputs and stm devices. Signed-off-by: Alexander Shishkin --- drivers/hwtracing/stm/core.c | 17 +++++++++++++++++ drivers/hwtracing/stm/stm.h | 1 + 2 files changed, 18 insertions(+) diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index fb5a6a582b..6a254ce4b9 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -185,6 +185,9 @@ static void stm_output_claim(struct stm_device *stm, struct stm_output *output) { struct stp_master *master = stm_master(stm, output->master); + lockdep_assert_held(&stm->mc_lock); + lockdep_assert_held(&output->lock); + if (WARN_ON_ONCE(master->nr_free < output->nr_chans)) return; @@ -199,6 +202,9 @@ stm_output_disclaim(struct stm_device *stm, struct stm_output *output) { struct stp_master *master = stm_master(stm, output->master); + lockdep_assert_held(&stm->mc_lock); + lockdep_assert_held(&output->lock); + bitmap_release_region(&master->chan_map[0], output->channel, ilog2(output->nr_chans)); @@ -288,6 +294,7 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width, } spin_lock(&stm->mc_lock); + spin_lock(&output->lock); /* output is already assigned -- shouldn't happen */ if (WARN_ON_ONCE(output->nr_chans)) goto unlock; @@ -304,6 +311,7 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width, ret = 0; unlock: + spin_unlock(&output->lock); spin_unlock(&stm->mc_lock); return ret; @@ -312,11 +320,18 @@ unlock: static void stm_output_free(struct stm_device *stm, struct stm_output *output) { spin_lock(&stm->mc_lock); + spin_lock(&output->lock); if (output->nr_chans) stm_output_disclaim(stm, output); + spin_unlock(&output->lock); spin_unlock(&stm->mc_lock); } +static void stm_output_init(struct stm_output *output) +{ + spin_lock_init(&output->lock); +} + static int major_match(struct device *dev, const void *data) { unsigned int major = *(unsigned int *)data; @@ -339,6 +354,7 @@ static int stm_char_open(struct inode *inode, struct file *file) if (!stmf) return -ENOMEM; + stm_output_init(&stmf->output); stmf->stm = to_stm_device(dev); if (!try_module_get(stmf->stm->owner)) @@ -952,6 +968,7 @@ int stm_source_register_device(struct device *parent, if (err) goto err; + stm_output_init(&src->output); spin_lock_init(&src->link_lock); INIT_LIST_HEAD(&src->link_entry); src->data = data; diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h index 97ee022414..4e8c692626 100644 --- a/drivers/hwtracing/stm/stm.h +++ b/drivers/hwtracing/stm/stm.h @@ -57,6 +57,7 @@ struct stm_device { container_of((_d), struct stm_device, dev) struct stm_output { + spinlock_t lock; unsigned int master; unsigned int channel; unsigned int nr_chans; -- 2.7.0