Skip to content

Commit d5cb81b

Browse files
committed
Merge patch series "netfs, cifs: Fixes to retry-related code"
David Howells <[email protected]> says: Here are some miscellaneous fixes and changes for netfslib and cifs, if you could consider pulling them. Many of these were found because a bug in Samba was causing smbd to crash and restart after about 1-2s and this was vigorously and abruptly exercising the netfslib retry paths. Subsequent testing of the cifs RDMA support showed up some more bugs, but the fixes for those went via the cifs tree and have been removed from this set as they're now upstream. First, there are some netfs fixes: (1) Fix a hang due to missing case in final DIO read result collection not breaking out of a loop if the request finished, but there were no subrequests being processed and NETFS_RREQ_ALL_QUEUED wasn't yet set. (2) Fix a double put of the netfs_io_request struct if completion happened in the pause loop. (3) Provide some helpers to abstract out NETFS_RREQ_IN_PROGRESS flag wrangling. (4) Fix infinite looping in netfs_wait_for_pause/request() which wa caused by a loop waiting for NETFS_RREQ_ALL_QUEUED to get set - but which wouldn't get set until the looping function returned. This uses patch (3) above. (5) Fix a ref leak on an extra subrequest inserted into a request's list of subreqs because more subreq records were needed for retrying than were needed for the original request (say, for instance, that the amount of cifs credit available was reduced and, subsequently, the ops had to be smaller). Then a bunch of cifs fixes, some of which are from other people: (6-8) cifs: Fix various RPC callbacks to set NETFS_SREQ_NEED_RETRY if a subrequest fails retriably. (10) Fix a warning in the workqueue code when reconnecting a channel. Followed by some patches to deal with i_size handling: (11) Fix the updating of i_size to use a lock to avoid a race between testing if we should have extended the file with a DIO write and changing i_size. (12) A follow-up patch to (11) to merge the places in netfslib that update i_size on write. And finally a couple of patches to improve tracing output, but that should otherwise not affect functionality: (13) Renumber the NETFS_RREQ_* flags to make the hex values easier to interpret by eye, including moving the main status flags down to the lowest bits, with IN_PROGRESS in bit 0. (14) Update the tracepoints in a number of ways, including adding more tracepoints into the cifs read/write RPC callback so that differend MID_RESPONSE_* values can be differentiated. * patches from https://lore.kernel.org/[email protected]: netfs: Update tracepoints in a number of ways netfs: Renumber the NETFS_RREQ_* flags to make traces easier to read netfs: Merge i_size update functions netfs: Fix i_size updating smb: client: set missing retry flag in cifs_writev_callback() smb: client: set missing retry flag in cifs_readv_callback() smb: client: set missing retry flag in smb2_writev_callback() netfs: Fix ref leak on inserted extra subreq in write retry netfs: Fix looping in wait functions netfs: Provide helpers to perform NETFS_RREQ_IN_PROGRESS flag wangling netfs: Fix double put of request netfs: Fix hang due to missing case in final DIO read result collection Link: https://lore.kernel.org/[email protected] Signed-off-by: Christian Brauner <[email protected]>
2 parents 8c44dac + 90b3ccf commit d5cb81b

File tree

12 files changed

+178
-90
lines changed

12 files changed

+178
-90
lines changed

fs/netfs/buffered_write.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,30 +53,40 @@ static struct folio *netfs_grab_folio_for_write(struct address_space *mapping,
5353
* data written into the pagecache until we can find out from the server what
5454
* the values actually are.
5555
*/
56-
static void netfs_update_i_size(struct netfs_inode *ctx, struct inode *inode,
57-
loff_t i_size, loff_t pos, size_t copied)
56+
void netfs_update_i_size(struct netfs_inode *ctx, struct inode *inode,
57+
loff_t pos, size_t copied)
5858
{
59+
loff_t i_size, end = pos + copied;
5960
blkcnt_t add;
6061
size_t gap;
6162

63+
if (end <= i_size_read(inode))
64+
return;
65+
6266
if (ctx->ops->update_i_size) {
63-
ctx->ops->update_i_size(inode, pos);
67+
ctx->ops->update_i_size(inode, end);
6468
return;
6569
}
6670

67-
i_size_write(inode, pos);
71+
spin_lock(&inode->i_lock);
72+
73+
i_size = i_size_read(inode);
74+
if (end > i_size) {
75+
i_size_write(inode, end);
6876
#if IS_ENABLED(CONFIG_FSCACHE)
69-
fscache_update_cookie(ctx->cache, NULL, &pos);
77+
fscache_update_cookie(ctx->cache, NULL, &end);
7078
#endif
7179

72-
gap = SECTOR_SIZE - (i_size & (SECTOR_SIZE - 1));
73-
if (copied > gap) {
74-
add = DIV_ROUND_UP(copied - gap, SECTOR_SIZE);
80+
gap = SECTOR_SIZE - (i_size & (SECTOR_SIZE - 1));
81+
if (copied > gap) {
82+
add = DIV_ROUND_UP(copied - gap, SECTOR_SIZE);
7583

76-
inode->i_blocks = min_t(blkcnt_t,
77-
DIV_ROUND_UP(pos, SECTOR_SIZE),
78-
inode->i_blocks + add);
84+
inode->i_blocks = min_t(blkcnt_t,
85+
DIV_ROUND_UP(end, SECTOR_SIZE),
86+
inode->i_blocks + add);
87+
}
7988
}
89+
spin_unlock(&inode->i_lock);
8090
}
8191

8292
/**
@@ -111,7 +121,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
111121
struct folio *folio = NULL, *writethrough = NULL;
112122
unsigned int bdp_flags = (iocb->ki_flags & IOCB_NOWAIT) ? BDP_ASYNC : 0;
113123
ssize_t written = 0, ret, ret2;
114-
loff_t i_size, pos = iocb->ki_pos;
124+
loff_t pos = iocb->ki_pos;
115125
size_t max_chunk = mapping_max_folio_size(mapping);
116126
bool maybe_trouble = false;
117127

@@ -344,10 +354,8 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
344354
flush_dcache_folio(folio);
345355

346356
/* Update the inode size if we moved the EOF marker */
357+
netfs_update_i_size(ctx, inode, pos, copied);
347358
pos += copied;
348-
i_size = i_size_read(inode);
349-
if (pos > i_size)
350-
netfs_update_i_size(ctx, inode, i_size, pos, copied);
351359
written += copied;
352360

353361
if (likely(!wreq)) {

fs/netfs/direct_write.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,6 @@
99
#include <linux/uio.h>
1010
#include "internal.h"
1111

12-
static void netfs_cleanup_dio_write(struct netfs_io_request *wreq)
13-
{
14-
struct inode *inode = wreq->inode;
15-
unsigned long long end = wreq->start + wreq->transferred;
16-
17-
if (!wreq->error &&
18-
i_size_read(inode) < end) {
19-
if (wreq->netfs_ops->update_i_size)
20-
wreq->netfs_ops->update_i_size(inode, end);
21-
else
22-
i_size_write(inode, end);
23-
}
24-
}
25-
2612
/*
2713
* Perform an unbuffered write where we may have to do an RMW operation on an
2814
* encrypted file. This can also be used for direct I/O writes.
@@ -98,15 +84,13 @@ ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *
9884
if (async)
9985
wreq->iocb = iocb;
10086
wreq->len = iov_iter_count(&wreq->buffer.iter);
101-
wreq->cleanup = netfs_cleanup_dio_write;
10287
ret = netfs_unbuffered_write(wreq, is_sync_kiocb(iocb), wreq->len);
10388
if (ret < 0) {
10489
_debug("begin = %zd", ret);
10590
goto out;
10691
}
10792

10893
if (!async) {
109-
trace_netfs_rreq(wreq, netfs_rreq_trace_wait_ip);
11094
ret = netfs_wait_for_write(wreq);
11195
if (ret > 0)
11296
iocb->ki_pos += ret;

fs/netfs/internal.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error);
2727
int netfs_prefetch_for_write(struct file *file, struct folio *folio,
2828
size_t offset, size_t len);
2929

30+
/*
31+
* buffered_write.c
32+
*/
33+
void netfs_update_i_size(struct netfs_inode *ctx, struct inode *inode,
34+
loff_t pos, size_t copied);
35+
3036
/*
3137
* main.c
3238
*/
@@ -267,13 +273,31 @@ static inline void netfs_wake_rreq_flag(struct netfs_io_request *rreq,
267273
enum netfs_rreq_trace trace)
268274
{
269275
if (test_bit(rreq_flag, &rreq->flags)) {
270-
trace_netfs_rreq(rreq, trace);
271276
clear_bit_unlock(rreq_flag, &rreq->flags);
272277
smp_mb__after_atomic(); /* Set flag before task state */
278+
trace_netfs_rreq(rreq, trace);
273279
wake_up(&rreq->waitq);
274280
}
275281
}
276282

283+
/*
284+
* Test the NETFS_RREQ_IN_PROGRESS flag, inserting an appropriate barrier.
285+
*/
286+
static inline bool netfs_check_rreq_in_progress(const struct netfs_io_request *rreq)
287+
{
288+
/* Order read of flags before read of anything else, such as error. */
289+
return test_bit_acquire(NETFS_RREQ_IN_PROGRESS, &rreq->flags);
290+
}
291+
292+
/*
293+
* Test the NETFS_SREQ_IN_PROGRESS flag, inserting an appropriate barrier.
294+
*/
295+
static inline bool netfs_check_subreq_in_progress(const struct netfs_io_subrequest *subreq)
296+
{
297+
/* Order read of flags before read of anything else, such as error. */
298+
return test_bit_acquire(NETFS_SREQ_IN_PROGRESS, &subreq->flags);
299+
}
300+
277301
/*
278302
* fscache-cache.c
279303
*/

fs/netfs/main.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ static int netfs_requests_seq_show(struct seq_file *m, void *v)
5858

5959
if (v == &netfs_io_requests) {
6060
seq_puts(m,
61-
"REQUEST OR REF FL ERR OPS COVERAGE\n"
62-
"======== == === == ==== === =========\n"
61+
"REQUEST OR REF FLAG ERR OPS COVERAGE\n"
62+
"======== == === ==== ==== === =========\n"
6363
);
6464
return 0;
6565
}
6666

6767
rreq = list_entry(v, struct netfs_io_request, proc_link);
6868
seq_printf(m,
69-
"%08x %s %3d %2lx %4ld %3d @%04llx %llx/%llx",
69+
"%08x %s %3d %4lx %4ld %3d @%04llx %llx/%llx",
7070
rreq->debug_id,
7171
netfs_origins[rreq->origin],
7272
refcount_read(&rreq->ref),

fs/netfs/misc.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -356,22 +356,22 @@ void netfs_wait_for_in_progress_stream(struct netfs_io_request *rreq,
356356
DEFINE_WAIT(myself);
357357

358358
list_for_each_entry(subreq, &stream->subrequests, rreq_link) {
359-
if (!test_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags))
359+
if (!netfs_check_subreq_in_progress(subreq))
360360
continue;
361361

362-
trace_netfs_rreq(rreq, netfs_rreq_trace_wait_queue);
362+
trace_netfs_rreq(rreq, netfs_rreq_trace_wait_quiesce);
363363
for (;;) {
364364
prepare_to_wait(&rreq->waitq, &myself, TASK_UNINTERRUPTIBLE);
365365

366-
if (!test_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags))
366+
if (!netfs_check_subreq_in_progress(subreq))
367367
break;
368368

369369
trace_netfs_sreq(subreq, netfs_sreq_trace_wait_for);
370370
schedule();
371-
trace_netfs_rreq(rreq, netfs_rreq_trace_woke_queue);
372371
}
373372
}
374373

374+
trace_netfs_rreq(rreq, netfs_rreq_trace_waited_quiesce);
375375
finish_wait(&rreq->waitq, &myself);
376376
}
377377

@@ -381,7 +381,12 @@ void netfs_wait_for_in_progress_stream(struct netfs_io_request *rreq,
381381
static int netfs_collect_in_app(struct netfs_io_request *rreq,
382382
bool (*collector)(struct netfs_io_request *rreq))
383383
{
384-
bool need_collect = false, inactive = true;
384+
bool need_collect = false, inactive = true, done = true;
385+
386+
if (!netfs_check_rreq_in_progress(rreq)) {
387+
trace_netfs_rreq(rreq, netfs_rreq_trace_recollect);
388+
return 1; /* Done */
389+
}
385390

386391
for (int i = 0; i < NR_IO_STREAMS; i++) {
387392
struct netfs_io_subrequest *subreq;
@@ -395,14 +400,16 @@ static int netfs_collect_in_app(struct netfs_io_request *rreq,
395400
struct netfs_io_subrequest,
396401
rreq_link);
397402
if (subreq &&
398-
(!test_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags) ||
403+
(!netfs_check_subreq_in_progress(subreq) ||
399404
test_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags))) {
400405
need_collect = true;
401406
break;
402407
}
408+
if (subreq || !test_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags))
409+
done = false;
403410
}
404411

405-
if (!need_collect && !inactive)
412+
if (!need_collect && !inactive && !done)
406413
return 0; /* Sleep */
407414

408415
__set_current_state(TASK_RUNNING);
@@ -423,14 +430,13 @@ static int netfs_collect_in_app(struct netfs_io_request *rreq,
423430
/*
424431
* Wait for a request to complete, successfully or otherwise.
425432
*/
426-
static ssize_t netfs_wait_for_request(struct netfs_io_request *rreq,
427-
bool (*collector)(struct netfs_io_request *rreq))
433+
static ssize_t netfs_wait_for_in_progress(struct netfs_io_request *rreq,
434+
bool (*collector)(struct netfs_io_request *rreq))
428435
{
429436
DEFINE_WAIT(myself);
430437
ssize_t ret;
431438

432439
for (;;) {
433-
trace_netfs_rreq(rreq, netfs_rreq_trace_wait_queue);
434440
prepare_to_wait(&rreq->waitq, &myself, TASK_UNINTERRUPTIBLE);
435441

436442
if (!test_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &rreq->flags)) {
@@ -440,18 +446,22 @@ static ssize_t netfs_wait_for_request(struct netfs_io_request *rreq,
440446
case 1:
441447
goto all_collected;
442448
case 2:
449+
if (!netfs_check_rreq_in_progress(rreq))
450+
break;
451+
cond_resched();
443452
continue;
444453
}
445454
}
446455

447-
if (!test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags))
456+
if (!netfs_check_rreq_in_progress(rreq))
448457
break;
449458

459+
trace_netfs_rreq(rreq, netfs_rreq_trace_wait_ip);
450460
schedule();
451-
trace_netfs_rreq(rreq, netfs_rreq_trace_woke_queue);
452461
}
453462

454463
all_collected:
464+
trace_netfs_rreq(rreq, netfs_rreq_trace_waited_ip);
455465
finish_wait(&rreq->waitq, &myself);
456466

457467
ret = rreq->error;
@@ -478,12 +488,12 @@ static ssize_t netfs_wait_for_request(struct netfs_io_request *rreq,
478488

479489
ssize_t netfs_wait_for_read(struct netfs_io_request *rreq)
480490
{
481-
return netfs_wait_for_request(rreq, netfs_read_collection);
491+
return netfs_wait_for_in_progress(rreq, netfs_read_collection);
482492
}
483493

484494
ssize_t netfs_wait_for_write(struct netfs_io_request *rreq)
485495
{
486-
return netfs_wait_for_request(rreq, netfs_write_collection);
496+
return netfs_wait_for_in_progress(rreq, netfs_write_collection);
487497
}
488498

489499
/*
@@ -494,10 +504,8 @@ static void netfs_wait_for_pause(struct netfs_io_request *rreq,
494504
{
495505
DEFINE_WAIT(myself);
496506

497-
trace_netfs_rreq(rreq, netfs_rreq_trace_wait_pause);
498-
499507
for (;;) {
500-
trace_netfs_rreq(rreq, netfs_rreq_trace_wait_queue);
508+
trace_netfs_rreq(rreq, netfs_rreq_trace_wait_pause);
501509
prepare_to_wait(&rreq->waitq, &myself, TASK_UNINTERRUPTIBLE);
502510

503511
if (!test_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &rreq->flags)) {
@@ -507,19 +515,23 @@ static void netfs_wait_for_pause(struct netfs_io_request *rreq,
507515
case 1:
508516
goto all_collected;
509517
case 2:
518+
if (!netfs_check_rreq_in_progress(rreq) ||
519+
!test_bit(NETFS_RREQ_PAUSE, &rreq->flags))
520+
break;
521+
cond_resched();
510522
continue;
511523
}
512524
}
513525

514-
if (!test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags) ||
526+
if (!netfs_check_rreq_in_progress(rreq) ||
515527
!test_bit(NETFS_RREQ_PAUSE, &rreq->flags))
516528
break;
517529

518530
schedule();
519-
trace_netfs_rreq(rreq, netfs_rreq_trace_woke_queue);
520531
}
521532

522533
all_collected:
534+
trace_netfs_rreq(rreq, netfs_rreq_trace_waited_pause);
523535
finish_wait(&rreq->waitq, &myself);
524536
}
525537

fs/netfs/read_collect.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ static void netfs_collect_read_results(struct netfs_io_request *rreq)
218218
stream->collected_to = front->start;
219219
}
220220

221-
if (test_bit(NETFS_SREQ_IN_PROGRESS, &front->flags))
221+
if (netfs_check_subreq_in_progress(front))
222222
notes |= HIT_PENDING;
223223
smp_rmb(); /* Read counters after IN_PROGRESS flag. */
224224
transferred = READ_ONCE(front->transferred);
@@ -293,7 +293,9 @@ static void netfs_collect_read_results(struct netfs_io_request *rreq)
293293
spin_lock(&rreq->lock);
294294

295295
remove = front;
296-
trace_netfs_sreq(front, netfs_sreq_trace_discard);
296+
trace_netfs_sreq(front,
297+
notes & ABANDON_SREQ ?
298+
netfs_sreq_trace_abandoned : netfs_sreq_trace_consumed);
297299
list_del_init(&front->rreq_link);
298300
front = list_first_entry_or_null(&stream->subrequests,
299301
struct netfs_io_subrequest, rreq_link);
@@ -353,9 +355,11 @@ static void netfs_rreq_assess_dio(struct netfs_io_request *rreq)
353355

354356
if (rreq->iocb) {
355357
rreq->iocb->ki_pos += rreq->transferred;
356-
if (rreq->iocb->ki_complete)
358+
if (rreq->iocb->ki_complete) {
359+
trace_netfs_rreq(rreq, netfs_rreq_trace_ki_complete);
357360
rreq->iocb->ki_complete(
358361
rreq->iocb, rreq->error ? rreq->error : rreq->transferred);
362+
}
359363
}
360364
if (rreq->netfs_ops->done)
361365
rreq->netfs_ops->done(rreq);
@@ -379,9 +383,11 @@ static void netfs_rreq_assess_single(struct netfs_io_request *rreq)
379383

380384
if (rreq->iocb) {
381385
rreq->iocb->ki_pos += rreq->transferred;
382-
if (rreq->iocb->ki_complete)
386+
if (rreq->iocb->ki_complete) {
387+
trace_netfs_rreq(rreq, netfs_rreq_trace_ki_complete);
383388
rreq->iocb->ki_complete(
384389
rreq->iocb, rreq->error ? rreq->error : rreq->transferred);
390+
}
385391
}
386392
if (rreq->netfs_ops->done)
387393
rreq->netfs_ops->done(rreq);
@@ -445,7 +451,7 @@ void netfs_read_collection_worker(struct work_struct *work)
445451
struct netfs_io_request *rreq = container_of(work, struct netfs_io_request, work);
446452

447453
netfs_see_request(rreq, netfs_rreq_trace_see_work);
448-
if (test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags)) {
454+
if (netfs_check_rreq_in_progress(rreq)) {
449455
if (netfs_read_collection(rreq))
450456
/* Drop the ref from the IN_PROGRESS flag. */
451457
netfs_put_request(rreq, netfs_rreq_trace_put_work_ip);

0 commit comments

Comments
 (0)