diff options
| author | Ilya Dryomov <idryomov@gmail.com> | 2017-04-13 06:17:38 -0400 |
|---|---|---|
| committer | Ilya Dryomov <idryomov@gmail.com> | 2017-05-04 03:19:23 -0400 |
| commit | 14bb211d324d6c8140167bd6b2b8a80757348a2f (patch) | |
| tree | aafb98077b59c9a8488b2e15082099fec2ce9a9d | |
| parent | cbbfb0ff115159847121afe9c7553bd5c86f6062 (diff) | |
rbd: support updating the lock cookie without releasing the lock
As we no longer release the lock before potentially raising BLACKLISTED
in rbd_reregister_watch(), the "either locked or blacklisted" assert in
rbd_queue_workfn() needs to go: we can be both locked and blacklisted
at that point now.
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Jason Dillaman <dillaman@redhat.com>
| -rw-r--r-- | drivers/block/rbd.c | 66 | ||||
| -rw-r--r-- | include/linux/ceph/cls_lock_client.h | 5 | ||||
| -rw-r--r-- | net/ceph/cls_lock_client.c | 51 |
3 files changed, 97 insertions, 25 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 5f563db59820..063c8f06fb9c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
| @@ -3820,24 +3820,51 @@ static void rbd_unregister_watch(struct rbd_device *rbd_dev) | |||
| 3820 | ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); | 3820 | ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); |
| 3821 | } | 3821 | } |
| 3822 | 3822 | ||
| 3823 | /* | ||
| 3824 | * lock_rwsem must be held for write | ||
| 3825 | */ | ||
| 3826 | static void rbd_reacquire_lock(struct rbd_device *rbd_dev) | ||
| 3827 | { | ||
| 3828 | struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; | ||
| 3829 | char cookie[32]; | ||
| 3830 | int ret; | ||
| 3831 | |||
| 3832 | WARN_ON(rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED); | ||
| 3833 | |||
| 3834 | format_lock_cookie(rbd_dev, cookie); | ||
| 3835 | ret = ceph_cls_set_cookie(osdc, &rbd_dev->header_oid, | ||
| 3836 | &rbd_dev->header_oloc, RBD_LOCK_NAME, | ||
| 3837 | CEPH_CLS_LOCK_EXCLUSIVE, rbd_dev->lock_cookie, | ||
| 3838 | RBD_LOCK_TAG, cookie); | ||
| 3839 | if (ret) { | ||
| 3840 | if (ret != -EOPNOTSUPP) | ||
| 3841 | rbd_warn(rbd_dev, "failed to update lock cookie: %d", | ||
| 3842 | ret); | ||
| 3843 | |||
| 3844 | /* | ||
| 3845 | * Lock cookie cannot be updated on older OSDs, so do | ||
| 3846 | * a manual release and queue an acquire. | ||
| 3847 | */ | ||
| 3848 | if (rbd_release_lock(rbd_dev)) | ||
| 3849 | queue_delayed_work(rbd_dev->task_wq, | ||
| 3850 | &rbd_dev->lock_dwork, 0); | ||
| 3851 | } else { | ||
| 3852 | strcpy(rbd_dev->lock_cookie, cookie); | ||
| 3853 | } | ||
| 3854 | } | ||
| 3855 | |||
| 3823 | static void rbd_reregister_watch(struct work_struct *work) | 3856 | static void rbd_reregister_watch(struct work_struct *work) |
| 3824 | { | 3857 | { |
| 3825 | struct rbd_device *rbd_dev = container_of(to_delayed_work(work), | 3858 | struct rbd_device *rbd_dev = container_of(to_delayed_work(work), |
| 3826 | struct rbd_device, watch_dwork); | 3859 | struct rbd_device, watch_dwork); |
| 3827 | bool was_lock_owner = false; | ||
| 3828 | bool need_to_wake = false; | ||
| 3829 | int ret; | 3860 | int ret; |
| 3830 | 3861 | ||
| 3831 | dout("%s rbd_dev %p\n", __func__, rbd_dev); | 3862 | dout("%s rbd_dev %p\n", __func__, rbd_dev); |
| 3832 | 3863 | ||
| 3833 | down_write(&rbd_dev->lock_rwsem); | ||
| 3834 | if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) | ||
| 3835 | was_lock_owner = rbd_release_lock(rbd_dev); | ||
| 3836 | |||
| 3837 | mutex_lock(&rbd_dev->watch_mutex); | 3864 | mutex_lock(&rbd_dev->watch_mutex); |
| 3838 | if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR) { | 3865 | if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR) { |
| 3839 | mutex_unlock(&rbd_dev->watch_mutex); | 3866 | mutex_unlock(&rbd_dev->watch_mutex); |
| 3840 | goto out; | 3867 | return; |
| 3841 | } | 3868 | } |
| 3842 | 3869 | ||
| 3843 | ret = __rbd_register_watch(rbd_dev); | 3870 | ret = __rbd_register_watch(rbd_dev); |
| @@ -3845,36 +3872,28 @@ static void rbd_reregister_watch(struct work_struct *work) | |||
| 3845 | rbd_warn(rbd_dev, "failed to reregister watch: %d", ret); | 3872 | rbd_warn(rbd_dev, "failed to reregister watch: %d", ret); |
| 3846 | if (ret == -EBLACKLISTED || ret == -ENOENT) { | 3873 | if (ret == -EBLACKLISTED || ret == -ENOENT) { |
| 3847 | set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags); | 3874 | set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags); |
| 3848 | need_to_wake = true; | 3875 | wake_requests(rbd_dev, true); |
| 3849 | } else { | 3876 | } else { |
| 3850 | queue_delayed_work(rbd_dev->task_wq, | 3877 | queue_delayed_work(rbd_dev->task_wq, |
| 3851 | &rbd_dev->watch_dwork, | 3878 | &rbd_dev->watch_dwork, |
| 3852 | RBD_RETRY_DELAY); | 3879 | RBD_RETRY_DELAY); |
| 3853 | } | 3880 | } |
| 3854 | mutex_unlock(&rbd_dev->watch_mutex); | 3881 | mutex_unlock(&rbd_dev->watch_mutex); |
| 3855 | goto out; | 3882 | return; |
| 3856 | } | 3883 | } |
| 3857 | 3884 | ||
| 3858 | need_to_wake = true; | ||
| 3859 | rbd_dev->watch_state = RBD_WATCH_STATE_REGISTERED; | 3885 | rbd_dev->watch_state = RBD_WATCH_STATE_REGISTERED; |
| 3860 | rbd_dev->watch_cookie = rbd_dev->watch_handle->linger_id; | 3886 | rbd_dev->watch_cookie = rbd_dev->watch_handle->linger_id; |
| 3861 | mutex_unlock(&rbd_dev->watch_mutex); | 3887 | mutex_unlock(&rbd_dev->watch_mutex); |
| 3862 | 3888 | ||
| 3889 | down_write(&rbd_dev->lock_rwsem); | ||
| 3890 | if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) | ||
| 3891 | rbd_reacquire_lock(rbd_dev); | ||
| 3892 | up_write(&rbd_dev->lock_rwsem); | ||
| 3893 | |||
| 3863 | ret = rbd_dev_refresh(rbd_dev); | 3894 | ret = rbd_dev_refresh(rbd_dev); |
| 3864 | if (ret) | 3895 | if (ret) |
| 3865 | rbd_warn(rbd_dev, "reregisteration refresh failed: %d", ret); | 3896 | rbd_warn(rbd_dev, "reregisteration refresh failed: %d", ret); |
| 3866 | |||
| 3867 | if (was_lock_owner) { | ||
| 3868 | ret = rbd_try_lock(rbd_dev); | ||
| 3869 | if (ret) | ||
| 3870 | rbd_warn(rbd_dev, "reregisteration lock failed: %d", | ||
| 3871 | ret); | ||
| 3872 | } | ||
| 3873 | |||
| 3874 | out: | ||
| 3875 | up_write(&rbd_dev->lock_rwsem); | ||
| 3876 | if (need_to_wake) | ||
| 3877 | wake_requests(rbd_dev, true); | ||
| 3878 | } | 3897 | } |
| 3879 | 3898 | ||
| 3880 | /* | 3899 | /* |
| @@ -4052,9 +4071,6 @@ static void rbd_queue_workfn(struct work_struct *work) | |||
| 4052 | if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED && | 4071 | if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED && |
| 4053 | !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) | 4072 | !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) |
| 4054 | rbd_wait_state_locked(rbd_dev); | 4073 | rbd_wait_state_locked(rbd_dev); |
| 4055 | |||
| 4056 | WARN_ON((rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) ^ | ||
| 4057 | !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)); | ||
| 4058 | if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) { | 4074 | if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) { |
| 4059 | result = -EBLACKLISTED; | 4075 | result = -EBLACKLISTED; |
| 4060 | goto err_unlock; | 4076 | goto err_unlock; |
diff --git a/include/linux/ceph/cls_lock_client.h b/include/linux/ceph/cls_lock_client.h index 84884d8d4710..0594d3bba774 100644 --- a/include/linux/ceph/cls_lock_client.h +++ b/include/linux/ceph/cls_lock_client.h | |||
| @@ -37,6 +37,11 @@ int ceph_cls_break_lock(struct ceph_osd_client *osdc, | |||
| 37 | struct ceph_object_locator *oloc, | 37 | struct ceph_object_locator *oloc, |
| 38 | char *lock_name, char *cookie, | 38 | char *lock_name, char *cookie, |
| 39 | struct ceph_entity_name *locker); | 39 | struct ceph_entity_name *locker); |
| 40 | int ceph_cls_set_cookie(struct ceph_osd_client *osdc, | ||
| 41 | struct ceph_object_id *oid, | ||
| 42 | struct ceph_object_locator *oloc, | ||
| 43 | char *lock_name, u8 type, char *old_cookie, | ||
| 44 | char *tag, char *new_cookie); | ||
| 40 | 45 | ||
| 41 | void ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers); | 46 | void ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers); |
| 42 | 47 | ||
diff --git a/net/ceph/cls_lock_client.c b/net/ceph/cls_lock_client.c index b9233b990399..08ada893f01e 100644 --- a/net/ceph/cls_lock_client.c +++ b/net/ceph/cls_lock_client.c | |||
| @@ -179,6 +179,57 @@ int ceph_cls_break_lock(struct ceph_osd_client *osdc, | |||
| 179 | } | 179 | } |
| 180 | EXPORT_SYMBOL(ceph_cls_break_lock); | 180 | EXPORT_SYMBOL(ceph_cls_break_lock); |
| 181 | 181 | ||
| 182 | int ceph_cls_set_cookie(struct ceph_osd_client *osdc, | ||
| 183 | struct ceph_object_id *oid, | ||
| 184 | struct ceph_object_locator *oloc, | ||
| 185 | char *lock_name, u8 type, char *old_cookie, | ||
| 186 | char *tag, char *new_cookie) | ||
| 187 | { | ||
| 188 | int cookie_op_buf_size; | ||
| 189 | int name_len = strlen(lock_name); | ||
| 190 | int old_cookie_len = strlen(old_cookie); | ||
| 191 | int tag_len = strlen(tag); | ||
| 192 | int new_cookie_len = strlen(new_cookie); | ||
| 193 | void *p, *end; | ||
| 194 | struct page *cookie_op_page; | ||
| 195 | int ret; | ||
| 196 | |||
| 197 | cookie_op_buf_size = name_len + sizeof(__le32) + | ||
| 198 | old_cookie_len + sizeof(__le32) + | ||
| 199 | tag_len + sizeof(__le32) + | ||
| 200 | new_cookie_len + sizeof(__le32) + | ||
| 201 | sizeof(u8) + CEPH_ENCODING_START_BLK_LEN; | ||
| 202 | if (cookie_op_buf_size > PAGE_SIZE) | ||
| 203 | return -E2BIG; | ||
| 204 | |||
| 205 | cookie_op_page = alloc_page(GFP_NOIO); | ||
| 206 | if (!cookie_op_page) | ||
| 207 | return -ENOMEM; | ||
| 208 | |||
| 209 | p = page_address(cookie_op_page); | ||
| 210 | end = p + cookie_op_buf_size; | ||
| 211 | |||
| 212 | /* encode cls_lock_set_cookie_op struct */ | ||
| 213 | ceph_start_encoding(&p, 1, 1, | ||
| 214 | cookie_op_buf_size - CEPH_ENCODING_START_BLK_LEN); | ||
| 215 | ceph_encode_string(&p, end, lock_name, name_len); | ||
| 216 | ceph_encode_8(&p, type); | ||
| 217 | ceph_encode_string(&p, end, old_cookie, old_cookie_len); | ||
| 218 | ceph_encode_string(&p, end, tag, tag_len); | ||
| 219 | ceph_encode_string(&p, end, new_cookie, new_cookie_len); | ||
| 220 | |||
| 221 | dout("%s lock_name %s type %d old_cookie %s tag %s new_cookie %s\n", | ||
| 222 | __func__, lock_name, type, old_cookie, tag, new_cookie); | ||
| 223 | ret = ceph_osdc_call(osdc, oid, oloc, "lock", "set_cookie", | ||
| 224 | CEPH_OSD_FLAG_WRITE, cookie_op_page, | ||
| 225 | cookie_op_buf_size, NULL, NULL); | ||
| 226 | |||
| 227 | dout("%s: status %d\n", __func__, ret); | ||
| 228 | __free_page(cookie_op_page); | ||
| 229 | return ret; | ||
| 230 | } | ||
| 231 | EXPORT_SYMBOL(ceph_cls_set_cookie); | ||
| 232 | |||
| 182 | void ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers) | 233 | void ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers) |
| 183 | { | 234 | { |
| 184 | int i; | 235 | int i; |
