@@ -4937,6 +4937,7 @@ static bool io_poll_remove_one(struct io_kiocb *req)
49374937 io_cqring_fill_event (req , - ECANCELED );
49384938 io_commit_cqring (req -> ctx );
49394939 req -> flags |= REQ_F_COMP_LOCKED ;
4940+ req_set_fail_links (req );
49404941 io_put_req (req );
49414942 }
49424943
@@ -5109,14 +5110,30 @@ static enum hrtimer_restart io_timeout_fn(struct hrtimer *timer)
51095110 return HRTIMER_NORESTART ;
51105111}
51115112
5113+ static int __io_timeout_cancel (struct io_kiocb * req )
5114+ {
5115+ int ret ;
5116+
5117+ list_del_init (& req -> timeout .list );
5118+
5119+ ret = hrtimer_try_to_cancel (& req -> io -> timeout .timer );
5120+ if (ret == -1 )
5121+ return - EALREADY ;
5122+
5123+ req_set_fail_links (req );
5124+ req -> flags |= REQ_F_COMP_LOCKED ;
5125+ io_cqring_fill_event (req , - ECANCELED );
5126+ io_put_req (req );
5127+ return 0 ;
5128+ }
5129+
51125130static int io_timeout_cancel (struct io_ring_ctx * ctx , __u64 user_data )
51135131{
51145132 struct io_kiocb * req ;
51155133 int ret = - ENOENT ;
51165134
51175135 list_for_each_entry (req , & ctx -> timeout_list , timeout .list ) {
51185136 if (user_data == req -> user_data ) {
5119- list_del_init (& req -> timeout .list );
51205137 ret = 0 ;
51215138 break ;
51225139 }
@@ -5125,15 +5142,7 @@ static int io_timeout_cancel(struct io_ring_ctx *ctx, __u64 user_data)
51255142 if (ret == - ENOENT )
51265143 return ret ;
51275144
5128- ret = hrtimer_try_to_cancel (& req -> io -> timeout .timer );
5129- if (ret == -1 )
5130- return - EALREADY ;
5131-
5132- req_set_fail_links (req );
5133- req -> flags |= REQ_F_COMP_LOCKED ;
5134- io_cqring_fill_event (req , - ECANCELED );
5135- io_put_req (req );
5136- return 0 ;
5145+ return __io_timeout_cancel (req );
51375146}
51385147
51395148static int io_timeout_remove_prep (struct io_kiocb * req ,
@@ -7935,6 +7944,71 @@ static bool io_wq_files_match(struct io_wq_work *work, void *data)
79357944 return work -> files == files ;
79367945}
79377946
7947+ /*
7948+ * Returns true if 'preq' is the link parent of 'req'
7949+ */
7950+ static bool io_match_link (struct io_kiocb * preq , struct io_kiocb * req )
7951+ {
7952+ struct io_kiocb * link ;
7953+
7954+ if (!(preq -> flags & REQ_F_LINK_HEAD ))
7955+ return false;
7956+
7957+ list_for_each_entry (link , & preq -> link_list , link_list ) {
7958+ if (link == req )
7959+ return true;
7960+ }
7961+
7962+ return false;
7963+ }
7964+
7965+ /*
7966+ * We're looking to cancel 'req' because it's holding on to our files, but
7967+ * 'req' could be a link to another request. See if it is, and cancel that
7968+ * parent request if so.
7969+ */
7970+ static bool io_poll_remove_link (struct io_ring_ctx * ctx , struct io_kiocb * req )
7971+ {
7972+ struct hlist_node * tmp ;
7973+ struct io_kiocb * preq ;
7974+ bool found = false;
7975+ int i ;
7976+
7977+ spin_lock_irq (& ctx -> completion_lock );
7978+ for (i = 0 ; i < (1U << ctx -> cancel_hash_bits ); i ++ ) {
7979+ struct hlist_head * list ;
7980+
7981+ list = & ctx -> cancel_hash [i ];
7982+ hlist_for_each_entry_safe (preq , tmp , list , hash_node ) {
7983+ found = io_match_link (preq , req );
7984+ if (found ) {
7985+ io_poll_remove_one (preq );
7986+ break ;
7987+ }
7988+ }
7989+ }
7990+ spin_unlock_irq (& ctx -> completion_lock );
7991+ return found ;
7992+ }
7993+
7994+ static bool io_timeout_remove_link (struct io_ring_ctx * ctx ,
7995+ struct io_kiocb * req )
7996+ {
7997+ struct io_kiocb * preq ;
7998+ bool found = false;
7999+
8000+ spin_lock_irq (& ctx -> completion_lock );
8001+ list_for_each_entry (preq , & ctx -> timeout_list , timeout .list ) {
8002+ found = io_match_link (preq , req );
8003+ if (found ) {
8004+ __io_timeout_cancel (preq );
8005+ break ;
8006+ }
8007+ }
8008+ spin_unlock_irq (& ctx -> completion_lock );
8009+ return found ;
8010+ }
8011+
79388012static void io_uring_cancel_files (struct io_ring_ctx * ctx ,
79398013 struct files_struct * files )
79408014{
@@ -7989,6 +8063,9 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
79898063 }
79908064 } else {
79918065 io_wq_cancel_work (ctx -> io_wq , & cancel_req -> work );
8066+ /* could be a link, check and remove if it is */
8067+ if (!io_poll_remove_link (ctx , cancel_req ))
8068+ io_timeout_remove_link (ctx , cancel_req );
79928069 io_put_req (cancel_req );
79938070 }
79948071
0 commit comments