Re: [PATCH v3] rbd: support timeout in rbd_wait_state_locked

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Mar 26, 2018 at 4:22 PM, Dongsheng Yang
<dongsheng.yang@xxxxxxxxxxxx> 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.
>
> This patch allow user to set the lock_timeout in rbd mapping.
>
> Signed-off-by: Dongsheng Yang <dongsheng.yang@xxxxxxxxxxxx>
> ---
>  drivers/block/rbd.c | 35 +++++++++++++++++++++++++++++++----
>  1 file changed, 31 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
> index f1d9e60..58edead 100644
> --- a/drivers/block/rbd.c
> +++ b/drivers/block/rbd.c
> @@ -726,6 +726,7 @@ static struct rbd_client *rbd_client_find(struct ceph_options *ceph_opts)
>   */
>  enum {
>         Opt_queue_depth,
> +       Opt_lock_timeout,
>         Opt_last_int,
>         /* int args above */
>         Opt_last_string,
> @@ -739,6 +740,7 @@ enum {
>
>  static match_table_t rbd_opts_tokens = {
>         {Opt_queue_depth, "queue_depth=%d"},
> +       {Opt_lock_timeout, "lock_timeout=%d"},
>         /* int args above */
>         /* string args above */
>         {Opt_read_only, "read_only"},
> @@ -752,6 +754,7 @@ enum {
>
>  struct rbd_options {
>         int     queue_depth;
> +       unsigned long   lock_timeout;
>         bool    read_only;
>         bool    lock_on_read;
>         bool    exclusive;
> @@ -761,6 +764,7 @@ struct rbd_options {
>  #define RBD_READ_ONLY_DEFAULT  false
>  #define RBD_LOCK_ON_READ_DEFAULT false
>  #define RBD_EXCLUSIVE_DEFAULT  false
> +#define RBD_LOCK_TIMEOUT_DEFAULT       0  /* no timeout */
>
>  static int parse_rbd_opts_token(char *c, void *private)
>  {
> @@ -790,6 +794,14 @@ static int parse_rbd_opts_token(char *c, void *private)
>                 }
>                 rbd_opts->queue_depth = intval;
>                 break;
> +       case Opt_lock_timeout:
> +               /* 0 is "wait forever" (i.e. infinite timeout) */
> +               if (intval < 0 || intval > INT_MAX / 1000) {
> +                       pr_err("lock_timeout out of range\n");
> +                       return -EINVAL;
> +               }
> +               rbd_opts->lock_timeout = msecs_to_jiffies(intval * 1000);
> +               break;
>         case Opt_read_only:
>                 rbd_opts->read_only = true;
>                 break;
> @@ -3494,8 +3506,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)
>  {
> +       unsigned long timeout = 0;
>         DEFINE_WAIT(wait);
>
>         do {
> @@ -3508,12 +3521,19 @@ 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();
> +               timeout = schedule_timeout(ceph_timeout_jiffies(
> +                                               rbd_dev->opts->lock_timeout));
>                 down_read(&rbd_dev->lock_rwsem);
> +               if (!timeout) {
> +                       finish_wait(&rbd_dev->lock_waitq, &wait);
> +                       rbd_warn(rbd_dev, "timed out in 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 +3626,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;
> @@ -5139,6 +5161,7 @@ static int rbd_add_parse_args(const char *buf,
>
>         rbd_opts->read_only = RBD_READ_ONLY_DEFAULT;
>         rbd_opts->queue_depth = RBD_QUEUE_DEPTH_DEFAULT;
> +       rbd_opts->lock_timeout = RBD_LOCK_TIMEOUT_DEFAULT;
>         rbd_opts->lock_on_read = RBD_LOCK_ON_READ_DEFAULT;
>         rbd_opts->exclusive = RBD_EXCLUSIVE_DEFAULT;
>
> @@ -5209,6 +5232,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;
> @@ -5216,8 +5241,10 @@ 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;

Looks good to me.

I don't like that rbd_wait_state_locked() has kind of two return values
now: the error code and RBD_DEV_FLAG_BLACKLISTED flag which needs to be
tested afterwards, but I'll fix it myself.

Thanks,

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



[Index of Archives]     [CEPH Users]     [Ceph Large]     [Information on CEPH]     [Linux BTRFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux