Skip to content

Commit eddf51f

Browse files
dhowellsbrauner
authored andcommitted
afs: Make {Y,}FS.FetchData an asynchronous operation
Make FS.FetchData and YFS.FetchData an asynchronous operation in that the request is queued in AF_RXRPC and then we return to the caller rather than waiting. Processing of the returning packets is then done inline if it's a synchronous VFS/VM call (readdir, read_folio, sync DIO, prep for write) or offloaded to a workqueue if asynchronous VM calls (eg. readahead, async DIO). This reduces the chain of workqueues invoking workqueues and cuts out some of the overhead, driving rxrpc data extraction and netfslib read collection from a thread that's going to block to completion anyway if possible. The ->done() call op is also split with ->immediate_cancel() handling the cancellation on failure to begin the call and ->done() handling the rest. This means that the AFS async FetchData code doesn't try to terminate the netfs subrequest twice. Signed-off-by: David Howells <[email protected]> Link: https://lore.kernel.org/r/[email protected] cc: Marc Dionne <[email protected]> cc: [email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 9750be9 commit eddf51f

File tree

9 files changed

+170
-37
lines changed

9 files changed

+170
-37
lines changed

fs/afs/file.c

Lines changed: 112 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -225,26 +225,111 @@ static void afs_fetch_data_aborted(struct afs_operation *op)
225225
afs_fetch_data_notify(op);
226226
}
227227

228-
static void afs_fetch_data_put(struct afs_operation *op)
229-
{
230-
op->fetch.subreq->error = afs_op_error(op);
231-
}
232-
233228
const struct afs_operation_ops afs_fetch_data_operation = {
234229
.issue_afs_rpc = afs_fs_fetch_data,
235230
.issue_yfs_rpc = yfs_fs_fetch_data,
236231
.success = afs_fetch_data_success,
237232
.aborted = afs_fetch_data_aborted,
238233
.failed = afs_fetch_data_notify,
239-
.put = afs_fetch_data_put,
240234
};
241235

236+
static void afs_issue_read_call(struct afs_operation *op)
237+
{
238+
op->call_responded = false;
239+
op->call_error = 0;
240+
op->call_abort_code = 0;
241+
if (test_bit(AFS_SERVER_FL_IS_YFS, &op->server->flags))
242+
yfs_fs_fetch_data(op);
243+
else
244+
afs_fs_fetch_data(op);
245+
}
246+
247+
static void afs_end_read(struct afs_operation *op)
248+
{
249+
if (op->call_responded && op->server)
250+
set_bit(AFS_SERVER_FL_RESPONDING, &op->server->flags);
251+
252+
if (!afs_op_error(op))
253+
afs_fetch_data_success(op);
254+
else if (op->cumul_error.aborted)
255+
afs_fetch_data_aborted(op);
256+
else
257+
afs_fetch_data_notify(op);
258+
259+
afs_end_vnode_operation(op);
260+
afs_put_operation(op);
261+
}
262+
263+
/*
264+
* Perform I/O processing on an asynchronous call. The work item carries a ref
265+
* to the call struct that we either need to release or to pass on.
266+
*/
267+
static void afs_read_receive(struct afs_call *call)
268+
{
269+
struct afs_operation *op = call->op;
270+
enum afs_call_state state;
271+
272+
_enter("");
273+
274+
state = READ_ONCE(call->state);
275+
if (state == AFS_CALL_COMPLETE)
276+
return;
277+
278+
while (state < AFS_CALL_COMPLETE && READ_ONCE(call->need_attention)) {
279+
WRITE_ONCE(call->need_attention, false);
280+
afs_deliver_to_call(call);
281+
state = READ_ONCE(call->state);
282+
}
283+
284+
if (state < AFS_CALL_COMPLETE) {
285+
netfs_read_subreq_progress(op->fetch.subreq);
286+
if (rxrpc_kernel_check_life(call->net->socket, call->rxcall))
287+
return;
288+
/* rxrpc terminated the call. */
289+
afs_set_call_complete(call, call->error, call->abort_code);
290+
}
291+
292+
op->call_abort_code = call->abort_code;
293+
op->call_error = call->error;
294+
op->call_responded = call->responded;
295+
op->call = NULL;
296+
call->op = NULL;
297+
afs_put_call(call);
298+
299+
/* If the call failed, then we need to crank the server rotation
300+
* handle and try the next.
301+
*/
302+
if (afs_select_fileserver(op)) {
303+
afs_issue_read_call(op);
304+
return;
305+
}
306+
307+
afs_end_read(op);
308+
}
309+
310+
void afs_fetch_data_async_rx(struct work_struct *work)
311+
{
312+
struct afs_call *call = container_of(work, struct afs_call, async_work);
313+
314+
afs_read_receive(call);
315+
afs_put_call(call);
316+
}
317+
318+
void afs_fetch_data_immediate_cancel(struct afs_call *call)
319+
{
320+
if (call->async) {
321+
afs_get_call(call, afs_call_trace_wake);
322+
if (!queue_work(afs_async_calls, &call->async_work))
323+
afs_deferred_put_call(call);
324+
flush_work(&call->async_work);
325+
}
326+
}
327+
242328
/*
243329
* Fetch file data from the volume.
244330
*/
245-
static void afs_read_worker(struct work_struct *work)
331+
static void afs_issue_read(struct netfs_io_subrequest *subreq)
246332
{
247-
struct netfs_io_subrequest *subreq = container_of(work, struct netfs_io_subrequest, work);
248333
struct afs_operation *op;
249334
struct afs_vnode *vnode = AFS_FS_I(subreq->rreq->inode);
250335
struct key *key = subreq->rreq->netfs_priv;
@@ -269,13 +354,26 @@ static void afs_read_worker(struct work_struct *work)
269354
op->ops = &afs_fetch_data_operation;
270355

271356
trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
272-
afs_do_sync_operation(op);
273-
}
274357

275-
static void afs_issue_read(struct netfs_io_subrequest *subreq)
276-
{
277-
INIT_WORK(&subreq->work, afs_read_worker);
278-
queue_work(system_long_wq, &subreq->work);
358+
if (subreq->rreq->origin == NETFS_READAHEAD ||
359+
subreq->rreq->iocb) {
360+
op->flags |= AFS_OPERATION_ASYNC;
361+
362+
if (!afs_begin_vnode_operation(op)) {
363+
subreq->error = afs_put_operation(op);
364+
netfs_read_subreq_terminated(subreq);
365+
return;
366+
}
367+
368+
if (!afs_select_fileserver(op)) {
369+
afs_end_read(op);
370+
return;
371+
}
372+
373+
afs_issue_read_call(op);
374+
} else {
375+
afs_do_sync_operation(op);
376+
}
279377
}
280378

281379
static int afs_init_request(struct netfs_io_request *rreq, struct file *file)

fs/afs/fs_operation.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ bool afs_begin_vnode_operation(struct afs_operation *op)
256256
/*
257257
* Tidy up a filesystem cursor and unlock the vnode.
258258
*/
259-
static void afs_end_vnode_operation(struct afs_operation *op)
259+
void afs_end_vnode_operation(struct afs_operation *op)
260260
{
261261
_enter("");
262262

fs/afs/fsclient.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,6 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
352352
ret = afs_extract_data(call, true);
353353
subreq->transferred += count_before - call->iov_len;
354354
call->remaining -= count_before - call->iov_len;
355-
netfs_read_subreq_progress(subreq);
356355
if (ret < 0)
357356
return ret;
358357

@@ -409,14 +408,18 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
409408
static const struct afs_call_type afs_RXFSFetchData = {
410409
.name = "FS.FetchData",
411410
.op = afs_FS_FetchData,
411+
.async_rx = afs_fetch_data_async_rx,
412412
.deliver = afs_deliver_fs_fetch_data,
413+
.immediate_cancel = afs_fetch_data_immediate_cancel,
413414
.destructor = afs_flat_call_destructor,
414415
};
415416

416417
static const struct afs_call_type afs_RXFSFetchData64 = {
417418
.name = "FS.FetchData64",
418419
.op = afs_FS_FetchData64,
420+
.async_rx = afs_fetch_data_async_rx,
419421
.deliver = afs_deliver_fs_fetch_data,
422+
.immediate_cancel = afs_fetch_data_immediate_cancel,
420423
.destructor = afs_flat_call_destructor,
421424
};
422425

@@ -436,6 +439,9 @@ static void afs_fs_fetch_data64(struct afs_operation *op)
436439
if (!call)
437440
return afs_op_nomem(op);
438441

442+
if (op->flags & AFS_OPERATION_ASYNC)
443+
call->async = true;
444+
439445
/* marshall the parameters */
440446
bp = call->request;
441447
bp[0] = htonl(FSFETCHDATA64);
@@ -1730,6 +1736,7 @@ static const struct afs_call_type afs_RXFSGetCapabilities = {
17301736
.op = afs_FS_GetCapabilities,
17311737
.deliver = afs_deliver_fs_get_capabilities,
17321738
.done = afs_fileserver_probe_result,
1739+
.immediate_cancel = afs_fileserver_probe_result,
17331740
.destructor = afs_fs_get_capabilities_destructor,
17341741
};
17351742

fs/afs/internal.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,17 @@ struct afs_call_type {
202202
/* clean up a call */
203203
void (*destructor)(struct afs_call *call);
204204

205+
/* Async receive processing function */
206+
void (*async_rx)(struct work_struct *work);
207+
205208
/* Work function */
206209
void (*work)(struct work_struct *work);
207210

208211
/* Call done function (gets called immediately on success or failure) */
209212
void (*done)(struct afs_call *call);
213+
214+
/* Handle a call being immediately cancelled. */
215+
void (*immediate_cancel)(struct afs_call *call);
210216
};
211217

212218
/*
@@ -942,6 +948,7 @@ struct afs_operation {
942948
#define AFS_OPERATION_TRIED_ALL 0x0400 /* Set if we've tried all the fileservers */
943949
#define AFS_OPERATION_RETRY_SERVER 0x0800 /* Set if we should retry the current server */
944950
#define AFS_OPERATION_DIR_CONFLICT 0x1000 /* Set if we detected a 3rd-party dir change */
951+
#define AFS_OPERATION_ASYNC 0x2000 /* Set if should run asynchronously */
945952
};
946953

947954
/*
@@ -1104,6 +1111,8 @@ extern int afs_cache_wb_key(struct afs_vnode *, struct afs_file *);
11041111
extern void afs_put_wb_key(struct afs_wb_key *);
11051112
extern int afs_open(struct inode *, struct file *);
11061113
extern int afs_release(struct inode *, struct file *);
1114+
void afs_fetch_data_async_rx(struct work_struct *work);
1115+
void afs_fetch_data_immediate_cancel(struct afs_call *call);
11071116

11081117
/*
11091118
* flock.c
@@ -1155,6 +1164,7 @@ extern void afs_fs_store_acl(struct afs_operation *);
11551164
extern struct afs_operation *afs_alloc_operation(struct key *, struct afs_volume *);
11561165
extern int afs_put_operation(struct afs_operation *);
11571166
extern bool afs_begin_vnode_operation(struct afs_operation *);
1167+
extern void afs_end_vnode_operation(struct afs_operation *op);
11581168
extern void afs_wait_for_operation(struct afs_operation *);
11591169
extern int afs_do_sync_operation(struct afs_operation *);
11601170

@@ -1326,6 +1336,7 @@ extern void afs_charge_preallocation(struct work_struct *);
13261336
extern void afs_put_call(struct afs_call *);
13271337
void afs_deferred_put_call(struct afs_call *call);
13281338
void afs_make_call(struct afs_call *call, gfp_t gfp);
1339+
void afs_deliver_to_call(struct afs_call *call);
13291340
void afs_wait_for_call_to_complete(struct afs_call *call);
13301341
extern struct afs_call *afs_alloc_flat_call(struct afs_net *,
13311342
const struct afs_call_type *,
@@ -1336,6 +1347,19 @@ extern void afs_send_simple_reply(struct afs_call *, const void *, size_t);
13361347
extern int afs_extract_data(struct afs_call *, bool);
13371348
extern int afs_protocol_error(struct afs_call *, enum afs_eproto_cause);
13381349

1350+
static inline struct afs_call *afs_get_call(struct afs_call *call,
1351+
enum afs_call_trace why)
1352+
{
1353+
int r;
1354+
1355+
__refcount_inc(&call->ref, &r);
1356+
1357+
trace_afs_call(call->debug_id, why, r + 1,
1358+
atomic_read(&call->net->nr_outstanding_calls),
1359+
__builtin_return_address(0));
1360+
return call;
1361+
}
1362+
13391363
static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why)
13401364
{
13411365
int r = refcount_read(&call->ref);

fs/afs/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ static int __init afs_init(void)
177177
afs_wq = alloc_workqueue("afs", 0, 0);
178178
if (!afs_wq)
179179
goto error_afs_wq;
180-
afs_async_calls = alloc_workqueue("kafsd", WQ_MEM_RECLAIM, 0);
180+
afs_async_calls = alloc_workqueue("kafsd", WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
181181
if (!afs_async_calls)
182182
goto error_async;
183183
afs_lock_manager = alloc_workqueue("kafs_lockd", WQ_MEM_RECLAIM, 0);

fs/afs/rxrpc.c

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
149149
call->net = net;
150150
call->debug_id = atomic_inc_return(&rxrpc_debug_id);
151151
refcount_set(&call->ref, 1);
152-
INIT_WORK(&call->async_work, afs_process_async_call);
152+
INIT_WORK(&call->async_work, type->async_rx ?: afs_process_async_call);
153+
INIT_WORK(&call->work, call->type->work);
153154
INIT_WORK(&call->free_work, afs_deferred_free_worker);
154155
init_waitqueue_head(&call->waitq);
155156
spin_lock_init(&call->state_lock);
@@ -235,27 +236,12 @@ void afs_deferred_put_call(struct afs_call *call)
235236
schedule_work(&call->free_work);
236237
}
237238

238-
static struct afs_call *afs_get_call(struct afs_call *call,
239-
enum afs_call_trace why)
240-
{
241-
int r;
242-
243-
__refcount_inc(&call->ref, &r);
244-
245-
trace_afs_call(call->debug_id, why, r + 1,
246-
atomic_read(&call->net->nr_outstanding_calls),
247-
__builtin_return_address(0));
248-
return call;
249-
}
250-
251239
/*
252240
* Queue the call for actual work.
253241
*/
254242
static void afs_queue_call_work(struct afs_call *call)
255243
{
256244
if (call->type->work) {
257-
INIT_WORK(&call->work, call->type->work);
258-
259245
afs_get_call(call, afs_call_trace_work);
260246
if (!queue_work(afs_wq, &call->work))
261247
afs_put_call(call);
@@ -452,8 +438,8 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
452438
error_kill_call:
453439
if (call->async)
454440
afs_see_call(call, afs_call_trace_async_kill);
455-
if (call->type->done)
456-
call->type->done(call);
441+
if (call->type->immediate_cancel)
442+
call->type->immediate_cancel(call);
457443

458444
/* We need to dispose of the extra ref we grabbed for an async call.
459445
* The call, however, might be queued on afs_async_calls and we need to
@@ -508,7 +494,7 @@ static void afs_log_error(struct afs_call *call, s32 remote_abort)
508494
/*
509495
* deliver messages to a call
510496
*/
511-
static void afs_deliver_to_call(struct afs_call *call)
497+
void afs_deliver_to_call(struct afs_call *call)
512498
{
513499
enum afs_call_state state;
514500
size_t len;
@@ -809,6 +795,7 @@ static int afs_deliver_cm_op_id(struct afs_call *call)
809795
return -ENOTSUPP;
810796

811797
trace_afs_cb_call(call);
798+
call->work.func = call->type->work;
812799

813800
/* pass responsibility for the remainer of this message off to the
814801
* cache manager op */

fs/afs/vlclient.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ static const struct afs_call_type afs_RXVLGetCapabilities = {
370370
.name = "VL.GetCapabilities",
371371
.op = afs_VL_GetCapabilities,
372372
.deliver = afs_deliver_vl_get_capabilities,
373+
.immediate_cancel = afs_vlserver_probe_result,
373374
.done = afs_vlserver_probe_result,
374375
.destructor = afs_destroy_vl_get_capabilities,
375376
};

fs/afs/write.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,18 @@ void afs_retry_request(struct netfs_io_request *wreq, struct netfs_io_stream *st
196196
list_first_entry(&stream->subrequests,
197197
struct netfs_io_subrequest, rreq_link);
198198

199+
switch (wreq->origin) {
200+
case NETFS_READAHEAD:
201+
case NETFS_READPAGE:
202+
case NETFS_READ_GAPS:
203+
case NETFS_READ_SINGLE:
204+
case NETFS_READ_FOR_WRITE:
205+
case NETFS_DIO_READ:
206+
return;
207+
default:
208+
break;
209+
}
210+
199211
switch (subreq->error) {
200212
case -EACCES:
201213
case -EPERM:

0 commit comments

Comments
 (0)