Message ID | 20220920112821.975359-14-nuno.sa@analog.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Make 'mlock' really private | expand |
Hi Nuno, nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 +0200: > The pattern used in this device does not quite fit in the > iio_device_claim_direct_mode() typical usage. In this case, > iio_buffer_enabled() was being used not to prevent the raw access but to > allow it. Hence to get rid of the 'mlock' we need to: > > 1. Use iio_device_claim_direct_mode() to check if direct mode can be > claimed and if we can return -EINVAL (as the original code); > > 2. Make sure that buffering is not disabled while doing a raw read. For > that, we can make use of the local lock that already exists. > > While at it, fixed a minor coding style complain... > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > --- > drivers/iio/health/max30100.c | 24 +++++++++++++++++------- > 1 file changed, 17 insertions(+), 7 deletions(-) > > diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c > index ad5717965223..aa494cad5df0 100644 > --- a/drivers/iio/health/max30100.c > +++ b/drivers/iio/health/max30100.c > @@ -185,8 +185,19 @@ static int max30100_buffer_postenable(struct iio_dev *indio_dev) > static int max30100_buffer_predisable(struct iio_dev *indio_dev) > { > struct max30100_data *data = iio_priv(indio_dev); > + int ret; > + > + /* > + * As stated in the comment in the read_raw() function, temperature > + * can only be acquired if the engine is running. As such the mutex > + * is used to make sure we do not power down while doing a temperature > + * reading. > + */ > + mutex_lock(&data->lock); > + ret = max30100_set_powermode(data, false); > + mutex_unlock(&data->lock); > > - return max30100_set_powermode(data, false); > + return ret; > } > > static const struct iio_buffer_setup_ops max30100_buffer_setup_ops = { > @@ -387,18 +398,17 @@ static int max30100_read_raw(struct iio_dev *indio_dev, > * Temperature reading can only be acquired while engine > * is running > */ > - mutex_lock(&indio_dev->mlock); > - > - if (!iio_buffer_enabled(indio_dev)) > + if (!iio_device_claim_direct_mode(indio_dev)) { I wonder if this line change here is really needed. I agree the whole construction looks like what iio_device_claim_direct_mode() does but in practice I don't see the point of acquiring any lock here if we just release it no matter what happens right after. Unless of course if there is a hidden goal like "stop exporting iio_buffer_enabled()" or something like that. At least I would separate this from the main change which targets the removal of mlock because I don't see how it is directly related. > ret = -EAGAIN; > - else { > + iio_device_release_direct_mode(indio_dev); > + } else { > + mutex_lock(&data->lock); > ret = max30100_get_temp(data, val); > if (!ret) > ret = IIO_VAL_INT; > - > + mutex_unlock(&data->lock); > } > > - mutex_unlock(&indio_dev->mlock); > break; > case IIO_CHAN_INFO_SCALE: > *val = 1; /* 0.0625 */ In any case, nice series, thanks for writing it! Thanks, Miquèl
> -----Original Message----- > From: Miquel Raynal <miquel.raynal@bootlin.com> > Sent: Tuesday, September 20, 2022 2:23 PM > To: Sa, Nuno <Nuno.Sa@analog.com> > Cc: linux-arm-kernel@lists.infradead.org; linux-rockchip@lists.infradead.org; > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; Hennerich, > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > <martin.blumenstingl@googlemail.com>; Sascha Hauer > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; Kevin > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy <vz@mleia.com>; > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru Ardelean > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; Andriy > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo Chen > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans de > Goede <hdegoede@redhat.com>; Jerome Brunet <jbrunet@baylibre.com>; > Heiko Stuebner <heiko@sntech.de>; Florian Boor > <florian.boor@kernelconcepts.de>; Regus, Ciprian > <Ciprian.Regus@analog.com>; Lars-Peter Clausen <lars@metafoo.de>; Andy > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; Baolin > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson Zhai > <orsonzhai@gmail.com> > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use internal iio_dev > lock > > [External] > > Hi Nuno, > Hi Miquel, Thanks for reviewing... > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 +0200: > > > The pattern used in this device does not quite fit in the > > iio_device_claim_direct_mode() typical usage. In this case, > > iio_buffer_enabled() was being used not to prevent the raw access but to > > allow it. Hence to get rid of the 'mlock' we need to: > > > > 1. Use iio_device_claim_direct_mode() to check if direct mode can be > > claimed and if we can return -EINVAL (as the original code); > > > > 2. Make sure that buffering is not disabled while doing a raw read. For > > that, we can make use of the local lock that already exists. > > > > While at it, fixed a minor coding style complain... > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > --- > > drivers/iio/health/max30100.c | 24 +++++++++++++++++------- > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c > > index ad5717965223..aa494cad5df0 100644 > > --- a/drivers/iio/health/max30100.c > > +++ b/drivers/iio/health/max30100.c > > @@ -185,8 +185,19 @@ static int max30100_buffer_postenable(struct > iio_dev *indio_dev) > > static int max30100_buffer_predisable(struct iio_dev *indio_dev) > > { > > struct max30100_data *data = iio_priv(indio_dev); > > + int ret; > > + > > + /* > > + * As stated in the comment in the read_raw() function, temperature > > + * can only be acquired if the engine is running. As such the mutex > > + * is used to make sure we do not power down while doing a > temperature > > + * reading. > > + */ > > + mutex_lock(&data->lock); > > + ret = max30100_set_powermode(data, false); > > + mutex_unlock(&data->lock); > > > > - return max30100_set_powermode(data, false); > > + return ret; > > } > > > > static const struct iio_buffer_setup_ops max30100_buffer_setup_ops = { > > @@ -387,18 +398,17 @@ static int max30100_read_raw(struct iio_dev > *indio_dev, > > * Temperature reading can only be acquired while engine > > * is running > > */ > > - mutex_lock(&indio_dev->mlock); > > - > > - if (!iio_buffer_enabled(indio_dev)) > > + if (!iio_device_claim_direct_mode(indio_dev)) { > > I wonder if this line change here is really needed. I agree the whole > construction looks like what iio_device_claim_direct_mode() does but in > practice I don't see the point of acquiring any lock here if we just > release it no matter what happens right after. > I can see that this is odd (at the very least) but AFAIK, this is the only way to safely infer if buffering is enabled or not. iio_buffer_enabled() has no protection against someone concurrently enabling/disabling the buffer. So the call is needed to make sure 'mlock' is internally grabbed before calling iio_buffer_enabled(). > Unless of course if there is a hidden goal like "stop exporting > iio_buffer_enabled()" or something like that. > > At least I would separate this from the main change which targets the > removal of mlock because I don't see how it is directly related. In a sense both changes are needed to ultimately get rid of mlock. I'm also not sure how could I do the separation... Do you have something in mind? - Nuno Sá
Hi Nuno, Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 12:44:08 +0000: > > -----Original Message----- > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > Sent: Tuesday, September 20, 2022 2:23 PM > > To: Sa, Nuno <Nuno.Sa@analog.com> > > Cc: linux-arm-kernel@lists.infradead.org; linux-rockchip@lists.infradead.org; > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; Hennerich, > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; Kevin > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy <vz@mleia.com>; > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru Ardelean > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; Andriy > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo Chen > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans de > > Goede <hdegoede@redhat.com>; Jerome Brunet <jbrunet@baylibre.com>; > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen <lars@metafoo.de>; Andy > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; Baolin > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson Zhai > > <orsonzhai@gmail.com> > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use internal iio_dev > > lock > > > > [External] > > > > Hi Nuno, > > > > Hi Miquel, > > Thanks for reviewing... > > > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 +0200: > > > > > The pattern used in this device does not quite fit in the > > > iio_device_claim_direct_mode() typical usage. In this case, > > > iio_buffer_enabled() was being used not to prevent the raw access but to > > > allow it. Hence to get rid of the 'mlock' we need to: > > > > > > 1. Use iio_device_claim_direct_mode() to check if direct mode can be > > > claimed and if we can return -EINVAL (as the original code); > > > > > > 2. Make sure that buffering is not disabled while doing a raw read. For > > > that, we can make use of the local lock that already exists. > > > > > > While at it, fixed a minor coding style complain... > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > --- > > > drivers/iio/health/max30100.c | 24 +++++++++++++++++------- > > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > > > diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c > > > index ad5717965223..aa494cad5df0 100644 > > > --- a/drivers/iio/health/max30100.c > > > +++ b/drivers/iio/health/max30100.c > > > @@ -185,8 +185,19 @@ static int max30100_buffer_postenable(struct > > iio_dev *indio_dev) > > > static int max30100_buffer_predisable(struct iio_dev *indio_dev) > > > { > > > struct max30100_data *data = iio_priv(indio_dev); > > > + int ret; > > > + > > > + /* > > > + * As stated in the comment in the read_raw() function, temperature > > > + * can only be acquired if the engine is running. As such the mutex > > > + * is used to make sure we do not power down while doing a > > temperature > > > + * reading. > > > + */ > > > + mutex_lock(&data->lock); > > > + ret = max30100_set_powermode(data, false); > > > + mutex_unlock(&data->lock); > > > > > > - return max30100_set_powermode(data, false); > > > + return ret; > > > } > > > > > > static const struct iio_buffer_setup_ops max30100_buffer_setup_ops = { > > > @@ -387,18 +398,17 @@ static int max30100_read_raw(struct iio_dev > > *indio_dev, > > > * Temperature reading can only be acquired while engine > > > * is running > > > */ > > > - mutex_lock(&indio_dev->mlock); > > > - > > > - if (!iio_buffer_enabled(indio_dev)) > > > + if (!iio_device_claim_direct_mode(indio_dev)) { > > > > I wonder if this line change here is really needed. I agree the whole > > construction looks like what iio_device_claim_direct_mode() does but in > > practice I don't see the point of acquiring any lock here if we just > > release it no matter what happens right after. > > > > I can see that this is odd (at the very least) but AFAIK, this is the only way > to safely infer if buffering is enabled or not. iio_buffer_enabled() has no > protection against someone concurrently enabling/disabling the buffer. Yes, but this is only relevant if you want to infer that the "buffers are enabled" and be sure that it cannot be otherwise during the next lines until you release the lock. Acquiring a lock, doing the if and then unconditionally releasing the lock, IMHO, does not make any sense (but I'm not a locking guru) because when you enter the else clause, you are not protected anyway, so in both cases all this is completely racy. > So the call is needed to make sure 'mlock' is internally grabbed before > calling iio_buffer_enabled(). > > > Unless of course if there is a hidden goal like "stop exporting > > iio_buffer_enabled()" or something like that. > > > > At least I would separate this from the main change which targets the > > removal of mlock because I don't see how it is directly related. > > In a sense both changes are needed to ultimately get rid of mlock. I'm > also not sure how could I do the separation... Do you have something > in mind? > > - Nuno Sá Thanks, Miquèl
> -----Original Message----- > From: Miquel Raynal <miquel.raynal@bootlin.com> > Sent: Tuesday, September 20, 2022 2:56 PM > To: Sa, Nuno <Nuno.Sa@analog.com> > Cc: linux-arm-kernel@lists.infradead.org; linux-rockchip@lists.infradead.org; > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; Hennerich, > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > <martin.blumenstingl@googlemail.com>; Sascha Hauer > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; Kevin > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy <vz@mleia.com>; > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru Ardelean > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; Andriy > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo Chen > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans de > Goede <hdegoede@redhat.com>; Jerome Brunet <jbrunet@baylibre.com>; > Heiko Stuebner <heiko@sntech.de>; Florian Boor > <florian.boor@kernelconcepts.de>; Regus, Ciprian > <Ciprian.Regus@analog.com>; Lars-Peter Clausen <lars@metafoo.de>; Andy > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; Baolin > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson Zhai > <orsonzhai@gmail.com> > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use internal iio_dev > lock > > [External] > > Hi Nuno, > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 12:44:08 +0000: > > > > -----Original Message----- > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > Sent: Tuesday, September 20, 2022 2:23 PM > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > Cc: linux-arm-kernel@lists.infradead.org; linux- > rockchip@lists.infradead.org; > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > Hennerich, > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; Kevin > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy <vz@mleia.com>; > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > Ardelean > > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; > Andriy > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo Chen > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans de > > > Goede <hdegoede@redhat.com>; Jerome Brunet > <jbrunet@baylibre.com>; > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen <lars@metafoo.de>; > Andy > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; Baolin > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson Zhai > > > <orsonzhai@gmail.com> > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use internal > iio_dev > > > lock > > > > > > [External] > > > > > > Hi Nuno, > > > > > > > Hi Miquel, > > > > Thanks for reviewing... > > > > > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 +0200: > > > > > > > The pattern used in this device does not quite fit in the > > > > iio_device_claim_direct_mode() typical usage. In this case, > > > > iio_buffer_enabled() was being used not to prevent the raw access but > to > > > > allow it. Hence to get rid of the 'mlock' we need to: > > > > > > > > 1. Use iio_device_claim_direct_mode() to check if direct mode can be > > > > claimed and if we can return -EINVAL (as the original code); > > > > > > > > 2. Make sure that buffering is not disabled while doing a raw read. For > > > > that, we can make use of the local lock that already exists. > > > > > > > > While at it, fixed a minor coding style complain... > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > > --- > > > > drivers/iio/health/max30100.c | 24 +++++++++++++++++------- > > > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > > > > > diff --git a/drivers/iio/health/max30100.c > b/drivers/iio/health/max30100.c > > > > index ad5717965223..aa494cad5df0 100644 > > > > --- a/drivers/iio/health/max30100.c > > > > +++ b/drivers/iio/health/max30100.c > > > > @@ -185,8 +185,19 @@ static int max30100_buffer_postenable(struct > > > iio_dev *indio_dev) > > > > static int max30100_buffer_predisable(struct iio_dev *indio_dev) > > > > { > > > > struct max30100_data *data = iio_priv(indio_dev); > > > > + int ret; > > > > + > > > > + /* > > > > + * As stated in the comment in the read_raw() function, temperature > > > > + * can only be acquired if the engine is running. As such the mutex > > > > + * is used to make sure we do not power down while doing a > > > temperature > > > > + * reading. > > > > + */ > > > > + mutex_lock(&data->lock); > > > > + ret = max30100_set_powermode(data, false); > > > > + mutex_unlock(&data->lock); > > > > > > > > - return max30100_set_powermode(data, false); > > > > + return ret; > > > > } > > > > > > > > static const struct iio_buffer_setup_ops max30100_buffer_setup_ops > = { > > > > @@ -387,18 +398,17 @@ static int max30100_read_raw(struct iio_dev > > > *indio_dev, > > > > * Temperature reading can only be acquired while engine > > > > * is running > > > > */ > > > > - mutex_lock(&indio_dev->mlock); > > > > - > > > > - if (!iio_buffer_enabled(indio_dev)) > > > > + if (!iio_device_claim_direct_mode(indio_dev)) { > > > > > > I wonder if this line change here is really needed. I agree the whole > > > construction looks like what iio_device_claim_direct_mode() does but in > > > practice I don't see the point of acquiring any lock here if we just > > > release it no matter what happens right after. > > > > > > > I can see that this is odd (at the very least) but AFAIK, this is the only way > > to safely infer if buffering is enabled or not. iio_buffer_enabled() has no > > protection against someone concurrently enabling/disabling the buffer. > > Yes, but this is only relevant if you want to infer that the "buffers > are enabled" and be sure that it cannot be otherwise during the next > lines until you release the lock. Acquiring a lock, doing the if and > then unconditionally releasing the lock, IMHO, does not make any sense > (but I'm not a locking guru) because when you enter the else clause, > you are not protected anyway, so in both cases all this is completely > racy. > Ahh crap, yes you are right... It is still racy since we can still try to read the temperature with the device powered off. I'm not really sure how to address this. One way could be to just use an internal control variable to reflect the device power state (set/clear on the buffer callbacks) and only use the local lock (completely ditching the call to iio_device_claim_direct_mode())... Other options would be to have helpers for acquiring/releasing the lock (I think this would defeat the idea of not abusing this lock at all) or have A version iio_device_claim_direct_mode() that does not release the lock in case buffering is enabled. Any preference? - Nuno Sá
Hi Nuno, Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 13:15:32 +0000: > > -----Original Message----- > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > Sent: Tuesday, September 20, 2022 2:56 PM > > To: Sa, Nuno <Nuno.Sa@analog.com> > > Cc: linux-arm-kernel@lists.infradead.org; linux-rockchip@lists.infradead.org; > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; Hennerich, > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; Kevin > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy <vz@mleia.com>; > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru Ardelean > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; Andriy > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo Chen > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans de > > Goede <hdegoede@redhat.com>; Jerome Brunet <jbrunet@baylibre.com>; > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen <lars@metafoo.de>; Andy > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; Baolin > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson Zhai > > <orsonzhai@gmail.com> > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use internal iio_dev > > lock > > > > [External] > > > > Hi Nuno, > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 12:44:08 +0000: > > > > > > -----Original Message----- > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > Sent: Tuesday, September 20, 2022 2:23 PM > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > Cc: linux-arm-kernel@lists.infradead.org; linux- > > rockchip@lists.infradead.org; > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > > Hennerich, > > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; Kevin > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy <vz@mleia.com>; > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > > Ardelean > > > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; > > Andriy > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo Chen > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans de > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > <jbrunet@baylibre.com>; > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen <lars@metafoo.de>; > > Andy > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; Baolin > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson Zhai > > > > <orsonzhai@gmail.com> > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use internal > > iio_dev > > > > lock > > > > > > > > [External] > > > > > > > > Hi Nuno, > > > > > > > > > > Hi Miquel, > > > > > > Thanks for reviewing... > > > > > > > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 +0200: > > > > > > > > > The pattern used in this device does not quite fit in the > > > > > iio_device_claim_direct_mode() typical usage. In this case, > > > > > iio_buffer_enabled() was being used not to prevent the raw access but > > to > > > > > allow it. Hence to get rid of the 'mlock' we need to: > > > > > > > > > > 1. Use iio_device_claim_direct_mode() to check if direct mode can be > > > > > claimed and if we can return -EINVAL (as the original code); > > > > > > > > > > 2. Make sure that buffering is not disabled while doing a raw read. For > > > > > that, we can make use of the local lock that already exists. > > > > > > > > > > While at it, fixed a minor coding style complain... > > > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > > > --- > > > > > drivers/iio/health/max30100.c | 24 +++++++++++++++++------- > > > > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > > > > > > > diff --git a/drivers/iio/health/max30100.c > > b/drivers/iio/health/max30100.c > > > > > index ad5717965223..aa494cad5df0 100644 > > > > > --- a/drivers/iio/health/max30100.c > > > > > +++ b/drivers/iio/health/max30100.c > > > > > @@ -185,8 +185,19 @@ static int max30100_buffer_postenable(struct > > > > iio_dev *indio_dev) > > > > > static int max30100_buffer_predisable(struct iio_dev *indio_dev) > > > > > { > > > > > struct max30100_data *data = iio_priv(indio_dev); > > > > > + int ret; > > > > > + > > > > > + /* > > > > > + * As stated in the comment in the read_raw() function, temperature > > > > > + * can only be acquired if the engine is running. As such the mutex > > > > > + * is used to make sure we do not power down while doing a > > > > temperature > > > > > + * reading. > > > > > + */ > > > > > + mutex_lock(&data->lock); > > > > > + ret = max30100_set_powermode(data, false); > > > > > + mutex_unlock(&data->lock); > > > > > > > > > > - return max30100_set_powermode(data, false); > > > > > + return ret; > > > > > } > > > > > > > > > > static const struct iio_buffer_setup_ops max30100_buffer_setup_ops > > = { > > > > > @@ -387,18 +398,17 @@ static int max30100_read_raw(struct iio_dev > > > > *indio_dev, > > > > > * Temperature reading can only be acquired while engine > > > > > * is running > > > > > */ > > > > > - mutex_lock(&indio_dev->mlock); > > > > > - > > > > > - if (!iio_buffer_enabled(indio_dev)) > > > > > + if (!iio_device_claim_direct_mode(indio_dev)) { > > > > > > > > I wonder if this line change here is really needed. I agree the whole > > > > construction looks like what iio_device_claim_direct_mode() does but in > > > > practice I don't see the point of acquiring any lock here if we just > > > > release it no matter what happens right after. > > > > > > > > > > I can see that this is odd (at the very least) but AFAIK, this is the only way > > > to safely infer if buffering is enabled or not. iio_buffer_enabled() has no > > > protection against someone concurrently enabling/disabling the buffer. > > > > Yes, but this is only relevant if you want to infer that the "buffers > > are enabled" and be sure that it cannot be otherwise during the next > > lines until you release the lock. Acquiring a lock, doing the if and > > then unconditionally releasing the lock, IMHO, does not make any sense > > (but I'm not a locking guru) because when you enter the else clause, > > you are not protected anyway, so in both cases all this is completely > > racy. > > > > Ahh crap, yes you are right... It is still racy since we can still try to read > the temperature with the device powered off. I'm not really sure how to > address this. One way could be to just use an internal control variable > to reflect the device power state (set/clear on the buffer callbacks) and > only use the local lock (completely ditching the call to > iio_device_claim_direct_mode())... I tend to prefer this option than the one below. I guess your implementation already prevents buffer_predisable() to run thanks to the local lock being held during the operation. Maybe we should just verify that buffers are enabled from within the local lock being held instead of just acquiring it for the get_temp() measure. It would probably solve the situation here. > Other options would be to have helpers for acquiring/releasing the lock > (I think this would defeat the idea of not abusing this lock at all) or have > A version iio_device_claim_direct_mode() that does not release the > lock in case buffering is enabled. Any preference? > > - Nuno Sá Thanks, Miquèl
On Tue, 2022-09-20 at 15:53 +0200, Miquel Raynal wrote: > Hi Nuno, > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 13:15:32 +0000: > > > > -----Original Message----- > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > Sent: Tuesday, September 20, 2022 2:56 PM > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > Cc: linux-arm-kernel@lists.infradead.org; > > > linux-rockchip@lists.infradead.org; > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > > > Hennerich, > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; > > > Kevin > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy <vz@mleia.com>; > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > > > Ardelean > > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; > > > Andriy > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo Chen > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans de > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > <jbrunet@baylibre.com>; > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen <lars@metafoo.de>; > > > Andy > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; > > > Baolin > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson Zhai > > > <orsonzhai@gmail.com> > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use > > > internal iio_dev > > > lock > > > > > > [External] > > > > > > Hi Nuno, > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 12:44:08 +0000: > > > > > > > > -----Original Message----- > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > Sent: Tuesday, September 20, 2022 2:23 PM > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > Cc: linux-arm-kernel@lists.infradead.org; linux- > > > rockchip@lists.infradead.org; > > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > > > Hennerich, > > > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; > > > > > Kevin > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy > > > > > <vz@mleia.com>; > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > > > Ardelean > > > > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; > > > Andriy > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo > > > > > Chen > > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans > > > > > de > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > <jbrunet@baylibre.com>; > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen > > > > > <lars@metafoo.de>; > > > Andy > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; > > > > > Baolin > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson > > > > > Zhai > > > > > <orsonzhai@gmail.com> > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use > > > > > internal > > > iio_dev > > > > > lock > > > > > > > > > > [External] > > > > > > > > > > Hi Nuno, > > > > > > > > > > > > > Hi Miquel, > > > > > > > > Thanks for reviewing... > > > > > > > > > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 +0200: > > > > > > > > > > > The pattern used in this device does not quite fit in the > > > > > > iio_device_claim_direct_mode() typical usage. In this case, > > > > > > iio_buffer_enabled() was being used not to prevent the raw > > > > > > access but > > > to > > > > > > allow it. Hence to get rid of the 'mlock' we need to: > > > > > > > > > > > > 1. Use iio_device_claim_direct_mode() to check if direct > > > > > > mode can be > > > > > > claimed and if we can return -EINVAL (as the original > > > > > > code); > > > > > > > > > > > > 2. Make sure that buffering is not disabled while doing a > > > > > > raw read. For > > > > > > that, we can make use of the local lock that already > > > > > > exists. > > > > > > > > > > > > While at it, fixed a minor coding style complain... > > > > > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > > > > --- > > > > > > drivers/iio/health/max30100.c | 24 +++++++++++++++++------ > > > > > > - > > > > > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > > > > > > > > > diff --git a/drivers/iio/health/max30100.c > > > b/drivers/iio/health/max30100.c > > > > > > index ad5717965223..aa494cad5df0 100644 > > > > > > --- a/drivers/iio/health/max30100.c > > > > > > +++ b/drivers/iio/health/max30100.c > > > > > > @@ -185,8 +185,19 @@ static int > > > > > > max30100_buffer_postenable(struct > > > > > iio_dev *indio_dev) > > > > > > static int max30100_buffer_predisable(struct iio_dev > > > > > > *indio_dev) > > > > > > { > > > > > > struct max30100_data *data = iio_priv(indio_dev); > > > > > > + int ret; > > > > > > + > > > > > > + /* > > > > > > + * As stated in the comment in the read_raw() > > > > > > function, temperature > > > > > > + * can only be acquired if the engine is running. > > > > > > As such the mutex > > > > > > + * is used to make sure we do not power down while > > > > > > doing a > > > > > temperature > > > > > > + * reading. > > > > > > + */ > > > > > > + mutex_lock(&data->lock); > > > > > > + ret = max30100_set_powermode(data, false); > > > > > > + mutex_unlock(&data->lock); > > > > > > > > > > > > - return max30100_set_powermode(data, false); > > > > > > + return ret; > > > > > > } > > > > > > > > > > > > static const struct iio_buffer_setup_ops > > > > > > max30100_buffer_setup_ops > > > = { > > > > > > @@ -387,18 +398,17 @@ static int max30100_read_raw(struct > > > > > > iio_dev > > > > > *indio_dev, > > > > > > * Temperature reading can only be acquired > > > > > > while engine > > > > > > * is running > > > > > > */ > > > > > > - mutex_lock(&indio_dev->mlock); > > > > > > - > > > > > > - if (!iio_buffer_enabled(indio_dev)) > > > > > > + if > > > > > > (!iio_device_claim_direct_mode(indio_dev)) { > > > > > > > > > > I wonder if this line change here is really needed. I agree > > > > > the whole > > > > > construction looks like what iio_device_claim_direct_mode() > > > > > does but in > > > > > practice I don't see the point of acquiring any lock here if > > > > > we just > > > > > release it no matter what happens right after. > > > > > > > > > > > > > I can see that this is odd (at the very least) but AFAIK, this > > > > is the only way > > > > to safely infer if buffering is enabled or not. > > > > iio_buffer_enabled() has no > > > > protection against someone concurrently enabling/disabling the > > > > buffer. > > > > > > Yes, but this is only relevant if you want to infer that the > > > "buffers > > > are enabled" and be sure that it cannot be otherwise during the > > > next > > > lines until you release the lock. Acquiring a lock, doing the if > > > and > > > then unconditionally releasing the lock, IMHO, does not make any > > > sense > > > (but I'm not a locking guru) because when you enter the else > > > clause, > > > you are not protected anyway, so in both cases all this is > > > completely > > > racy. > > > > > > > Ahh crap, yes you are right... It is still racy since we can still > > try to read > > the temperature with the device powered off. I'm not really sure > > how to > > address this. One way could be to just use an internal control > > variable > > to reflect the device power state (set/clear on the buffer > > callbacks) and > > only use the local lock (completely ditching the call to > > iio_device_claim_direct_mode())... > > I tend to prefer this option than the one below. > > I guess your implementation already prevents buffer_predisable() to > run > thanks to the local lock being held during the operation. Maybe we > should just verify that buffers are enabled from within the local > lock > being held instead of just acquiring it for the get_temp() measure. > It > would probably solve the situation here. > > Not sure if I understood... You mean something like: mutex_lock(&data->lock); if (!iio_buffer_enabled(indio_dev)) { ret = -EINVAL; } else { ret = max30100_get_temp(data, val); if (!ret) ret = IIO_VAL_INT; } mutex_unlock(&data->lock); If so, I think this is still racy since we release the lock after the predisable which means we could still detect the buffers as enabled (in the above block) and try to get_temp on a powered down device. Since we pretty much only care about the power state of the device (and we are using the buffering state to infer that AFAIU), I was thinking in something like: mutex_lock(&data->lock); if (!data->powered) { ret = -EINVAL; } else { ret = max30100_get_temp(data, val); if (!ret) ret = IIO_VAL_INT; } mutex_unlock(&data->lock); Then, in the predisable, something like I have but setting the flag to false and the opposite on the postenable... Naturally we could also just read the registers (and I actually tend to prefer it) instead of a new flag but I guess the flag is enough in this case. - Nuno Sá >
Hi Nuno, noname.nuno@gmail.com wrote on Tue, 20 Sep 2022 16:56:01 +0200: > On Tue, 2022-09-20 at 15:53 +0200, Miquel Raynal wrote: > > Hi Nuno, > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 13:15:32 +0000: > > > > > > -----Original Message----- > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > Sent: Tuesday, September 20, 2022 2:56 PM > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > Cc: linux-arm-kernel@lists.infradead.org; > > > > linux-rockchip@lists.infradead.org; > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > > > > Hennerich, > > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; > > > > Kevin > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy <vz@mleia.com>; > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > > > > Ardelean > > > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; > > > > Andriy > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo Chen > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans de > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > <jbrunet@baylibre.com>; > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen <lars@metafoo.de>; > > > > Andy > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; > > > > Baolin > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson Zhai > > > > <orsonzhai@gmail.com> > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use > > > > internal iio_dev > > > > lock > > > > > > > > [External] > > > > > > > > Hi Nuno, > > > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 12:44:08 +0000: > > > > > > > > > > -----Original Message----- > > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > > Sent: Tuesday, September 20, 2022 2:23 PM > > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > > Cc: linux-arm-kernel@lists.infradead.org; linux- > > > > rockchip@lists.infradead.org; > > > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > > > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > > > > Hennerich, > > > > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; > > > > > > Kevin > > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy > > > > > > <vz@mleia.com>; > > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > > > > Ardelean > > > > > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; > > > > Andriy > > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo > > > > > > Chen > > > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans > > > > > > de > > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > <jbrunet@baylibre.com>; > > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen > > > > > > <lars@metafoo.de>; > > > > Andy > > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > > > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; > > > > > > Baolin > > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson > > > > > > Zhai > > > > > > <orsonzhai@gmail.com> > > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use > > > > > > internal > > > > iio_dev > > > > > > lock > > > > > > > > > > > > [External] > > > > > > > > > > > > Hi Nuno, > > > > > > > > > > > > > > > > Hi Miquel, > > > > > > > > > > Thanks for reviewing... > > > > > > > > > > > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 +0200: > > > > > > > > > > > > > The pattern used in this device does not quite fit in the > > > > > > > iio_device_claim_direct_mode() typical usage. In this case, > > > > > > > iio_buffer_enabled() was being used not to prevent the raw > > > > > > > access but > > > > to > > > > > > > allow it. Hence to get rid of the 'mlock' we need to: > > > > > > > > > > > > > > 1. Use iio_device_claim_direct_mode() to check if direct > > > > > > > mode can be > > > > > > > claimed and if we can return -EINVAL (as the original > > > > > > > code); > > > > > > > > > > > > > > 2. Make sure that buffering is not disabled while doing a > > > > > > > raw read. For > > > > > > > that, we can make use of the local lock that already > > > > > > > exists. > > > > > > > > > > > > > > While at it, fixed a minor coding style complain... > > > > > > > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > > > > > --- > > > > > > > drivers/iio/health/max30100.c | 24 +++++++++++++++++------ > > > > > > > - > > > > > > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > > > > > > > > > > > diff --git a/drivers/iio/health/max30100.c > > > > b/drivers/iio/health/max30100.c > > > > > > > index ad5717965223..aa494cad5df0 100644 > > > > > > > --- a/drivers/iio/health/max30100.c > > > > > > > +++ b/drivers/iio/health/max30100.c > > > > > > > @@ -185,8 +185,19 @@ static int > > > > > > > max30100_buffer_postenable(struct > > > > > > iio_dev *indio_dev) > > > > > > > static int max30100_buffer_predisable(struct iio_dev > > > > > > > *indio_dev) > > > > > > > { > > > > > > > struct max30100_data *data = iio_priv(indio_dev); > > > > > > > + int ret; > > > > > > > + > > > > > > > + /* > > > > > > > + * As stated in the comment in the read_raw() > > > > > > > function, temperature > > > > > > > + * can only be acquired if the engine is running. > > > > > > > As such the mutex > > > > > > > + * is used to make sure we do not power down while > > > > > > > doing a > > > > > > temperature > > > > > > > + * reading. > > > > > > > + */ > > > > > > > + mutex_lock(&data->lock); > > > > > > > + ret = max30100_set_powermode(data, false); > > > > > > > + mutex_unlock(&data->lock); > > > > > > > > > > > > > > - return max30100_set_powermode(data, false); > > > > > > > + return ret; > > > > > > > } > > > > > > > > > > > > > > static const struct iio_buffer_setup_ops > > > > > > > max30100_buffer_setup_ops > > > > = { > > > > > > > @@ -387,18 +398,17 @@ static int max30100_read_raw(struct > > > > > > > iio_dev > > > > > > *indio_dev, > > > > > > > * Temperature reading can only be acquired > > > > > > > while engine > > > > > > > * is running > > > > > > > */ > > > > > > > - mutex_lock(&indio_dev->mlock); > > > > > > > - > > > > > > > - if (!iio_buffer_enabled(indio_dev)) > > > > > > > + if > > > > > > > (!iio_device_claim_direct_mode(indio_dev)) { > > > > > > > > > > > > I wonder if this line change here is really needed. I agree > > > > > > the whole > > > > > > construction looks like what iio_device_claim_direct_mode() > > > > > > does but in > > > > > > practice I don't see the point of acquiring any lock here if > > > > > > we just > > > > > > release it no matter what happens right after. > > > > > > > > > > > > > > > > I can see that this is odd (at the very least) but AFAIK, this > > > > > is the only way > > > > > to safely infer if buffering is enabled or not. > > > > > iio_buffer_enabled() has no > > > > > protection against someone concurrently enabling/disabling the > > > > > buffer. > > > > > > > > Yes, but this is only relevant if you want to infer that the > > > > "buffers > > > > are enabled" and be sure that it cannot be otherwise during the > > > > next > > > > lines until you release the lock. Acquiring a lock, doing the if > > > > and > > > > then unconditionally releasing the lock, IMHO, does not make any > > > > sense > > > > (but I'm not a locking guru) because when you enter the else > > > > clause, > > > > you are not protected anyway, so in both cases all this is > > > > completely > > > > racy. > > > > > > > > > > Ahh crap, yes you are right... It is still racy since we can still > > > try to read > > > the temperature with the device powered off. I'm not really sure > > > how to > > > address this. One way could be to just use an internal control > > > variable > > > to reflect the device power state (set/clear on the buffer > > > callbacks) and > > > only use the local lock (completely ditching the call to > > > iio_device_claim_direct_mode())... > > > > I tend to prefer this option than the one below. > > > > I guess your implementation already prevents buffer_predisable() to > > run > > thanks to the local lock being held during the operation. Maybe we > > should just verify that buffers are enabled from within the local > > lock > > being held instead of just acquiring it for the get_temp() measure. > > It > > would probably solve the situation here. > > > > Not sure if I understood... You mean something like: > > mutex_lock(&data->lock); > if (!iio_buffer_enabled(indio_dev)) { > ret = -EINVAL; > } else { > ret = max30100_get_temp(data, val); > if (!ret) > ret = IIO_VAL_INT; > > } > mutex_unlock(&data->lock); > > If so, I think this is still racy since we release the lock after the > predisable which means we could still detect the buffers as enabled (in > the above block) and try to get_temp on a powered down device. True. > > Since we pretty much only care about the power state of the device (and > we are using the buffering state to infer that AFAIU), I was thinking > in something like: > > > mutex_lock(&data->lock); > if (!data->powered) { > ret = -EINVAL; > } else { > ret = max30100_get_temp(data, val); > if (!ret) > ret = IIO_VAL_INT; > > } > mutex_unlock(&data->lock); LGTM. > > Then, in the predisable, something like I have but setting the flag to > false and the opposite on the postenable... Naturally we could also > just read the registers (and I actually tend to prefer it) instead of a > new flag but I guess the flag is enough in this case. > > - Nuno Sá > > Thanks, Miquèl
On Tue, 20 Sep 2022 17:10:33 +0200 Miquel Raynal <miquel.raynal@bootlin.com> wrote: > Hi Nuno, > > noname.nuno@gmail.com wrote on Tue, 20 Sep 2022 16:56:01 +0200: > > > On Tue, 2022-09-20 at 15:53 +0200, Miquel Raynal wrote: > > > Hi Nuno, > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 13:15:32 +0000: > > > > > > > > -----Original Message----- > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > Sent: Tuesday, September 20, 2022 2:56 PM > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > Cc: linux-arm-kernel@lists.infradead.org; > > > > > linux-rockchip@lists.infradead.org; > > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > > > > > Hennerich, > > > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; > > > > > Kevin > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy <vz@mleia.com>; > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > > > > > Ardelean > > > > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; > > > > > Andriy > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo Chen > > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans de > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > > <jbrunet@baylibre.com>; > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen <lars@metafoo.de>; > > > > > Andy > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; > > > > > Baolin > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson Zhai > > > > > <orsonzhai@gmail.com> > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use > > > > > internal iio_dev > > > > > lock > > > > > > > > > > [External] > > > > > > > > > > Hi Nuno, > > > > > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 12:44:08 +0000: > > > > > > > > > > > > -----Original Message----- > > > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > > > Sent: Tuesday, September 20, 2022 2:23 PM > > > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > > > Cc: linux-arm-kernel@lists.infradead.org; linux- > > > > > rockchip@lists.infradead.org; > > > > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; linux- > > > > > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > > > > > Hennerich, > > > > > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > > > <s.hauer@pengutronix.de>; Cixi Geng <cixi.geng1@unisoc.com>; > > > > > > > Kevin > > > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy > > > > > > > <vz@mleia.com>; > > > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > > > > > Ardelean > > > > > > > <aardelean@deviqon.com>; Fabio Estevam <festevam@gmail.com>; > > > > > Andriy > > > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo > > > > > > > Chen > > > > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans > > > > > > > de > > > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > > <jbrunet@baylibre.com>; > > > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen > > > > > > > <lars@metafoo.de>; > > > > > Andy > > > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > > > > > <jic23@kernel.org>; Neil Armstrong <narmstrong@baylibre.com>; > > > > > > > Baolin > > > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson > > > > > > > Zhai > > > > > > > <orsonzhai@gmail.com> > > > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not use > > > > > > > internal > > > > > iio_dev > > > > > > > lock > > > > > > > > > > > > > > [External] > > > > > > > > > > > > > > Hi Nuno, > > > > > > > > > > > > > > > > > > > Hi Miquel, > > > > > > > > > > > > Thanks for reviewing... > > > > > > > > > > > > > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 +0200: > > > > > > > > > > > > > > > The pattern used in this device does not quite fit in the > > > > > > > > iio_device_claim_direct_mode() typical usage. In this case, > > > > > > > > iio_buffer_enabled() was being used not to prevent the raw > > > > > > > > access but > > > > > to > > > > > > > > allow it. Hence to get rid of the 'mlock' we need to: > > > > > > > > > > > > > > > > 1. Use iio_device_claim_direct_mode() to check if direct > > > > > > > > mode can be > > > > > > > > claimed and if we can return -EINVAL (as the original > > > > > > > > code); > > > > > > > > > > > > > > > > 2. Make sure that buffering is not disabled while doing a > > > > > > > > raw read. For > > > > > > > > that, we can make use of the local lock that already > > > > > > > > exists. > > > > > > > > > > > > > > > > While at it, fixed a minor coding style complain... > > > > > > > > > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > > > > > > --- > > > > > > > > drivers/iio/health/max30100.c | 24 +++++++++++++++++------ > > > > > > > > - > > > > > > > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > > > > > > > > > > > > > diff --git a/drivers/iio/health/max30100.c > > > > > b/drivers/iio/health/max30100.c > > > > > > > > index ad5717965223..aa494cad5df0 100644 > > > > > > > > --- a/drivers/iio/health/max30100.c > > > > > > > > +++ b/drivers/iio/health/max30100.c > > > > > > > > @@ -185,8 +185,19 @@ static int > > > > > > > > max30100_buffer_postenable(struct > > > > > > > iio_dev *indio_dev) > > > > > > > > static int max30100_buffer_predisable(struct iio_dev > > > > > > > > *indio_dev) > > > > > > > > { > > > > > > > > struct max30100_data *data = iio_priv(indio_dev); > > > > > > > > + int ret; > > > > > > > > + > > > > > > > > + /* > > > > > > > > + * As stated in the comment in the read_raw() > > > > > > > > function, temperature > > > > > > > > + * can only be acquired if the engine is running. > > > > > > > > As such the mutex > > > > > > > > + * is used to make sure we do not power down while > > > > > > > > doing a > > > > > > > temperature > > > > > > > > + * reading. > > > > > > > > + */ > > > > > > > > + mutex_lock(&data->lock); > > > > > > > > + ret = max30100_set_powermode(data, false); > > > > > > > > + mutex_unlock(&data->lock); > > > > > > > > > > > > > > > > - return max30100_set_powermode(data, false); > > > > > > > > + return ret; > > > > > > > > } > > > > > > > > > > > > > > > > static const struct iio_buffer_setup_ops > > > > > > > > max30100_buffer_setup_ops > > > > > = { > > > > > > > > @@ -387,18 +398,17 @@ static int max30100_read_raw(struct > > > > > > > > iio_dev > > > > > > > *indio_dev, > > > > > > > > * Temperature reading can only be acquired > > > > > > > > while engine > > > > > > > > * is running > > > > > > > > */ > > > > > > > > - mutex_lock(&indio_dev->mlock); > > > > > > > > - > > > > > > > > - if (!iio_buffer_enabled(indio_dev)) > > > > > > > > + if > > > > > > > > (!iio_device_claim_direct_mode(indio_dev)) { > > > > > > > > > > > > > > I wonder if this line change here is really needed. I agree > > > > > > > the whole > > > > > > > construction looks like what iio_device_claim_direct_mode() > > > > > > > does but in > > > > > > > practice I don't see the point of acquiring any lock here if > > > > > > > we just > > > > > > > release it no matter what happens right after. > > > > > > > > > > > > > > > > > > > I can see that this is odd (at the very least) but AFAIK, this > > > > > > is the only way > > > > > > to safely infer if buffering is enabled or not. > > > > > > iio_buffer_enabled() has no > > > > > > protection against someone concurrently enabling/disabling the > > > > > > buffer. > > > > > > > > > > Yes, but this is only relevant if you want to infer that the > > > > > "buffers > > > > > are enabled" and be sure that it cannot be otherwise during the > > > > > next > > > > > lines until you release the lock. Acquiring a lock, doing the if > > > > > and > > > > > then unconditionally releasing the lock, IMHO, does not make any > > > > > sense > > > > > (but I'm not a locking guru) because when you enter the else > > > > > clause, > > > > > you are not protected anyway, so in both cases all this is > > > > > completely > > > > > racy. > > > > > > > > > > > > > Ahh crap, yes you are right... It is still racy since we can still > > > > try to read > > > > the temperature with the device powered off. I'm not really sure > > > > how to > > > > address this. One way could be to just use an internal control > > > > variable > > > > to reflect the device power state (set/clear on the buffer > > > > callbacks) and > > > > only use the local lock (completely ditching the call to > > > > iio_device_claim_direct_mode())... > > > > > > I tend to prefer this option than the one below. > > > > > > I guess your implementation already prevents buffer_predisable() to > > > run > > > thanks to the local lock being held during the operation. Maybe we > > > should just verify that buffers are enabled from within the local > > > lock > > > being held instead of just acquiring it for the get_temp() measure. > > > It > > > would probably solve the situation here. > > > > > > Not sure if I understood... You mean something like: > > > > mutex_lock(&data->lock); > > if (!iio_buffer_enabled(indio_dev)) { > > ret = -EINVAL; > > } else { > > ret = max30100_get_temp(data, val); > > if (!ret) > > ret = IIO_VAL_INT; > > > > } > > mutex_unlock(&data->lock); > > > > If so, I think this is still racy since we release the lock after the > > predisable which means we could still detect the buffers as enabled (in > > the above block) and try to get_temp on a powered down device. > > True. > > > > > Since we pretty much only care about the power state of the device (and > > we are using the buffering state to infer that AFAIU), I was thinking > > in something like: > > > > > > mutex_lock(&data->lock); > > if (!data->powered) { > > ret = -EINVAL; > > } else { > > ret = max30100_get_temp(data, val); > > if (!ret) > > ret = IIO_VAL_INT; > > > > } > > mutex_unlock(&data->lock); > > LGTM. A reference counted power up flag would probably work as we'd want to disable power only when the reference count goes to 0. Note all checks of that flag would need to be done under the lock as well. As an alternative... Whilst it is a serious oddity, how about flipping the logic and having an iio_device_claim_buffered_mode() that takes mlock and holds it only if we are in buffered mode - then holds it until matching release? Now, I've only done a superficial audit of the buffer removal paths to check they hold the lock before we call predisable() but it looks like they do - so this should work. Just wanted to muddy the waters :) > > > > > Then, in the predisable, something like I have but setting the flag to > > false and the opposite on the postenable... Naturally we could also > > just read the registers (and I actually tend to prefer it) instead of a > > new flag but I guess the flag is enough in this case. > > > > - Nuno Sá > > > > > > Thanks, > Miquèl
On Sat, 2022-09-24 at 16:53 +0100, Jonathan Cameron wrote: > On Tue, 20 Sep 2022 17:10:33 +0200 > Miquel Raynal <miquel.raynal@bootlin.com> wrote: > > > Hi Nuno, > > > > noname.nuno@gmail.com wrote on Tue, 20 Sep 2022 16:56:01 +0200: > > > > > On Tue, 2022-09-20 at 15:53 +0200, Miquel Raynal wrote: > > > > Hi Nuno, > > > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 13:15:32 +0000: > > > > > > > > > > -----Original Message----- > > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > > Sent: Tuesday, September 20, 2022 2:56 PM > > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > > Cc: linux-arm-kernel@lists.infradead.org; > > > > > > linux-rockchip@lists.infradead.org; > > > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; > > > > > > linux- > > > > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > > > > > > Hennerich, > > > > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > > <s.hauer@pengutronix.de>; Cixi Geng > > > > > > <cixi.geng1@unisoc.com>; > > > > > > Kevin > > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy > > > > > > <vz@mleia.com>; > > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > > > > > > Ardelean > > > > > > <aardelean@deviqon.com>; Fabio Estevam > > > > > > <festevam@gmail.com>; > > > > > > Andriy > > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo > > > > > > Chen > > > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans > > > > > > de > > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > > > <jbrunet@baylibre.com>; > > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen > > > > > > <lars@metafoo.de>; > > > > > > Andy > > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > > > > <jic23@kernel.org>; Neil Armstrong > > > > > > <narmstrong@baylibre.com>; > > > > > > Baolin > > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson > > > > > > Zhai > > > > > > <orsonzhai@gmail.com> > > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not > > > > > > use > > > > > > internal iio_dev > > > > > > lock > > > > > > > > > > > > [External] > > > > > > > > > > > > Hi Nuno, > > > > > > > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 12:44:08 > > > > > > +0000: > > > > > > > > > > > > > > -----Original Message----- > > > > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > > > > Sent: Tuesday, September 20, 2022 2:23 PM > > > > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > > > > Cc: linux-arm-kernel@lists.infradead.org; linux- > > > > > > rockchip@lists.infradead.org; > > > > > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; > > > > > > > > linux- > > > > > > > > iio@vger.kernel.org; Chunyan Zhang > > > > > > > > <zhang.lyra@gmail.com>; > > > > > > Hennerich, > > > > > > > > Michael <Michael.Hennerich@analog.com>; Martin > > > > > > > > Blumenstingl > > > > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > > > > <s.hauer@pengutronix.de>; Cixi Geng > > > > > > > > <cixi.geng1@unisoc.com>; > > > > > > > > Kevin > > > > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy > > > > > > > > <vz@mleia.com>; > > > > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; > > > > > > > > Alexandru > > > > > > Ardelean > > > > > > > > <aardelean@deviqon.com>; Fabio Estevam > > > > > > > > <festevam@gmail.com>; > > > > > > Andriy > > > > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; > > > > > > > > Haibo > > > > > > > > Chen > > > > > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; > > > > > > > > Hans > > > > > > > > de > > > > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > > > <jbrunet@baylibre.com>; > > > > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen > > > > > > > > <lars@metafoo.de>; > > > > > > Andy > > > > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan > > > > > > > > Cameron > > > > > > > > <jic23@kernel.org>; Neil Armstrong > > > > > > > > <narmstrong@baylibre.com>; > > > > > > > > Baolin > > > > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; > > > > > > > > Orson > > > > > > > > Zhai > > > > > > > > <orsonzhai@gmail.com> > > > > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do > > > > > > > > not use > > > > > > > > internal > > > > > > iio_dev > > > > > > > > lock > > > > > > > > > > > > > > > > [External] > > > > > > > > > > > > > > > > Hi Nuno, > > > > > > > > > > > > > > > > > > > > > > Hi Miquel, > > > > > > > > > > > > > > Thanks for reviewing... > > > > > > > > > > > > > > > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 > > > > > > > > +0200: > > > > > > > > > > > > > > > > > The pattern used in this device does not quite fit in > > > > > > > > > the > > > > > > > > > iio_device_claim_direct_mode() typical usage. In this > > > > > > > > > case, > > > > > > > > > iio_buffer_enabled() was being used not to prevent > > > > > > > > > the raw > > > > > > > > > access but > > > > > > to > > > > > > > > > allow it. Hence to get rid of the 'mlock' we need to: > > > > > > > > > > > > > > > > > > 1. Use iio_device_claim_direct_mode() to check if > > > > > > > > > direct > > > > > > > > > mode can be > > > > > > > > > claimed and if we can return -EINVAL (as the original > > > > > > > > > code); > > > > > > > > > > > > > > > > > > 2. Make sure that buffering is not disabled while > > > > > > > > > doing a > > > > > > > > > raw read. For > > > > > > > > > that, we can make use of the local lock that already > > > > > > > > > exists. > > > > > > > > > > > > > > > > > > While at it, fixed a minor coding style complain... > > > > > > > > > > > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > > > > > > > --- > > > > > > > > > drivers/iio/health/max30100.c | 24 > > > > > > > > > +++++++++++++++++------ > > > > > > > > > - > > > > > > > > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > > > > > > > > > > > > > > > diff --git a/drivers/iio/health/max30100.c > > > > > > b/drivers/iio/health/max30100.c > > > > > > > > > index ad5717965223..aa494cad5df0 100644 > > > > > > > > > --- a/drivers/iio/health/max30100.c > > > > > > > > > +++ b/drivers/iio/health/max30100.c > > > > > > > > > @@ -185,8 +185,19 @@ static int > > > > > > > > > max30100_buffer_postenable(struct > > > > > > > > iio_dev *indio_dev) > > > > > > > > > static int max30100_buffer_predisable(struct iio_dev > > > > > > > > > *indio_dev) > > > > > > > > > { > > > > > > > > > struct max30100_data *data = > > > > > > > > > iio_priv(indio_dev); > > > > > > > > > + int ret; > > > > > > > > > + > > > > > > > > > + /* > > > > > > > > > + * As stated in the comment in the read_raw() > > > > > > > > > function, temperature > > > > > > > > > + * can only be acquired if the engine is > > > > > > > > > running. > > > > > > > > > As such the mutex > > > > > > > > > + * is used to make sure we do not power down > > > > > > > > > while > > > > > > > > > doing a > > > > > > > > temperature > > > > > > > > > + * reading. > > > > > > > > > + */ > > > > > > > > > + mutex_lock(&data->lock); > > > > > > > > > + ret = max30100_set_powermode(data, false); > > > > > > > > > + mutex_unlock(&data->lock); > > > > > > > > > > > > > > > > > > - return max30100_set_powermode(data, false); > > > > > > > > > + return ret; > > > > > > > > > } > > > > > > > > > > > > > > > > > > static const struct iio_buffer_setup_ops > > > > > > > > > max30100_buffer_setup_ops > > > > > > = { > > > > > > > > > @@ -387,18 +398,17 @@ static int > > > > > > > > > max30100_read_raw(struct > > > > > > > > > iio_dev > > > > > > > > *indio_dev, > > > > > > > > > * Temperature reading can only be > > > > > > > > > acquired > > > > > > > > > while engine > > > > > > > > > * is running > > > > > > > > > */ > > > > > > > > > - mutex_lock(&indio_dev->mlock); > > > > > > > > > - > > > > > > > > > - if (!iio_buffer_enabled(indio_dev)) > > > > > > > > > + if > > > > > > > > > (!iio_device_claim_direct_mode(indio_dev)) { > > > > > > > > > > > > > > > > I wonder if this line change here is really needed. I > > > > > > > > agree > > > > > > > > the whole > > > > > > > > construction looks like what > > > > > > > > iio_device_claim_direct_mode() > > > > > > > > does but in > > > > > > > > practice I don't see the point of acquiring any lock > > > > > > > > here if > > > > > > > > we just > > > > > > > > release it no matter what happens right after. > > > > > > > > > > > > > > > > > > > > > > I can see that this is odd (at the very least) but AFAIK, > > > > > > > this > > > > > > > is the only way > > > > > > > to safely infer if buffering is enabled or not. > > > > > > > iio_buffer_enabled() has no > > > > > > > protection against someone concurrently > > > > > > > enabling/disabling the > > > > > > > buffer. > > > > > > > > > > > > Yes, but this is only relevant if you want to infer that > > > > > > the > > > > > > "buffers > > > > > > are enabled" and be sure that it cannot be otherwise during > > > > > > the > > > > > > next > > > > > > lines until you release the lock. Acquiring a lock, doing > > > > > > the if > > > > > > and > > > > > > then unconditionally releasing the lock, IMHO, does not > > > > > > make any > > > > > > sense > > > > > > (but I'm not a locking guru) because when you enter the > > > > > > else > > > > > > clause, > > > > > > you are not protected anyway, so in both cases all this is > > > > > > completely > > > > > > racy. > > > > > > > > > > > > > > > > Ahh crap, yes you are right... It is still racy since we can > > > > > still > > > > > try to read > > > > > the temperature with the device powered off. I'm not really > > > > > sure > > > > > how to > > > > > address this. One way could be to just use an internal > > > > > control > > > > > variable > > > > > to reflect the device power state (set/clear on the buffer > > > > > callbacks) and > > > > > only use the local lock (completely ditching the call to > > > > > iio_device_claim_direct_mode())... > > > > > > > > I tend to prefer this option than the one below. > > > > > > > > I guess your implementation already prevents > > > > buffer_predisable() to > > > > run > > > > thanks to the local lock being held during the operation. Maybe > > > > we > > > > should just verify that buffers are enabled from within the > > > > local > > > > lock > > > > being held instead of just acquiring it for the get_temp() > > > > measure. > > > > It > > > > would probably solve the situation here. > > > > > > > > Not sure if I understood... You mean something like: > > > > > > mutex_lock(&data->lock); > > > if (!iio_buffer_enabled(indio_dev)) { > > > ret = -EINVAL; > > > } else { > > > ret = max30100_get_temp(data, val); > > > if (!ret) > > > ret = IIO_VAL_INT; > > > > > > } > > > mutex_unlock(&data->lock); > > > > > > If so, I think this is still racy since we release the lock after > > > the > > > predisable which means we could still detect the buffers as > > > enabled (in > > > the above block) and try to get_temp on a powered down device. > > > > True. > > > > > > > > Since we pretty much only care about the power state of the > > > device (and > > > we are using the buffering state to infer that AFAIU), I was > > > thinking > > > in something like: > > > > > > > > > mutex_lock(&data->lock); > > > if (!data->powered) { > > > ret = -EINVAL; > > > } else { > > > ret = max30100_get_temp(data, val); > > > if (!ret) > > > ret = IIO_VAL_INT; > > > > > > } > > > mutex_unlock(&data->lock); > > > > LGTM. > > A reference counted power up flag would probably work as we'd want to > disable > power only when the reference count goes to 0. Note all checks of > that flag > would need to be done under the lock as well. > Is there any way to enable a buffer more than once? Otherwise I'm not sure we really need a refcount... Any ways, your below approach looks good to me and surely easier. > As an alternative... > > Whilst it is a serious oddity, how about flipping the logic and > having > an iio_device_claim_buffered_mode() that takes mlock and holds it > only > if we are in buffered mode - then holds it until matching release? > This goes along with one of my suggestions: "A version iio_device_claim_direct_mode() that does not release the lock in case buffering is enabled." You just gave it a name (and one that I would not ever remember)... > Now, I've only done a superficial audit of the buffer removal paths > to check they hold the lock before we call predisable() but it looks Otherwise I guess we would have to fix it :) - Nuno Sá
On Mon, 26 Sep 2022 12:06:13 +0200 Nuno Sá <noname.nuno@gmail.com> wrote: > On Sat, 2022-09-24 at 16:53 +0100, Jonathan Cameron wrote: > > On Tue, 20 Sep 2022 17:10:33 +0200 > > Miquel Raynal <miquel.raynal@bootlin.com> wrote: > > > > > Hi Nuno, > > > > > > noname.nuno@gmail.com wrote on Tue, 20 Sep 2022 16:56:01 +0200: > > > > > > > On Tue, 2022-09-20 at 15:53 +0200, Miquel Raynal wrote: > > > > > Hi Nuno, > > > > > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 13:15:32 +0000: > > > > > > > > > > > > -----Original Message----- > > > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > > > Sent: Tuesday, September 20, 2022 2:56 PM > > > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > > > Cc: linux-arm-kernel@lists.infradead.org; > > > > > > > linux-rockchip@lists.infradead.org; > > > > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; > > > > > > > linux- > > > > > > > iio@vger.kernel.org; Chunyan Zhang <zhang.lyra@gmail.com>; > > > > > > > Hennerich, > > > > > > > Michael <Michael.Hennerich@analog.com>; Martin Blumenstingl > > > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > > > <s.hauer@pengutronix.de>; Cixi Geng > > > > > > > <cixi.geng1@unisoc.com>; > > > > > > > Kevin > > > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy > > > > > > > <vz@mleia.com>; > > > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; Alexandru > > > > > > > Ardelean > > > > > > > <aardelean@deviqon.com>; Fabio Estevam > > > > > > > <festevam@gmail.com>; > > > > > > > Andriy > > > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; Haibo > > > > > > > Chen > > > > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; Hans > > > > > > > de > > > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > > > > <jbrunet@baylibre.com>; > > > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen > > > > > > > <lars@metafoo.de>; > > > > > > > Andy > > > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan Cameron > > > > > > > <jic23@kernel.org>; Neil Armstrong > > > > > > > <narmstrong@baylibre.com>; > > > > > > > Baolin > > > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; Orson > > > > > > > Zhai > > > > > > > <orsonzhai@gmail.com> > > > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do not > > > > > > > use > > > > > > > internal iio_dev > > > > > > > lock > > > > > > > > > > > > > > [External] > > > > > > > > > > > > > > Hi Nuno, > > > > > > > > > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 12:44:08 > > > > > > > +0000: > > > > > > > > > > > > > > > > -----Original Message----- > > > > > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > > > > > Sent: Tuesday, September 20, 2022 2:23 PM > > > > > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > > > > > Cc: linux-arm-kernel@lists.infradead.org; linux- > > > > > > > rockchip@lists.infradead.org; > > > > > > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; > > > > > > > > > linux- > > > > > > > > > iio@vger.kernel.org; Chunyan Zhang > > > > > > > > > <zhang.lyra@gmail.com>; > > > > > > > Hennerich, > > > > > > > > > Michael <Michael.Hennerich@analog.com>; Martin > > > > > > > > > Blumenstingl > > > > > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > > > > > <s.hauer@pengutronix.de>; Cixi Geng > > > > > > > > > <cixi.geng1@unisoc.com>; > > > > > > > > > Kevin > > > > > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy > > > > > > > > > <vz@mleia.com>; > > > > > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; > > > > > > > > > Alexandru > > > > > > > Ardelean > > > > > > > > > <aardelean@deviqon.com>; Fabio Estevam > > > > > > > > > <festevam@gmail.com>; > > > > > > > Andriy > > > > > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; > > > > > > > > > Haibo > > > > > > > > > Chen > > > > > > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; > > > > > > > > > Hans > > > > > > > > > de > > > > > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > > > > <jbrunet@baylibre.com>; > > > > > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen > > > > > > > > > <lars@metafoo.de>; > > > > > > > Andy > > > > > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan > > > > > > > > > Cameron > > > > > > > > > <jic23@kernel.org>; Neil Armstrong > > > > > > > > > <narmstrong@baylibre.com>; > > > > > > > > > Baolin > > > > > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; > > > > > > > > > Orson > > > > > > > > > Zhai > > > > > > > > > <orsonzhai@gmail.com> > > > > > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do > > > > > > > > > not use > > > > > > > > > internal > > > > > > > iio_dev > > > > > > > > > lock > > > > > > > > > > > > > > > > > > [External] > > > > > > > > > > > > > > > > > > Hi Nuno, > > > > > > > > > > > > > > > > > > > > > > > > > Hi Miquel, > > > > > > > > > > > > > > > > Thanks for reviewing... > > > > > > > > > > > > > > > > > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 13:28:19 > > > > > > > > > +0200: > > > > > > > > > > > > > > > > > > > The pattern used in this device does not quite fit in > > > > > > > > > > the > > > > > > > > > > iio_device_claim_direct_mode() typical usage. In this > > > > > > > > > > case, > > > > > > > > > > iio_buffer_enabled() was being used not to prevent > > > > > > > > > > the raw > > > > > > > > > > access but > > > > > > > to > > > > > > > > > > allow it. Hence to get rid of the 'mlock' we need to: > > > > > > > > > > > > > > > > > > > > 1. Use iio_device_claim_direct_mode() to check if > > > > > > > > > > direct > > > > > > > > > > mode can be > > > > > > > > > > claimed and if we can return -EINVAL (as the original > > > > > > > > > > code); > > > > > > > > > > > > > > > > > > > > 2. Make sure that buffering is not disabled while > > > > > > > > > > doing a > > > > > > > > > > raw read. For > > > > > > > > > > that, we can make use of the local lock that already > > > > > > > > > > exists. > > > > > > > > > > > > > > > > > > > > While at it, fixed a minor coding style complain... > > > > > > > > > > > > > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > > > > > > > > --- > > > > > > > > > > drivers/iio/health/max30100.c | 24 > > > > > > > > > > +++++++++++++++++------ > > > > > > > > > > - > > > > > > > > > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > > > > > > > > > > > > > > > > > diff --git a/drivers/iio/health/max30100.c > > > > > > > b/drivers/iio/health/max30100.c > > > > > > > > > > index ad5717965223..aa494cad5df0 100644 > > > > > > > > > > --- a/drivers/iio/health/max30100.c > > > > > > > > > > +++ b/drivers/iio/health/max30100.c > > > > > > > > > > @@ -185,8 +185,19 @@ static int > > > > > > > > > > max30100_buffer_postenable(struct > > > > > > > > > iio_dev *indio_dev) > > > > > > > > > > static int max30100_buffer_predisable(struct iio_dev > > > > > > > > > > *indio_dev) > > > > > > > > > > { > > > > > > > > > > struct max30100_data *data = > > > > > > > > > > iio_priv(indio_dev); > > > > > > > > > > + int ret; > > > > > > > > > > + > > > > > > > > > > + /* > > > > > > > > > > + * As stated in the comment in the read_raw() > > > > > > > > > > function, temperature > > > > > > > > > > + * can only be acquired if the engine is > > > > > > > > > > running. > > > > > > > > > > As such the mutex > > > > > > > > > > + * is used to make sure we do not power down > > > > > > > > > > while > > > > > > > > > > doing a > > > > > > > > > temperature > > > > > > > > > > + * reading. > > > > > > > > > > + */ > > > > > > > > > > + mutex_lock(&data->lock); > > > > > > > > > > + ret = max30100_set_powermode(data, false); > > > > > > > > > > + mutex_unlock(&data->lock); > > > > > > > > > > > > > > > > > > > > - return max30100_set_powermode(data, false); > > > > > > > > > > + return ret; > > > > > > > > > > } > > > > > > > > > > > > > > > > > > > > static const struct iio_buffer_setup_ops > > > > > > > > > > max30100_buffer_setup_ops > > > > > > > = { > > > > > > > > > > @@ -387,18 +398,17 @@ static int > > > > > > > > > > max30100_read_raw(struct > > > > > > > > > > iio_dev > > > > > > > > > *indio_dev, > > > > > > > > > > * Temperature reading can only be > > > > > > > > > > acquired > > > > > > > > > > while engine > > > > > > > > > > * is running > > > > > > > > > > */ > > > > > > > > > > - mutex_lock(&indio_dev->mlock); > > > > > > > > > > - > > > > > > > > > > - if (!iio_buffer_enabled(indio_dev)) > > > > > > > > > > + if > > > > > > > > > > (!iio_device_claim_direct_mode(indio_dev)) { > > > > > > > > > > > > > > > > > > I wonder if this line change here is really needed. I > > > > > > > > > agree > > > > > > > > > the whole > > > > > > > > > construction looks like what > > > > > > > > > iio_device_claim_direct_mode() > > > > > > > > > does but in > > > > > > > > > practice I don't see the point of acquiring any lock > > > > > > > > > here if > > > > > > > > > we just > > > > > > > > > release it no matter what happens right after. > > > > > > > > > > > > > > > > > > > > > > > > > I can see that this is odd (at the very least) but AFAIK, > > > > > > > > this > > > > > > > > is the only way > > > > > > > > to safely infer if buffering is enabled or not. > > > > > > > > iio_buffer_enabled() has no > > > > > > > > protection against someone concurrently > > > > > > > > enabling/disabling the > > > > > > > > buffer. > > > > > > > > > > > > > > Yes, but this is only relevant if you want to infer that > > > > > > > the > > > > > > > "buffers > > > > > > > are enabled" and be sure that it cannot be otherwise during > > > > > > > the > > > > > > > next > > > > > > > lines until you release the lock. Acquiring a lock, doing > > > > > > > the if > > > > > > > and > > > > > > > then unconditionally releasing the lock, IMHO, does not > > > > > > > make any > > > > > > > sense > > > > > > > (but I'm not a locking guru) because when you enter the > > > > > > > else > > > > > > > clause, > > > > > > > you are not protected anyway, so in both cases all this is > > > > > > > completely > > > > > > > racy. > > > > > > > > > > > > > > > > > > > Ahh crap, yes you are right... It is still racy since we can > > > > > > still > > > > > > try to read > > > > > > the temperature with the device powered off. I'm not really > > > > > > sure > > > > > > how to > > > > > > address this. One way could be to just use an internal > > > > > > control > > > > > > variable > > > > > > to reflect the device power state (set/clear on the buffer > > > > > > callbacks) and > > > > > > only use the local lock (completely ditching the call to > > > > > > iio_device_claim_direct_mode())... > > > > > > > > > > I tend to prefer this option than the one below. > > > > > > > > > > I guess your implementation already prevents > > > > > buffer_predisable() to > > > > > run > > > > > thanks to the local lock being held during the operation. Maybe > > > > > we > > > > > should just verify that buffers are enabled from within the > > > > > local > > > > > lock > > > > > being held instead of just acquiring it for the get_temp() > > > > > measure. > > > > > It > > > > > would probably solve the situation here. > > > > > > > > > > Not sure if I understood... You mean something like: > > > > > > > > mutex_lock(&data->lock); > > > > if (!iio_buffer_enabled(indio_dev)) { > > > > ret = -EINVAL; > > > > } else { > > > > ret = max30100_get_temp(data, val); > > > > if (!ret) > > > > ret = IIO_VAL_INT; > > > > > > > > } > > > > mutex_unlock(&data->lock); > > > > > > > > If so, I think this is still racy since we release the lock after > > > > the > > > > predisable which means we could still detect the buffers as > > > > enabled (in > > > > the above block) and try to get_temp on a powered down device. > > > > > > True. > > > > > > > > > > > Since we pretty much only care about the power state of the > > > > device (and > > > > we are using the buffering state to infer that AFAIU), I was > > > > thinking > > > > in something like: > > > > > > > > > > > > mutex_lock(&data->lock); > > > > if (!data->powered) { > > > > ret = -EINVAL; > > > > } else { > > > > ret = max30100_get_temp(data, val); > > > > if (!ret) > > > > ret = IIO_VAL_INT; > > > > > > > > } > > > > mutex_unlock(&data->lock); > > > > > > LGTM. > > > > A reference counted power up flag would probably work as we'd want to > > disable > > power only when the reference count goes to 0. Note all checks of > > that flag > > would need to be done under the lock as well. > > > > Is there any way to enable a buffer more than once? Otherwise I'm not > sure we really need a refcount... Any ways, your below approach looks > good to me and surely easier. Indeed can only have the buffer enabled once, but there may be a race with the disable of the buffer and this path. Hence need a ref count to detect when the count goes to zero, what ever the reason. A flag only covers one side of the race. > > > As an alternative... > > > > Whilst it is a serious oddity, how about flipping the logic and > > having > > an iio_device_claim_buffered_mode() that takes mlock and holds it > > only > > if we are in buffered mode - then holds it until matching release? > > > > This goes along with one of my suggestions: > > "A version iio_device_claim_direct_mode() that does not release the > lock in case buffering is enabled." Ah. I missed that suggestion. > > You just gave it a name (and one that I would not ever remember)... :) It's used in so few paths that I'm not that bothered if it's hard to remember! > > > Now, I've only done a superficial audit of the buffer removal paths > > to check they hold the lock before we call predisable() but it looks > > Otherwise I guess we would have to fix it :) True, though testing these more obscure devices is a real pain. Jonathan > > > - Nuno Sá
On Sun, 2022-10-02 at 12:03 +0100, Jonathan Cameron wrote: > On Mon, 26 Sep 2022 12:06:13 +0200 > Nuno Sá <noname.nuno@gmail.com> wrote: > > > On Sat, 2022-09-24 at 16:53 +0100, Jonathan Cameron wrote: > > > On Tue, 20 Sep 2022 17:10:33 +0200 > > > Miquel Raynal <miquel.raynal@bootlin.com> wrote: > > > > > > > Hi Nuno, > > > > > > > > noname.nuno@gmail.com wrote on Tue, 20 Sep 2022 16:56:01 +0200: > > > > > > > > > On Tue, 2022-09-20 at 15:53 +0200, Miquel Raynal wrote: > > > > > > Hi Nuno, > > > > > > > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 13:15:32 > > > > > > +0000: > > > > > > > > > > > > > > -----Original Message----- > > > > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > > > > Sent: Tuesday, September 20, 2022 2:56 PM > > > > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > > > > Cc: linux-arm-kernel@lists.infradead.org; > > > > > > > > linux-rockchip@lists.infradead.org; > > > > > > > > linux-amlogic@lists.infradead.org; linux-imx@nxp.com; > > > > > > > > linux- > > > > > > > > iio@vger.kernel.org; Chunyan Zhang > > > > > > > > <zhang.lyra@gmail.com>; > > > > > > > > Hennerich, > > > > > > > > Michael <Michael.Hennerich@analog.com>; Martin > > > > > > > > Blumenstingl > > > > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > > > > <s.hauer@pengutronix.de>; Cixi Geng > > > > > > > > <cixi.geng1@unisoc.com>; > > > > > > > > Kevin > > > > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy > > > > > > > > <vz@mleia.com>; > > > > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; > > > > > > > > Alexandru > > > > > > > > Ardelean > > > > > > > > <aardelean@deviqon.com>; Fabio Estevam > > > > > > > > <festevam@gmail.com>; > > > > > > > > Andriy > > > > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; > > > > > > > > Haibo > > > > > > > > Chen > > > > > > > > <haibo.chen@nxp.com>; Shawn Guo <shawnguo@kernel.org>; > > > > > > > > Hans > > > > > > > > de > > > > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > > > > > <jbrunet@baylibre.com>; > > > > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen > > > > > > > > <lars@metafoo.de>; > > > > > > > > Andy > > > > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan > > > > > > > > Cameron > > > > > > > > <jic23@kernel.org>; Neil Armstrong > > > > > > > > <narmstrong@baylibre.com>; > > > > > > > > Baolin > > > > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > > > > <jbhayana@google.com>; Chen-Yu Tsai <wens@csie.org>; > > > > > > > > Orson > > > > > > > > Zhai > > > > > > > > <orsonzhai@gmail.com> > > > > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: do > > > > > > > > not > > > > > > > > use > > > > > > > > internal iio_dev > > > > > > > > lock > > > > > > > > > > > > > > > > [External] > > > > > > > > > > > > > > > > Hi Nuno, > > > > > > > > > > > > > > > > Nuno.Sa@analog.com wrote on Tue, 20 Sep 2022 12:44:08 > > > > > > > > +0000: > > > > > > > > > > > > > > > > > > -----Original Message----- > > > > > > > > > > From: Miquel Raynal <miquel.raynal@bootlin.com> > > > > > > > > > > Sent: Tuesday, September 20, 2022 2:23 PM > > > > > > > > > > To: Sa, Nuno <Nuno.Sa@analog.com> > > > > > > > > > > Cc: linux-arm-kernel@lists.infradead.org; linux- > > > > > > > > > > > > > > > > > > rockchip@lists.infradead.org; > > > > > > > > > > linux-amlogic@lists.infradead.org; > > > > > > > > > > linux-imx@nxp.com; > > > > > > > > > > linux- > > > > > > > > > > iio@vger.kernel.org; Chunyan Zhang > > > > > > > > > > <zhang.lyra@gmail.com>; > > > > > > > > Hennerich, > > > > > > > > > > Michael <Michael.Hennerich@analog.com>; Martin > > > > > > > > > > Blumenstingl > > > > > > > > > > <martin.blumenstingl@googlemail.com>; Sascha Hauer > > > > > > > > > > <s.hauer@pengutronix.de>; Cixi Geng > > > > > > > > > > <cixi.geng1@unisoc.com>; > > > > > > > > > > Kevin > > > > > > > > > > Hilman <khilman@baylibre.com>; Vladimir Zapolskiy > > > > > > > > > > <vz@mleia.com>; > > > > > > > > > > Pengutronix Kernel Team <kernel@pengutronix.de>; > > > > > > > > > > Alexandru > > > > > > > > Ardelean > > > > > > > > > > <aardelean@deviqon.com>; Fabio Estevam > > > > > > > > > > <festevam@gmail.com>; > > > > > > > > Andriy > > > > > > > > > > Tryshnivskyy <andriy.tryshnivskyy@opensynergy.com>; > > > > > > > > > > Haibo > > > > > > > > > > Chen > > > > > > > > > > <haibo.chen@nxp.com>; Shawn Guo > > > > > > > > > > <shawnguo@kernel.org>; > > > > > > > > > > Hans > > > > > > > > > > de > > > > > > > > > > Goede <hdegoede@redhat.com>; Jerome Brunet > > > > > > > > <jbrunet@baylibre.com>; > > > > > > > > > > Heiko Stuebner <heiko@sntech.de>; Florian Boor > > > > > > > > > > <florian.boor@kernelconcepts.de>; Regus, Ciprian > > > > > > > > > > <Ciprian.Regus@analog.com>; Lars-Peter Clausen > > > > > > > > > > <lars@metafoo.de>; > > > > > > > > Andy > > > > > > > > > > Shevchenko <andy.shevchenko@gmail.com>; Jonathan > > > > > > > > > > Cameron > > > > > > > > > > <jic23@kernel.org>; Neil Armstrong > > > > > > > > > > <narmstrong@baylibre.com>; > > > > > > > > > > Baolin > > > > > > > > > > Wang <baolin.wang@linux.alibaba.com>; Jyoti Bhayana > > > > > > > > > > <jbhayana@google.com>; Chen-Yu Tsai > > > > > > > > > > <wens@csie.org>; > > > > > > > > > > Orson > > > > > > > > > > Zhai > > > > > > > > > > <orsonzhai@gmail.com> > > > > > > > > > > Subject: Re: [PATCH 13/15] iio: health: max30100: > > > > > > > > > > do > > > > > > > > > > not use > > > > > > > > > > internal > > > > > > > > iio_dev > > > > > > > > > > lock > > > > > > > > > > > > > > > > > > > > [External] > > > > > > > > > > > > > > > > > > > > Hi Nuno, > > > > > > > > > > > > > > > > > > > > > > > > > > > > Hi Miquel, > > > > > > > > > > > > > > > > > > Thanks for reviewing... > > > > > > > > > > > > > > > > > > > nuno.sa@analog.com wrote on Tue, 20 Sep 2022 > > > > > > > > > > 13:28:19 > > > > > > > > > > +0200: > > > > > > > > > > > > > > > > > > > > > The pattern used in this device does not quite > > > > > > > > > > > fit in > > > > > > > > > > > the > > > > > > > > > > > iio_device_claim_direct_mode() typical usage. In > > > > > > > > > > > this > > > > > > > > > > > case, > > > > > > > > > > > iio_buffer_enabled() was being used not to > > > > > > > > > > > prevent > > > > > > > > > > > the raw > > > > > > > > > > > access but > > > > > > > > to > > > > > > > > > > > allow it. Hence to get rid of the 'mlock' we need > > > > > > > > > > > to: > > > > > > > > > > > > > > > > > > > > > > 1. Use iio_device_claim_direct_mode() to check if > > > > > > > > > > > direct > > > > > > > > > > > mode can be > > > > > > > > > > > claimed and if we can return -EINVAL (as the > > > > > > > > > > > original > > > > > > > > > > > code); > > > > > > > > > > > > > > > > > > > > > > 2. Make sure that buffering is not disabled while > > > > > > > > > > > doing a > > > > > > > > > > > raw read. For > > > > > > > > > > > that, we can make use of the local lock that > > > > > > > > > > > already > > > > > > > > > > > exists. > > > > > > > > > > > > > > > > > > > > > > While at it, fixed a minor coding style > > > > > > > > > > > complain... > > > > > > > > > > > > > > > > > > > > > > Signed-off-by: Nuno Sá <nuno.sa@analog.com> > > > > > > > > > > > --- > > > > > > > > > > > drivers/iio/health/max30100.c | 24 > > > > > > > > > > > +++++++++++++++++------ > > > > > > > > > > > - > > > > > > > > > > > 1 file changed, 17 insertions(+), 7 deletions(-) > > > > > > > > > > > > > > > > > > > > > > diff --git a/drivers/iio/health/max30100.c > > > > > > > > b/drivers/iio/health/max30100.c > > > > > > > > > > > index ad5717965223..aa494cad5df0 100644 > > > > > > > > > > > --- a/drivers/iio/health/max30100.c > > > > > > > > > > > +++ b/drivers/iio/health/max30100.c > > > > > > > > > > > @@ -185,8 +185,19 @@ static int > > > > > > > > > > > max30100_buffer_postenable(struct > > > > > > > > > > iio_dev *indio_dev) > > > > > > > > > > > static int max30100_buffer_predisable(struct > > > > > > > > > > > iio_dev > > > > > > > > > > > *indio_dev) > > > > > > > > > > > { > > > > > > > > > > > struct max30100_data *data = > > > > > > > > > > > iio_priv(indio_dev); > > > > > > > > > > > + int ret; > > > > > > > > > > > + > > > > > > > > > > > + /* > > > > > > > > > > > + * As stated in the comment in the > > > > > > > > > > > read_raw() > > > > > > > > > > > function, temperature > > > > > > > > > > > + * can only be acquired if the engine is > > > > > > > > > > > running. > > > > > > > > > > > As such the mutex > > > > > > > > > > > + * is used to make sure we do not power > > > > > > > > > > > down > > > > > > > > > > > while > > > > > > > > > > > doing a > > > > > > > > > > temperature > > > > > > > > > > > + * reading. > > > > > > > > > > > + */ > > > > > > > > > > > + mutex_lock(&data->lock); > > > > > > > > > > > + ret = max30100_set_powermode(data, > > > > > > > > > > > false); > > > > > > > > > > > + mutex_unlock(&data->lock); > > > > > > > > > > > > > > > > > > > > > > - return max30100_set_powermode(data, > > > > > > > > > > > false); > > > > > > > > > > > + return ret; > > > > > > > > > > > } > > > > > > > > > > > > > > > > > > > > > > static const struct iio_buffer_setup_ops > > > > > > > > > > > max30100_buffer_setup_ops > > > > > > > > = { > > > > > > > > > > > @@ -387,18 +398,17 @@ static int > > > > > > > > > > > max30100_read_raw(struct > > > > > > > > > > > iio_dev > > > > > > > > > > *indio_dev, > > > > > > > > > > > * Temperature reading can only > > > > > > > > > > > be > > > > > > > > > > > acquired > > > > > > > > > > > while engine > > > > > > > > > > > * is running > > > > > > > > > > > */ > > > > > > > > > > > - mutex_lock(&indio_dev->mlock); > > > > > > > > > > > - > > > > > > > > > > > - if > > > > > > > > > > > (!iio_buffer_enabled(indio_dev)) > > > > > > > > > > > + if > > > > > > > > > > > (!iio_device_claim_direct_mode(indio_dev)) > > > > > > > > > > > { > > > > > > > > > > > > > > > > > > > > I wonder if this line change here is really needed. > > > > > > > > > > I > > > > > > > > > > agree > > > > > > > > > > the whole > > > > > > > > > > construction looks like what > > > > > > > > > > iio_device_claim_direct_mode() > > > > > > > > > > does but in > > > > > > > > > > practice I don't see the point of acquiring any > > > > > > > > > > lock > > > > > > > > > > here if > > > > > > > > > > we just > > > > > > > > > > release it no matter what happens right after. > > > > > > > > > > > > > > > > > > > > > > > > > > > > I can see that this is odd (at the very least) but > > > > > > > > > AFAIK, > > > > > > > > > this > > > > > > > > > is the only way > > > > > > > > > to safely infer if buffering is enabled or not. > > > > > > > > > iio_buffer_enabled() has no > > > > > > > > > protection against someone concurrently > > > > > > > > > enabling/disabling the > > > > > > > > > buffer. > > > > > > > > > > > > > > > > Yes, but this is only relevant if you want to infer > > > > > > > > that > > > > > > > > the > > > > > > > > "buffers > > > > > > > > are enabled" and be sure that it cannot be otherwise > > > > > > > > during > > > > > > > > the > > > > > > > > next > > > > > > > > lines until you release the lock. Acquiring a lock, > > > > > > > > doing > > > > > > > > the if > > > > > > > > and > > > > > > > > then unconditionally releasing the lock, IMHO, does not > > > > > > > > make any > > > > > > > > sense > > > > > > > > (but I'm not a locking guru) because when you enter the > > > > > > > > else > > > > > > > > clause, > > > > > > > > you are not protected anyway, so in both cases all this > > > > > > > > is > > > > > > > > completely > > > > > > > > racy. > > > > > > > > > > > > > > > > > > > > > > Ahh crap, yes you are right... It is still racy since we > > > > > > > can > > > > > > > still > > > > > > > try to read > > > > > > > the temperature with the device powered off. I'm not > > > > > > > really > > > > > > > sure > > > > > > > how to > > > > > > > address this. One way could be to just use an internal > > > > > > > control > > > > > > > variable > > > > > > > to reflect the device power state (set/clear on the > > > > > > > buffer > > > > > > > callbacks) and > > > > > > > only use the local lock (completely ditching the call to > > > > > > > iio_device_claim_direct_mode())... > > > > > > > > > > > > I tend to prefer this option than the one below. > > > > > > > > > > > > I guess your implementation already prevents > > > > > > buffer_predisable() to > > > > > > run > > > > > > thanks to the local lock being held during the operation. > > > > > > Maybe > > > > > > we > > > > > > should just verify that buffers are enabled from within the > > > > > > local > > > > > > lock > > > > > > being held instead of just acquiring it for the get_temp() > > > > > > measure. > > > > > > It > > > > > > would probably solve the situation here. > > > > > > > > > > > > Not sure if I understood... You mean something like: > > > > > > > > > > mutex_lock(&data->lock); > > > > > if (!iio_buffer_enabled(indio_dev)) { > > > > > ret = -EINVAL; > > > > > } else { > > > > > ret = max30100_get_temp(data, val); > > > > > if (!ret) > > > > > ret = IIO_VAL_INT; > > > > > > > > > > } > > > > > mutex_unlock(&data->lock); > > > > > > > > > > If so, I think this is still racy since we release the lock > > > > > after > > > > > the > > > > > predisable which means we could still detect the buffers as > > > > > enabled (in > > > > > the above block) and try to get_temp on a powered down > > > > > device. > > > > > > > > True. > > > > > > > > > > > > > > Since we pretty much only care about the power state of the > > > > > device (and > > > > > we are using the buffering state to infer that AFAIU), I was > > > > > thinking > > > > > in something like: > > > > > > > > > > > > > > > mutex_lock(&data->lock); > > > > > if (!data->powered) { > > > > > ret = -EINVAL; > > > > > } else { > > > > > ret = max30100_get_temp(data, val); > > > > > if (!ret) > > > > > ret = IIO_VAL_INT; > > > > > > > > > > } > > > > > mutex_unlock(&data->lock); > > > > > > > > LGTM. > > > > > > A reference counted power up flag would probably work as we'd > > > want to > > > disable > > > power only when the reference count goes to 0. Note all checks > > > of > > > that flag > > > would need to be done under the lock as well. > > > > > > > Is there any way to enable a buffer more than once? Otherwise I'm > > not > > sure we really need a refcount... Any ways, your below approach > > looks > > good to me and surely easier. > > Indeed can only have the buffer enabled once, but there may be a race > with the disable of the buffer and this path. Hence need a ref count > to detect when the count goes to zero, what ever the reason. > A flag only covers one side of the race. > > > > Sure, but I would "secure" it with the same lock on 'data->lock' and the flag setting would be obviously under that lock (same on the postenable side of things). IMO, I don't think we need to that far as using refcounts in here. Anyways, I will give a try to the suggestion you made in the other patch. - Nuno Sá > >
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index ad5717965223..aa494cad5df0 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -185,8 +185,19 @@ static int max30100_buffer_postenable(struct iio_dev *indio_dev) static int max30100_buffer_predisable(struct iio_dev *indio_dev) { struct max30100_data *data = iio_priv(indio_dev); + int ret; + + /* + * As stated in the comment in the read_raw() function, temperature + * can only be acquired if the engine is running. As such the mutex + * is used to make sure we do not power down while doing a temperature + * reading. + */ + mutex_lock(&data->lock); + ret = max30100_set_powermode(data, false); + mutex_unlock(&data->lock); - return max30100_set_powermode(data, false); + return ret; } static const struct iio_buffer_setup_ops max30100_buffer_setup_ops = { @@ -387,18 +398,17 @@ static int max30100_read_raw(struct iio_dev *indio_dev, * Temperature reading can only be acquired while engine * is running */ - mutex_lock(&indio_dev->mlock); - - if (!iio_buffer_enabled(indio_dev)) + if (!iio_device_claim_direct_mode(indio_dev)) { ret = -EAGAIN; - else { + iio_device_release_direct_mode(indio_dev); + } else { + mutex_lock(&data->lock); ret = max30100_get_temp(data, val); if (!ret) ret = IIO_VAL_INT; - + mutex_unlock(&data->lock); } - mutex_unlock(&indio_dev->mlock); break; case IIO_CHAN_INFO_SCALE: *val = 1; /* 0.0625 */
The pattern used in this device does not quite fit in the iio_device_claim_direct_mode() typical usage. In this case, iio_buffer_enabled() was being used not to prevent the raw access but to allow it. Hence to get rid of the 'mlock' we need to: 1. Use iio_device_claim_direct_mode() to check if direct mode can be claimed and if we can return -EINVAL (as the original code); 2. Make sure that buffering is not disabled while doing a raw read. For that, we can make use of the local lock that already exists. While at it, fixed a minor coding style complain... Signed-off-by: Nuno Sá <nuno.sa@analog.com> --- drivers/iio/health/max30100.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)