From: Greg Kroah-Hartman Date: Tue, 15 Jan 2013 18:01:46 +0000 (-0800) Subject: 3.7-stable patches X-Git-Tag: v3.7.3~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1fb8fa812eac41b5762a6bdfa5b05cace030ce0b;p=thirdparty%2Fkernel%2Fstable-queue.git 3.7-stable patches added patches: ceph-call-handle_cap_grant-for-cap-import-message.patch ceph-don-t-add-dirty-inode-to-dirty-list-if-caps-is-in-migration.patch ceph-don-t-reference-req-after-put.patch ceph-don-t-update-i_max_size-when-handling-non-auth-cap.patch ceph-fix-__ceph_do_pending_vmtruncate.patch ceph-fix-infinite-loop-in-__wake_requests.patch libceph-avoid-using-freed-osd-in-__kick_osd_requests.patch libceph-fix-osdmap-decode-error-paths.patch libceph-fix-protocol-feature-mismatch-failure-path.patch libceph-remove-osdtimeout-option.patch libceph-unlock-unprocessed-pages-in-start_read-error-path.patch rbd-do-not-allow-remove-of-mounted-on-image.patch rbd-fix-bug-in-rbd_dev_id_put.patch rbd-fix-read-only-option-name.patch rbd-get-rid-of-rbd_max_seg_name_len.patch rbd-increase-maximum-snapshot-name-length.patch rbd-remove-linger-unconditionally.patch rbd-remove-snapshots-on-error-in-rbd_add.patch rbd-zero-return-code-in-rbd_dev_image_id.patch --- diff --git a/queue-3.7/ceph-call-handle_cap_grant-for-cap-import-message.patch b/queue-3.7/ceph-call-handle_cap_grant-for-cap-import-message.patch new file mode 100644 index 00000000000..7ae90a4cd19 --- /dev/null +++ b/queue-3.7/ceph-call-handle_cap_grant-for-cap-import-message.patch @@ -0,0 +1,50 @@ +From 0747d15ddb5eac0e83376e2722e3654ae01d252f Mon Sep 17 00:00:00 2001 +From: "Yan, Zheng" +Date: Mon, 19 Nov 2012 10:49:09 +0800 +Subject: ceph: call handle_cap_grant() for cap import message + + +From: "Yan, Zheng" + +(cherry picked from commit 0e5e1774a92e6fe9c511585de8f078b4c4c68dbb) + +If client sends cap message that requests new max size during +exporting caps, the exporting MDS will drop the message quietly. +So the client may wait for the reply that updates the max size +forever. call handle_cap_grant() for cap import message can +avoid this issue. + +Signed-off-by: Yan, Zheng +Signed-off-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/caps.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -2749,6 +2749,7 @@ static void handle_cap_import(struct cep + + /* make sure we re-request max_size, if necessary */ + spin_lock(&ci->i_ceph_lock); ++ ci->i_wanted_max_size = 0; /* reset */ + ci->i_requested_max_size = 0; + spin_unlock(&ci->i_ceph_lock); + } +@@ -2844,8 +2845,6 @@ void ceph_handle_caps(struct ceph_mds_se + case CEPH_CAP_OP_IMPORT: + handle_cap_import(mdsc, inode, h, session, + snaptrace, snaptrace_len); +- ceph_check_caps(ceph_inode(inode), 0, session); +- goto done_unlocked; + } + + /* the rest require a cap */ +@@ -2862,6 +2861,7 @@ void ceph_handle_caps(struct ceph_mds_se + switch (op) { + case CEPH_CAP_OP_REVOKE: + case CEPH_CAP_OP_GRANT: ++ case CEPH_CAP_OP_IMPORT: + handle_cap_grant(inode, h, session, cap, msg->middle); + goto done_unlocked; + diff --git a/queue-3.7/ceph-don-t-add-dirty-inode-to-dirty-list-if-caps-is-in-migration.patch b/queue-3.7/ceph-don-t-add-dirty-inode-to-dirty-list-if-caps-is-in-migration.patch new file mode 100644 index 00000000000..0ce4c5fcbfc --- /dev/null +++ b/queue-3.7/ceph-don-t-add-dirty-inode-to-dirty-list-if-caps-is-in-migration.patch @@ -0,0 +1,41 @@ +From f409f158fb190ab9915fd94dce367e462a0c02f6 Mon Sep 17 00:00:00 2001 +From: "Yan, Zheng" +Date: Mon, 19 Nov 2012 10:49:07 +0800 +Subject: ceph: Don't add dirty inode to dirty list if caps is in migration + + +From: "Yan, Zheng" + +(cherry picked from commit 0685235ffd9dbdb9ccbda587f8a3c83ad1d5a921) + +Add dirty inode to cap_dirty_migrating list instead, this can avoid +ceph_flush_dirty_caps() entering infinite loop. + +Signed-off-by: Yan, Zheng +Signed-off-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/caps.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -1349,11 +1349,15 @@ int __ceph_mark_dirty_caps(struct ceph_i + if (!ci->i_head_snapc) + ci->i_head_snapc = ceph_get_snap_context( + ci->i_snap_realm->cached_context); +- dout(" inode %p now dirty snapc %p\n", &ci->vfs_inode, +- ci->i_head_snapc); ++ dout(" inode %p now dirty snapc %p auth cap %p\n", ++ &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap); + BUG_ON(!list_empty(&ci->i_dirty_item)); + spin_lock(&mdsc->cap_dirty_lock); +- list_add(&ci->i_dirty_item, &mdsc->cap_dirty); ++ if (ci->i_auth_cap) ++ list_add(&ci->i_dirty_item, &mdsc->cap_dirty); ++ else ++ list_add(&ci->i_dirty_item, ++ &mdsc->cap_dirty_migrating); + spin_unlock(&mdsc->cap_dirty_lock); + if (ci->i_flushing_caps == 0) { + ihold(inode); diff --git a/queue-3.7/ceph-don-t-reference-req-after-put.patch b/queue-3.7/ceph-don-t-reference-req-after-put.patch new file mode 100644 index 00000000000..dfa2c8928ab --- /dev/null +++ b/queue-3.7/ceph-don-t-reference-req-after-put.patch @@ -0,0 +1,38 @@ +From a6bbcd6741d53b326a2a3a7edef6e15334de6ea3 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Thu, 29 Nov 2012 08:37:03 -0600 +Subject: ceph: don't reference req after put + + +From: Alex Elder + +(cherry picked from commit 7d5f24812bd182a2471cb69c1c2baf0648332e1f) + +In __unregister_request(), there is a call to list_del_init() +referencing a request that was the subject of a call to +ceph_osdc_put_request() on the previous line. This is not +safe, because the request structure could have been freed +by the time we reach the list_del_init(). + +Fix this by reversing the order of these lines. + +Signed-off-by: Alex Elder +Reviewed-off-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osd_client.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -873,9 +873,9 @@ static void __unregister_request(struct + req->r_osd = NULL; + } + ++ list_del_init(&req->r_req_lru_item); + ceph_osdc_put_request(req); + +- list_del_init(&req->r_req_lru_item); + if (osdc->num_requests == 0) { + dout(" no requests, canceling timeout\n"); + __cancel_osd_timeout(osdc); diff --git a/queue-3.7/ceph-don-t-update-i_max_size-when-handling-non-auth-cap.patch b/queue-3.7/ceph-don-t-update-i_max_size-when-handling-non-auth-cap.patch new file mode 100644 index 00000000000..72f73534bcd --- /dev/null +++ b/queue-3.7/ceph-don-t-update-i_max_size-when-handling-non-auth-cap.patch @@ -0,0 +1,30 @@ +From 76c834d784c36bda3a8d56f5cdf3e1282b0979f9 Mon Sep 17 00:00:00 2001 +From: "Yan, Zheng" +Date: Mon, 19 Nov 2012 10:49:04 +0800 +Subject: ceph: Don't update i_max_size when handling non-auth cap + + +From: "Yan, Zheng" + +(cherry picked from commit 5e62ad30157d0da04cf40c6d1a2f4bc840948b9c) + +The cap from non-auth mds doesn't have a meaningful max_size value. + +Signed-off-by: Yan, Zheng +Signed-off-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/caps.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -2388,7 +2388,7 @@ static void handle_cap_grant(struct inod + &atime); + + /* max size increase? */ +- if (max_size != ci->i_max_size) { ++ if (ci->i_auth_cap == cap && max_size != ci->i_max_size) { + dout("max_size %lld -> %llu\n", ci->i_max_size, max_size); + ci->i_max_size = max_size; + if (max_size >= ci->i_wanted_max_size) { diff --git a/queue-3.7/ceph-fix-__ceph_do_pending_vmtruncate.patch b/queue-3.7/ceph-fix-__ceph_do_pending_vmtruncate.patch new file mode 100644 index 00000000000..2c0000a78ab --- /dev/null +++ b/queue-3.7/ceph-fix-__ceph_do_pending_vmtruncate.patch @@ -0,0 +1,55 @@ +From 0e6789acaba2e40768a778a1e553c92723a19a30 Mon Sep 17 00:00:00 2001 +From: "Yan, Zheng" +Date: Mon, 19 Nov 2012 10:49:08 +0800 +Subject: ceph: Fix __ceph_do_pending_vmtruncate + + +From: "Yan, Zheng" + +(cherry picked from commit a85f50b6ef93fbbb2ae932ce9b2376509d172796) + +we should set i_truncate_pending to 0 after page cache is truncated +to i_truncate_size + +Signed-off-by: Yan, Zheng +Signed-off-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/inode.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +--- a/fs/ceph/inode.c ++++ b/fs/ceph/inode.c +@@ -1466,7 +1466,7 @@ void __ceph_do_pending_vmtruncate(struct + { + struct ceph_inode_info *ci = ceph_inode(inode); + u64 to; +- int wrbuffer_refs, wake = 0; ++ int wrbuffer_refs, finish = 0; + + retry: + spin_lock(&ci->i_ceph_lock); +@@ -1498,15 +1498,18 @@ retry: + truncate_inode_pages(inode->i_mapping, to); + + spin_lock(&ci->i_ceph_lock); +- ci->i_truncate_pending--; +- if (ci->i_truncate_pending == 0) +- wake = 1; ++ if (to == ci->i_truncate_size) { ++ ci->i_truncate_pending = 0; ++ finish = 1; ++ } + spin_unlock(&ci->i_ceph_lock); ++ if (!finish) ++ goto retry; + + if (wrbuffer_refs == 0) + ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); +- if (wake) +- wake_up_all(&ci->i_cap_wq); ++ ++ wake_up_all(&ci->i_cap_wq); + } + + diff --git a/queue-3.7/ceph-fix-infinite-loop-in-__wake_requests.patch b/queue-3.7/ceph-fix-infinite-loop-in-__wake_requests.patch new file mode 100644 index 00000000000..12abc6cc2ff --- /dev/null +++ b/queue-3.7/ceph-fix-infinite-loop-in-__wake_requests.patch @@ -0,0 +1,41 @@ +From 0fd2af5e838e87cf449c657b6e19535b64da6c4c Mon Sep 17 00:00:00 2001 +From: "Yan, Zheng" +Date: Mon, 19 Nov 2012 10:49:06 +0800 +Subject: ceph: Fix infinite loop in __wake_requests + + +From: "Yan, Zheng" + +(cherry picked from commit ed75ec2cd19b47efcd292b6e23f58e56f4c5bc34) + +__wake_requests() will enter infinite loop if we use it to wake +requests in the session->s_waiting list. __wake_requests() deletes +requests from the list and __do_request() adds requests back to +the list. + +Signed-off-by: Yan, Zheng +Signed-off-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/mds_client.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/fs/ceph/mds_client.c ++++ b/fs/ceph/mds_client.c +@@ -1876,9 +1876,14 @@ finish: + static void __wake_requests(struct ceph_mds_client *mdsc, + struct list_head *head) + { +- struct ceph_mds_request *req, *nreq; ++ struct ceph_mds_request *req; ++ LIST_HEAD(tmp_list); + +- list_for_each_entry_safe(req, nreq, head, r_wait) { ++ list_splice_init(head, &tmp_list); ++ ++ while (!list_empty(&tmp_list)) { ++ req = list_entry(tmp_list.next, ++ struct ceph_mds_request, r_wait); + list_del_init(&req->r_wait); + __do_request(mdsc, req); + } diff --git a/queue-3.7/libceph-avoid-using-freed-osd-in-__kick_osd_requests.patch b/queue-3.7/libceph-avoid-using-freed-osd-in-__kick_osd_requests.patch new file mode 100644 index 00000000000..d15abd0c8b4 --- /dev/null +++ b/queue-3.7/libceph-avoid-using-freed-osd-in-__kick_osd_requests.patch @@ -0,0 +1,48 @@ +From f4a3fea610cb6a9fc9cb722a0765194e19b82e7b Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Fri, 7 Dec 2012 09:57:58 -0600 +Subject: libceph: avoid using freed osd in __kick_osd_requests() + + +From: Alex Elder + +(cherry picked from commit 685a7555ca69030739ddb57a47f0ea8ea80196a4) + +If an osd has no requests and no linger requests, __reset_osd() +will just remove it with a call to __remove_osd(). That drops +a reference to the osd, and therefore the osd may have been free +by the time __reset_osd() returns. That function offers no +indication this may have occurred, and as a result the osd will +continue to be used even when it's no longer valid. + +Change__reset_osd() so it returns an error (ENODEV) when it +deletes the osd being reset. And change __kick_osd_requests() so it +returns immediately (before referencing osd again) if __reset_osd() +returns *any* error. + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osd_client.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -581,7 +581,7 @@ static void __kick_osd_requests(struct c + + dout("__kick_osd_requests osd%d\n", osd->o_osd); + err = __reset_osd(osdc, osd); +- if (err == -EAGAIN) ++ if (err) + return; + + list_for_each_entry(req, &osd->o_requests, r_osd_item) { +@@ -752,6 +752,7 @@ static int __reset_osd(struct ceph_osd_c + if (list_empty(&osd->o_requests) && + list_empty(&osd->o_linger_requests)) { + __remove_osd(osdc, osd); ++ ret = -ENODEV; + } else if (memcmp(&osdc->osdmap->osd_addr[osd->o_osd], + &osd->o_con.peer_addr, + sizeof(osd->o_con.peer_addr)) == 0 && diff --git a/queue-3.7/libceph-fix-osdmap-decode-error-paths.patch b/queue-3.7/libceph-fix-osdmap-decode-error-paths.patch new file mode 100644 index 00000000000..1aaa4203233 --- /dev/null +++ b/queue-3.7/libceph-fix-osdmap-decode-error-paths.patch @@ -0,0 +1,103 @@ +From 71630f053c8da3b7d8e52c99ff2592f44dd28979 Mon Sep 17 00:00:00 2001 +From: Sage Weil +Date: Mon, 29 Oct 2012 11:01:42 -0700 +Subject: libceph: fix osdmap decode error paths + + +From: Sage Weil + +(cherry picked from commit 0ed7285e0001b960c888e5455ae982025210ed3d) + +Ensure that we set the err value correctly so that we do not pass a 0 +value to ERR_PTR and confuse the calling code. (In particular, +osd_client.c handle_map() will BUG(!newmap)). + +Signed-off-by: Sage Weil +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osdmap.c | 31 ++++++++++++++++++++----------- + 1 file changed, 20 insertions(+), 11 deletions(-) + +--- a/net/ceph/osdmap.c ++++ b/net/ceph/osdmap.c +@@ -645,10 +645,12 @@ struct ceph_osdmap *osdmap_decode(void * + ceph_decode_32_safe(p, end, max, bad); + while (max--) { + ceph_decode_need(p, end, 4 + 1 + sizeof(pi->v), bad); ++ err = -ENOMEM; + pi = kzalloc(sizeof(*pi), GFP_NOFS); + if (!pi) + goto bad; + pi->id = ceph_decode_32(p); ++ err = -EINVAL; + ev = ceph_decode_8(p); /* encoding version */ + if (ev > CEPH_PG_POOL_VERSION) { + pr_warning("got unknown v %d > %d of ceph_pg_pool\n", +@@ -664,8 +666,13 @@ struct ceph_osdmap *osdmap_decode(void * + __insert_pg_pool(&map->pg_pools, pi); + } + +- if (version >= 5 && __decode_pool_names(p, end, map) < 0) +- goto bad; ++ if (version >= 5) { ++ err = __decode_pool_names(p, end, map); ++ if (err < 0) { ++ dout("fail to decode pool names"); ++ goto bad; ++ } ++ } + + ceph_decode_32_safe(p, end, map->pool_max, bad); + +@@ -745,7 +752,7 @@ struct ceph_osdmap *osdmap_decode(void * + return map; + + bad: +- dout("osdmap_decode fail\n"); ++ dout("osdmap_decode fail err %d\n", err); + ceph_osdmap_destroy(map); + return ERR_PTR(err); + } +@@ -839,6 +846,7 @@ struct ceph_osdmap *osdmap_apply_increme + if (ev > CEPH_PG_POOL_VERSION) { + pr_warning("got unknown v %d > %d of ceph_pg_pool\n", + ev, CEPH_PG_POOL_VERSION); ++ err = -EINVAL; + goto bad; + } + pi = __lookup_pg_pool(&map->pg_pools, pool); +@@ -855,8 +863,11 @@ struct ceph_osdmap *osdmap_apply_increme + if (err < 0) + goto bad; + } +- if (version >= 5 && __decode_pool_names(p, end, map) < 0) +- goto bad; ++ if (version >= 5) { ++ err = __decode_pool_names(p, end, map); ++ if (err < 0) ++ goto bad; ++ } + + /* old_pool */ + ceph_decode_32_safe(p, end, len, bad); +@@ -932,15 +943,13 @@ struct ceph_osdmap *osdmap_apply_increme + (void) __remove_pg_mapping(&map->pg_temp, pgid); + + /* insert */ +- if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) { +- err = -EINVAL; ++ err = -EINVAL; ++ if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) + goto bad; +- } ++ err = -ENOMEM; + pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS); +- if (!pg) { +- err = -ENOMEM; ++ if (!pg) + goto bad; +- } + pg->pgid = pgid; + pg->len = pglen; + for (j = 0; j < pglen; j++) diff --git a/queue-3.7/libceph-fix-protocol-feature-mismatch-failure-path.patch b/queue-3.7/libceph-fix-protocol-feature-mismatch-failure-path.patch new file mode 100644 index 00000000000..a05660978a5 --- /dev/null +++ b/queue-3.7/libceph-fix-protocol-feature-mismatch-failure-path.patch @@ -0,0 +1,75 @@ +From f10a18433a1b3192e71eecffeaeca5f5f1694016 Mon Sep 17 00:00:00 2001 +From: Sage Weil +Date: Thu, 27 Dec 2012 20:27:04 -0600 +Subject: libceph: fix protocol feature mismatch failure path + + +From: Sage Weil + +(cherry picked from commit 0fa6ebc600bc8e830551aee47a0e929e818a1868) + +We should not set con->state to CLOSED here; that happens in +ceph_fault() in the caller, where it first asserts that the state +is not yet CLOSED. Avoids a BUG when the features don't match. + +Since the fail_protocol() has become a trivial wrapper, replace +calls to it with direct calls to reset_connection(). + +Signed-off-by: Sage Weil +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/messenger.c | 14 ++++---------- + 1 file changed, 4 insertions(+), 10 deletions(-) + +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -506,6 +506,7 @@ static void reset_connection(struct ceph + { + /* reset connection, out_queue, msg_ and connect_seq */ + /* discard existing out_queue and msg_seq */ ++ dout("reset_connection %p\n", con); + ceph_msg_remove_list(&con->out_queue); + ceph_msg_remove_list(&con->out_sent); + +@@ -1506,13 +1507,6 @@ static int process_banner(struct ceph_co + return 0; + } + +-static void fail_protocol(struct ceph_connection *con) +-{ +- reset_connection(con); +- WARN_ON(con->state != CON_STATE_NEGOTIATING); +- con->state = CON_STATE_CLOSED; +-} +- + static int process_connect(struct ceph_connection *con) + { + u64 sup_feat = con->msgr->supported_features; +@@ -1530,7 +1524,7 @@ static int process_connect(struct ceph_c + ceph_pr_addr(&con->peer_addr.in_addr), + sup_feat, server_feat, server_feat & ~sup_feat); + con->error_msg = "missing required protocol features"; +- fail_protocol(con); ++ reset_connection(con); + return -1; + + case CEPH_MSGR_TAG_BADPROTOVER: +@@ -1541,7 +1535,7 @@ static int process_connect(struct ceph_c + le32_to_cpu(con->out_connect.protocol_version), + le32_to_cpu(con->in_reply.protocol_version)); + con->error_msg = "protocol version mismatch"; +- fail_protocol(con); ++ reset_connection(con); + return -1; + + case CEPH_MSGR_TAG_BADAUTHORIZER: +@@ -1631,7 +1625,7 @@ static int process_connect(struct ceph_c + ceph_pr_addr(&con->peer_addr.in_addr), + req_feat, server_feat, req_feat & ~server_feat); + con->error_msg = "missing required protocol features"; +- fail_protocol(con); ++ reset_connection(con); + return -1; + } + diff --git a/queue-3.7/libceph-remove-osdtimeout-option.patch b/queue-3.7/libceph-remove-osdtimeout-option.patch new file mode 100644 index 00000000000..13f62acc1e2 --- /dev/null +++ b/queue-3.7/libceph-remove-osdtimeout-option.patch @@ -0,0 +1,161 @@ +From aa852ff17166b53b1d29388af472bb9c32297f05 Mon Sep 17 00:00:00 2001 +From: Sage Weil +Date: Wed, 28 Nov 2012 12:28:24 -0800 +Subject: libceph: remove 'osdtimeout' option + + +From: Sage Weil + +(cherry picked from commit 83aff95eb9d60aff5497e9f44a2ae906b86d8e88) + +This would reset a connection with any OSD that had an outstanding +request that was taking more than N seconds. The idea was that if the +OSD was buggy, the client could compensate by resending the request. + +In reality, this only served to hide server bugs, and we haven't +actually seen such a bug in quite a while. Moreover, the userspace +client code never did this. + +More importantly, often the request is taking a long time because the +OSD is trying to recover, or overloaded, and killing the connection +and retrying would only make the situation worse by giving the OSD +more work to do. + +Signed-off-by: Sage Weil +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/super.c | 2 - + include/linux/ceph/libceph.h | 2 - + net/ceph/ceph_common.c | 3 -- + net/ceph/osd_client.c | 47 +++---------------------------------------- + 4 files changed, 5 insertions(+), 49 deletions(-) + +--- a/fs/ceph/super.c ++++ b/fs/ceph/super.c +@@ -403,8 +403,6 @@ static int ceph_show_options(struct seq_ + seq_printf(m, ",mount_timeout=%d", opt->mount_timeout); + if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) + seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl); +- if (opt->osd_timeout != CEPH_OSD_TIMEOUT_DEFAULT) +- seq_printf(m, ",osdtimeout=%d", opt->osd_timeout); + if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) + seq_printf(m, ",osdkeepalivetimeout=%d", + opt->osd_keepalive_timeout); +--- a/include/linux/ceph/libceph.h ++++ b/include/linux/ceph/libceph.h +@@ -43,7 +43,6 @@ struct ceph_options { + struct ceph_entity_addr my_addr; + int mount_timeout; + int osd_idle_ttl; +- int osd_timeout; + int osd_keepalive_timeout; + + /* +@@ -63,7 +62,6 @@ struct ceph_options { + * defaults + */ + #define CEPH_MOUNT_TIMEOUT_DEFAULT 60 +-#define CEPH_OSD_TIMEOUT_DEFAULT 60 /* seconds */ + #define CEPH_OSD_KEEPALIVE_DEFAULT 5 + #define CEPH_OSD_IDLE_TTL_DEFAULT 60 + +--- a/net/ceph/ceph_common.c ++++ b/net/ceph/ceph_common.c +@@ -305,7 +305,6 @@ ceph_parse_options(char *options, const + + /* start with defaults */ + opt->flags = CEPH_OPT_DEFAULT; +- opt->osd_timeout = CEPH_OSD_TIMEOUT_DEFAULT; + opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT; + opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */ + opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; /* seconds */ +@@ -391,7 +390,7 @@ ceph_parse_options(char *options, const + + /* misc */ + case Opt_osdtimeout: +- opt->osd_timeout = intval; ++ pr_warning("ignoring deprecated osdtimeout option\n"); + break; + case Opt_osdkeepalivetimeout: + opt->osd_keepalive_timeout = intval; +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -608,14 +608,6 @@ static void __kick_osd_requests(struct c + } + } + +-static void kick_osd_requests(struct ceph_osd_client *osdc, +- struct ceph_osd *kickosd) +-{ +- mutex_lock(&osdc->request_mutex); +- __kick_osd_requests(osdc, kickosd); +- mutex_unlock(&osdc->request_mutex); +-} +- + /* + * If the osd connection drops, we need to resubmit all requests. + */ +@@ -629,7 +621,9 @@ static void osd_reset(struct ceph_connec + dout("osd_reset osd%d\n", osd->o_osd); + osdc = osd->o_osdc; + down_read(&osdc->map_sem); +- kick_osd_requests(osdc, osd); ++ mutex_lock(&osdc->request_mutex); ++ __kick_osd_requests(osdc, osd); ++ mutex_unlock(&osdc->request_mutex); + send_queued(osdc); + up_read(&osdc->map_sem); + } +@@ -1093,12 +1087,10 @@ static void handle_timeout(struct work_s + { + struct ceph_osd_client *osdc = + container_of(work, struct ceph_osd_client, timeout_work.work); +- struct ceph_osd_request *req, *last_req = NULL; ++ struct ceph_osd_request *req; + struct ceph_osd *osd; +- unsigned long timeout = osdc->client->options->osd_timeout * HZ; + unsigned long keepalive = + osdc->client->options->osd_keepalive_timeout * HZ; +- unsigned long last_stamp = 0; + struct list_head slow_osds; + dout("timeout\n"); + down_read(&osdc->map_sem); +@@ -1108,37 +1100,6 @@ static void handle_timeout(struct work_s + mutex_lock(&osdc->request_mutex); + + /* +- * reset osds that appear to be _really_ unresponsive. this +- * is a failsafe measure.. we really shouldn't be getting to +- * this point if the system is working properly. the monitors +- * should mark the osd as failed and we should find out about +- * it from an updated osd map. +- */ +- while (timeout && !list_empty(&osdc->req_lru)) { +- req = list_entry(osdc->req_lru.next, struct ceph_osd_request, +- r_req_lru_item); +- +- /* hasn't been long enough since we sent it? */ +- if (time_before(jiffies, req->r_stamp + timeout)) +- break; +- +- /* hasn't been long enough since it was acked? */ +- if (req->r_request->ack_stamp == 0 || +- time_before(jiffies, req->r_request->ack_stamp + timeout)) +- break; +- +- BUG_ON(req == last_req && req->r_stamp == last_stamp); +- last_req = req; +- last_stamp = req->r_stamp; +- +- osd = req->r_osd; +- BUG_ON(!osd); +- pr_warning(" tid %llu timed out on osd%d, will reset osd\n", +- req->r_tid, osd->o_osd); +- __kick_osd_requests(osdc, osd); +- } +- +- /* + * ping osds that are a bit slow. this ensures that if there + * is a break in the TCP connection we will notice, and reopen + * a connection with that osd (from the fault callback). diff --git a/queue-3.7/libceph-unlock-unprocessed-pages-in-start_read-error-path.patch b/queue-3.7/libceph-unlock-unprocessed-pages-in-start_read-error-path.patch new file mode 100644 index 00000000000..76d9b416bf6 --- /dev/null +++ b/queue-3.7/libceph-unlock-unprocessed-pages-in-start_read-error-path.patch @@ -0,0 +1,47 @@ +From 9fa5ba96f32fbea354457fc7ece06b2ee81b1b71 Mon Sep 17 00:00:00 2001 +From: David Zafman +Date: Mon, 3 Dec 2012 19:14:05 -0800 +Subject: libceph: Unlock unprocessed pages in start_read() error path + + +From: David Zafman + +(cherry picked from commit 8884d53dd63b1d9315b343564fcbe1ede004a99e) + +Function start_read() can get an error before processing all pages. +It must not only release the remaining pages, but unlock them too. + +This fixes http://tracker.newdream.net/issues/3370 + +Signed-off-by: David Zafman +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/addr.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/fs/ceph/addr.c ++++ b/fs/ceph/addr.c +@@ -267,6 +267,14 @@ static void finish_read(struct ceph_osd_ + kfree(req->r_pages); + } + ++static void ceph_unlock_page_vector(struct page **pages, int num_pages) ++{ ++ int i; ++ ++ for (i = 0; i < num_pages; i++) ++ unlock_page(pages[i]); ++} ++ + /* + * start an async read(ahead) operation. return nr_pages we submitted + * a read for on success, or negative error code. +@@ -347,6 +355,7 @@ static int start_read(struct inode *inod + return nr_pages; + + out_pages: ++ ceph_unlock_page_vector(pages, nr_pages); + ceph_release_page_vector(pages, nr_pages); + out: + ceph_osdc_put_request(req); diff --git a/queue-3.7/rbd-do-not-allow-remove-of-mounted-on-image.patch b/queue-3.7/rbd-do-not-allow-remove-of-mounted-on-image.patch new file mode 100644 index 00000000000..64bea18ad7f --- /dev/null +++ b/queue-3.7/rbd-do-not-allow-remove-of-mounted-on-image.patch @@ -0,0 +1,74 @@ +From 730406993ec6d044a81115fc19091ba6abfcbb15 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Fri, 16 Nov 2012 09:29:16 -0600 +Subject: rbd: do not allow remove of mounted-on image + + +From: Alex Elder + +(cherry picked from commit 42382b709bd1d143b9f0fa93e0a3a1f2f4210707) + +There is no check in rbd_remove() to see if anybody holds open the +image being removed. That's not cool. + +Add a simple open count that goes up and down with opens and closes +(releases) of the device, and don't allow an rbd image to be removed +if the count is non-zero. + +Protect the updates of the open count value with ctl_mutex to ensure +the underlying rbd device doesn't get removed while concurrently +being opened. + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -207,6 +207,7 @@ struct rbd_device { + + /* sysfs related */ + struct device dev; ++ unsigned long open_count; + }; + + static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */ +@@ -280,8 +281,11 @@ static int rbd_open(struct block_device + if ((mode & FMODE_WRITE) && rbd_dev->mapping.read_only) + return -EROFS; + ++ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + rbd_get_dev(rbd_dev); + set_device_ro(bdev, rbd_dev->mapping.read_only); ++ rbd_dev->open_count++; ++ mutex_unlock(&ctl_mutex); + + return 0; + } +@@ -290,7 +294,11 @@ static int rbd_release(struct gendisk *d + { + struct rbd_device *rbd_dev = disk->private_data; + ++ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); ++ rbd_assert(rbd_dev->open_count > 0); ++ rbd_dev->open_count--; + rbd_put_dev(rbd_dev); ++ mutex_unlock(&ctl_mutex); + + return 0; + } +@@ -3221,6 +3229,11 @@ static ssize_t rbd_remove(struct bus_typ + goto done; + } + ++ if (rbd_dev->open_count) { ++ ret = -EBUSY; ++ goto done; ++ } ++ + rbd_remove_all_snaps(rbd_dev); + rbd_bus_del_dev(rbd_dev); + diff --git a/queue-3.7/rbd-fix-bug-in-rbd_dev_id_put.patch b/queue-3.7/rbd-fix-bug-in-rbd_dev_id_put.patch new file mode 100644 index 00000000000..eaa7cc049d1 --- /dev/null +++ b/queue-3.7/rbd-fix-bug-in-rbd_dev_id_put.patch @@ -0,0 +1,37 @@ +From 8824d0eb9dee3bad29e9dba796d5d7953cab6719 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Wed, 10 Oct 2012 21:19:13 -0700 +Subject: rbd: fix bug in rbd_dev_id_put() + + +From: Alex Elder + +(cherry picked from commit b213e0b1a62637b2a9395a34349b13d73ca2b90a) + +In rbd_dev_id_put(), there's a loop that's intended to determine +the maximum device id in use. But it isn't doing that at all, +the effect of how it's written is to simply use the just-put id +number, which ignores whole purpose of this function. + +Fix the bug. + +Signed-off-by: Alex Elder +Reviewed-by: Josh Durgin +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 +@@ -2621,8 +2621,8 @@ static void rbd_dev_id_put(struct rbd_de + struct rbd_device *rbd_dev; + + rbd_dev = list_entry(tmp, struct rbd_device, node); +- if (rbd_id > max_id) +- max_id = rbd_id; ++ if (rbd_dev->dev_id > max_id) ++ max_id = rbd_dev->dev_id; + } + spin_unlock(&rbd_dev_list_lock); + diff --git a/queue-3.7/rbd-fix-read-only-option-name.patch b/queue-3.7/rbd-fix-read-only-option-name.patch new file mode 100644 index 00000000000..9d63019733f --- /dev/null +++ b/queue-3.7/rbd-fix-read-only-option-name.patch @@ -0,0 +1,36 @@ +From 9aca7b487cf1c996a13ff5abf0ea4ac560ea1dd4 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Mon, 22 Oct 2012 11:31:26 -0500 +Subject: rbd: fix read-only option name + + +From: Alex Elder + +(cherry picked from commit be466c1cc36621590ef17b05a6d342dfd33f7280) + +The name of the "read-only" mapping option was inadvertently changed +in this commit: + + f84344f3 rbd: separate mapping info in rbd_dev + +Revert that hunk to return it to what it should be. + +Signed-off-by: Alex Elder +Reviewed-by: Dan Mick +Reviewed-by: Josh Durgin +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 +@@ -388,7 +388,7 @@ enum { + static match_table_t rbd_opts_tokens = { + /* int args above */ + /* string args above */ +- {Opt_read_only, "mapping.read_only"}, ++ {Opt_read_only, "read_only"}, + {Opt_read_only, "ro"}, /* Alternate spelling */ + {Opt_read_write, "read_write"}, + {Opt_read_write, "rw"}, /* Alternate spelling */ diff --git a/queue-3.7/rbd-get-rid-of-rbd_max_seg_name_len.patch b/queue-3.7/rbd-get-rid-of-rbd_max_seg_name_len.patch new file mode 100644 index 00000000000..1aba13867e7 --- /dev/null +++ b/queue-3.7/rbd-get-rid-of-rbd_max_seg_name_len.patch @@ -0,0 +1,62 @@ +From 965f03ad3d796d03ec16f9809cb0096a64f6523d Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Fri, 9 Nov 2012 15:05:54 -0600 +Subject: rbd: get rid of RBD_MAX_SEG_NAME_LEN + + +From: Alex Elder + +(cherry picked from commit 2fd82b9e92c2a718ae81fc987b4468ceeee6979b) + +RBD_MAX_SEG_NAME_LEN represents the maximum length of an rbd object +name (i.e., one of the objects providing storage backing an rbd +image). + +Another symbol, MAX_OBJ_NAME_SIZE, is used in the osd client code to +define the maximum length of any object name in an osd request. + +Right now they disagree, with RBD_MAX_SEG_NAME_LEN being too big. + +There's no real benefit at this point to defining the rbd object +name length limit separate from any other object name, so just +get rid of RBD_MAX_SEG_NAME_LEN and use MAX_OBJ_NAME_SIZE in its +place. + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 6 +++--- + drivers/block/rbd_types.h | 2 -- + 2 files changed, 3 insertions(+), 5 deletions(-) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -706,13 +706,13 @@ static char *rbd_segment_name(struct rbd + u64 segment; + int ret; + +- name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO); ++ name = kmalloc(MAX_OBJ_NAME_SIZE + 1, GFP_NOIO); + if (!name) + return NULL; + segment = offset >> rbd_dev->header.obj_order; +- ret = snprintf(name, RBD_MAX_SEG_NAME_LEN, "%s.%012llx", ++ ret = snprintf(name, MAX_OBJ_NAME_SIZE + 1, "%s.%012llx", + rbd_dev->header.object_prefix, segment); +- if (ret < 0 || ret >= RBD_MAX_SEG_NAME_LEN) { ++ if (ret < 0 || ret > MAX_OBJ_NAME_SIZE) { + pr_err("error formatting segment name for #%llu (%d)\n", + segment, ret); + kfree(name); +--- a/drivers/block/rbd_types.h ++++ b/drivers/block/rbd_types.h +@@ -46,8 +46,6 @@ + #define RBD_MIN_OBJ_ORDER 16 + #define RBD_MAX_OBJ_ORDER 30 + +-#define RBD_MAX_SEG_NAME_LEN 128 +- + #define RBD_COMP_NONE 0 + #define RBD_CRYPT_NONE 0 + diff --git a/queue-3.7/rbd-increase-maximum-snapshot-name-length.patch b/queue-3.7/rbd-increase-maximum-snapshot-name-length.patch new file mode 100644 index 00000000000..f704b39205e --- /dev/null +++ b/queue-3.7/rbd-increase-maximum-snapshot-name-length.patch @@ -0,0 +1,77 @@ +From 1306be442fda1b7a92b879ab18a535f56da5ab0a Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Tue, 3 Jul 2012 16:01:19 -0500 +Subject: rbd: increase maximum snapshot name length + + +From: Alex Elder + +(cherry picked from commit d4b125e9eb43babd14538ba61718e3db71a98d29) + +Change RBD_MAX_SNAP_NAME_LEN to be based on NAME_MAX. That is a +practical limit for the length of a snapshot name (based on the +presence of a directory using the name under /sys/bus/rbd to +represent the snapshot). + +The /sys entry is created by prefixing it with "snap_"; define that +prefix symbolically, and take its length into account in defining +the snapshot name length limit. + +Enforce the limit in rbd_add_parse_args(). Also delete a dout() +call in that function that was not meant to be committed. + +Signed-off-by: Alex Elder +Reviewed-by: Dan Mick +Reviewed-by: Josh Durgin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -61,7 +61,10 @@ + + #define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */ + +-#define RBD_MAX_SNAP_NAME_LEN 32 ++#define RBD_SNAP_DEV_NAME_PREFIX "snap_" ++#define RBD_MAX_SNAP_NAME_LEN \ ++ (NAME_MAX - (sizeof (RBD_SNAP_DEV_NAME_PREFIX) - 1)) ++ + #define RBD_MAX_SNAP_COUNT 510 /* allows max snapc to fit in 4KB */ + #define RBD_MAX_OPT_LEN 1024 + +@@ -2073,7 +2076,7 @@ static int rbd_register_snap_dev(struct + dev->type = &rbd_snap_device_type; + dev->parent = parent; + dev->release = rbd_snap_dev_release; +- dev_set_name(dev, "snap_%s", snap->name); ++ dev_set_name(dev, "%s%s", RBD_SNAP_DEV_NAME_PREFIX, snap->name); + dout("%s: registering device for snapshot %s\n", __func__, snap->name); + + ret = device_register(dev); +@@ -2766,8 +2769,13 @@ static char *rbd_add_parse_args(struct r + if (!rbd_dev->image_name) + goto out_err; + +- /* Snapshot name is optional */ ++ /* Snapshot name is optional; default is to use "head" */ ++ + len = next_token(&buf); ++ if (len > RBD_MAX_SNAP_NAME_LEN) { ++ err_ptr = ERR_PTR(-ENAMETOOLONG); ++ goto out_err; ++ } + if (!len) { + buf = RBD_SNAP_HEAD_NAME; /* No snapshot supplied */ + len = sizeof (RBD_SNAP_HEAD_NAME) - 1; +@@ -2778,8 +2786,6 @@ static char *rbd_add_parse_args(struct r + memcpy(snap_name, buf, len); + *(snap_name + len) = '\0'; + +-dout(" SNAP_NAME is <%s>, len is %zd\n", snap_name, len); +- + return snap_name; + + out_err: diff --git a/queue-3.7/rbd-remove-linger-unconditionally.patch b/queue-3.7/rbd-remove-linger-unconditionally.patch new file mode 100644 index 00000000000..c6727ca5765 --- /dev/null +++ b/queue-3.7/rbd-remove-linger-unconditionally.patch @@ -0,0 +1,37 @@ +From 942784e7a6e2ef8f861043f65b054eb3ef10b2fd Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Thu, 6 Dec 2012 09:37:23 -0600 +Subject: rbd: remove linger unconditionally + + +From: Alex Elder + +(cherry picked from commit 61c74035626beb25a39b0273ccf7d75510bc36a1) + +In __unregister_linger_request(), the request is being removed +from the osd client's req_linger list only when the request +has a non-null osd pointer. It should be done whether or not +the request currently has an osd. + +This is most likely a non-issue because I believe the request +will always have an osd when this function is called. + +Signed-off-by: Alex Elder +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/osd_client.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -907,8 +907,8 @@ static void __unregister_linger_request( + struct ceph_osd_request *req) + { + dout("__unregister_linger_request %p\n", req); ++ list_del_init(&req->r_linger_item); + if (req->r_osd) { +- list_del_init(&req->r_linger_item); + list_del_init(&req->r_linger_osd); + + if (list_empty(&req->r_osd->o_requests) && diff --git a/queue-3.7/rbd-remove-snapshots-on-error-in-rbd_add.patch b/queue-3.7/rbd-remove-snapshots-on-error-in-rbd_add.patch new file mode 100644 index 00000000000..5f45bfae654 --- /dev/null +++ b/queue-3.7/rbd-remove-snapshots-on-error-in-rbd_add.patch @@ -0,0 +1,110 @@ +From 21bc037520c252304c04d3bb8131fb3d4ba5b2c5 Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Thu, 25 Oct 2012 23:34:40 -0500 +Subject: rbd: remove snapshots on error in rbd_add() + + +From: Alex Elder + +(cherry picked from commit 41f38c2b2f8b66b176a0e548ef06294343a7bfa2) + +If rbd_dev_snaps_update() has ever been called for an rbd device +structure there could be snapshot structures on its snaps list. +In rbd_add(), this function is called but a subsequent error +path neglected to clean up any of these snapshots. + +Add a call to rbd_remove_all_snaps() in the appropriate spot to +remedy this. Change a couple of error labels to be a little +clearer while there. + +Drop the leading underscores from the function name; there's nothing +special about that function that they might signify. As suggested +in review, the leading underscores in __rbd_remove_snap_dev() have +been removed as well. + +Signed-off-by: Alex Elder +Reviewed-by: Josh Durgin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -221,7 +221,7 @@ static int rbd_dev_snaps_update(struct r + static int rbd_dev_snaps_register(struct rbd_device *rbd_dev); + + static void rbd_dev_release(struct device *dev); +-static void __rbd_remove_snap_dev(struct rbd_snap *snap); ++static void rbd_remove_snap_dev(struct rbd_snap *snap); + + static ssize_t rbd_add(struct bus_type *bus, const char *buf, + size_t count); +@@ -1710,13 +1710,13 @@ static int rbd_read_header(struct rbd_de + return ret; + } + +-static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev) ++static void rbd_remove_all_snaps(struct rbd_device *rbd_dev) + { + struct rbd_snap *snap; + struct rbd_snap *next; + + list_for_each_entry_safe(snap, next, &rbd_dev->snaps, node) +- __rbd_remove_snap_dev(snap); ++ rbd_remove_snap_dev(snap); + } + + /* +@@ -2060,7 +2060,7 @@ static bool rbd_snap_registered(struct r + return ret; + } + +-static void __rbd_remove_snap_dev(struct rbd_snap *snap) ++static void rbd_remove_snap_dev(struct rbd_snap *snap) + { + list_del(&snap->node); + if (device_is_registered(&snap->dev)) +@@ -2442,7 +2442,7 @@ static int rbd_dev_snaps_update(struct r + + if (rbd_dev->mapping.snap_id == snap->id) + rbd_dev->mapping.snap_exists = false; +- __rbd_remove_snap_dev(snap); ++ rbd_remove_snap_dev(snap); + dout("%ssnap id %llu has been removed\n", + rbd_dev->mapping.snap_id == snap->id ? + "mapped " : "", +@@ -3053,11 +3053,11 @@ static ssize_t rbd_add(struct bus_type * + /* no need to lock here, as rbd_dev is not registered yet */ + rc = rbd_dev_snaps_update(rbd_dev); + if (rc) +- goto err_out_header; ++ goto err_out_probe; + + rc = rbd_dev_set_mapping(rbd_dev, snap_name); + if (rc) +- goto err_out_header; ++ goto err_out_snaps; + + /* generate unique id: find highest unique id, add one */ + rbd_dev_id_get(rbd_dev); +@@ -3121,7 +3121,9 @@ err_out_blkdev: + unregister_blkdev(rbd_dev->major, rbd_dev->name); + err_out_id: + rbd_dev_id_put(rbd_dev); +-err_out_header: ++err_out_snaps: ++ rbd_remove_all_snaps(rbd_dev); ++err_out_probe: + rbd_header_free(&rbd_dev->header); + err_out_client: + kfree(rbd_dev->header_name); +@@ -3219,7 +3221,7 @@ static ssize_t rbd_remove(struct bus_typ + goto done; + } + +- __rbd_remove_all_snaps(rbd_dev); ++ rbd_remove_all_snaps(rbd_dev); + rbd_bus_del_dev(rbd_dev); + + done: diff --git a/queue-3.7/rbd-zero-return-code-in-rbd_dev_image_id.patch b/queue-3.7/rbd-zero-return-code-in-rbd_dev_image_id.patch new file mode 100644 index 00000000000..e9b2b051bde --- /dev/null +++ b/queue-3.7/rbd-zero-return-code-in-rbd_dev_image_id.patch @@ -0,0 +1,47 @@ +From cc8b5fcd343b3c99468fc9f0b4c3e03a7eafa7fc Mon Sep 17 00:00:00 2001 +From: Alex Elder +Date: Wed, 10 Oct 2012 21:19:13 -0700 +Subject: rbd: zero return code in rbd_dev_image_id() + + +From: Alex Elder + +(cherry picked from commit a0ea3a40fd20b8c66381f747c454f89d6d1f50d4) + +When rbd_dev_probe() calls rbd_dev_image_id() it expects to get +a 0 return code if successful, but it is getting a positive value. + +The reason is that rbd_dev_image_id() returns the value it gets from +rbd_req_sync_exec(), which returns the number of bytes read in as a +result of the request. (This ultimately comes from +ceph_copy_from_page_vector() in rbd_req_sync_op()). + +Force the return value to 0 when successful in rbd_dev_image_id(). +Do the same in rbd_dev_v2_object_prefix(). + +Signed-off-by: Alex Elder +Reviewed-by: Josh Durgin +Reviewed-by: Dan Mick +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/rbd.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -2189,6 +2189,7 @@ static int rbd_dev_v2_object_prefix(stru + dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret); + if (ret < 0) + goto out; ++ ret = 0; /* rbd_req_sync_exec() can return positive */ + + p = reply_buf; + rbd_dev->header.object_prefix = ceph_extract_encoded_string(&p, +@@ -2841,6 +2842,7 @@ static int rbd_dev_image_id(struct rbd_d + dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret); + if (ret < 0) + goto out; ++ ret = 0; /* rbd_req_sync_exec() can return positive */ + + p = response; + rbd_dev->image_id = ceph_extract_encoded_string(&p, diff --git a/queue-3.7/series b/queue-3.7/series index 3e99311f93e..7e0314ea89d 100644 --- a/queue-3.7/series +++ b/queue-3.7/series @@ -197,3 +197,22 @@ kvm-ppc-44x-fix-dcr-read-write.patch 0008-libceph-always-reset-osds-when-kicking.patch 0009-libceph-WARN-don-t-BUG-on-unexpected-connection-stat.patch revert-drm-i915-no-lvds-quirk-for-zotac-zdbox-sd-id12-id13.patch +libceph-fix-protocol-feature-mismatch-failure-path.patch +libceph-fix-osdmap-decode-error-paths.patch +libceph-avoid-using-freed-osd-in-__kick_osd_requests.patch +libceph-remove-osdtimeout-option.patch +ceph-don-t-reference-req-after-put.patch +rbd-fix-bug-in-rbd_dev_id_put.patch +rbd-zero-return-code-in-rbd_dev_image_id.patch +rbd-fix-read-only-option-name.patch +rbd-increase-maximum-snapshot-name-length.patch +rbd-remove-snapshots-on-error-in-rbd_add.patch +rbd-do-not-allow-remove-of-mounted-on-image.patch +rbd-get-rid-of-rbd_max_seg_name_len.patch +rbd-remove-linger-unconditionally.patch +ceph-don-t-update-i_max_size-when-handling-non-auth-cap.patch +ceph-fix-infinite-loop-in-__wake_requests.patch +ceph-don-t-add-dirty-inode-to-dirty-list-if-caps-is-in-migration.patch +ceph-fix-__ceph_do_pending_vmtruncate.patch +ceph-call-handle_cap_grant-for-cap-import-message.patch +libceph-unlock-unprocessed-pages-in-start_read-error-path.patch