rbd: support timeout in rbd_wait_state_locked()
authorDongsheng Yang <dongsheng.yang@easystack.cn>
Mon, 26 Mar 2018 14:22:55 +0000 (10:22 -0400)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 16 Apr 2018 07:38:40 +0000 (09:38 +0200)
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@easystack.cn>
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
drivers/block/rbd.c

index f4b1b91e6d4dee0fc07d996557328c78a49c23f5..d5a51493e8b58099dc5d374a5bf4ce7e24f73adf 100644 (file)
@@ -732,6 +732,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,
@@ -745,6 +746,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"},
@@ -758,12 +760,14 @@ static match_table_t rbd_opts_tokens = {
 
 struct rbd_options {
        int     queue_depth;
+       unsigned long   lock_timeout;
        bool    read_only;
        bool    lock_on_read;
        bool    exclusive;
 };
 
 #define RBD_QUEUE_DEPTH_DEFAULT        BLKDEV_MAX_RQ
+#define RBD_LOCK_TIMEOUT_DEFAULT 0  /* no timeout */
 #define RBD_READ_ONLY_DEFAULT  false
 #define RBD_LOCK_ON_READ_DEFAULT false
 #define RBD_EXCLUSIVE_DEFAULT  false
@@ -796,6 +800,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;
@@ -3536,6 +3548,7 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
 static int rbd_wait_state_locked(struct rbd_device *rbd_dev, bool may_acquire)
 {
        DEFINE_WAIT(wait);
+       unsigned long timeout;
        int ret = 0;
 
        if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags))
@@ -3559,12 +3572,18 @@ static int rbd_wait_state_locked(struct rbd_device *rbd_dev, bool may_acquire)
                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 (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) {
                        ret = -EBLACKLISTED;
                        break;
                }
+               if (!timeout) {
+                       rbd_warn(rbd_dev, "timed out waiting for lock");
+                       ret = -ETIMEDOUT;
+                       break;
+               }
        } while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED);
 
        finish_wait(&rbd_dev->lock_waitq, &wait);
@@ -5186,6 +5205,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;