--- /dev/null
+From 0747d15ddb5eac0e83376e2722e3654ae01d252f Mon Sep 17 00:00:00 2001
+From: "Yan, Zheng" <zheng.z.yan@intel.com>
+Date: Mon, 19 Nov 2012 10:49:09 +0800
+Subject: ceph: call handle_cap_grant() for cap import message
+
+
+From: "Yan, Zheng" <zheng.z.yan@intel.com>
+
+(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 <zheng.z.yan@intel.com>
+Signed-off-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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;
+
--- /dev/null
+From f409f158fb190ab9915fd94dce367e462a0c02f6 Mon Sep 17 00:00:00 2001
+From: "Yan, Zheng" <zheng.z.yan@intel.com>
+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" <zheng.z.yan@intel.com>
+
+(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 <zheng.z.yan@intel.com>
+Signed-off-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
--- /dev/null
+From a6bbcd6741d53b326a2a3a7edef6e15334de6ea3 Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Thu, 29 Nov 2012 08:37:03 -0600
+Subject: ceph: don't reference req after put
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-off-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
--- /dev/null
+From 76c834d784c36bda3a8d56f5cdf3e1282b0979f9 Mon Sep 17 00:00:00 2001
+From: "Yan, Zheng" <zheng.z.yan@intel.com>
+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" <zheng.z.yan@intel.com>
+
+(cherry picked from commit 5e62ad30157d0da04cf40c6d1a2f4bc840948b9c)
+
+The cap from non-auth mds doesn't have a meaningful max_size value.
+
+Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
+Signed-off-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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) {
--- /dev/null
+From 0e6789acaba2e40768a778a1e553c92723a19a30 Mon Sep 17 00:00:00 2001
+From: "Yan, Zheng" <zheng.z.yan@intel.com>
+Date: Mon, 19 Nov 2012 10:49:08 +0800
+Subject: ceph: Fix __ceph_do_pending_vmtruncate
+
+
+From: "Yan, Zheng" <zheng.z.yan@intel.com>
+
+(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 <zheng.z.yan@intel.com>
+Signed-off-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
+ }
+
+
--- /dev/null
+From 0fd2af5e838e87cf449c657b6e19535b64da6c4c Mon Sep 17 00:00:00 2001
+From: "Yan, Zheng" <zheng.z.yan@intel.com>
+Date: Mon, 19 Nov 2012 10:49:06 +0800
+Subject: ceph: Fix infinite loop in __wake_requests
+
+
+From: "Yan, Zheng" <zheng.z.yan@intel.com>
+
+(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 <zheng.z.yan@intel.com>
+Signed-off-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
+ }
--- /dev/null
+From f4a3fea610cb6a9fc9cb722a0765194e19b82e7b Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Fri, 7 Dec 2012 09:57:58 -0600
+Subject: libceph: avoid using freed osd in __kick_osd_requests()
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 &&
--- /dev/null
+From 71630f053c8da3b7d8e52c99ff2592f44dd28979 Mon Sep 17 00:00:00 2001
+From: Sage Weil <sage@inktank.com>
+Date: Mon, 29 Oct 2012 11:01:42 -0700
+Subject: libceph: fix osdmap decode error paths
+
+
+From: Sage Weil <sage@inktank.com>
+
+(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 <sage@inktank.com>
+Reviewed-by: Alex Elder <elder@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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++)
--- /dev/null
+From f10a18433a1b3192e71eecffeaeca5f5f1694016 Mon Sep 17 00:00:00 2001
+From: Sage Weil <sage@inktank.com>
+Date: Thu, 27 Dec 2012 20:27:04 -0600
+Subject: libceph: fix protocol feature mismatch failure path
+
+
+From: Sage Weil <sage@inktank.com>
+
+(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 <sage@inktank.com>
+Reviewed-by: Alex Elder <elder@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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;
+ }
+
--- /dev/null
+From aa852ff17166b53b1d29388af472bb9c32297f05 Mon Sep 17 00:00:00 2001
+From: Sage Weil <sage@inktank.com>
+Date: Wed, 28 Nov 2012 12:28:24 -0800
+Subject: libceph: remove 'osdtimeout' option
+
+
+From: Sage Weil <sage@inktank.com>
+
+(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 <sage@inktank.com>
+Reviewed-by: Alex Elder <elder@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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).
--- /dev/null
+From 9fa5ba96f32fbea354457fc7ece06b2ee81b1b71 Mon Sep 17 00:00:00 2001
+From: David Zafman <david.zafman@inktank.com>
+Date: Mon, 3 Dec 2012 19:14:05 -0800
+Subject: libceph: Unlock unprocessed pages in start_read() error path
+
+
+From: David Zafman <david.zafman@inktank.com>
+
+(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 <david.zafman@inktank.com>
+Reviewed-by: Alex Elder <elder@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
--- /dev/null
+From 730406993ec6d044a81115fc19091ba6abfcbb15 Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Fri, 16 Nov 2012 09:29:16 -0600
+Subject: rbd: do not allow remove of mounted-on image
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
+
--- /dev/null
+From 8824d0eb9dee3bad29e9dba796d5d7953cab6719 Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Wed, 10 Oct 2012 21:19:13 -0700
+Subject: rbd: fix bug in rbd_dev_id_put()
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
+
--- /dev/null
+From 9aca7b487cf1c996a13ff5abf0ea4ac560ea1dd4 Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Mon, 22 Oct 2012 11:31:26 -0500
+Subject: rbd: fix read-only option name
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-by: Dan Mick <dan.mick@inktank.com>
+Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 */
--- /dev/null
+From 965f03ad3d796d03ec16f9809cb0096a64f6523d Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Fri, 9 Nov 2012 15:05:54 -0600
+Subject: rbd: get rid of RBD_MAX_SEG_NAME_LEN
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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
+
--- /dev/null
+From 1306be442fda1b7a92b879ab18a535f56da5ab0a Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Tue, 3 Jul 2012 16:01:19 -0500
+Subject: rbd: increase maximum snapshot name length
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-by: Dan Mick <dan.mick@inktank.com>
+Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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:
--- /dev/null
+From 942784e7a6e2ef8f861043f65b054eb3ef10b2fd Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Thu, 6 Dec 2012 09:37:23 -0600
+Subject: rbd: remove linger unconditionally
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-by: Sage Weil <sage@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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) &&
--- /dev/null
+From 21bc037520c252304c04d3bb8131fb3d4ba5b2c5 Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Thu, 25 Oct 2012 23:34:40 -0500
+Subject: rbd: remove snapshots on error in rbd_add()
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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:
--- /dev/null
+From cc8b5fcd343b3c99468fc9f0b4c3e03a7eafa7fc Mon Sep 17 00:00:00 2001
+From: Alex Elder <elder@inktank.com>
+Date: Wed, 10 Oct 2012 21:19:13 -0700
+Subject: rbd: zero return code in rbd_dev_image_id()
+
+
+From: Alex Elder <elder@inktank.com>
+
+(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 <elder@inktank.com>
+Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
+Reviewed-by: Dan Mick <dan.mick@inktank.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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,
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