From: Greg Kroah-Hartman Date: Wed, 21 Nov 2012 20:01:59 +0000 (-0800) Subject: 3.4-stable patches X-Git-Tag: v3.0.53~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=07fd9df15b21778a0fdfea71af0ae1ea36c66987;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: 0020-ceph-ensure-auth-ops-are-defined-before-use.patch 0021-ceph-have-get_authorizer-methods-return-pointers.patch 0022-ceph-use-info-returned-by-get_authorizer.patch 0023-ceph-return-pointer-from-prepare_connect_authorizer.patch 0024-ceph-rename-prepare_connect_authorizer.patch 0025-ceph-add-auth-buf-in-prepare_write_connect.patch 0026-libceph-avoid-unregistering-osd-request-when-not-reg.patch 0027-libceph-fix-pg_temp-updates.patch 0028-libceph-osd_client-don-t-drop-reply-reference-too-ea.patch 0029-libceph-use-con-get-put-ops-from-osd_client.patch 0030-rbd-Clear-ceph_msg-bio_iter-for-retransmitted-messag.patch 0031-libceph-flush-msgr-queue-during-mon_client-shutdown.patch 0032-libceph-fix-messenger-retry.patch 0033-rbd-don-t-hold-spinlock-during-messenger-flush.patch 0034-rbd-protect-read-of-snapshot-sequence-number.patch 0035-rbd-store-snapshot-id-instead-of-index.patch 0036-rbd-Fix-ceph_snap_context-size-calculation.patch 0037-ceph-check-PG_Private-flag-before-accessing-page-pri.patch 0038-libceph-eliminate-connection-state-DEAD.patch 0039-libceph-kill-bad_proto-ceph-connection-op.patch --- diff --git a/queue-3.4/0020-ceph-ensure-auth-ops-are-defined-before-use.patch b/queue-3.4/0020-ceph-ensure-auth-ops-are-defined-before-use.patch new file mode 100644 index 00000000000..bd7bebda156 --- /dev/null +++ b/queue-3.4/0020-ceph-ensure-auth-ops-are-defined-before-use.patch @@ -0,0 +1,102 @@ +From a00861eb3377fc51a555d0bc367cc2473d7b7efc Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Wed, 16 May 2012 15:16:39 -0500 +Subject: ceph: ensure auth ops are defined before use + +From: Alex Elder + +(cherry picked from commit a255651d4cad89f1a606edd36135af892ada4f20) + +In the create_authorizer method for both the mds and osd clients, +the auth_client->ops pointer is blindly dereferenced. There is no +obvious guarantee that this pointer has been assigned. And +furthermore, even if the ops pointer is non-null there is definitely +no guarantee that the create_authorizer or destroy_authorizer +methods are defined. + +Add checks in both routines to make sure they are defined (non-null) +before use. Add similar checks in a few other spots in these files +while we're at it. + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/mds_client.c | 14 ++++++-------- + net/ceph/osd_client.c | 15 ++++++++++----- + 2 files changed, 16 insertions(+), 13 deletions(-) + +--- a/fs/ceph/mds_client.c ++++ b/fs/ceph/mds_client.c +@@ -3406,16 +3406,14 @@ static int get_authorizer(struct ceph_co + int ret = 0; + + if (force_new && auth->authorizer) { +- ac->ops->destroy_authorizer(ac, auth->authorizer); ++ if (ac->ops && ac->ops->destroy_authorizer) ++ ac->ops->destroy_authorizer(ac, auth->authorizer); + auth->authorizer = NULL; + } +- if (auth->authorizer == NULL) { +- if (ac->ops->create_authorizer) { +- ret = ac->ops->create_authorizer(ac, +- CEPH_ENTITY_TYPE_MDS, auth); +- if (ret) +- return ret; +- } ++ if (!auth->authorizer && ac->ops && ac->ops->create_authorizer) { ++ ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_MDS, auth); ++ if (ret) ++ return ret; + } + + *proto = ac->protocol; +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -664,10 +664,10 @@ static void put_osd(struct ceph_osd *osd + { + dout("put_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref), + atomic_read(&osd->o_ref) - 1); +- if (atomic_dec_and_test(&osd->o_ref)) { ++ if (atomic_dec_and_test(&osd->o_ref) && osd->o_auth.authorizer) { + struct ceph_auth_client *ac = osd->o_osdc->client->monc.auth; + +- if (osd->o_auth.authorizer) ++ if (ac->ops && ac->ops->destroy_authorizer) + ac->ops->destroy_authorizer(ac, osd->o_auth.authorizer); + kfree(osd); + } +@@ -2119,10 +2119,11 @@ static int get_authorizer(struct ceph_co + int ret = 0; + + if (force_new && auth->authorizer) { +- ac->ops->destroy_authorizer(ac, auth->authorizer); ++ if (ac->ops && ac->ops->destroy_authorizer) ++ ac->ops->destroy_authorizer(ac, auth->authorizer); + auth->authorizer = NULL; + } +- if (auth->authorizer == NULL) { ++ if (!auth->authorizer && ac->ops && ac->ops->create_authorizer) { + ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_OSD, auth); + if (ret) + return ret; +@@ -2144,6 +2145,10 @@ static int verify_authorizer_reply(struc + struct ceph_osd_client *osdc = o->o_osdc; + struct ceph_auth_client *ac = osdc->client->monc.auth; + ++ /* ++ * XXX If ac->ops or ac->ops->verify_authorizer_reply is null, ++ * XXX which do we do: succeed or fail? ++ */ + return ac->ops->verify_authorizer_reply(ac, o->o_auth.authorizer, len); + } + +@@ -2153,7 +2158,7 @@ static int invalidate_authorizer(struct + struct ceph_osd_client *osdc = o->o_osdc; + struct ceph_auth_client *ac = osdc->client->monc.auth; + +- if (ac->ops->invalidate_authorizer) ++ if (ac->ops && ac->ops->invalidate_authorizer) + ac->ops->invalidate_authorizer(ac, CEPH_ENTITY_TYPE_OSD); + + return ceph_monc_validate_auth(&osdc->client->monc); diff --git a/queue-3.4/0021-ceph-have-get_authorizer-methods-return-pointers.patch b/queue-3.4/0021-ceph-have-get_authorizer-methods-return-pointers.patch new file mode 100644 index 00000000000..6a4fa05c6c3 --- /dev/null +++ b/queue-3.4/0021-ceph-have-get_authorizer-methods-return-pointers.patch @@ -0,0 +1,166 @@ +From b306a7107e65cde5350584e00ea2b04fe84faa6f Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Wed, 16 May 2012 15:16:39 -0500 +Subject: ceph: have get_authorizer methods return pointers + +From: Alex Elder + +(cherry picked from commit a3530df33eb91d787d08c7383a0a9982690e42d0) + +Have the get_authorizer auth_client method return a ceph_auth +pointer rather than an integer, pointer-encoding any returned +error value. This is to pave the way for making use of the +returned value in an upcoming patch. + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/mds_client.c | 20 +++++++++++++------- + include/linux/ceph/messenger.h | 8 +++++--- + net/ceph/messenger.c | 8 ++++---- + net/ceph/osd_client.c | 19 ++++++++++++------- + 4 files changed, 34 insertions(+), 21 deletions(-) + +--- a/fs/ceph/mds_client.c ++++ b/fs/ceph/mds_client.c +@@ -3395,15 +3395,20 @@ out: + /* + * authentication + */ +-static int get_authorizer(struct ceph_connection *con, +- void **buf, int *len, int *proto, +- void **reply_buf, int *reply_len, int force_new) ++ ++/* ++ * Note: returned pointer is the address of a structure that's ++ * managed separately. Caller must *not* attempt to free it. ++ */ ++static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, ++ void **buf, int *len, int *proto, ++ void **reply_buf, int *reply_len, ++ int force_new) + { + struct ceph_mds_session *s = con->private; + struct ceph_mds_client *mdsc = s->s_mdsc; + struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth; + struct ceph_auth_handshake *auth = &s->s_auth; +- int ret = 0; + + if (force_new && auth->authorizer) { + if (ac->ops && ac->ops->destroy_authorizer) +@@ -3411,9 +3416,10 @@ static int get_authorizer(struct ceph_co + auth->authorizer = NULL; + } + if (!auth->authorizer && ac->ops && ac->ops->create_authorizer) { +- ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_MDS, auth); ++ int ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_MDS, ++ auth); + if (ret) +- return ret; ++ return ERR_PTR(ret); + } + + *proto = ac->protocol; +@@ -3422,7 +3428,7 @@ static int get_authorizer(struct ceph_co + *reply_buf = auth->authorizer_reply_buf; + *reply_len = auth->authorizer_reply_buf_len; + +- return 0; ++ return auth; + } + + +--- a/include/linux/ceph/messenger.h ++++ b/include/linux/ceph/messenger.h +@@ -25,9 +25,11 @@ struct ceph_connection_operations { + void (*dispatch) (struct ceph_connection *con, struct ceph_msg *m); + + /* authorize an outgoing connection */ +- int (*get_authorizer) (struct ceph_connection *con, +- void **buf, int *len, int *proto, +- void **reply_buf, int *reply_len, int force_new); ++ struct ceph_auth_handshake *(*get_authorizer) ( ++ struct ceph_connection *con, ++ void **buf, int *len, int *proto, ++ void **reply_buf, int *reply_len, ++ int force_new); + int (*verify_authorizer_reply) (struct ceph_connection *con, int len); + int (*invalidate_authorizer)(struct ceph_connection *con); + +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -658,7 +658,7 @@ static int prepare_connect_authorizer(st + void *auth_buf; + int auth_len; + int auth_protocol; +- int ret; ++ struct ceph_auth_handshake *auth; + + if (!con->ops->get_authorizer) { + con->out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; +@@ -674,13 +674,13 @@ static int prepare_connect_authorizer(st + auth_buf = NULL; + auth_len = 0; + auth_protocol = CEPH_AUTH_UNKNOWN; +- ret = con->ops->get_authorizer(con, &auth_buf, &auth_len, ++ auth = con->ops->get_authorizer(con, &auth_buf, &auth_len, + &auth_protocol, &con->auth_reply_buf, + &con->auth_reply_buf_len, con->auth_retry); + mutex_lock(&con->mutex); + +- if (ret) +- return ret; ++ if (IS_ERR(auth)) ++ return PTR_ERR(auth); + + if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) + return -EAGAIN; +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -2108,15 +2108,19 @@ static void put_osd_con(struct ceph_conn + /* + * authentication + */ +-static int get_authorizer(struct ceph_connection *con, +- void **buf, int *len, int *proto, +- void **reply_buf, int *reply_len, int force_new) ++/* ++ * Note: returned pointer is the address of a structure that's ++ * managed separately. Caller must *not* attempt to free it. ++ */ ++static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, ++ void **buf, int *len, int *proto, ++ void **reply_buf, int *reply_len, ++ int force_new) + { + struct ceph_osd *o = con->private; + struct ceph_osd_client *osdc = o->o_osdc; + struct ceph_auth_client *ac = osdc->client->monc.auth; + struct ceph_auth_handshake *auth = &o->o_auth; +- int ret = 0; + + if (force_new && auth->authorizer) { + if (ac->ops && ac->ops->destroy_authorizer) +@@ -2124,9 +2128,10 @@ static int get_authorizer(struct ceph_co + auth->authorizer = NULL; + } + if (!auth->authorizer && ac->ops && ac->ops->create_authorizer) { +- ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_OSD, auth); ++ int ret = ac->ops->create_authorizer(ac, CEPH_ENTITY_TYPE_OSD, ++ auth); + if (ret) +- return ret; ++ return ERR_PTR(ret); + } + + *proto = ac->protocol; +@@ -2135,7 +2140,7 @@ static int get_authorizer(struct ceph_co + *reply_buf = auth->authorizer_reply_buf; + *reply_len = auth->authorizer_reply_buf_len; + +- return 0; ++ return auth; + } + + diff --git a/queue-3.4/0022-ceph-use-info-returned-by-get_authorizer.patch b/queue-3.4/0022-ceph-use-info-returned-by-get_authorizer.patch new file mode 100644 index 00000000000..f14bdc23dd8 --- /dev/null +++ b/queue-3.4/0022-ceph-use-info-returned-by-get_authorizer.patch @@ -0,0 +1,119 @@ +From 8f78f1676fed681923b213924d75474e4da08228 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Wed, 16 May 2012 15:16:39 -0500 +Subject: ceph: use info returned by get_authorizer + +From: Alex Elder + +(cherry picked from commit 8f43fb53894079bf0caab6e348ceaffe7adc651a) + +Rather than passing a bunch of arguments to be filled in with the +content of the ceph_auth_handshake buffer now returned by the +get_authorizer method, just use the returned information in the +caller, and drop the unnecessary arguments. + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/mds_client.c | 9 +-------- + include/linux/ceph/messenger.h | 4 +--- + net/ceph/messenger.c | 13 +++++++------ + net/ceph/osd_client.c | 9 +-------- + 4 files changed, 10 insertions(+), 25 deletions(-) + +--- a/fs/ceph/mds_client.c ++++ b/fs/ceph/mds_client.c +@@ -3401,9 +3401,7 @@ out: + * managed separately. Caller must *not* attempt to free it. + */ + static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, +- void **buf, int *len, int *proto, +- void **reply_buf, int *reply_len, +- int force_new) ++ int *proto, int force_new) + { + struct ceph_mds_session *s = con->private; + struct ceph_mds_client *mdsc = s->s_mdsc; +@@ -3421,12 +3419,7 @@ static struct ceph_auth_handshake *get_a + if (ret) + return ERR_PTR(ret); + } +- + *proto = ac->protocol; +- *buf = auth->authorizer_buf; +- *len = auth->authorizer_buf_len; +- *reply_buf = auth->authorizer_reply_buf; +- *reply_len = auth->authorizer_reply_buf_len; + + return auth; + } +--- a/include/linux/ceph/messenger.h ++++ b/include/linux/ceph/messenger.h +@@ -27,9 +27,7 @@ struct ceph_connection_operations { + /* authorize an outgoing connection */ + struct ceph_auth_handshake *(*get_authorizer) ( + struct ceph_connection *con, +- void **buf, int *len, int *proto, +- void **reply_buf, int *reply_len, +- int force_new); ++ int *proto, int force_new); + int (*verify_authorizer_reply) (struct ceph_connection *con, int len); + int (*invalidate_authorizer)(struct ceph_connection *con); + +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -671,20 +671,21 @@ static int prepare_connect_authorizer(st + + mutex_unlock(&con->mutex); + +- auth_buf = NULL; +- auth_len = 0; + auth_protocol = CEPH_AUTH_UNKNOWN; +- auth = con->ops->get_authorizer(con, &auth_buf, &auth_len, +- &auth_protocol, &con->auth_reply_buf, +- &con->auth_reply_buf_len, con->auth_retry); ++ auth = con->ops->get_authorizer(con, &auth_protocol, con->auth_retry); ++ + mutex_lock(&con->mutex); + + if (IS_ERR(auth)) + return PTR_ERR(auth); +- + if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) + return -EAGAIN; + ++ auth_buf = auth->authorizer_buf; ++ auth_len = auth->authorizer_buf_len; ++ con->auth_reply_buf = auth->authorizer_reply_buf; ++ con->auth_reply_buf_len = auth->authorizer_reply_buf_len; ++ + con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol); + con->out_connect.authorizer_len = cpu_to_le32(auth_len); + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -2113,9 +2113,7 @@ static void put_osd_con(struct ceph_conn + * managed separately. Caller must *not* attempt to free it. + */ + static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con, +- void **buf, int *len, int *proto, +- void **reply_buf, int *reply_len, +- int force_new) ++ int *proto, int force_new) + { + struct ceph_osd *o = con->private; + struct ceph_osd_client *osdc = o->o_osdc; +@@ -2133,12 +2131,7 @@ static struct ceph_auth_handshake *get_a + if (ret) + return ERR_PTR(ret); + } +- + *proto = ac->protocol; +- *buf = auth->authorizer_buf; +- *len = auth->authorizer_buf_len; +- *reply_buf = auth->authorizer_reply_buf; +- *reply_len = auth->authorizer_reply_buf_len; + + return auth; + } diff --git a/queue-3.4/0023-ceph-return-pointer-from-prepare_connect_authorizer.patch b/queue-3.4/0023-ceph-return-pointer-from-prepare_connect_authorizer.patch new file mode 100644 index 00000000000..daff2a13ef9 --- /dev/null +++ b/queue-3.4/0023-ceph-return-pointer-from-prepare_connect_authorizer.patch @@ -0,0 +1,82 @@ +From 38466376a17ef15fb40c879c76598a5c1ffdc042 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Wed, 16 May 2012 15:16:39 -0500 +Subject: ceph: return pointer from prepare_connect_authorizer() + +From: Alex Elder + +(cherry picked from commit 729796be9190f57ca40ccca315e8ad34a1eb8fef) + +Change prepare_connect_authorizer() so it returns a pointer (or +pointer-coded error). + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/messenger.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -653,7 +653,7 @@ static void prepare_write_keepalive(stru + * Connection negotiation. + */ + +-static int prepare_connect_authorizer(struct ceph_connection *con) ++static struct ceph_auth_handshake *prepare_connect_authorizer(struct ceph_connection *con) + { + void *auth_buf; + int auth_len; +@@ -664,7 +664,7 @@ static int prepare_connect_authorizer(st + con->out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; + con->out_connect.authorizer_len = 0; + +- return 0; ++ return NULL; + } + + /* Can't hold the mutex while getting authorizer */ +@@ -677,9 +677,9 @@ static int prepare_connect_authorizer(st + mutex_lock(&con->mutex); + + if (IS_ERR(auth)) +- return PTR_ERR(auth); ++ return auth; + if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) +- return -EAGAIN; ++ return ERR_PTR(-EAGAIN); + + auth_buf = auth->authorizer_buf; + auth_len = auth->authorizer_buf_len; +@@ -692,7 +692,7 @@ static int prepare_connect_authorizer(st + if (auth_len) + ceph_con_out_kvec_add(con, auth_len, auth_buf); + +- return 0; ++ return auth; + } + + /* +@@ -712,7 +712,7 @@ static int prepare_write_connect(struct + { + unsigned global_seq = get_global_seq(con->msgr, 0); + int proto; +- int ret; ++ struct ceph_auth_handshake *auth; + + switch (con->peer_name.type) { + case CEPH_ENTITY_TYPE_MON: +@@ -739,9 +739,9 @@ static int prepare_write_connect(struct + con->out_connect.flags = 0; + + ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); +- ret = prepare_connect_authorizer(con); +- if (ret) +- return ret; ++ auth = prepare_connect_authorizer(con); ++ if (IS_ERR(auth)) ++ return PTR_ERR(auth); + + con->out_more = 0; + set_bit(WRITE_PENDING, &con->state); diff --git a/queue-3.4/0024-ceph-rename-prepare_connect_authorizer.patch b/queue-3.4/0024-ceph-rename-prepare_connect_authorizer.patch new file mode 100644 index 00000000000..ef5279dbcfa --- /dev/null +++ b/queue-3.4/0024-ceph-rename-prepare_connect_authorizer.patch @@ -0,0 +1,80 @@ +From 6309b70e547cb121bdba4933d794237ab397bd54 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Wed, 16 May 2012 15:16:39 -0500 +Subject: ceph: rename prepare_connect_authorizer() + +From: Alex Elder + +(cherry picked from commit dac1e716c60161867a47745bca592987ca3a9cb2) + +Change the name of prepare_connect_authorizer(). The next +patch is going to make this function no longer add anything to the +connection's out_kvec, so it will no longer fit the pattern of +the rest of the prepare_connect_*() functions. + +In addition, pass the address of a variable that will hold the +authorization protocol to use. Move the assignment of that to the +connection's out_connect structure into prepare_write_connect(). + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/messenger.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -653,11 +653,11 @@ static void prepare_write_keepalive(stru + * Connection negotiation. + */ + +-static struct ceph_auth_handshake *prepare_connect_authorizer(struct ceph_connection *con) ++static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection *con, ++ int *auth_proto) + { + void *auth_buf; + int auth_len; +- int auth_protocol; + struct ceph_auth_handshake *auth; + + if (!con->ops->get_authorizer) { +@@ -671,8 +671,7 @@ static struct ceph_auth_handshake *prepa + + mutex_unlock(&con->mutex); + +- auth_protocol = CEPH_AUTH_UNKNOWN; +- auth = con->ops->get_authorizer(con, &auth_protocol, con->auth_retry); ++ auth = con->ops->get_authorizer(con, auth_proto, con->auth_retry); + + mutex_lock(&con->mutex); + +@@ -686,7 +685,6 @@ static struct ceph_auth_handshake *prepa + con->auth_reply_buf = auth->authorizer_reply_buf; + con->auth_reply_buf_len = auth->authorizer_reply_buf_len; + +- con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol); + con->out_connect.authorizer_len = cpu_to_le32(auth_len); + + if (auth_len) +@@ -712,6 +710,7 @@ static int prepare_write_connect(struct + { + unsigned global_seq = get_global_seq(con->msgr, 0); + int proto; ++ int auth_proto; + struct ceph_auth_handshake *auth; + + switch (con->peer_name.type) { +@@ -739,9 +738,11 @@ static int prepare_write_connect(struct + con->out_connect.flags = 0; + + ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); +- auth = prepare_connect_authorizer(con); ++ auth_proto = CEPH_AUTH_UNKNOWN; ++ auth = get_connect_authorizer(con, &auth_proto); + if (IS_ERR(auth)) + return PTR_ERR(auth); ++ con->out_connect.authorizer_protocol = cpu_to_le32(auth_proto); + + con->out_more = 0; + set_bit(WRITE_PENDING, &con->state); diff --git a/queue-3.4/0025-ceph-add-auth-buf-in-prepare_write_connect.patch b/queue-3.4/0025-ceph-add-auth-buf-in-prepare_write_connect.patch new file mode 100644 index 00000000000..c09a41294fe --- /dev/null +++ b/queue-3.4/0025-ceph-add-auth-buf-in-prepare_write_connect.patch @@ -0,0 +1,78 @@ +From 2c53b5a488ac87f848f0ce09742500108a4bfa23 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Wed, 16 May 2012 15:16:39 -0500 +Subject: ceph: add auth buf in prepare_write_connect() + +From: Alex Elder + +(cherry picked from commit 3da54776e2c0385c32d143fd497a7f40a88e29dd) + +Move the addition of the authorizer buffer to a connection's +out_kvec out of get_connect_authorizer() and into its caller. This +way, the caller--prepare_write_connect()--can avoid adding the +connect header to out_kvec before it has been fully initialized. + +Prior to this patch, it was possible for a connect header to be +sent over the wire before the authorizer protocol or buffer length +fields were initialized. An authorizer buffer associated with that +header could also be queued to send only after the connection header +that describes it was on the wire. + +Fixes http://tracker.newdream.net/issues/2424 + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/messenger.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -656,8 +656,6 @@ static void prepare_write_keepalive(stru + static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection *con, + int *auth_proto) + { +- void *auth_buf; +- int auth_len; + struct ceph_auth_handshake *auth; + + if (!con->ops->get_authorizer) { +@@ -680,15 +678,9 @@ static struct ceph_auth_handshake *get_c + if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state)) + return ERR_PTR(-EAGAIN); + +- auth_buf = auth->authorizer_buf; +- auth_len = auth->authorizer_buf_len; + con->auth_reply_buf = auth->authorizer_reply_buf; + con->auth_reply_buf_len = auth->authorizer_reply_buf_len; + +- con->out_connect.authorizer_len = cpu_to_le32(auth_len); +- +- if (auth_len) +- ceph_con_out_kvec_add(con, auth_len, auth_buf); + + return auth; + } +@@ -737,12 +729,20 @@ static int prepare_write_connect(struct + con->out_connect.protocol_version = cpu_to_le32(proto); + con->out_connect.flags = 0; + +- ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect); + auth_proto = CEPH_AUTH_UNKNOWN; + auth = get_connect_authorizer(con, &auth_proto); + if (IS_ERR(auth)) + return PTR_ERR(auth); ++ + con->out_connect.authorizer_protocol = cpu_to_le32(auth_proto); ++ con->out_connect.authorizer_len = auth ? ++ cpu_to_le32(auth->authorizer_buf_len) : 0; ++ ++ ceph_con_out_kvec_add(con, sizeof (con->out_connect), ++ &con->out_connect); ++ if (auth && auth->authorizer_buf_len) ++ ceph_con_out_kvec_add(con, auth->authorizer_buf_len, ++ auth->authorizer_buf); + + con->out_more = 0; + set_bit(WRITE_PENDING, &con->state); diff --git a/queue-3.4/0026-libceph-avoid-unregistering-osd-request-when-not-reg.patch b/queue-3.4/0026-libceph-avoid-unregistering-osd-request-when-not-reg.patch new file mode 100644 index 00000000000..e9118a957bb --- /dev/null +++ b/queue-3.4/0026-libceph-avoid-unregistering-osd-request-when-not-reg.patch @@ -0,0 +1,42 @@ +From 30b2118228f619ff7ec30651e914fe4d61ad7d3b Mon Sep 17 00:00:00 2001 +From: Sage Weil +Date: Wed, 16 May 2012 15:16:38 -0500 +Subject: libceph: avoid unregistering osd request when not registered + +From: Sage Weil + +(cherry picked from commit 35f9f8a09e1e88e31bd34a1e645ca0e5f070dd5c) + +There is a race between two __unregister_request() callers: the +reply path and the ceph_osdc_wait_request(). If we get a reply +*and* the timeout expires at roughly the same time, both callers +will try to unregister the request, and the second one will do bad +things. + +Simply check if the request is still already unregistered; if so, +return immediately and do nothing. + +Fixes http://tracker.newdream.net/issues/2420 + +Signed-off-by: Sage Weil +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osd_client.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -841,6 +841,12 @@ static void register_request(struct ceph + static void __unregister_request(struct ceph_osd_client *osdc, + struct ceph_osd_request *req) + { ++ if (RB_EMPTY_NODE(&req->r_node)) { ++ dout("__unregister_request %p tid %lld not registered\n", ++ req, req->r_tid); ++ return; ++ } ++ + dout("__unregister_request %p tid %lld\n", req, req->r_tid); + rb_erase(&req->r_node, &osdc->requests); + osdc->num_requests--; diff --git a/queue-3.4/0027-libceph-fix-pg_temp-updates.patch b/queue-3.4/0027-libceph-fix-pg_temp-updates.patch new file mode 100644 index 00000000000..fe955c19326 --- /dev/null +++ b/queue-3.4/0027-libceph-fix-pg_temp-updates.patch @@ -0,0 +1,40 @@ +From 0e27f7ac12ed7a3e6f57bfccec2150a028f2c92f Mon Sep 17 00:00:00 2001 +From: Sage Weil +Date: Mon, 21 May 2012 09:45:23 -0700 +Subject: libceph: fix pg_temp updates + +From: Sage Weil + +(cherry picked from commit 6bd9adbdf9ca6a052b0b7455ac67b925eb38cfad) + +Usually, we are adding pg_temp entries or removing them. Occasionally they +update. In that case, osdmap_apply_incremental() was failing because the +rbtree entry already exists. + +Fix by removing the existing entry before inserting a new one. + +Fixes http://tracker.newdream.net/issues/2446 + +Signed-off-by: Sage Weil +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osdmap.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -890,8 +890,12 @@ struct ceph_osdmap *osdmap_apply_increme + pglen = ceph_decode_32(p); + + if (pglen) { +- /* insert */ + ceph_decode_need(p, end, pglen*sizeof(u32), bad); ++ ++ /* removing existing (if any) */ ++ (void) __remove_pg_mapping(&map->pg_temp, pgid); ++ ++ /* insert */ + pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS); + if (!pg) { + err = -ENOMEM; diff --git a/queue-3.4/0028-libceph-osd_client-don-t-drop-reply-reference-too-ea.patch b/queue-3.4/0028-libceph-osd_client-don-t-drop-reply-reference-too-ea.patch new file mode 100644 index 00000000000..08cfea5c28d --- /dev/null +++ b/queue-3.4/0028-libceph-osd_client-don-t-drop-reply-reference-too-ea.patch @@ -0,0 +1,42 @@ +From b7a73c1b29db3186c5a612ff146e466a3286ce60 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Mon, 4 Jun 2012 14:43:32 -0500 +Subject: libceph: osd_client: don't drop reply reference too early + +From: Alex Elder + +(cherry picked from commit ab8cb34a4b2f60281a4b18b1f1ad23bc2313d91b) + +In ceph_osdc_release_request(), a reference to the r_reply message +is dropped. But just after that, that same message is revoked if it +was in use to receive an incoming reply. Reorder these so we are +sure we hold a reference until we're actually done with the message. + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +(cherry picked from commit 680584fab05efff732b5ae16ad601ba994d7b505) +--- + net/ceph/osd_client.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -139,8 +139,6 @@ void ceph_osdc_release_request(struct kr + + if (req->r_request) + ceph_msg_put(req->r_request); +- if (req->r_reply) +- ceph_msg_put(req->r_reply); + if (req->r_con_filling_msg) { + dout("release_request revoking pages %p from con %p\n", + req->r_pages, req->r_con_filling_msg); +@@ -148,6 +146,8 @@ void ceph_osdc_release_request(struct kr + req->r_reply); + ceph_con_put(req->r_con_filling_msg); + } ++ if (req->r_reply) ++ ceph_msg_put(req->r_reply); + if (req->r_own_pages) + ceph_release_page_vector(req->r_pages, + req->r_num_pages); diff --git a/queue-3.4/0029-libceph-use-con-get-put-ops-from-osd_client.patch b/queue-3.4/0029-libceph-use-con-get-put-ops-from-osd_client.patch new file mode 100644 index 00000000000..fa6a5a8c69b --- /dev/null +++ b/queue-3.4/0029-libceph-use-con-get-put-ops-from-osd_client.patch @@ -0,0 +1,69 @@ +From 2e8494b7f222e9a1d5eae5ed4af59c9e6e4d4864 Mon Sep 17 00:00:00 2001 +From: Sage Weil +Date: Thu, 31 May 2012 20:22:18 -0700 +Subject: libceph: use con get/put ops from osd_client + +From: Sage Weil + +(cherry picked from commit 0d47766f14211a73eaf54cab234db134ece79f49) + +There were a few direct calls to ceph_con_{get,put}() instead of the con +ops from osd_client.c. This is a bug since those ops aren't defined to +be ceph_con_get/put. + +This breaks refcounting on the ceph_osd structs that contain the +ceph_connections, and could lead to all manner of strangeness. + +The purpose of the ->get and ->put methods in a ceph connection are +to allow the connection to indicate it has a reference to something +external to the messaging system, *not* to indicate something +external has a reference to the connection. + +[elder@inktank.com: added that last sentence] + +Signed-off-by: Sage Weil +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +(cherry picked from commit 88ed6ea0b295f8e2383d599a04027ec596cdf97b) +--- + net/ceph/osd_client.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -144,7 +144,7 @@ void ceph_osdc_release_request(struct kr + req->r_pages, req->r_con_filling_msg); + ceph_con_revoke_message(req->r_con_filling_msg, + req->r_reply); +- ceph_con_put(req->r_con_filling_msg); ++ req->r_con_filling_msg->ops->put(req->r_con_filling_msg); + } + if (req->r_reply) + ceph_msg_put(req->r_reply); +@@ -1216,7 +1216,7 @@ static void handle_reply(struct ceph_osd + if (req->r_con_filling_msg == con && req->r_reply == msg) { + dout(" dropping con_filling_msg ref %p\n", con); + req->r_con_filling_msg = NULL; +- ceph_con_put(con); ++ con->ops->put(con); + } + + if (!req->r_got_reply) { +@@ -2028,7 +2028,7 @@ static struct ceph_msg *get_reply(struct + dout("get_reply revoking msg %p from old con %p\n", + req->r_reply, req->r_con_filling_msg); + ceph_con_revoke_message(req->r_con_filling_msg, req->r_reply); +- ceph_con_put(req->r_con_filling_msg); ++ req->r_con_filling_msg->ops->put(req->r_con_filling_msg); + req->r_con_filling_msg = NULL; + } + +@@ -2063,7 +2063,7 @@ static struct ceph_msg *get_reply(struct + #endif + } + *skip = 0; +- req->r_con_filling_msg = ceph_con_get(con); ++ req->r_con_filling_msg = con->ops->get(con); + dout("get_reply tid %lld %p\n", tid, m); + + out: diff --git a/queue-3.4/0030-rbd-Clear-ceph_msg-bio_iter-for-retransmitted-messag.patch b/queue-3.4/0030-rbd-Clear-ceph_msg-bio_iter-for-retransmitted-messag.patch new file mode 100644 index 00000000000..400a9c41488 --- /dev/null +++ b/queue-3.4/0030-rbd-Clear-ceph_msg-bio_iter-for-retransmitted-messag.patch @@ -0,0 +1,32 @@ +From da0ac672eb4e4d4dad4c1ef2d924b4ece702f947 Mon Sep 17 00:00:00 2001 +From: "Yan, Zheng" +Date: Wed, 6 Jun 2012 19:35:55 -0500 +Subject: rbd: Clear ceph_msg->bio_iter for retransmitted message + +From: "Yan, Zheng" + +(cherry picked from commit 43643528cce60ca184fe8197efa8e8da7c89a037) +(cherry picked from commit b132cf4c733f91bb4dd2277ea049243cf16e8b66) + +The bug can cause NULL pointer dereference in write_partial_msg_pages + +Signed-off-by: Zheng Yan +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/messenger.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -563,6 +563,10 @@ static void prepare_write_message(struct + m->hdr.seq = cpu_to_le64(++con->out_seq); + m->needs_out_seq = false; + } ++#ifdef CONFIG_BLOCK ++ else ++ m->bio_iter = NULL; ++#endif + + dout("prepare_write_message %p seq %lld type %d len %d+%d+%d %d pgs\n", + m, con->out_seq, le16_to_cpu(m->hdr.type), diff --git a/queue-3.4/0031-libceph-flush-msgr-queue-during-mon_client-shutdown.patch b/queue-3.4/0031-libceph-flush-msgr-queue-during-mon_client-shutdown.patch new file mode 100644 index 00000000000..32cdbbaac52 --- /dev/null +++ b/queue-3.4/0031-libceph-flush-msgr-queue-during-mon_client-shutdown.patch @@ -0,0 +1,61 @@ +From b3351398dab239cb1f34be383f1126011514b126 Mon Sep 17 00:00:00 2001 +From: Sage Weil +Date: Sun, 10 Jun 2012 20:43:56 -0700 +Subject: libceph: flush msgr queue during mon_client shutdown + +From: Sage Weil + +(cherry picked from commit f3dea7edd3d449fe7a6d402c1ce56a294b985261) +(cherry picked from commit 642c0dbde32f34baa7886e988a067089992adc8f) + +We need to flush the msgr workqueue during mon_client shutdown to +ensure that any work affecting our embedded ceph_connection is +finished so that we can be safely destroyed. + +Previously, we were flushing the work queue after osd_client +shutdown and before mon_client shutdown to ensure that any osd +connection refs to authorizers are flushed. Remove the redundant +flush, and document in the comment that the mon_client flush is +needed to cover that case as well. + +Signed-off-by: Sage Weil +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/ceph_common.c | 7 ------- + net/ceph/mon_client.c | 8 ++++++++ + 2 files changed, 8 insertions(+), 7 deletions(-) + +--- a/net/ceph/ceph_common.c ++++ b/net/ceph/ceph_common.c +@@ -504,13 +504,6 @@ void ceph_destroy_client(struct ceph_cli + /* unmount */ + ceph_osdc_stop(&client->osdc); + +- /* +- * make sure osd connections close out before destroying the +- * auth module, which is needed to free those connections' +- * ceph_authorizers. +- */ +- ceph_msgr_flush(); +- + ceph_monc_stop(&client->monc); + + ceph_debugfs_client_cleanup(client); +--- a/net/ceph/mon_client.c ++++ b/net/ceph/mon_client.c +@@ -847,6 +847,14 @@ void ceph_monc_stop(struct ceph_mon_clie + + mutex_unlock(&monc->mutex); + ++ /* ++ * flush msgr queue before we destroy ourselves to ensure that: ++ * - any work that references our embedded con is finished. ++ * - any osd_client or other work that may reference an authorizer ++ * finishes before we shut down the auth subsystem. ++ */ ++ ceph_msgr_flush(); ++ + ceph_auth_destroy(monc->auth); + + ceph_msg_put(monc->m_auth); diff --git a/queue-3.4/0032-libceph-fix-messenger-retry.patch b/queue-3.4/0032-libceph-fix-messenger-retry.patch new file mode 100644 index 00000000000..abfae73b4fc --- /dev/null +++ b/queue-3.4/0032-libceph-fix-messenger-retry.patch @@ -0,0 +1,85 @@ +From 97e7f3ee21ecef94c8cf6914b6c549d683e83739 Mon Sep 17 00:00:00 2001 +From: Sage Weil +Date: Tue, 10 Jul 2012 11:53:34 -0700 +Subject: libceph: fix messenger retry + +From: Sage Weil + +(cherry picked from commit 5bdca4e0768d3e0f4efa43d9a2cc8210aeb91ab9) + +In ancient times, the messenger could both initiate and accept connections. +An artifact if that was data structures to store/process an incoming +ceph_msg_connect request and send an outgoing ceph_msg_connect_reply. +Sadly, the negotiation code was referencing those structures and ignoring +important information (like the peer's connect_seq) from the correct ones. + +Among other things, this fixes tight reconnect loops where the server sends +RETRY_SESSION and we (the client) retries with the same connect_seq as last +time. This bug pretty easily triggered by injecting socket failures on the +MDS and running some fs workload like workunits/direct_io/test_sync_io. + +Signed-off-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/ceph/messenger.h | 12 ++---------- + net/ceph/messenger.c | 12 ++++++------ + 2 files changed, 8 insertions(+), 16 deletions(-) + +--- a/include/linux/ceph/messenger.h ++++ b/include/linux/ceph/messenger.h +@@ -163,16 +163,8 @@ struct ceph_connection { + + /* connection negotiation temps */ + char in_banner[CEPH_BANNER_MAX_LEN]; +- union { +- struct { /* outgoing connection */ +- struct ceph_msg_connect out_connect; +- struct ceph_msg_connect_reply in_reply; +- }; +- struct { /* incoming */ +- struct ceph_msg_connect in_connect; +- struct ceph_msg_connect_reply out_reply; +- }; +- }; ++ struct ceph_msg_connect out_connect; ++ struct ceph_msg_connect_reply in_reply; + struct ceph_entity_addr actual_peer_addr; + + /* message out temps */ +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -1423,7 +1423,7 @@ static int process_connect(struct ceph_c + * dropped messages. + */ + dout("process_connect got RESET peer seq %u\n", +- le32_to_cpu(con->in_connect.connect_seq)); ++ le32_to_cpu(con->in_reply.connect_seq)); + pr_err("%s%lld %s connection reset\n", + ENTITY_NAME(con->peer_name), + ceph_pr_addr(&con->peer_addr.in_addr)); +@@ -1450,10 +1450,10 @@ static int process_connect(struct ceph_c + * If we sent a smaller connect_seq than the peer has, try + * again with a larger value. + */ +- dout("process_connect got RETRY my seq = %u, peer_seq = %u\n", ++ dout("process_connect got RETRY_SESSION my seq %u, peer %u\n", + le32_to_cpu(con->out_connect.connect_seq), +- le32_to_cpu(con->in_connect.connect_seq)); +- con->connect_seq = le32_to_cpu(con->in_connect.connect_seq); ++ le32_to_cpu(con->in_reply.connect_seq)); ++ con->connect_seq = le32_to_cpu(con->in_reply.connect_seq); + ceph_con_out_kvec_reset(con); + ret = prepare_write_connect(con); + if (ret < 0) +@@ -1468,9 +1468,9 @@ static int process_connect(struct ceph_c + */ + dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n", + con->peer_global_seq, +- le32_to_cpu(con->in_connect.global_seq)); ++ le32_to_cpu(con->in_reply.global_seq)); + get_global_seq(con->msgr, +- le32_to_cpu(con->in_connect.global_seq)); ++ le32_to_cpu(con->in_reply.global_seq)); + ceph_con_out_kvec_reset(con); + ret = prepare_write_connect(con); + if (ret < 0) diff --git a/queue-3.4/0033-rbd-don-t-hold-spinlock-during-messenger-flush.patch b/queue-3.4/0033-rbd-don-t-hold-spinlock-during-messenger-flush.patch new file mode 100644 index 00000000000..b6324e0fea7 --- /dev/null +++ b/queue-3.4/0033-rbd-don-t-hold-spinlock-during-messenger-flush.patch @@ -0,0 +1,51 @@ +From 6d7e495a8347311ddf5f1785c94ce71627b3efe0 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Wed, 4 Apr 2012 13:35:44 -0500 +Subject: rbd: don't hold spinlock during messenger flush + +From: Alex Elder + +(cherry picked from commit cd9d9f5df6098c50726200d4185e9e8da32785b3) + +A recent change made changes to the rbd_client_list be protected by +a spinlock. Unfortunately in rbd_put_client(), the lock is taken +before possibly dropping the last reference to an rbd_client, and on +the last reference that eventually calls flush_workqueue() which can +sleep. + +The problem was flagged by a debug spinlock warning: + BUG: spinlock wrong CPU on CPU#3, rbd/27814 + +The solution is to move the spinlock acquisition and release inside +rbd_client_release(), which is the spot where it's really needed for +protecting the removal of the rbd_client from the client list. + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -450,7 +450,9 @@ static void rbd_client_release(struct kr + struct rbd_client *rbdc = container_of(kref, struct rbd_client, kref); + + dout("rbd_release_client %p\n", rbdc); ++ spin_lock(&rbd_client_list_lock); + list_del(&rbdc->node); ++ spin_unlock(&rbd_client_list_lock); + + ceph_destroy_client(rbdc->client); + kfree(rbdc->rbd_opts); +@@ -463,9 +465,7 @@ static void rbd_client_release(struct kr + */ + static void rbd_put_client(struct rbd_device *rbd_dev) + { +- spin_lock(&rbd_client_list_lock); + kref_put(&rbd_dev->rbd_client->kref, rbd_client_release); +- spin_unlock(&rbd_client_list_lock); + rbd_dev->rbd_client = NULL; + } + diff --git a/queue-3.4/0034-rbd-protect-read-of-snapshot-sequence-number.patch b/queue-3.4/0034-rbd-protect-read-of-snapshot-sequence-number.patch new file mode 100644 index 00000000000..df60f4f8ed7 --- /dev/null +++ b/queue-3.4/0034-rbd-protect-read-of-snapshot-sequence-number.patch @@ -0,0 +1,33 @@ +From ef2cfb917fb296102bf9c2f9cfbf83cfcb370000 Mon Sep 17 00:00:00 2001 +From: Josh Durgin +Date: Mon, 5 Dec 2011 10:47:13 -0800 +Subject: rbd: protect read of snapshot sequence number + +From: Josh Durgin + +(cherry picked from commit 403f24d3d51760a8b9368d595fa5f48c309f1a0f) + +This is updated whenever a snapshot is added or deleted, and the +snapc pointer is changed with every refresh of the header. + +Signed-off-by: Josh Durgin +Reviewed-by: Alex Elder +Reviewed-by: Yehuda Sadeh +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -1683,7 +1683,9 @@ static int rbd_header_add_snap(struct rb + if (ret < 0) + return ret; + +- dev->header.snapc->seq = new_snapid; ++ down_write(&dev->header_rwsem); ++ dev->header.snapc->seq = new_snapid; ++ up_write(&dev->header_rwsem); + + return 0; + bad: diff --git a/queue-3.4/0035-rbd-store-snapshot-id-instead-of-index.patch b/queue-3.4/0035-rbd-store-snapshot-id-instead-of-index.patch new file mode 100644 index 00000000000..3fa19ba7a08 --- /dev/null +++ b/queue-3.4/0035-rbd-store-snapshot-id-instead-of-index.patch @@ -0,0 +1,94 @@ +From 526a884fb3062978673b4ec3ae2d1498add6e532 Mon Sep 17 00:00:00 2001 +From: Josh Durgin +Date: Mon, 21 Nov 2011 13:04:42 -0800 +Subject: rbd: store snapshot id instead of index + +From: Josh Durgin + +(cherry picked from commit 77dfe99fe3cb0b2b0545e19e2d57b7a9134ee3c0) + +When a device was open at a snapshot, and snapshots were deleted or +added, data from the wrong snapshot could be read. Instead of +assuming the snap context is constant, store the actual snap id when +the device is initialized, and rely on the OSDs to signal an error +if we try reading from a snapshot that was deleted. + +Signed-off-by: Josh Durgin +Reviewed-by: Alex Elder +Reviewed-by: Yehuda Sadeh +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 27 +++++---------------------- + 1 file changed, 5 insertions(+), 22 deletions(-) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -175,8 +175,7 @@ struct rbd_device { + /* protects updating the header */ + struct rw_semaphore header_rwsem; + char snap_name[RBD_MAX_SNAP_NAME_LEN]; +- u32 cur_snap; /* index+1 of current snapshot within snap context +- 0 - for the head */ ++ u64 snap_id; /* current snapshot id */ + int read_only; + + struct list_head node; +@@ -552,21 +551,6 @@ err_snapc: + return -ENOMEM; + } + +-static int snap_index(struct rbd_image_header *header, int snap_num) +-{ +- return header->total_snaps - snap_num; +-} +- +-static u64 cur_snap_id(struct rbd_device *rbd_dev) +-{ +- struct rbd_image_header *header = &rbd_dev->header; +- +- if (!rbd_dev->cur_snap) +- return 0; +- +- return header->snapc->snaps[snap_index(header, rbd_dev->cur_snap)]; +-} +- + static int snap_by_name(struct rbd_image_header *header, const char *snap_name, + u64 *seq, u64 *size) + { +@@ -605,7 +589,7 @@ static int rbd_header_set_snap(struct rb + snapc->seq = header->snap_seq; + else + snapc->seq = 0; +- dev->cur_snap = 0; ++ dev->snap_id = CEPH_NOSNAP; + dev->read_only = 0; + if (size) + *size = header->image_size; +@@ -613,8 +597,7 @@ static int rbd_header_set_snap(struct rb + ret = snap_by_name(header, dev->snap_name, &snapc->seq, size); + if (ret < 0) + goto done; +- +- dev->cur_snap = header->total_snaps - ret; ++ dev->snap_id = snapc->seq; + dev->read_only = 1; + } + +@@ -1521,7 +1504,7 @@ static void rbd_rq_fn(struct request_que + coll, cur_seg); + else + rbd_req_read(rq, rbd_dev, +- cur_snap_id(rbd_dev), ++ rbd_dev->snap_id, + ofs, + op_size, bio, + coll, cur_seg); +@@ -1656,7 +1639,7 @@ static int rbd_header_add_snap(struct rb + struct ceph_mon_client *monc; + + /* we should create a snapshot only if we're pointing at the head */ +- if (dev->cur_snap) ++ if (dev->snap_id != CEPH_NOSNAP) + return -EINVAL; + + monc = &dev->rbd_client->client->monc; diff --git a/queue-3.4/0036-rbd-Fix-ceph_snap_context-size-calculation.patch b/queue-3.4/0036-rbd-Fix-ceph_snap_context-size-calculation.patch new file mode 100644 index 00000000000..03d8fdcaa11 --- /dev/null +++ b/queue-3.4/0036-rbd-Fix-ceph_snap_context-size-calculation.patch @@ -0,0 +1,29 @@ +From 46fc0381517148e9e24eec09413aa3311e7adaf6 Mon Sep 17 00:00:00 2001 +From: "Yan, Zheng" +Date: Wed, 6 Jun 2012 09:15:33 -0500 +Subject: rbd: Fix ceph_snap_context size calculation + +From: "Yan, Zheng" + +(cherry picked from commit f9f9a1904467816452fc70740165030e84c2c659) + +ceph_snap_context->snaps is an u64 array + +Signed-off-by: Zheng Yan +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -497,7 +497,7 @@ static int rbd_header_from_disk(struct r + + snap_count = le32_to_cpu(ondisk->snap_count); + header->snapc = kmalloc(sizeof(struct ceph_snap_context) + +- snap_count * sizeof (*ondisk), ++ snap_count * sizeof(u64), + gfp_flags); + if (!header->snapc) + return -ENOMEM; diff --git a/queue-3.4/0037-ceph-check-PG_Private-flag-before-accessing-page-pri.patch b/queue-3.4/0037-ceph-check-PG_Private-flag-before-accessing-page-pri.patch new file mode 100644 index 00000000000..c470a72072c --- /dev/null +++ b/queue-3.4/0037-ceph-check-PG_Private-flag-before-accessing-page-pri.patch @@ -0,0 +1,101 @@ +From f0be86dddb0ce060e6ea0b747206b807d446b51f Mon Sep 17 00:00:00 2001 +From: "Yan, Zheng" +Date: Mon, 28 May 2012 14:44:30 +0800 +Subject: ceph: check PG_Private flag before accessing page->private + +From: "Yan, Zheng" + +(cherry picked from commit 28c0254ede13ab575d2df5c6585ed3d4817c3e6b) + +I got lots of NULL pointer dereference Oops when compiling kernel on ceph. +The bug is because the kernel page migration routine replaces some pages +in the page cache with new pages, these new pages' private can be non-zero. + +Signed-off-by: Zheng Yan +Signed-off-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/addr.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +--- a/fs/ceph/addr.c ++++ b/fs/ceph/addr.c +@@ -54,7 +54,12 @@ + (CONGESTION_ON_THRESH(congestion_kb) - \ + (CONGESTION_ON_THRESH(congestion_kb) >> 2)) + +- ++static inline struct ceph_snap_context *page_snap_context(struct page *page) ++{ ++ if (PagePrivate(page)) ++ return (void *)page->private; ++ return NULL; ++} + + /* + * Dirty a page. Optimistically adjust accounting, on the assumption +@@ -142,10 +147,9 @@ static void ceph_invalidatepage(struct p + { + struct inode *inode; + struct ceph_inode_info *ci; +- struct ceph_snap_context *snapc = (void *)page->private; ++ struct ceph_snap_context *snapc = page_snap_context(page); + + BUG_ON(!PageLocked(page)); +- BUG_ON(!page->private); + BUG_ON(!PagePrivate(page)); + BUG_ON(!page->mapping); + +@@ -182,7 +186,6 @@ static int ceph_releasepage(struct page + struct inode *inode = page->mapping ? page->mapping->host : NULL; + dout("%p releasepage %p idx %lu\n", inode, page, page->index); + WARN_ON(PageDirty(page)); +- WARN_ON(page->private); + WARN_ON(PagePrivate(page)); + return 0; + } +@@ -443,7 +446,7 @@ static int writepage_nounlock(struct pag + osdc = &fsc->client->osdc; + + /* verify this is a writeable snap context */ +- snapc = (void *)page->private; ++ snapc = page_snap_context(page); + if (snapc == NULL) { + dout("writepage %p page %p not dirty?\n", inode, page); + goto out; +@@ -451,7 +454,7 @@ static int writepage_nounlock(struct pag + oldest = get_oldest_context(inode, &snap_size); + if (snapc->seq > oldest->seq) { + dout("writepage %p page %p snapc %p not writeable - noop\n", +- inode, page, (void *)page->private); ++ inode, page, snapc); + /* we should only noop if called by kswapd */ + WARN_ON((current->flags & PF_MEMALLOC) == 0); + ceph_put_snap_context(oldest); +@@ -591,7 +594,7 @@ static void writepages_finish(struct cep + clear_bdi_congested(&fsc->backing_dev_info, + BLK_RW_ASYNC); + +- ceph_put_snap_context((void *)page->private); ++ ceph_put_snap_context(page_snap_context(page)); + page->private = 0; + ClearPagePrivate(page); + dout("unlocking %d %p\n", i, page); +@@ -795,7 +798,7 @@ get_more_pages: + } + + /* only if matching snap context */ +- pgsnapc = (void *)page->private; ++ pgsnapc = page_snap_context(page); + if (pgsnapc->seq > snapc->seq) { + dout("page snapc %p %lld > oldest %p %lld\n", + pgsnapc, pgsnapc->seq, snapc, snapc->seq); +@@ -984,7 +987,7 @@ retry_locked: + BUG_ON(!ci->i_snap_realm); + down_read(&mdsc->snap_rwsem); + BUG_ON(!ci->i_snap_realm->cached_context); +- snapc = (void *)page->private; ++ snapc = page_snap_context(page); + if (snapc && snapc != ci->i_head_snapc) { + /* + * this page is already dirty in another (older) snap diff --git a/queue-3.4/0038-libceph-eliminate-connection-state-DEAD.patch b/queue-3.4/0038-libceph-eliminate-connection-state-DEAD.patch new file mode 100644 index 00000000000..ccc22831313 --- /dev/null +++ b/queue-3.4/0038-libceph-eliminate-connection-state-DEAD.patch @@ -0,0 +1,45 @@ +From b9adfb9e021bad7c0c49620b0f10f9395aa69c90 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Tue, 22 May 2012 11:41:43 -0500 +Subject: libceph: eliminate connection state "DEAD" + +From: Alex Elder + +(cherry picked from commit e5e372da9a469dfe3ece40277090a7056c566838) + +The ceph connection state "DEAD" is never set and is therefore not +needed. Eliminate it. + +Signed-off-by: Alex Elder +Reviewed-by: Yehuda Sadeh +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/ceph/messenger.h | 1 - + net/ceph/messenger.c | 6 ------ + 2 files changed, 7 deletions(-) + +--- a/include/linux/ceph/messenger.h ++++ b/include/linux/ceph/messenger.h +@@ -119,7 +119,6 @@ struct ceph_msg_pos { + #define CLOSED 10 /* we've closed the connection */ + #define SOCK_CLOSED 11 /* socket state changed to closed */ + #define OPENING 13 /* open connection w/ (possibly new) peer */ +-#define DEAD 14 /* dead, about to kfree */ + #define BACKOFF 15 + + /* +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -2091,12 +2091,6 @@ bad_tag: + */ + static void queue_con(struct ceph_connection *con) + { +- if (test_bit(DEAD, &con->state)) { +- dout("queue_con %p ignoring: DEAD\n", +- con); +- return; +- } +- + if (!con->ops->get(con)) { + dout("queue_con %p ref count 0\n", con); + return; diff --git a/queue-3.4/0039-libceph-kill-bad_proto-ceph-connection-op.patch b/queue-3.4/0039-libceph-kill-bad_proto-ceph-connection-op.patch new file mode 100644 index 00000000000..e020b73d1b2 --- /dev/null +++ b/queue-3.4/0039-libceph-kill-bad_proto-ceph-connection-op.patch @@ -0,0 +1,46 @@ +From cf2b6bf7d77fb4a85e864ba147f5964e7e6f86f5 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Tue, 29 May 2012 21:47:38 -0500 +Subject: libceph: kill bad_proto ceph connection op + +From: Alex Elder + +(cherry picked from commit 6384bb8b8e88a9c6bf2ae0d9517c2c0199177c34) + +No code sets a bad_proto method in its ceph connection operations +vector, so just get rid of it. + +Signed-off-by: Alex Elder +Reviewed-by: Yehuda Sadeh +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/ceph/messenger.h | 3 --- + net/ceph/messenger.c | 5 ----- + 2 files changed, 8 deletions(-) + +--- a/include/linux/ceph/messenger.h ++++ b/include/linux/ceph/messenger.h +@@ -31,9 +31,6 @@ struct ceph_connection_operations { + int (*verify_authorizer_reply) (struct ceph_connection *con, int len); + int (*invalidate_authorizer)(struct ceph_connection *con); + +- /* protocol version mismatch */ +- void (*bad_proto) (struct ceph_connection *con); +- + /* there was some error on the socket (disconnect, whatever) */ + void (*fault) (struct ceph_connection *con); + +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -1360,11 +1360,6 @@ static void fail_protocol(struct ceph_co + { + reset_connection(con); + set_bit(CLOSED, &con->state); /* in case there's queued work */ +- +- mutex_unlock(&con->mutex); +- if (con->ops->bad_proto) +- con->ops->bad_proto(con); +- mutex_lock(&con->mutex); + } + + static int process_connect(struct ceph_connection *con) diff --git a/queue-3.4/series b/queue-3.4/series index 101ba5cf464..a0104435621 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -72,3 +72,23 @@ selinux-fix-sel_netnode_insert-suspicious-rcu-dereference.patch 0017-ceph-messenger-check-return-from-get_authorizer.patch 0018-ceph-define-ceph_auth_handshake-type.patch 0019-ceph-messenger-reduce-args-to-create_authorizer.patch +0020-ceph-ensure-auth-ops-are-defined-before-use.patch +0021-ceph-have-get_authorizer-methods-return-pointers.patch +0022-ceph-use-info-returned-by-get_authorizer.patch +0023-ceph-return-pointer-from-prepare_connect_authorizer.patch +0024-ceph-rename-prepare_connect_authorizer.patch +0025-ceph-add-auth-buf-in-prepare_write_connect.patch +0026-libceph-avoid-unregistering-osd-request-when-not-reg.patch +0027-libceph-fix-pg_temp-updates.patch +0028-libceph-osd_client-don-t-drop-reply-reference-too-ea.patch +0029-libceph-use-con-get-put-ops-from-osd_client.patch +0030-rbd-Clear-ceph_msg-bio_iter-for-retransmitted-messag.patch +0031-libceph-flush-msgr-queue-during-mon_client-shutdown.patch +0032-libceph-fix-messenger-retry.patch +0033-rbd-don-t-hold-spinlock-during-messenger-flush.patch +0034-rbd-protect-read-of-snapshot-sequence-number.patch +0035-rbd-store-snapshot-id-instead-of-index.patch +0036-rbd-Fix-ceph_snap_context-size-calculation.patch +0037-ceph-check-PG_Private-flag-before-accessing-page-pri.patch +0038-libceph-eliminate-connection-state-DEAD.patch +0039-libceph-kill-bad_proto-ceph-connection-op.patch