@@ -4937,6 +4937,7 @@ static bool io_poll_remove_one(struct io_kiocb *req)
4937
4937
io_cqring_fill_event (req , - ECANCELED );
4938
4938
io_commit_cqring (req -> ctx );
4939
4939
req -> flags |= REQ_F_COMP_LOCKED ;
4940
+ req_set_fail_links (req );
4940
4941
io_put_req (req );
4941
4942
}
4942
4943
@@ -5109,14 +5110,30 @@ static enum hrtimer_restart io_timeout_fn(struct hrtimer *timer)
5109
5110
return HRTIMER_NORESTART ;
5110
5111
}
5111
5112
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
+
5112
5130
static int io_timeout_cancel (struct io_ring_ctx * ctx , __u64 user_data )
5113
5131
{
5114
5132
struct io_kiocb * req ;
5115
5133
int ret = - ENOENT ;
5116
5134
5117
5135
list_for_each_entry (req , & ctx -> timeout_list , timeout .list ) {
5118
5136
if (user_data == req -> user_data ) {
5119
- list_del_init (& req -> timeout .list );
5120
5137
ret = 0 ;
5121
5138
break ;
5122
5139
}
@@ -5125,15 +5142,7 @@ static int io_timeout_cancel(struct io_ring_ctx *ctx, __u64 user_data)
5125
5142
if (ret == - ENOENT )
5126
5143
return ret ;
5127
5144
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 );
5137
5146
}
5138
5147
5139
5148
static 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)
7935
7944
return work -> files == files ;
7936
7945
}
7937
7946
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
+
7938
8012
static void io_uring_cancel_files (struct io_ring_ctx * ctx ,
7939
8013
struct files_struct * files )
7940
8014
{
@@ -7989,6 +8063,9 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
7989
8063
}
7990
8064
} else {
7991
8065
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 );
7992
8069
io_put_req (cancel_req );
7993
8070
}
7994
8071
0 commit comments