Skip to content

Commit 2408a80

Browse files
committed
Merge tag 'vfs-6.14-rc4.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner: "It was reported that the acct(2) system call can be used to trigger a NULL deref in cases where it is set to write to a file that triggers an internal lookup. This can e.g., happen when pointing acct(2) to /sys/power/resume. At the point the where the write to this file happens the calling task has already exited and called exit_fs() but an internal lookup might be triggered through lookup_bdev(). This may trigger a NULL-deref when accessing current->fs. Reorganize the code so that the the final write happens from the workqueue but with the caller's credentials. This preserves the (strange) permission model and has almost no regression risk. Also block access to kernel internal filesystems as well as procfs and sysfs in the first place. Various fixes for netfslib: - Fix a number of read-retry hangs, including: - Incorrect getting/putting of references on subreqs as we retry them - Failure to track whether a last old subrequest in a retried set is superfluous - Inconsistency in the usage of wait queues used for subrequests (ie. using clear_and_wake_up_bit() whilst waiting on a private waitqueue) - Add stats counters for retries and publish in /proc/fs/netfs/stats. This is not a fix per se, but is useful in debugging and shouldn't otherwise change the operation of the code - Fix the ordering of queuing subrequests with respect to setting the request flag that says we've now queued them all" * tag 'vfs-6.14-rc4.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: netfs: Fix setting NETFS_RREQ_ALL_QUEUED to be after all subreqs queued netfs: Add retry stat counters netfs: Fix a number of read-retry hangs acct: block access to kernel internal filesystems acct: perform last write from workqueue
2 parents 6186bdd + a33f725 commit 2408a80

File tree

10 files changed

+154
-70
lines changed

10 files changed

+154
-70
lines changed

fs/netfs/buffered_read.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,9 @@ static void netfs_read_cache_to_pagecache(struct netfs_io_request *rreq,
155155
netfs_cache_read_terminated, subreq);
156156
}
157157

158-
static void netfs_issue_read(struct netfs_io_request *rreq,
159-
struct netfs_io_subrequest *subreq)
158+
static void netfs_queue_read(struct netfs_io_request *rreq,
159+
struct netfs_io_subrequest *subreq,
160+
bool last_subreq)
160161
{
161162
struct netfs_io_stream *stream = &rreq->io_streams[0];
162163

@@ -177,8 +178,17 @@ static void netfs_issue_read(struct netfs_io_request *rreq,
177178
}
178179
}
179180

181+
if (last_subreq) {
182+
smp_wmb(); /* Write lists before ALL_QUEUED. */
183+
set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags);
184+
}
185+
180186
spin_unlock(&rreq->lock);
187+
}
181188

189+
static void netfs_issue_read(struct netfs_io_request *rreq,
190+
struct netfs_io_subrequest *subreq)
191+
{
182192
switch (subreq->source) {
183193
case NETFS_DOWNLOAD_FROM_SERVER:
184194
rreq->netfs_ops->issue_read(subreq);
@@ -293,11 +303,8 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq)
293303
}
294304
size -= slice;
295305
start += slice;
296-
if (size <= 0) {
297-
smp_wmb(); /* Write lists before ALL_QUEUED. */
298-
set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags);
299-
}
300306

307+
netfs_queue_read(rreq, subreq, size <= 0);
301308
netfs_issue_read(rreq, subreq);
302309
cond_resched();
303310
} while (size > 0);

fs/netfs/internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ extern atomic_t netfs_n_rh_write_begin;
135135
extern atomic_t netfs_n_rh_write_done;
136136
extern atomic_t netfs_n_rh_write_failed;
137137
extern atomic_t netfs_n_rh_write_zskip;
138+
extern atomic_t netfs_n_rh_retry_read_req;
139+
extern atomic_t netfs_n_rh_retry_read_subreq;
138140
extern atomic_t netfs_n_wh_buffered_write;
139141
extern atomic_t netfs_n_wh_writethrough;
140142
extern atomic_t netfs_n_wh_dio_write;
@@ -147,6 +149,8 @@ extern atomic_t netfs_n_wh_upload_failed;
147149
extern atomic_t netfs_n_wh_write;
148150
extern atomic_t netfs_n_wh_write_done;
149151
extern atomic_t netfs_n_wh_write_failed;
152+
extern atomic_t netfs_n_wh_retry_write_req;
153+
extern atomic_t netfs_n_wh_retry_write_subreq;
150154
extern atomic_t netfs_n_wb_lock_skip;
151155
extern atomic_t netfs_n_wb_lock_wait;
152156
extern atomic_t netfs_n_folioq;

fs/netfs/read_collect.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,8 @@ void netfs_read_collection_worker(struct work_struct *work)
470470
*/
471471
void netfs_wake_read_collector(struct netfs_io_request *rreq)
472472
{
473-
if (test_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &rreq->flags)) {
473+
if (test_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &rreq->flags) &&
474+
!test_bit(NETFS_RREQ_RETRYING, &rreq->flags)) {
474475
if (!work_pending(&rreq->work)) {
475476
netfs_get_request(rreq, netfs_rreq_trace_get_work);
476477
if (!queue_work(system_unbound_wq, &rreq->work))
@@ -586,7 +587,8 @@ void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq)
586587
smp_mb__after_atomic(); /* Clear IN_PROGRESS before task state */
587588

588589
/* If we are at the head of the queue, wake up the collector. */
589-
if (list_is_first(&subreq->rreq_link, &stream->subrequests))
590+
if (list_is_first(&subreq->rreq_link, &stream->subrequests) ||
591+
test_bit(NETFS_RREQ_RETRYING, &rreq->flags))
590592
netfs_wake_read_collector(rreq);
591593

592594
netfs_put_subrequest(subreq, true, netfs_sreq_trace_put_terminated);

fs/netfs/read_retry.c

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ static void netfs_reissue_read(struct netfs_io_request *rreq,
1414
{
1515
__clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
1616
__set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags);
17-
netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit);
17+
netfs_stat(&netfs_n_rh_retry_read_subreq);
1818
subreq->rreq->netfs_ops->issue_read(subreq);
1919
}
2020

@@ -48,6 +48,7 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq)
4848
__clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
4949
subreq->retry_count++;
5050
netfs_reset_iter(subreq);
51+
netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit);
5152
netfs_reissue_read(rreq, subreq);
5253
}
5354
}
@@ -75,7 +76,7 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq)
7576
struct iov_iter source;
7677
unsigned long long start, len;
7778
size_t part;
78-
bool boundary = false;
79+
bool boundary = false, subreq_superfluous = false;
7980

8081
/* Go through the subreqs and find the next span of contiguous
8182
* buffer that we then rejig (cifs, for example, needs the
@@ -116,8 +117,10 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq)
116117
/* Work through the sublist. */
117118
subreq = from;
118119
list_for_each_entry_from(subreq, &stream->subrequests, rreq_link) {
119-
if (!len)
120+
if (!len) {
121+
subreq_superfluous = true;
120122
break;
123+
}
121124
subreq->source = NETFS_DOWNLOAD_FROM_SERVER;
122125
subreq->start = start - subreq->transferred;
123126
subreq->len = len + subreq->transferred;
@@ -154,19 +157,21 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq)
154157

155158
netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit);
156159
netfs_reissue_read(rreq, subreq);
157-
if (subreq == to)
160+
if (subreq == to) {
161+
subreq_superfluous = false;
158162
break;
163+
}
159164
}
160165

161166
/* If we managed to use fewer subreqs, we can discard the
162167
* excess; if we used the same number, then we're done.
163168
*/
164169
if (!len) {
165-
if (subreq == to)
170+
if (!subreq_superfluous)
166171
continue;
167172
list_for_each_entry_safe_from(subreq, tmp,
168173
&stream->subrequests, rreq_link) {
169-
trace_netfs_sreq(subreq, netfs_sreq_trace_discard);
174+
trace_netfs_sreq(subreq, netfs_sreq_trace_superfluous);
170175
list_del(&subreq->rreq_link);
171176
netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_done);
172177
if (subreq == to)
@@ -187,14 +192,12 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq)
187192
subreq->source = NETFS_DOWNLOAD_FROM_SERVER;
188193
subreq->start = start;
189194
subreq->len = len;
190-
subreq->debug_index = atomic_inc_return(&rreq->subreq_counter);
191195
subreq->stream_nr = stream->stream_nr;
192196
subreq->retry_count = 1;
193197

194198
trace_netfs_sreq_ref(rreq->debug_id, subreq->debug_index,
195199
refcount_read(&subreq->ref),
196200
netfs_sreq_trace_new);
197-
netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit);
198201

199202
list_add(&subreq->rreq_link, &to->rreq_link);
200203
to = list_next_entry(to, rreq_link);
@@ -256,14 +259,34 @@ void netfs_retry_reads(struct netfs_io_request *rreq)
256259
{
257260
struct netfs_io_subrequest *subreq;
258261
struct netfs_io_stream *stream = &rreq->io_streams[0];
262+
DEFINE_WAIT(myself);
263+
264+
netfs_stat(&netfs_n_rh_retry_read_req);
265+
266+
set_bit(NETFS_RREQ_RETRYING, &rreq->flags);
259267

260268
/* Wait for all outstanding I/O to quiesce before performing retries as
261269
* we may need to renegotiate the I/O sizes.
262270
*/
263271
list_for_each_entry(subreq, &stream->subrequests, rreq_link) {
264-
wait_on_bit(&subreq->flags, NETFS_SREQ_IN_PROGRESS,
265-
TASK_UNINTERRUPTIBLE);
272+
if (!test_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags))
273+
continue;
274+
275+
trace_netfs_rreq(rreq, netfs_rreq_trace_wait_queue);
276+
for (;;) {
277+
prepare_to_wait(&rreq->waitq, &myself, TASK_UNINTERRUPTIBLE);
278+
279+
if (!test_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags))
280+
break;
281+
282+
trace_netfs_sreq(subreq, netfs_sreq_trace_wait_for);
283+
schedule();
284+
trace_netfs_rreq(rreq, netfs_rreq_trace_woke_queue);
285+
}
286+
287+
finish_wait(&rreq->waitq, &myself);
266288
}
289+
clear_bit(NETFS_RREQ_RETRYING, &rreq->flags);
267290

268291
trace_netfs_rreq(rreq, netfs_rreq_trace_resubmit);
269292
netfs_retry_read_subrequests(rreq);

fs/netfs/stats.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ atomic_t netfs_n_rh_write_begin;
2929
atomic_t netfs_n_rh_write_done;
3030
atomic_t netfs_n_rh_write_failed;
3131
atomic_t netfs_n_rh_write_zskip;
32+
atomic_t netfs_n_rh_retry_read_req;
33+
atomic_t netfs_n_rh_retry_read_subreq;
3234
atomic_t netfs_n_wh_buffered_write;
3335
atomic_t netfs_n_wh_writethrough;
3436
atomic_t netfs_n_wh_dio_write;
@@ -41,6 +43,8 @@ atomic_t netfs_n_wh_upload_failed;
4143
atomic_t netfs_n_wh_write;
4244
atomic_t netfs_n_wh_write_done;
4345
atomic_t netfs_n_wh_write_failed;
46+
atomic_t netfs_n_wh_retry_write_req;
47+
atomic_t netfs_n_wh_retry_write_subreq;
4448
atomic_t netfs_n_wb_lock_skip;
4549
atomic_t netfs_n_wb_lock_wait;
4650
atomic_t netfs_n_folioq;
@@ -81,6 +85,11 @@ int netfs_stats_show(struct seq_file *m, void *v)
8185
atomic_read(&netfs_n_wh_write),
8286
atomic_read(&netfs_n_wh_write_done),
8387
atomic_read(&netfs_n_wh_write_failed));
88+
seq_printf(m, "Retries: rq=%u rs=%u wq=%u ws=%u\n",
89+
atomic_read(&netfs_n_rh_retry_read_req),
90+
atomic_read(&netfs_n_rh_retry_read_subreq),
91+
atomic_read(&netfs_n_wh_retry_write_req),
92+
atomic_read(&netfs_n_wh_retry_write_subreq));
8493
seq_printf(m, "Objs : rr=%u sr=%u foq=%u wsc=%u\n",
8594
atomic_read(&netfs_n_rh_rreq),
8695
atomic_read(&netfs_n_rh_sreq),

fs/netfs/write_issue.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ void netfs_reissue_write(struct netfs_io_stream *stream,
253253
subreq->retry_count++;
254254
__clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
255255
__set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags);
256+
netfs_stat(&netfs_n_wh_retry_write_subreq);
256257
netfs_do_issue_write(stream, subreq);
257258
}
258259

fs/netfs/write_retry.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ void netfs_retry_writes(struct netfs_io_request *wreq)
203203
struct netfs_io_stream *stream;
204204
int s;
205205

206+
netfs_stat(&netfs_n_wh_retry_write_req);
207+
206208
/* Wait for all outstanding I/O to quiesce before performing retries as
207209
* we may need to renegotiate the I/O sizes.
208210
*/

include/linux/netfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ struct netfs_io_request {
278278
#define NETFS_RREQ_PAUSE 11 /* Pause subrequest generation */
279279
#define NETFS_RREQ_USE_IO_ITER 12 /* Use ->io_iter rather than ->i_pages */
280280
#define NETFS_RREQ_ALL_QUEUED 13 /* All subreqs are now queued */
281-
#define NETFS_RREQ_NEED_RETRY 14 /* Need to try retrying */
281+
#define NETFS_RREQ_RETRYING 14 /* Set if we're in the retry path */
282282
#define NETFS_RREQ_USE_PGPRIV2 31 /* [DEPRECATED] Use PG_private_2 to mark
283283
* write to cache on read */
284284
const struct netfs_request_ops *netfs_ops;

include/trace/events/netfs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
EM(netfs_sreq_trace_limited, "LIMIT") \
100100
EM(netfs_sreq_trace_need_clear, "N-CLR") \
101101
EM(netfs_sreq_trace_partial_read, "PARTR") \
102-
EM(netfs_sreq_trace_need_retry, "NRTRY") \
102+
EM(netfs_sreq_trace_need_retry, "ND-RT") \
103103
EM(netfs_sreq_trace_prepare, "PREP ") \
104104
EM(netfs_sreq_trace_prep_failed, "PRPFL") \
105105
EM(netfs_sreq_trace_progress, "PRGRS") \
@@ -108,7 +108,9 @@
108108
EM(netfs_sreq_trace_short, "SHORT") \
109109
EM(netfs_sreq_trace_split, "SPLIT") \
110110
EM(netfs_sreq_trace_submit, "SUBMT") \
111+
EM(netfs_sreq_trace_superfluous, "SPRFL") \
111112
EM(netfs_sreq_trace_terminated, "TERM ") \
113+
EM(netfs_sreq_trace_wait_for, "_WAIT") \
112114
EM(netfs_sreq_trace_write, "WRITE") \
113115
EM(netfs_sreq_trace_write_skip, "SKIP ") \
114116
E_(netfs_sreq_trace_write_term, "WTERM")

0 commit comments

Comments
 (0)