libceph: wait for latest osdmap in ceph_monc_blacklist_add()
authorIlya Dryomov <idryomov@gmail.com>
Wed, 20 Mar 2019 08:46:58 +0000 (09:46 +0100)
committerIlya Dryomov <idryomov@gmail.com>
Wed, 20 Mar 2019 15:27:40 +0000 (16:27 +0100)
Because map updates are distributed lazily, an OSD may not know about
the new blacklist for quite some time after "osd blacklist add" command
is completed.  This makes it possible for a blacklisted but still alive
client to overwrite a post-blacklist update, resulting in data
corruption.

Waiting for latest osdmap in ceph_monc_blacklist_add() and thus using
the post-blacklist epoch for all post-blacklist requests ensures that
all such requests "wait" for the blacklist to come into force on their
respective OSDs.

Cc: stable@vger.kernel.org
Fixes: 6305a3b41515 ("libceph: support for blacklisting clients")
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Jason Dillaman <dillaman@redhat.com>
include/linux/ceph/libceph.h
net/ceph/ceph_common.c
net/ceph/mon_client.c

index a420c07904bcd7f6e7a082ebe0e78d913f94674e..337d5049ff93b5849b925086f33d509f29da5efa 100644 (file)
@@ -294,6 +294,8 @@ extern void ceph_destroy_client(struct ceph_client *client);
 extern int __ceph_open_session(struct ceph_client *client,
                               unsigned long started);
 extern int ceph_open_session(struct ceph_client *client);
+int ceph_wait_for_latest_osdmap(struct ceph_client *client,
+                               unsigned long timeout);
 
 /* pagevec.c */
 extern void ceph_release_page_vector(struct page **pages, int num_pages);
index 9cab80207ced6346b5b5b97b56e98674f28def73..79eac465ec65e99cf22e475f3edb0609ea4787e5 100644 (file)
@@ -738,7 +738,6 @@ int __ceph_open_session(struct ceph_client *client, unsigned long started)
 }
 EXPORT_SYMBOL(__ceph_open_session);
 
-
 int ceph_open_session(struct ceph_client *client)
 {
        int ret;
@@ -754,6 +753,23 @@ int ceph_open_session(struct ceph_client *client)
 }
 EXPORT_SYMBOL(ceph_open_session);
 
+int ceph_wait_for_latest_osdmap(struct ceph_client *client,
+                               unsigned long timeout)
+{
+       u64 newest_epoch;
+       int ret;
+
+       ret = ceph_monc_get_version(&client->monc, "osdmap", &newest_epoch);
+       if (ret)
+               return ret;
+
+       if (client->osdc.osdmap->epoch >= newest_epoch)
+               return 0;
+
+       ceph_osdc_maybe_request_map(&client->osdc);
+       return ceph_monc_wait_osdmap(&client->monc, newest_epoch, timeout);
+}
+EXPORT_SYMBOL(ceph_wait_for_latest_osdmap);
 
 static int __init init_ceph_lib(void)
 {
index 18deb3d889c4ae94a10417457fa0275a77568b48..a53e4fbb631918ccf94536849e5e25acad2dfdc6 100644 (file)
@@ -922,6 +922,15 @@ int ceph_monc_blacklist_add(struct ceph_mon_client *monc,
        mutex_unlock(&monc->mutex);
 
        ret = wait_generic_request(req);
+       if (!ret)
+               /*
+                * Make sure we have the osdmap that includes the blacklist
+                * entry.  This is needed to ensure that the OSDs pick up the
+                * new blacklist before processing any future requests from
+                * this client.
+                */
+               ret = ceph_wait_for_latest_osdmap(monc->client, 0);
+
 out:
        put_generic_request(req);
        return ret;