summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xqa/workunits/rbd/test_lock_fence.sh49
-rw-r--r--src/pybind/rbd.py6
-rwxr-xr-xsrc/test/librbd/rbdrw.py31
3 files changed, 85 insertions, 1 deletions
diff --git a/qa/workunits/rbd/test_lock_fence.sh b/qa/workunits/rbd/test_lock_fence.sh
new file mode 100755
index 00000000000..ee015043fbd
--- /dev/null
+++ b/qa/workunits/rbd/test_lock_fence.sh
@@ -0,0 +1,49 @@
+#!/bin/bash -x
+# can't use -e because of background process
+
+IMAGE=rbdrw-image
+LOCKID=rbdrw
+RBDRW=rbdrw.py
+CEPH_REF=${CEPH_REF:-master}
+
+wget -O $RBDRW "https://ceph.com/git/?p=ceph.git;a=blob_plain;hb=$CEPH_REF;f=src/test/librbd/rbdrw.py"
+
+rbd create $IMAGE --size 10 --image-format 2 || exit 1
+
+# rbdrw loops doing I/O to $IMAGE after locking with lockid $LOCKID
+python $RBDRW $IMAGE $LOCKID &
+iochild=$!
+
+# give client time to lock and start reading/writing
+LOCKS='{}'
+while [ "$LOCKS" == "{}" ]
+do
+ LOCKS=$(rbd lock list $IMAGE --format json)
+ sleep 1
+done
+
+clientaddr=$(rbd lock list $IMAGE | tail -1 | awk '{print $NF;}')
+clientid=$(rbd lock list $IMAGE | tail -1 | awk '{print $1;}')
+echo "clientaddr: $clientaddr"
+echo "clientid: $clientid"
+
+ceph osd blacklist add $clientaddr || exit 1
+
+wait $iochild
+rbdrw_exitcode=$?
+if [ $rbdrw_exitcode != 108 ]
+then
+ echo "wrong exitcode from rbdrw: $rbdrw_exitcode"
+ exit 1
+else
+ echo "rbdrw stopped with ESHUTDOWN"
+fi
+
+set -e
+ceph osd blacklist rm $clientaddr
+rbd lock remove $IMAGE $LOCKID "$clientid"
+# rbdrw will have exited with an existing watch, so, until #3527 is fixed,
+# hang out until the watch expires
+sleep 30
+rbd rm $IMAGE
+echo OK
diff --git a/src/pybind/rbd.py b/src/pybind/rbd.py
index f4d844a17ec..4ce1a0e819b 100644
--- a/src/pybind/rbd.py
+++ b/src/pybind/rbd.py
@@ -68,6 +68,9 @@ class FunctionNotSupported(Error):
class ArgumentOutOfRange(Error):
pass
+class ConnectionShutdown(Error):
+ pass
+
def make_ex(ret, msg):
"""
Translate a librbd return code into an exception.
@@ -89,7 +92,8 @@ def make_ex(ret, msg):
errno.EBUSY : ImageBusy,
errno.ENOTEMPTY : ImageHasSnapshots,
errno.ENOSYS : FunctionNotSupported,
- errno.EDOM : ArgumentOutOfRange
+ errno.EDOM : ArgumentOutOfRange,
+ errno.ESHUTDOWN : ConnectionShutdown
}
ret = abs(ret)
if ret in errors:
diff --git a/src/test/librbd/rbdrw.py b/src/test/librbd/rbdrw.py
new file mode 100755
index 00000000000..6034ad055cf
--- /dev/null
+++ b/src/test/librbd/rbdrw.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+"""
+Loop writing/reading the first 4k of image argv[1] in pool rbd,
+after acquiring exclusive lock named argv[2]. When an exception
+happens, split off the last number in the exception 'args' string
+and use it as the process exit code, if it's convertible to a number.
+
+Designed to run against a blacklist operation and verify the
+ESHUTDOWN expected from the image operation.
+
+Note: this cannot be run with writeback caching on, currently, as
+writeback errors cause reads be marked dirty rather than error, and
+even if they were marked as errored, ObjectCacher would retry them
+rather than note them as errored.
+"""
+
+import rados, rbd, sys
+
+with rados.Rados(conffile='') as r:
+ with r.open_ioctx('rbd') as ioctx:
+ with rbd.Image(ioctx, sys.argv[1]) as image:
+ image.lock_exclusive(sys.argv[2])
+ while True:
+ try:
+ image.write('A' * 4096, 0)
+ r = image.read(0, 4096)
+ except rbd.ConnectionShutdown:
+ # it so happens that the errno here is 108, but
+ # anything recognizable would do
+ exit(108)
+