diff mbox

[1/3] rbd: support timeout in rbd_wait_state_locked

Message ID 1521541979-15995-2-git-send-email-dongsheng.yang@easystack.cn (mailing list archive)
State New, archived
Headers show

Commit Message

Dongsheng Yang March 20, 2018, 10:32 a.m. UTC
currently, the rbd_wait_state_locked() will wait forever if we
can't get our state locked. Example:

rbd map --exclusive test1  --> /dev/rbd0
rbd map test1  --> /dev/rbd1
dd if=/dev/zero of=/dev/rbd1 bs=1M count=1 --> IO blocked

To avoid this problem, this patch introduce a timeout design
in rbd_wait_state_locked(). Then rbd_wait_state_locked() will
return error when we reach a timeout.

Signed-off-by: Dongsheng Yang <dongsheng.yang@easystack.cn>
---
 drivers/block/rbd.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

Comments

Ilya Dryomov March 26, 2018, 7:56 a.m. UTC | #1
On Tue, Mar 20, 2018 at 11:32 AM, Dongsheng Yang
<dongsheng.yang@easystack.cn> wrote:
> currently, the rbd_wait_state_locked() will wait forever if we
> can't get our state locked. Example:
>
> rbd map --exclusive test1  --> /dev/rbd0
> rbd map test1  --> /dev/rbd1
> dd if=/dev/zero of=/dev/rbd1 bs=1M count=1 --> IO blocked
>
> To avoid this problem, this patch introduce a timeout design
> in rbd_wait_state_locked(). Then rbd_wait_state_locked() will
> return error when we reach a timeout.
>
> Signed-off-by: Dongsheng Yang <dongsheng.yang@easystack.cn>
> ---
>  drivers/block/rbd.c | 23 +++++++++++++++++++----
>  1 file changed, 19 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
> index 96657ad..199819d 100644
> --- a/drivers/block/rbd.c
> +++ b/drivers/block/rbd.c
> @@ -761,6 +761,7 @@ struct rbd_options {
>  #define RBD_READ_ONLY_DEFAULT  false
>  #define RBD_LOCK_ON_READ_DEFAULT false
>  #define RBD_EXCLUSIVE_DEFAULT  false
> +#define RBD_WAIT_LOCK_TIMEOUT_DEFAULT  MAX_SCHEDULE_TIMEOUT

#define RBD_LOCK_TIMEOUT_DEFAULT  0  /* no timeout */

Passing lock_timeout=0 on the command line for "no timeout" must be
supported.  0 -> MAX_SCHEDULE_TIMEOUT will be handled by
ceph_timeout_jiffies() in rbd_wait_state_locked().

>
>  static int parse_rbd_opts_token(char *c, void *private)
>  {
> @@ -3494,8 +3495,9 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
>  /*
>   * lock_rwsem must be held for read
>   */
> -static void rbd_wait_state_locked(struct rbd_device *rbd_dev)
> +static int rbd_wait_state_locked(struct rbd_device *rbd_dev)
>  {
> +       long timeo = RBD_WAIT_LOCK_TIMEOUT_DEFAULT;
>         DEFINE_WAIT(wait);
>
>         do {
> @@ -3508,12 +3510,18 @@ static void rbd_wait_state_locked(struct rbd_device *rbd_dev)
>                 prepare_to_wait_exclusive(&rbd_dev->lock_waitq, &wait,
>                                           TASK_UNINTERRUPTIBLE);
>                 up_read(&rbd_dev->lock_rwsem);
> -               schedule();
> +               timeo = schedule_timeout(timeo);
>                 down_read(&rbd_dev->lock_rwsem);
> +               if (!timeo) {
> +                       finish_wait(&rbd_dev->lock_waitq, &wait);
> +                       rbd_warn(rbd_dev, "timed out in waiting state locked");

"timed out waiting for lock"

> +                       return -ETIMEDOUT;
> +               }
>         } while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED &&
>                  !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags));
>
>         finish_wait(&rbd_dev->lock_waitq, &wait);
> +       return 0;
>  }
>
>  static void rbd_queue_workfn(struct work_struct *work)
> @@ -3606,7 +3614,9 @@ static void rbd_queue_workfn(struct work_struct *work)
>                                 result = -EROFS;
>                                 goto err_unlock;
>                         }
> -                       rbd_wait_state_locked(rbd_dev);
> +                       result = rbd_wait_state_locked(rbd_dev);
> +                       if (result)
> +                               goto err_unlock;
>                 }
>                 if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) {
>                         result = -EBLACKLISTED;
> @@ -5261,6 +5271,8 @@ static void rbd_dev_image_unlock(struct rbd_device *rbd_dev)
>
>  static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
>  {
> +       int ret = 0;
> +
>         if (!(rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK)) {
>                 rbd_warn(rbd_dev, "exclusive-lock feature is not enabled");
>                 return -EINVAL;
> @@ -5268,8 +5280,11 @@ static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
>
>         /* FIXME: "rbd map --exclusive" should be in interruptible */
>         down_read(&rbd_dev->lock_rwsem);
> -       rbd_wait_state_locked(rbd_dev);
> +       ret = rbd_wait_state_locked(rbd_dev);
>         up_read(&rbd_dev->lock_rwsem);
> +       if (ret) {
> +               return ret;
> +       }

Unneeded braces.

Thanks,

                Ilya
--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 96657ad..199819d 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -761,6 +761,7 @@  struct rbd_options {
 #define RBD_READ_ONLY_DEFAULT	false
 #define RBD_LOCK_ON_READ_DEFAULT false
 #define RBD_EXCLUSIVE_DEFAULT	false
+#define RBD_WAIT_LOCK_TIMEOUT_DEFAULT	MAX_SCHEDULE_TIMEOUT
 
 static int parse_rbd_opts_token(char *c, void *private)
 {
@@ -3494,8 +3495,9 @@  static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
 /*
  * lock_rwsem must be held for read
  */
-static void rbd_wait_state_locked(struct rbd_device *rbd_dev)
+static int rbd_wait_state_locked(struct rbd_device *rbd_dev)
 {
+	long timeo = RBD_WAIT_LOCK_TIMEOUT_DEFAULT;
 	DEFINE_WAIT(wait);
 
 	do {
@@ -3508,12 +3510,18 @@  static void rbd_wait_state_locked(struct rbd_device *rbd_dev)
 		prepare_to_wait_exclusive(&rbd_dev->lock_waitq, &wait,
 					  TASK_UNINTERRUPTIBLE);
 		up_read(&rbd_dev->lock_rwsem);
-		schedule();
+		timeo = schedule_timeout(timeo);
 		down_read(&rbd_dev->lock_rwsem);
+		if (!timeo) {
+			finish_wait(&rbd_dev->lock_waitq, &wait);
+			rbd_warn(rbd_dev, "timed out in waiting state locked");
+			return -ETIMEDOUT;
+		}
 	} while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED &&
 		 !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags));
 
 	finish_wait(&rbd_dev->lock_waitq, &wait);
+	return 0;
 }
 
 static void rbd_queue_workfn(struct work_struct *work)
@@ -3606,7 +3614,9 @@  static void rbd_queue_workfn(struct work_struct *work)
 				result = -EROFS;
 				goto err_unlock;
 			}
-			rbd_wait_state_locked(rbd_dev);
+			result = rbd_wait_state_locked(rbd_dev);
+			if (result)
+				goto err_unlock;
 		}
 		if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) {
 			result = -EBLACKLISTED;
@@ -5261,6 +5271,8 @@  static void rbd_dev_image_unlock(struct rbd_device *rbd_dev)
 
 static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
 {
+	int ret = 0;
+
 	if (!(rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK)) {
 		rbd_warn(rbd_dev, "exclusive-lock feature is not enabled");
 		return -EINVAL;
@@ -5268,8 +5280,11 @@  static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
 
 	/* FIXME: "rbd map --exclusive" should be in interruptible */
 	down_read(&rbd_dev->lock_rwsem);
-	rbd_wait_state_locked(rbd_dev);
+	ret = rbd_wait_state_locked(rbd_dev);
 	up_read(&rbd_dev->lock_rwsem);
+	if (ret) {
+		return ret;
+	}
 	if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) {
 		rbd_warn(rbd_dev, "failed to acquire exclusive lock");
 		return -EROFS;