@ -30,8 +30,11 @@ static void __send_queued(struct ceph_osd_client *osdc);
static int __reset_osd ( struct ceph_osd_client * osdc , struct ceph_osd * osd ) ;
static void __register_request ( struct ceph_osd_client * osdc ,
struct ceph_osd_request * req ) ;
static void __unregister_request ( struct ceph_osd_client * osdc ,
struct ceph_osd_request * req ) ;
static void __unregister_linger_request ( struct ceph_osd_client * osdc ,
struct ceph_osd_request * req ) ;
static void __enqueue_request ( struct ceph_osd_request * req ) ;
static void __send_request ( struct ceph_osd_client * osdc ,
struct ceph_osd_request * req ) ;
@ -892,6 +895,37 @@ __lookup_request_ge(struct ceph_osd_client *osdc,
return NULL ;
}
static void __kick_linger_request ( struct ceph_osd_request * req )
{
struct ceph_osd_client * osdc = req - > r_osdc ;
struct ceph_osd * osd = req - > r_osd ;
/*
* Linger requests need to be resent with a new tid to avoid
* the dup op detection logic on the OSDs . Achieve this with
* a re - register dance instead of open - coding .
*/
ceph_osdc_get_request ( req ) ;
if ( ! list_empty ( & req - > r_linger_item ) )
__unregister_linger_request ( osdc , req ) ;
else
__unregister_request ( osdc , req ) ;
__register_request ( osdc , req ) ;
ceph_osdc_put_request ( req ) ;
/*
* Unless request has been registered as both normal and
* lingering , __unregister { , _linger } _request clears r_osd .
* However , here we need to preserve r_osd to make sure we
* requeue on the same OSD .
*/
WARN_ON ( req - > r_osd | | ! osd ) ;
req - > r_osd = osd ;
dout ( " %s requeueing %p tid %llu \n " , __func__ , req , req - > r_tid ) ;
__enqueue_request ( req ) ;
}
/*
* Resubmit requests pending on the given osd .
*/
@ -900,12 +934,14 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc,
{
struct ceph_osd_request * req , * nreq ;
LIST_HEAD ( resend ) ;
LIST_HEAD ( resend_linger ) ;
int err ;
dout ( " __kick_osd_request s osd%d\n " , osd - > o_osd ) ;
dout ( " % s osd%d\n " , __func__ , osd - > o_osd ) ;
err = __reset_osd ( osdc , osd ) ;
if ( err )
return ;
/*
* Build up a list of requests to resend by traversing the
* osd ' s list of requests . Requests for a given object are
@ -926,33 +962,32 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc,
list_for_each_entry ( req , & osd - > o_requests , r_osd_item ) {
if ( ! req - > r_sent )
break ;
list_move_tail ( & req - > r_req_lru_item , & resend ) ;
dout ( " requeueing %p tid %llu osd%d \n " , req , req - > r_tid ,
osd - > o_osd ) ;
if ( ! req - > r_linger )
if ( ! req - > r_linger ) {
dout ( " %s requeueing %p tid %llu \n " , __func__ , req ,
req - > r_tid ) ;
list_move_tail ( & req - > r_req_lru_item , & resend ) ;
req - > r_flags | = CEPH_OSD_FLAG_RETRY ;
} else {
list_move_tail ( & req - > r_req_lru_item , & resend_linger ) ;
}
}
list_splice ( & resend , & osdc - > req_unsent ) ;
/*
* Linger requests are re - registered before sending , which
* sets up a new tid for each . We add them to the unsent
* list at the end to keep things in tid order .
* Both registered and not yet registered linger requests are
* enqueued with a new tid on the same OSD . We add / move them
* to req_unsent / o_requests at the end to keep things in tid
* order .
*/
list_for_each_entry_safe ( req , nreq , & osd - > o_linger_requests ,
r_linger_osd_item ) {
/*
* reregister request prior to unregistering linger so
* that r_osd is preserved .
*/
BUG_ON ( ! list_empty ( & req - > r_req_lru_item ) ) ;
__register_request ( osdc , req ) ;
list_add_tail ( & req - > r_req_lru_item , & osdc - > req_unsent ) ;
list_add_tail ( & req - > r_osd_item , & req - > r_osd - > o_requests ) ;
__unregister_linger_request ( osdc , req ) ;
dout ( " requeued lingering %p tid %llu osd%d \n " , req , req - > r_tid ,
osd - > o_osd ) ;
WARN_ON ( ! list_empty ( & req - > r_req_lru_item ) ) ;
__kick_linger_request ( req ) ;
}
list_for_each_entry_safe ( req , nreq , & resend_linger , r_req_lru_item )
__kick_linger_request ( req ) ;
}
/*