diff options
author | Alex Elder <elder@inktank.com> | 2013-04-01 17:12:14 -0400 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-05-02 00:17:54 -0400 |
commit | ace6d3a96f00c271b3f337adcde8e8cbe39c3820 (patch) | |
tree | cb93ac34e892b61ee9303e051384bb64ed925caa /net/ceph | |
parent | 25d71cb92d8eb48df9cbd8cc4bb28e88ee8e88d9 (diff) |
libceph: drop ceph_osd_request->r_con_filling_msg
A field in an osd request keeps track of whether a connection is
currently filling the request's reply message. This patch gets rid
of that field.
An osd request includes two messages--a request and a reply--and
they're both associated with the connection that existed to its
the target osd at the time the request was created.
An osd request can be dropped early, even when it's in flight.
And at that time both messages are released. It's possible the
reply message has been supplied to its connection to receive
an incoming response message at the time the osd request gets
dropped. So ceph_osdc_release_request() revokes that message
from the connection before releasing it so things get cleaned up
properly.
Previously this may have caused a problem, because the connection
that a message was associated with might have gone away before the
revoke request. And to avoid any problems using that connection,
the osd client held a reference to it when it supplies its response
message.
However since this commit:
38941f80 libceph: have messages point to their connection
all messages hold a reference to the connection they are associated
with whenever the connection is actively operating on the message
(i.e. while the message is queued to send or sending, and when it
data is being received into it). And if a message has no connection
associated with it, ceph_msg_revoke_incoming() won't do anything
when asked to revoke it.
As a result, there is no need to keep an additional reference to the
connection associated with a message when we hand the message to the
messenger when it calls our alloc_msg() method to receive something.
If the connection *were* operating on it, it would have its own
reference, and if not, there's no work to be done when we need to
revoke it.
So get rid of the osd request's r_con_filling_msg field.
This resolves:
http://tracker.ceph.com/issues/4647
Signed-off-by: Alex Elder <elder@inktank.com>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Diffstat (limited to 'net/ceph')
-rw-r--r-- | net/ceph/osd_client.c | 29 |
1 files changed, 5 insertions, 24 deletions
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index ca79cad50840..e0887923e5ab 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c | |||
@@ -91,15 +91,10 @@ void ceph_osdc_release_request(struct kref *kref) | |||
91 | 91 | ||
92 | if (req->r_request) | 92 | if (req->r_request) |
93 | ceph_msg_put(req->r_request); | 93 | ceph_msg_put(req->r_request); |
94 | if (req->r_con_filling_msg) { | 94 | if (req->r_reply) { |
95 | dout("%s revoking msg %p from con %p\n", __func__, | ||
96 | req->r_reply, req->r_con_filling_msg); | ||
97 | ceph_msg_revoke_incoming(req->r_reply); | 95 | ceph_msg_revoke_incoming(req->r_reply); |
98 | req->r_con_filling_msg->ops->put(req->r_con_filling_msg); | ||
99 | req->r_con_filling_msg = NULL; | ||
100 | } | ||
101 | if (req->r_reply) | ||
102 | ceph_msg_put(req->r_reply); | 96 | ceph_msg_put(req->r_reply); |
97 | } | ||
103 | 98 | ||
104 | if (req->r_data_in.type == CEPH_OSD_DATA_TYPE_PAGES && | 99 | if (req->r_data_in.type == CEPH_OSD_DATA_TYPE_PAGES && |
105 | req->r_data_in.own_pages) { | 100 | req->r_data_in.own_pages) { |
@@ -1353,16 +1348,6 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg, | |||
1353 | for (i = 0; i < numops; i++) | 1348 | for (i = 0; i < numops; i++) |
1354 | req->r_reply_op_result[i] = ceph_decode_32(&p); | 1349 | req->r_reply_op_result[i] = ceph_decode_32(&p); |
1355 | 1350 | ||
1356 | /* | ||
1357 | * if this connection filled our message, drop our reference now, to | ||
1358 | * avoid a (safe but slower) revoke later. | ||
1359 | */ | ||
1360 | if (req->r_con_filling_msg == con && req->r_reply == msg) { | ||
1361 | dout(" dropping con_filling_msg ref %p\n", con); | ||
1362 | req->r_con_filling_msg = NULL; | ||
1363 | con->ops->put(con); | ||
1364 | } | ||
1365 | |||
1366 | if (!req->r_got_reply) { | 1351 | if (!req->r_got_reply) { |
1367 | unsigned int bytes; | 1352 | unsigned int bytes; |
1368 | 1353 | ||
@@ -2199,13 +2184,10 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, | |||
2199 | goto out; | 2184 | goto out; |
2200 | } | 2185 | } |
2201 | 2186 | ||
2202 | if (req->r_con_filling_msg) { | 2187 | if (req->r_reply->con) |
2203 | dout("%s revoking msg %p from old con %p\n", __func__, | 2188 | dout("%s revoking msg %p from old con %p\n", __func__, |
2204 | req->r_reply, req->r_con_filling_msg); | 2189 | req->r_reply, req->r_reply->con); |
2205 | ceph_msg_revoke_incoming(req->r_reply); | 2190 | ceph_msg_revoke_incoming(req->r_reply); |
2206 | req->r_con_filling_msg->ops->put(req->r_con_filling_msg); | ||
2207 | req->r_con_filling_msg = NULL; | ||
2208 | } | ||
2209 | 2191 | ||
2210 | if (front > req->r_reply->front.iov_len) { | 2192 | if (front > req->r_reply->front.iov_len) { |
2211 | pr_warning("get_reply front %d > preallocated %d\n", | 2193 | pr_warning("get_reply front %d > preallocated %d\n", |
@@ -2236,7 +2218,6 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, | |||
2236 | } | 2218 | } |
2237 | } | 2219 | } |
2238 | *skip = 0; | 2220 | *skip = 0; |
2239 | req->r_con_filling_msg = con->ops->get(con); | ||
2240 | dout("get_reply tid %lld %p\n", tid, m); | 2221 | dout("get_reply tid %lld %p\n", tid, m); |
2241 | 2222 | ||
2242 | out: | 2223 | out: |