Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async I/O (syscalls 245 - 249) #1584

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0b2b56a
Individually stub each AIO syscall
kmeisthax Sep 27, 2021
175c52c
Add a structure in the task for AIO contexts to live in.
kmeisthax Sep 27, 2021
9c4a3f8
Implement `io_setup`
kmeisthax Sep 28, 2021
241fe79
Implement `io_destroy`.
kmeisthax Sep 30, 2021
5f041a3
Store the owning PID of each AIO context, so that resolved requests c…
kmeisthax Oct 1, 2021
9912680
Elaborate on the event structure to be able to hold pending requests,…
kmeisthax Oct 1, 2021
cce2d45
Add method for submitting a pending event.
kmeisthax Oct 1, 2021
314f335
Add functions for retrieving pending events from a context.
kmeisthax Oct 3, 2021
5390cf5
Add AIO syscalls to systrace
kmeisthax Oct 3, 2021
0cf305b
Add aioctx table method for retrieving (and retaining) a context by i…
kmeisthax Oct 3, 2021
032d31d
Half-implement io_submit.
kmeisthax Oct 3, 2021
ecfeae1
Add `aioctx_cancel_event` & other documentation fixes
kmeisthax Oct 3, 2021
da5a606
Add io_submit op so that FDs can handle asynchronous operations.
kmeisthax Oct 3, 2021
a4560f5
Add method to complete pending events.
kmeisthax Oct 4, 2021
9510f30
Add fallback for filesystems that don't yet implement true async I/O.
kmeisthax Oct 4, 2021
1dd76fe
Submitted events must retain the guest address of the IOCB structure …
kmeisthax Oct 4, 2021
8638202
Implement completion polling (io_getevents)
kmeisthax Oct 4, 2021
1c9f39a
Everything except io_setup takes a context ID directly, not a pointer…
kmeisthax Oct 4, 2021
d678aad
Properly initialize the lock and refcount in AIO contexts.
kmeisthax Oct 10, 2021
940d53d
Fix a bunch of bounds checks
kmeisthax Oct 10, 2021
21bd634
Always NULL out contexts in the task context table when removing them…
kmeisthax Oct 10, 2021
b504474
Add E2E test for AIO read and write.
kmeisthax Oct 10, 2021
867e899
Don't specify an enum impl type because gcc doesn't support that C gi…
kmeisthax Oct 11, 2021
09b2e07
In fallback code, treat FDSYNC as a full FSYNC.
kmeisthax Oct 24, 2021
fc90511
Pull the pread/pwrite emulation code out into separate functions.
kmeisthax Oct 25, 2021
8ffda31
Add E2E test for vectored async IO
kmeisthax Oct 25, 2021
f270bc1
Implement vectored async IO fallback
kmeisthax Oct 25, 2021
9769c6e
Fix incorrect/spurious failure on seeking to non-zero offsets
kmeisthax Oct 25, 2021
0a8c063
Remove implicit coercions in tests so that they don't sign-extend thi…
kmeisthax Oct 31, 2021
e8d3c9f
Add a condition variable for waiting on events, and wait for it to be…
kmeisthax Nov 21, 2021
6ea8dce
Formatting & consistency nits
kmeisthax Nov 21, 2021
1174ec7
Rip out and replace the `AIO_IOCB_` family of constants with a host s…
kmeisthax Nov 21, 2021
399265e
Also rip out the `AIO_IO_EVENT` constants for another host-compiled s…
kmeisthax Nov 21, 2021
6c09ad5
Remove e2e tests dependency on `linux/aio_abi.h` header
kmeisthax Nov 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Prev Previous commit
Next Next commit
Store the owning PID of each AIO context, so that resolved requests c…
…an access allocated memory in the guest.

This also slightly changes the AIO context ownership model: while it is still refcounted and retained by any pending requests, any context that does not have a valid task cannot resolve those requests. We flag such orphaned contexts, but allow the context to live until all pending requests have gotten the message and released the context.
  • Loading branch information
kmeisthax committed Nov 14, 2021
commit 5f041a3318f9e2d8a1323ad57036c2a42c1de812
28 changes: 21 additions & 7 deletions fs/aio.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ static int _aioctx_table_ensure(struct aioctx_table *tbl, unsigned int newcap) {
return 0;
}

struct aioctx *aioctx_new(int events_capacity) {
struct aioctx *aioctx_new(int events_capacity, pid_t pid) {
if ((INT_MAX / sizeof(struct aioctx_event)) < events_capacity) return NULL;

struct aioctx *aioctx = malloc(sizeof(struct aioctx));
Expand All @@ -46,6 +46,8 @@ struct aioctx *aioctx_new(int events_capacity) {

aioctx->events_capacity = events_capacity;
aioctx->events = aioctx_events;
aioctx->is_owned_by_task = true;
aioctx->pid = pid;

return aioctx;
}
Expand All @@ -58,10 +60,7 @@ void aioctx_retain(struct aioctx *ctx) {
unlock(&ctx->lock);
}

void aioctx_release(struct aioctx *ctx) {
if (ctx == NULL) return;

lock(&ctx->lock);
static void _aioctx_decrement_ref(struct aioctx *ctx) {
if (--ctx->refcount == 0) {
free(ctx->events);
free(ctx);
Expand All @@ -70,6 +69,21 @@ void aioctx_release(struct aioctx *ctx) {
}
}

void aioctx_release(struct aioctx *ctx) {
if (ctx == NULL) return;

lock(&ctx->lock);
_aioctx_decrement_ref(ctx);
}

void aioctx_release_from_task(struct aioctx *ctx) {
if (ctx == NULL) return;

lock(&ctx->lock);
ctx->is_owned_by_task = false;
_aioctx_decrement_ref(ctx);
}

struct aioctx_table *aioctx_table_new(unsigned int capacity) {
struct aioctx_table *tbl = malloc(sizeof(struct aioctx_table));
if (tbl == NULL) return NULL;
Expand All @@ -90,7 +104,7 @@ void aioctx_table_delete(struct aioctx_table *tbl) {
lock(&tbl->lock);
for (int i = 0; i < tbl->capacity; i += 1) {
if (tbl->contexts[i] != NULL) {
aioctx_release(tbl->contexts[i]);
aioctx_release_from_task(tbl->contexts[i]);
}
}
free(tbl->contexts);
Expand Down Expand Up @@ -143,7 +157,7 @@ signed int aioctx_table_remove(struct aioctx_table *tbl, unsigned int ctx_id) {
return _EINVAL;
}

aioctx_release(ctx);
aioctx_release_from_task(ctx);

unlock(&tbl->lock);

Expand Down
28 changes: 26 additions & 2 deletions fs/aio.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,24 @@ struct aioctx_event {
struct aioctx {
atomic_uint refcount;
lock_t lock;

// Indicates if this context is owned by a task.
//
// If true, then the `pid` field is guaranteed to be valid, and correspond
// to the task that made the request. If false, then the `pid` is invalid,
// and any pending or completed events should be treated as cancelled.
bool is_owned_by_task;

// The process that currently owns the context.
pid_t pid;

// The capacity of the events structure.
//
// This is specified by `io_setup`; requests that would potentially
// overflow the events table should be rejected with `_EAGAIN`.
dword_t events_capacity;

// The current table of pending events.
// The current table of pending and completed events.
struct aioctx_event* events;
};

Expand Down Expand Up @@ -71,10 +81,24 @@ signed int aioctx_table_insert(struct aioctx_table *tbl, struct aioctx *ctx);
// Remove an AIO context from the table by it's position (context ID).
//
// This returns an error code if the context ID is not valid for this table.
//
// All pending I/O requests on the given context will retain the context until
// they resolve. The context will also be flagged as having been released by
// the task, which is treated as an implicit cancellation of any pending
// requests.
signed int aioctx_table_remove(struct aioctx_table *tbl, unsigned int ctx_id);

struct aioctx *aioctx_new(int events_capacity);
struct aioctx *aioctx_new(int events_capacity, pid_t pid);
void aioctx_retain(struct aioctx *ctx);
void aioctx_release(struct aioctx *ctx);

// Release the AIO context and flag it as no longer being owned by a valid
// task.
//
// All pending I/O requests on the given context will retain the context until
// they resolve. The context will also be flagged as having been released by
// the task, which is treated as an implicit cancellation of any pending
// requests.
void aioctx_release_from_task(struct aioctx *ctx);

#endif
4 changes: 2 additions & 2 deletions kernel/aio.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "fs/aio.h"

dword_t sys_io_setup(dword_t nr_events, addr_t ctx_idp) {
struct aioctx *ctx = aioctx_new(nr_events);
struct aioctx *ctx = aioctx_new(nr_events, current->pid);
if (ctx == NULL) return _ENOMEM;
if (IS_ERR(ctx)) return PTR_ERR(ctx);

Expand All @@ -24,7 +24,7 @@ dword_t sys_io_setup(dword_t nr_events, addr_t ctx_idp) {
dword_t sys_io_destroy(addr_t p_ctx_id) {
unsigned int ctx_id = 0;
if (user_read(p_ctx_id, &ctx_id, sizeof(ctx_id))) return _EFAULT;

int err = aioctx_table_remove(current->aioctx, ctx_id) < 0;
if (err < 0) {
return err;
Expand Down