rbd: retrieve and check lock owner twice before blocklisting
[sfrench/cifs-2.6.git] / drivers / block / rbd.c
index 94629e826369129c4c20787a7d5a17304247c755..24afcc93ac0126215dde188510c4064652e3478b 100644 (file)
@@ -3849,6 +3849,15 @@ static void wake_lock_waiters(struct rbd_device *rbd_dev, int result)
        list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list);
 }
 
+static bool locker_equal(const struct ceph_locker *lhs,
+                        const struct ceph_locker *rhs)
+{
+       return lhs->id.name.type == rhs->id.name.type &&
+              lhs->id.name.num == rhs->id.name.num &&
+              !strcmp(lhs->id.cookie, rhs->id.cookie) &&
+              ceph_addr_equal_no_type(&lhs->info.addr, &rhs->info.addr);
+}
+
 static void free_locker(struct ceph_locker *locker)
 {
        if (locker)
@@ -3969,11 +3978,11 @@ out:
 static int rbd_try_lock(struct rbd_device *rbd_dev)
 {
        struct ceph_client *client = rbd_dev->rbd_client->client;
-       struct ceph_locker *locker;
+       struct ceph_locker *locker, *refreshed_locker;
        int ret;
 
        for (;;) {
-               locker = NULL;
+               locker = refreshed_locker = NULL;
 
                ret = rbd_lock(rbd_dev);
                if (ret != -EBUSY)
@@ -3993,6 +4002,16 @@ static int rbd_try_lock(struct rbd_device *rbd_dev)
                if (ret)
                        goto out; /* request lock or error */
 
+               refreshed_locker = get_lock_owner_info(rbd_dev);
+               if (IS_ERR(refreshed_locker)) {
+                       ret = PTR_ERR(refreshed_locker);
+                       refreshed_locker = NULL;
+                       goto out;
+               }
+               if (!refreshed_locker ||
+                   !locker_equal(locker, refreshed_locker))
+                       goto again;
+
                rbd_warn(rbd_dev, "breaking header lock owned by %s%llu",
                         ENTITY_NAME(locker->id.name));
 
@@ -4014,10 +4033,12 @@ static int rbd_try_lock(struct rbd_device *rbd_dev)
                }
 
 again:
+               free_locker(refreshed_locker);
                free_locker(locker);
        }
 
 out:
+       free_locker(refreshed_locker);
        free_locker(locker);
        return ret;
 }