diff mbox series

[05/24] Introduce locking functions for block device setup on NetBSD

Message ID 20201214163623.2127-6-bouyer@netbsd.org (mailing list archive)
State New, archived
Headers show
Series NetBSD fixes | expand

Commit Message

Manuel Bouyer Dec. 14, 2020, 4:36 p.m. UTC
---
 tools/hotplug/NetBSD/Makefile   |  1 +
 tools/hotplug/NetBSD/block      |  5 ++-
 tools/hotplug/NetBSD/locking.sh | 72 +++++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 1 deletion(-)
 create mode 100644 tools/hotplug/NetBSD/locking.sh

Comments

Roger Pau Monne Dec. 29, 2020, 11:29 a.m. UTC | #1
I think you want tot CC the tools dev on this one, specially Ian who
knows how the Linux one is implemented and can likely give valuable
input.

On Mon, Dec 14, 2020 at 05:36:04PM +0100, Manuel Bouyer wrote:
> ---
>  tools/hotplug/NetBSD/Makefile   |  1 +
>  tools/hotplug/NetBSD/block      |  5 ++-
>  tools/hotplug/NetBSD/locking.sh | 72 +++++++++++++++++++++++++++++++++

Seeing the file itself, I don't think there's any NetBSD specific
stuff, so we might want to consider putting it in BSD/ instead, so it
can be used by FreeBSD also?

I'm also not sure if it would be useful to Linux folks?

Thanks, Roger.
Manuel Bouyer Jan. 4, 2021, 10:20 a.m. UTC | #2
On Tue, Dec 29, 2020 at 12:29:09PM +0100, Roger Pau Monné wrote:
> I think you want tot CC the tools dev on this one, specially Ian who
> knows how the Linux one is implemented and can likely give valuable
> input.
> 
> On Mon, Dec 14, 2020 at 05:36:04PM +0100, Manuel Bouyer wrote:
> > ---
> >  tools/hotplug/NetBSD/Makefile   |  1 +
> >  tools/hotplug/NetBSD/block      |  5 ++-
> >  tools/hotplug/NetBSD/locking.sh | 72 +++++++++++++++++++++++++++++++++
> 
> Seeing the file itself, I don't think there's any NetBSD specific
> stuff, so we might want to consider putting it in BSD/ instead, so it
> can be used by FreeBSD also?

I'm not sure if FreeBSD needs the locking stuff.
Also, there are certainly differences in block device handling between
FreeBSD and NetBSD. Both OSes have diverged in this area.
Ian Jackson Jan. 20, 2021, 3:13 p.m. UTC | #3
Manuel Bouyer writes ("Re: [PATCH 05/24] Introduce locking functions for block device setup on NetBSD"):
> On Tue, Dec 29, 2020 at 12:29:09PM +0100, Roger Pau Monné wrote:
> > I think you want tot CC the tools dev on this one, specially Ian who
> > knows how the Linux one is implemented and can likely give valuable
> > input.
...
> > Seeing the file itself, I don't think there's any NetBSD specific
> > stuff, so we might want to consider putting it in BSD/ instead, so it
> > can be used by FreeBSD also?
> 
> I'm not sure if FreeBSD needs the locking stuff.
> Also, there are certainly differences in block device handling between
> FreeBSD and NetBSD. Both OSes have diverged in this area.

I think most operating systems will want some kind of locking here.

I loooked at the code in the new tools/hotplug/NetBSD/locking.sh.
Unfortunately this area is complex and the available APIs and tools
are awkard, and the field is troubled by broken "traditional"
approaches involving O_EXCL or the moral equivalent, which cannot be
made reliable (if you think reliability implies never being broken due
to stale lock).

I doubt that the code in this patch is correct.  It uses shlock(1)
which is based on link(2) and kill(2) and so on, which I think is
basically an O_EXCL-based approach as I discuss above.  (I don't have
a formal proof of this contention.)  The presence of an invocation of
the "trap" shell builtin in the new NetBSD script is a bad sign - a
reliable locking protocol would need that.

I see from https://man.netbsd.org that NetBSD has flock(1) and
stat(1).  I think this means we could reuse the code in
tools/hotplug/Linux/locking.sh.  Maybe it will need to be lightly
adapted, to NetBSD's flock(1) and stat(1).  Perhaps via some kind of
substitution to avoid all the clone-and-hack.

Regards,
Ian.
Manuel Bouyer Jan. 20, 2021, 3:59 p.m. UTC | #4
On Wed, Jan 20, 2021 at 03:13:22PM +0000, Ian Jackson wrote:
> Manuel Bouyer writes ("Re: [PATCH 05/24] Introduce locking functions for block device setup on NetBSD"):
> > On Tue, Dec 29, 2020 at 12:29:09PM +0100, Roger Pau Monné wrote:
> > > I think you want tot CC the tools dev on this one, specially Ian who
> > > knows how the Linux one is implemented and can likely give valuable
> > > input.
> ...
> > > Seeing the file itself, I don't think there's any NetBSD specific
> > > stuff, so we might want to consider putting it in BSD/ instead, so it
> > > can be used by FreeBSD also?
> > 
> > I'm not sure if FreeBSD needs the locking stuff.
> > Also, there are certainly differences in block device handling between
> > FreeBSD and NetBSD. Both OSes have diverged in this area.
> 
> I think most operating systems will want some kind of locking here.
> 
> I loooked at the code in the new tools/hotplug/NetBSD/locking.sh.
> Unfortunately this area is complex and the available APIs and tools
> are awkard, and the field is troubled by broken "traditional"
> approaches involving O_EXCL or the moral equivalent, which cannot be
> made reliable (if you think reliability implies never being broken due
> to stale lock).
> 
> I doubt that the code in this patch is correct.  It uses shlock(1)
> which is based on link(2) and kill(2) and so on, which I think is
> basically an O_EXCL-based approach as I discuss above.  (I don't have
> a formal proof of this contention.)  The presence of an invocation of
> the "trap" shell builtin in the new NetBSD script is a bad sign - a
> reliable locking protocol would need that.

Actually this patch is old - since Xen 4.8 at last.

> 
> I see from https://man.netbsd.org that NetBSD has flock(1) and
> stat(1).  I think this means we could reuse the code in
> tools/hotplug/Linux/locking.sh.  Maybe it will need to be lightly
> adapted, to NetBSD's flock(1) and stat(1).  Perhaps via some kind of
> substitution to avoid all the clone-and-hack.

Yes, at last the stat call will need to be patched.
But it seems to rely on a linux-specific behavoir, which is that
/dev/stdin points to the real file on redirection:
>ls -l /dev/stdin /proc/self/fd/0 < /etc/passwd
lrwxrwxrwx 1 root   root      15 Apr 30  2019 /dev/stdin -> /proc/self/fd/0
lr-x------ 1 bouyer ita-iatos 64 Jan 20 16:54 /proc/self/fd/0 -> /etc/passwd

On NetBSD (and I guess other BSDs) this won't work, as /dev/stdin is a
specific device:
>ls -l /dev/stdin 
crw-rw-rw-  1 root  wheel  22, 0 Nov 15  2007 /dev/stdin

so stat -L will always return the same data. We can't use the same protocol.
Ian Jackson Jan. 20, 2021, 4:12 p.m. UTC | #5
Manuel Bouyer writes ("Re: [PATCH 05/24] Introduce locking functions for block device setup on NetBSD"):
> Yes, at last the stat call will need to be patched.
> But it seems to rely on a linux-specific behavoir, which is that
> /dev/stdin points to the real file on redirection:
> >ls -l /dev/stdin /proc/self/fd/0 < /etc/passwd
> lrwxrwxrwx 1 root   root      15 Apr 30  2019 /dev/stdin -> /proc/self/fd/0
> lr-x------ 1 bouyer ita-iatos 64 Jan 20 16:54 /proc/self/fd/0 -> /etc/passwd
> 
> On NetBSD (and I guess other BSDs) this won't work, as /dev/stdin is a
> specific device:
> >ls -l /dev/stdin 
> crw-rw-rw-  1 root  wheel  22, 0 Nov 15  2007 /dev/stdin
> 
> so stat -L will always return the same data. We can't use the same
> protocol.

Ah.

The manpage I am looking at says:

     If no argument is given, stat displays information about the
     file descriptor for standard input.

Here NetBSD has a better command line API than Linux - Linux requires
pratting about with /dev/stdin and NetBSD doesn't.  So I think
where on Linux we have
   stat .... /dev/stdin
on NetBsd we can simply have
   stat ....
with no filename argument.

I think NetBSD's stat(1) also takes different argumnts to specify the
format.  NetBSD uses -f, whereas Linux uses -c.  So the exact rune
will have to be different.

Ian.
Manuel Bouyer Jan. 20, 2021, 4:59 p.m. UTC | #6
On Wed, Jan 20, 2021 at 04:12:29PM +0000, Ian Jackson wrote:
> Manuel Bouyer writes ("Re: [PATCH 05/24] Introduce locking functions for block device setup on NetBSD"):
> > Yes, at last the stat call will need to be patched.
> > But it seems to rely on a linux-specific behavoir, which is that
> > /dev/stdin points to the real file on redirection:
> > >ls -l /dev/stdin /proc/self/fd/0 < /etc/passwd
> > lrwxrwxrwx 1 root   root      15 Apr 30  2019 /dev/stdin -> /proc/self/fd/0
> > lr-x------ 1 bouyer ita-iatos 64 Jan 20 16:54 /proc/self/fd/0 -> /etc/passwd
> > 
> > On NetBSD (and I guess other BSDs) this won't work, as /dev/stdin is a
> > specific device:
> > >ls -l /dev/stdin 
> > crw-rw-rw-  1 root  wheel  22, 0 Nov 15  2007 /dev/stdin
> > 
> > so stat -L will always return the same data. We can't use the same
> > protocol.
> 
> Ah.
> 
> The manpage I am looking at says:
> 
>      If no argument is given, stat displays information about the
>      file descriptor for standard input.
> 
> Here NetBSD has a better command line API than Linux - Linux requires
> pratting about with /dev/stdin and NetBSD doesn't.  So I think
> where on Linux we have
>    stat .... /dev/stdin
> on NetBsd we can simply have
>    stat ....
> with no filename argument.

Right, thanks. Then it would need to be done with 2 different calls
but I don't think that's a problem (even with the linux version it would
not be atomic anyway).

> 
> I think NetBSD's stat(1) also takes different argumnts to specify the
> format.  NetBSD uses -f, whereas Linux uses -c.  So the exact rune
> will have to be different.

Yes, and NetBSD doens't have %D (only %d)
Ian Jackson Jan. 20, 2021, 5:03 p.m. UTC | #7
Manuel Bouyer writes ("Re: [PATCH 05/24] Introduce locking functions for block device setup on NetBSD"):
> On Wed, Jan 20, 2021 at 04:12:29PM +0000, Ian Jackson wrote:
> > I think NetBSD's stat(1) also takes different argumnts to specify the
> > format.  NetBSD uses -f, whereas Linux uses -c.  So the exact rune
> > will have to be different.
> 
> Yes, and NetBSD doens't have %D (only %d)

What's really important here is the inode number.  But %d will do
nicely.  I only used %D on Linux since device numbers are two-element
bitfields so displaying them in hex makes more sense to humans who
might be debugging this.

Ian.
Ian Jackson Jan. 20, 2021, 5:19 p.m. UTC | #8
Manuel Bouyer writes ("Re: [PATCH 05/24] Introduce locking functions for block device setup on NetBSD"):
> Right, thanks. Then it would need to be done with 2 different calls
> but I don't think that's a problem (even with the linux version it would
> not be atomic anyway).

Sorry, I forgot to reply to this.  Yes, it would need to invocations
of stat(1).  You are correct that the Linux version is not atomic in
that sense.

Ian.
diff mbox series

Patch

diff --git a/tools/hotplug/NetBSD/Makefile b/tools/hotplug/NetBSD/Makefile
index 6926885ab8..114b223207 100644
--- a/tools/hotplug/NetBSD/Makefile
+++ b/tools/hotplug/NetBSD/Makefile
@@ -3,6 +3,7 @@  include $(XEN_ROOT)/tools/Rules.mk
 
 # Xen script dir and scripts to go there.
 XEN_SCRIPTS =
+XEN_SCRIPTS += locking.sh
 XEN_SCRIPTS += block
 XEN_SCRIPTS += vif-bridge
 XEN_SCRIPTS += vif-ip
diff --git a/tools/hotplug/NetBSD/block b/tools/hotplug/NetBSD/block
index 32c20b6c89..23c8e38ebf 100644
--- a/tools/hotplug/NetBSD/block
+++ b/tools/hotplug/NetBSD/block
@@ -6,6 +6,7 @@ 
 
 DIR=$(dirname "$0")
 . "${DIR}/hotplugpath.sh"
+. "${DIR}/locking.sh"
 
 PATH=${bindir}:${sbindir}:${LIBEXEC_BIN}:/bin:/usr/bin:/sbin:/usr/sbin
 export PATH
@@ -62,6 +63,7 @@  case $xstatus in
 			available_disks="$available_disks $disk"
 			eval $disk=free
 		done
+		claim_lock block
 		# Mark the used vnd(4) devices as ``used''.
 		for disk in `sysctl hw.disknames`; do
 			case $disk in
@@ -77,6 +79,7 @@  case $xstatus in
 				break	
 			fi
 		done
+		release_lock block
 		if [ x$device = x ] ; then
 			error "no available vnd device"
 		fi
@@ -86,7 +89,7 @@  case $xstatus in
 		device=$xparams
 		;;
 	esac
-	physical_device=$(stat -f '%r' "$device")
+	physical_device=$(stat -L -f '%r' "$device")
 	xenstore-write $xpath/physical-device $physical_device
 	xenstore-write $xpath/hotplug-status connected
 	exit 0
diff --git a/tools/hotplug/NetBSD/locking.sh b/tools/hotplug/NetBSD/locking.sh
new file mode 100644
index 0000000000..88257f62b7
--- /dev/null
+++ b/tools/hotplug/NetBSD/locking.sh
@@ -0,0 +1,72 @@ 
+#!/bin/sh
+#
+# Copyright (c) 2016, Christoph Badura.  All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+LOCK_BASEDIR="$XEN_LOCK_DIR/xen-hotplug"
+
+_lockfd=9
+_have_lock=0	# lock not taken yet.
+
+SHLOCK="shlock ${_shlock_debug-}"
+
+_lock_set_vars() {
+	_lockfile="$LOCK_BASEDIR/$1.lock"
+	_lockfifo="$LOCK_BASEDIR/$1.fifo"
+}
+
+_lock_init() {
+	mkdir -p "$LOCK_BASEDIR" 2>/dev/null || true
+	mkfifo $_lockfifo 2>/dev/null || true
+}
+
+#
+# use a named pipe as condition variable
+# opening for read-only blocks when there's no writer.
+# opening for read-write never blocks but unblocks any waiting readers.
+# 
+_lock_wait_cv() {
+	eval "exec $_lockfd<  $_lockfifo ; exec $_lockfd<&-"
+}
+_lock_signal_cv() {
+	eval "exec $_lockfd<> $_lockfifo ; exec $_lockfd<&-"
+}
+
+claim_lock() {
+	_lock_set_vars $1
+	_lock_init
+	until $SHLOCK -f $_lockfile -p $$; do
+		_lock_wait_cv
+	done
+	_have_lock=1
+	# be sure to release the lock when the shell exits
+	trap "release_lock $1" 0 1 2 15
+}
+
+release_lock() {
+	_lock_set_vars $1
+	[ "$_have_lock" != 0 -a -f $_lockfile ] && rm $_lockfile
+	_have_lock=0
+	_lock_signal_cv;
+}