projects/linux·commit 5007928e

Merge tag 'io_uring-5.6-2020-03-13' of git://git.kernel.dk/linux-block

5007928e · Linus Torvalds <[email protected]> · 2020-03-13 13:00:08 -07:00

Pull io_uring fix from Jens Axboe:
 "Just a single fix here, improving the RCU callback ordering from last
  week. After a bit more perusing by Paul, he poked a hole in the
  original"

* tag 'io_uring-5.6-2020-03-13' of git://git.kernel.dk/linux-block:
  io_uring: ensure RCU callback ordering with rcu_barrier()
Commit
5007928eaeb7681501e94ac7516f6c6200f993fa
Parents
17829c5a · 805b13ad

Merge commit. Changes below are compared with the first parent: 17829c5a.

Changes

1 files changed · +13 −16

FileStatusAddDelContent
fs/io_uring.cmodified+13−16View file

fs/io_uring.c

View file
diff --git a/fs/io_uring.c b/fs/io_uring.c
index c06082b..1b25172 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -191,7 +191,6 @@ struct fixed_file_data {
struct llist_head put_llist;
struct work_struct ref_work;
struct completion done;
- struct rcu_head rcu;
};
struct io_ring_ctx {
@@ -5331,24 +5330,21 @@ static void io_file_ref_kill(struct percpu_ref *ref)
complete(&data->done);
}
-static void __io_file_ref_exit_and_free(struct rcu_head *rcu)
+static void io_file_ref_exit_and_free(struct work_struct *work)
{
- struct fixed_file_data *data = container_of(rcu, struct fixed_file_data,
- rcu);
- percpu_ref_exit(&data->refs);
- kfree(data);
-}
+ struct fixed_file_data *data;
+
+ data = container_of(work, struct fixed_file_data, ref_work);
-static void io_file_ref_exit_and_free(struct rcu_head *rcu)
-{
/*
- * We need to order our exit+free call against the potentially
- * existing call_rcu() for switching to atomic. One way to do that
- * is to have this rcu callback queue the final put and free, as we
- * could otherwise have a pre-existing atomic switch complete _after_
- * the free callback we queued.
+ * Ensure any percpu-ref atomic switch callback has run, it could have
+ * been in progress when the files were being unregistered. Once
+ * that's done, we can safely exit and free the ref and containing
+ * data structure.
*/
- call_rcu(rcu, __io_file_ref_exit_and_free);
+ rcu_barrier();
+ percpu_ref_exit(&data->refs);
+ kfree(data);
}
static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
@@ -5369,7 +5365,8 @@ static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
for (i = 0; i < nr_tables; i++)
kfree(data->table[i].files);
kfree(data->table);
- call_rcu(&data->rcu, io_file_ref_exit_and_free);
+ INIT_WORK(&data->ref_work, io_file_ref_exit_and_free);
+ queue_work(system_wq, &data->ref_work);
ctx->file_data = NULL;
ctx->nr_user_files = 0;
return 0;