Skip to content

Commit 71eb6b6

Browse files
Kent Overstreetbrauner
authored andcommitted
fs/aio: obey min_nr when doing wakeups
I've been observing workloads where IPIs due to wakeups in aio_complete() are ~15% of total CPU time in the profile. Most of those wakeups are unnecessary when completion batching is in use in io_getevents(). This plumbs min_nr through via the wait eventry, so that aio_complete() can avoid doing unnecessary wakeups. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev> Link: https://lore.kernel.org/r/20231122234257.179390-1-kent.overstreet@linux.dev Cc: Benjamin LaHaise <bcrl@kvack.org> Cc: Christian Brauner <brauner@kernel.org> Cc: <linux-aio@kvack.org> Cc: <linux-fsdevel@vger.kernel.org> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent b7638ad commit 71eb6b6

File tree

1 file changed

+57
-10
lines changed

1 file changed

+57
-10
lines changed

fs/aio.c

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,11 @@ static inline void iocb_destroy(struct aio_kiocb *iocb)
11061106
kmem_cache_free(kiocb_cachep, iocb);
11071107
}
11081108

1109+
struct aio_waiter {
1110+
struct wait_queue_entry w;
1111+
size_t min_nr;
1112+
};
1113+
11091114
/* aio_complete
11101115
* Called when the io request on the given iocb is complete.
11111116
*/
@@ -1114,7 +1119,7 @@ static void aio_complete(struct aio_kiocb *iocb)
11141119
struct kioctx *ctx = iocb->ki_ctx;
11151120
struct aio_ring *ring;
11161121
struct io_event *ev_page, *event;
1117-
unsigned tail, pos, head;
1122+
unsigned tail, pos, head, avail;
11181123
unsigned long flags;
11191124

11201125
/*
@@ -1156,6 +1161,10 @@ static void aio_complete(struct aio_kiocb *iocb)
11561161
ctx->completed_events++;
11571162
if (ctx->completed_events > 1)
11581163
refill_reqs_available(ctx, head, tail);
1164+
1165+
avail = tail > head
1166+
? tail - head
1167+
: tail + ctx->nr_events - head;
11591168
spin_unlock_irqrestore(&ctx->completion_lock, flags);
11601169

11611170
pr_debug("added to ring %p at [%u]\n", iocb, tail);
@@ -1176,8 +1185,18 @@ static void aio_complete(struct aio_kiocb *iocb)
11761185
*/
11771186
smp_mb();
11781187

1179-
if (waitqueue_active(&ctx->wait))
1180-
wake_up(&ctx->wait);
1188+
if (waitqueue_active(&ctx->wait)) {
1189+
struct aio_waiter *curr, *next;
1190+
unsigned long flags;
1191+
1192+
spin_lock_irqsave(&ctx->wait.lock, flags);
1193+
list_for_each_entry_safe(curr, next, &ctx->wait.head, w.entry)
1194+
if (avail >= curr->min_nr) {
1195+
list_del_init_careful(&curr->w.entry);
1196+
wake_up_process(curr->w.private);
1197+
}
1198+
spin_unlock_irqrestore(&ctx->wait.lock, flags);
1199+
}
11811200
}
11821201

11831202
static inline void iocb_put(struct aio_kiocb *iocb)
@@ -1290,7 +1309,9 @@ static long read_events(struct kioctx *ctx, long min_nr, long nr,
12901309
struct io_event __user *event,
12911310
ktime_t until)
12921311
{
1293-
long ret = 0;
1312+
struct hrtimer_sleeper t;
1313+
struct aio_waiter w;
1314+
long ret = 0, ret2 = 0;
12941315

12951316
/*
12961317
* Note that aio_read_events() is being called as the conditional - i.e.
@@ -1306,12 +1327,38 @@ static long read_events(struct kioctx *ctx, long min_nr, long nr,
13061327
* the ringbuffer empty. So in practice we should be ok, but it's
13071328
* something to be aware of when touching this code.
13081329
*/
1309-
if (until == 0)
1310-
aio_read_events(ctx, min_nr, nr, event, &ret);
1311-
else
1312-
wait_event_interruptible_hrtimeout(ctx->wait,
1313-
aio_read_events(ctx, min_nr, nr, event, &ret),
1314-
until);
1330+
aio_read_events(ctx, min_nr, nr, event, &ret);
1331+
if (until == 0 || ret < 0 || ret >= min_nr)
1332+
return ret;
1333+
1334+
hrtimer_init_sleeper_on_stack(&t, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1335+
if (until != KTIME_MAX) {
1336+
hrtimer_set_expires_range_ns(&t.timer, until, current->timer_slack_ns);
1337+
hrtimer_sleeper_start_expires(&t, HRTIMER_MODE_REL);
1338+
}
1339+
1340+
init_wait(&w.w);
1341+
1342+
while (1) {
1343+
unsigned long nr_got = ret;
1344+
1345+
w.min_nr = min_nr - ret;
1346+
1347+
ret2 = prepare_to_wait_event(&ctx->wait, &w.w, TASK_INTERRUPTIBLE);
1348+
if (!ret2 && !t.task)
1349+
ret2 = -ETIME;
1350+
1351+
if (aio_read_events(ctx, min_nr, nr, event, &ret) || ret2)
1352+
break;
1353+
1354+
if (nr_got == ret)
1355+
schedule();
1356+
}
1357+
1358+
finish_wait(&ctx->wait, &w.w);
1359+
hrtimer_cancel(&t.timer);
1360+
destroy_hrtimer_on_stack(&t.timer);
1361+
13151362
return ret;
13161363
}
13171364

0 commit comments

Comments
 (0)