Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libceph: resend lingering requests with a new tid

Both not yet registered (r_linger && list_empty(&r_linger_item)) and
registered linger requests should use the new tid on resend to avoid
the dup op detection logic on the OSDs, yet we were doing this only for
"registered" case. Factor out and simplify the "registered" logic and
use the new helper for "not registered" case as well.

Fixes: http://tracker.ceph.com/issues/8806

Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
Reviewed-by: Alex Elder <elder@linaro.org>

authored by

Ilya Dryomov and committed by
Ilya Dryomov
2cc6128a f671b581

+54 -19
+54 -19
net/ceph/osd_client.c
··· 30 30 static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd); 31 31 static void __register_request(struct ceph_osd_client *osdc, 32 32 struct ceph_osd_request *req); 33 + static void __unregister_request(struct ceph_osd_client *osdc, 34 + struct ceph_osd_request *req); 33 35 static void __unregister_linger_request(struct ceph_osd_client *osdc, 34 36 struct ceph_osd_request *req); 37 + static void __enqueue_request(struct ceph_osd_request *req); 35 38 static void __send_request(struct ceph_osd_client *osdc, 36 39 struct ceph_osd_request *req); 37 40 ··· 895 892 return NULL; 896 893 } 897 894 895 + static void __kick_linger_request(struct ceph_osd_request *req) 896 + { 897 + struct ceph_osd_client *osdc = req->r_osdc; 898 + struct ceph_osd *osd = req->r_osd; 899 + 900 + /* 901 + * Linger requests need to be resent with a new tid to avoid 902 + * the dup op detection logic on the OSDs. Achieve this with 903 + * a re-register dance instead of open-coding. 904 + */ 905 + ceph_osdc_get_request(req); 906 + if (!list_empty(&req->r_linger_item)) 907 + __unregister_linger_request(osdc, req); 908 + else 909 + __unregister_request(osdc, req); 910 + __register_request(osdc, req); 911 + ceph_osdc_put_request(req); 912 + 913 + /* 914 + * Unless request has been registered as both normal and 915 + * lingering, __unregister{,_linger}_request clears r_osd. 916 + * However, here we need to preserve r_osd to make sure we 917 + * requeue on the same OSD. 918 + */ 919 + WARN_ON(req->r_osd || !osd); 920 + req->r_osd = osd; 921 + 922 + dout("%s requeueing %p tid %llu\n", __func__, req, req->r_tid); 923 + __enqueue_request(req); 924 + } 925 + 898 926 /* 899 927 * Resubmit requests pending on the given osd. 900 928 */ ··· 934 900 { 935 901 struct ceph_osd_request *req, *nreq; 936 902 LIST_HEAD(resend); 903 + LIST_HEAD(resend_linger); 937 904 int err; 938 905 939 - dout("__kick_osd_requests osd%d\n", osd->o_osd); 906 + dout("%s osd%d\n", __func__, osd->o_osd); 940 907 err = __reset_osd(osdc, osd); 941 908 if (err) 942 909 return; 910 + 943 911 /* 944 912 * Build up a list of requests to resend by traversing the 945 913 * osd's list of requests. Requests for a given object are ··· 962 926 list_for_each_entry(req, &osd->o_requests, r_osd_item) { 963 927 if (!req->r_sent) 964 928 break; 965 - list_move_tail(&req->r_req_lru_item, &resend); 966 - dout("requeueing %p tid %llu osd%d\n", req, req->r_tid, 967 - osd->o_osd); 968 - if (!req->r_linger) 929 + 930 + if (!req->r_linger) { 931 + dout("%s requeueing %p tid %llu\n", __func__, req, 932 + req->r_tid); 933 + list_move_tail(&req->r_req_lru_item, &resend); 969 934 req->r_flags |= CEPH_OSD_FLAG_RETRY; 935 + } else { 936 + list_move_tail(&req->r_req_lru_item, &resend_linger); 937 + } 970 938 } 971 939 list_splice(&resend, &osdc->req_unsent); 972 940 973 941 /* 974 - * Linger requests are re-registered before sending, which 975 - * sets up a new tid for each. We add them to the unsent 976 - * list at the end to keep things in tid order. 942 + * Both registered and not yet registered linger requests are 943 + * enqueued with a new tid on the same OSD. We add/move them 944 + * to req_unsent/o_requests at the end to keep things in tid 945 + * order. 977 946 */ 978 947 list_for_each_entry_safe(req, nreq, &osd->o_linger_requests, 979 948 r_linger_osd_item) { 980 - /* 981 - * reregister request prior to unregistering linger so 982 - * that r_osd is preserved. 983 - */ 984 - BUG_ON(!list_empty(&req->r_req_lru_item)); 985 - __register_request(osdc, req); 986 - list_add_tail(&req->r_req_lru_item, &osdc->req_unsent); 987 - list_add_tail(&req->r_osd_item, &req->r_osd->o_requests); 988 - __unregister_linger_request(osdc, req); 989 - dout("requeued lingering %p tid %llu osd%d\n", req, req->r_tid, 990 - osd->o_osd); 949 + WARN_ON(!list_empty(&req->r_req_lru_item)); 950 + __kick_linger_request(req); 991 951 } 952 + 953 + list_for_each_entry_safe(req, nreq, &resend_linger, r_req_lru_item) 954 + __kick_linger_request(req); 992 955 } 993 956 994 957 /*