Skip to content

Commit d874367

Browse files
committed
Merge tag 'vfs-6.17-rc8.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner: - Prevent double unlock in netfs - Fix a NULL pointer dereference in afs_put_server() - Fix a reference leak in netfs * tag 'vfs-6.17-rc8.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: netfs: fix reference leak afs: Fix potential null pointer dereference in afs_put_server netfs: Prevent duplicate unlocking
2 parents 0d97ef7 + 4d428dc commit d874367

File tree

10 files changed

+50
-16
lines changed

10 files changed

+50
-16
lines changed

fs/afs/server.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,13 +331,14 @@ struct afs_server *afs_use_server(struct afs_server *server, bool activate,
331331
void afs_put_server(struct afs_net *net, struct afs_server *server,
332332
enum afs_server_trace reason)
333333
{
334-
unsigned int a, debug_id = server->debug_id;
334+
unsigned int a, debug_id;
335335
bool zero;
336336
int r;
337337

338338
if (!server)
339339
return;
340340

341+
debug_id = server->debug_id;
341342
a = atomic_read(&server->active);
342343
zero = __refcount_dec_and_test(&server->ref, &r);
343344
trace_afs_server(debug_id, r - 1, a, reason);

fs/netfs/buffered_read.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ void netfs_readahead(struct readahead_control *ractl)
369369
return netfs_put_request(rreq, netfs_rreq_trace_put_return);
370370

371371
cleanup_free:
372-
return netfs_put_request(rreq, netfs_rreq_trace_put_failed);
372+
return netfs_put_failed_request(rreq);
373373
}
374374
EXPORT_SYMBOL(netfs_readahead);
375375

@@ -472,7 +472,7 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
472472
return ret < 0 ? ret : 0;
473473

474474
discard:
475-
netfs_put_request(rreq, netfs_rreq_trace_put_discard);
475+
netfs_put_failed_request(rreq);
476476
alloc_error:
477477
folio_unlock(folio);
478478
return ret;
@@ -532,7 +532,7 @@ int netfs_read_folio(struct file *file, struct folio *folio)
532532
return ret < 0 ? ret : 0;
533533

534534
discard:
535-
netfs_put_request(rreq, netfs_rreq_trace_put_discard);
535+
netfs_put_failed_request(rreq);
536536
alloc_error:
537537
folio_unlock(folio);
538538
return ret;
@@ -699,7 +699,7 @@ int netfs_write_begin(struct netfs_inode *ctx,
699699
return 0;
700700

701701
error_put:
702-
netfs_put_request(rreq, netfs_rreq_trace_put_failed);
702+
netfs_put_failed_request(rreq);
703703
error:
704704
if (folio) {
705705
folio_unlock(folio);
@@ -754,7 +754,7 @@ int netfs_prefetch_for_write(struct file *file, struct folio *folio,
754754
return ret < 0 ? ret : 0;
755755

756756
error_put:
757-
netfs_put_request(rreq, netfs_rreq_trace_put_discard);
757+
netfs_put_failed_request(rreq);
758758
error:
759759
_leave(" = %d", ret);
760760
return ret;

fs/netfs/buffered_write.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
347347
folio_put(folio);
348348
ret = filemap_write_and_wait_range(mapping, fpos, fpos + flen - 1);
349349
if (ret < 0)
350-
goto error_folio_unlock;
350+
goto out;
351351
continue;
352352

353353
copied:

fs/netfs/direct_read.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ static ssize_t netfs_unbuffered_read(struct netfs_io_request *rreq, bool sync)
131131

132132
if (rreq->len == 0) {
133133
pr_err("Zero-sized read [R=%x]\n", rreq->debug_id);
134+
netfs_put_request(rreq, netfs_rreq_trace_put_discard);
134135
return -EIO;
135136
}
136137

@@ -205,7 +206,7 @@ ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *i
205206
if (user_backed_iter(iter)) {
206207
ret = netfs_extract_user_iter(iter, rreq->len, &rreq->buffer.iter, 0);
207208
if (ret < 0)
208-
goto out;
209+
goto error_put;
209210
rreq->direct_bv = (struct bio_vec *)rreq->buffer.iter.bvec;
210211
rreq->direct_bv_count = ret;
211212
rreq->direct_bv_unpin = iov_iter_extract_will_pin(iter);
@@ -238,6 +239,10 @@ ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *i
238239
if (ret > 0)
239240
orig_count -= ret;
240241
return ret;
242+
243+
error_put:
244+
netfs_put_failed_request(rreq);
245+
return ret;
241246
}
242247
EXPORT_SYMBOL(netfs_unbuffered_read_iter_locked);
243248

fs/netfs/direct_write.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *
5757
n = netfs_extract_user_iter(iter, len, &wreq->buffer.iter, 0);
5858
if (n < 0) {
5959
ret = n;
60-
goto out;
60+
goto error_put;
6161
}
6262
wreq->direct_bv = (struct bio_vec *)wreq->buffer.iter.bvec;
6363
wreq->direct_bv_count = n;
@@ -101,6 +101,10 @@ ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *
101101
out:
102102
netfs_put_request(wreq, netfs_rreq_trace_put_return);
103103
return ret;
104+
105+
error_put:
106+
netfs_put_failed_request(wreq);
107+
return ret;
104108
}
105109
EXPORT_SYMBOL(netfs_unbuffered_write_iter_locked);
106110

fs/netfs/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
8787
void netfs_get_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace what);
8888
void netfs_clear_subrequests(struct netfs_io_request *rreq);
8989
void netfs_put_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace what);
90+
void netfs_put_failed_request(struct netfs_io_request *rreq);
9091
struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq);
9192

9293
static inline void netfs_see_request(struct netfs_io_request *rreq,

fs/netfs/objects.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,8 @@ static void netfs_free_request_rcu(struct rcu_head *rcu)
116116
netfs_stat_d(&netfs_n_rh_rreq);
117117
}
118118

119-
static void netfs_free_request(struct work_struct *work)
119+
static void netfs_deinit_request(struct netfs_io_request *rreq)
120120
{
121-
struct netfs_io_request *rreq =
122-
container_of(work, struct netfs_io_request, cleanup_work);
123121
struct netfs_inode *ictx = netfs_inode(rreq->inode);
124122
unsigned int i;
125123

@@ -149,6 +147,14 @@ static void netfs_free_request(struct work_struct *work)
149147

150148
if (atomic_dec_and_test(&ictx->io_count))
151149
wake_up_var(&ictx->io_count);
150+
}
151+
152+
static void netfs_free_request(struct work_struct *work)
153+
{
154+
struct netfs_io_request *rreq =
155+
container_of(work, struct netfs_io_request, cleanup_work);
156+
157+
netfs_deinit_request(rreq);
152158
call_rcu(&rreq->rcu, netfs_free_request_rcu);
153159
}
154160

@@ -167,6 +173,24 @@ void netfs_put_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace
167173
}
168174
}
169175

176+
/*
177+
* Free a request (synchronously) that was just allocated but has
178+
* failed before it could be submitted.
179+
*/
180+
void netfs_put_failed_request(struct netfs_io_request *rreq)
181+
{
182+
int r = refcount_read(&rreq->ref);
183+
184+
/* new requests have two references (see
185+
* netfs_alloc_request(), and this function is only allowed on
186+
* new request objects
187+
*/
188+
WARN_ON_ONCE(r != 2);
189+
190+
trace_netfs_rreq_ref(rreq->debug_id, r, netfs_rreq_trace_put_failed);
191+
netfs_free_request(&rreq->cleanup_work);
192+
}
193+
170194
/*
171195
* Allocate and partially initialise an I/O request structure.
172196
*/

fs/netfs/read_pgpriv2.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ static struct netfs_io_request *netfs_pgpriv2_begin_copy_to_cache(
118118
return creq;
119119

120120
cancel_put:
121-
netfs_put_request(creq, netfs_rreq_trace_put_return);
121+
netfs_put_failed_request(creq);
122122
cancel:
123123
rreq->copy_to_cache = ERR_PTR(-ENOBUFS);
124124
clear_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &rreq->flags);

fs/netfs/read_single.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ ssize_t netfs_read_single(struct inode *inode, struct file *file, struct iov_ite
189189
return ret;
190190

191191
cleanup_free:
192-
netfs_put_request(rreq, netfs_rreq_trace_put_failed);
192+
netfs_put_failed_request(rreq);
193193
return ret;
194194
}
195195
EXPORT_SYMBOL(netfs_read_single);

fs/netfs/write_issue.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping,
133133

134134
return wreq;
135135
nomem:
136-
wreq->error = -ENOMEM;
137-
netfs_put_request(wreq, netfs_rreq_trace_put_failed);
136+
netfs_put_failed_request(wreq);
138137
return ERR_PTR(-ENOMEM);
139138
}
140139

0 commit comments

Comments
 (0)