Skip to content

Commit 7166c32

Browse files
committed
Merge tag 'vfs-6.12-rc5.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner: "afs: - Fix a lock recursion in afs_wake_up_async_call() on ->notify_lock netfs: - Drop the references to a folio immediately after the folio has been extracted to prevent races with future I/O collection - Fix a documenation build error - Downgrade the i_rwsem for buffered writes to fix a cifs reported performance regression when switching to netfslib vfs: - Explicitly return -E2BIG from openat2() if the specified size is unexpectedly large. This aligns openat2() with other extensible struct based system calls - When copying a mount namespace ensure that we only try to remove the new copy from the mount namespace rbtree if it has already been added to it nilfs: - Clear the buffer delay flag when clearing the buffer state clags when a buffer head is discarded to prevent a kernel OOPs ocfs2: - Fix an unitialized value warning in ocfs2_setattr() proc: - Fix a kernel doc warning" * tag 'vfs-6.12-rc5.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: proc: Fix W=1 build kernel-doc warning afs: Fix lock recursion fs: Fix uninitialized value issue in from_kuid and from_kgid fs: don't try and remove empty rbtree node netfs: Downgrade i_rwsem for a buffered write nilfs2: fix kernel bug due to missing clearing of buffer delay flag openat2: explicitly return -E2BIG for (usize > PAGE_SIZE) netfs: fix documentation build error netfs: In readahead, put the folio refs as soon extracted
2 parents a777c32 + 197231d commit 7166c32

File tree

12 files changed

+95
-67
lines changed

12 files changed

+95
-67
lines changed

Documentation/filesystems/netfs_library.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,4 +592,3 @@ API Function Reference
592592

593593
.. kernel-doc:: include/linux/netfs.h
594594
.. kernel-doc:: fs/netfs/buffered_read.c
595-
.. kernel-doc:: fs/netfs/io.c

fs/afs/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ struct afs_call {
130130
wait_queue_head_t waitq; /* processes awaiting completion */
131131
struct work_struct async_work; /* async I/O processor */
132132
struct work_struct work; /* actual work processor */
133+
struct work_struct free_work; /* Deferred free processor */
133134
struct rxrpc_call *rxcall; /* RxRPC call handle */
134135
struct rxrpc_peer *peer; /* Remote endpoint */
135136
struct key *key; /* security for this call */
@@ -1331,6 +1332,7 @@ extern int __net_init afs_open_socket(struct afs_net *);
13311332
extern void __net_exit afs_close_socket(struct afs_net *);
13321333
extern void afs_charge_preallocation(struct work_struct *);
13331334
extern void afs_put_call(struct afs_call *);
1335+
void afs_deferred_put_call(struct afs_call *call);
13341336
void afs_make_call(struct afs_call *call, gfp_t gfp);
13351337
void afs_wait_for_call_to_complete(struct afs_call *call);
13361338
extern struct afs_call *afs_alloc_flat_call(struct afs_net *,

fs/afs/rxrpc.c

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
struct workqueue_struct *afs_async_calls;
2020

21+
static void afs_deferred_free_worker(struct work_struct *work);
2122
static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long);
2223
static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long);
2324
static void afs_process_async_call(struct work_struct *);
@@ -149,6 +150,7 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
149150
call->debug_id = atomic_inc_return(&rxrpc_debug_id);
150151
refcount_set(&call->ref, 1);
151152
INIT_WORK(&call->async_work, afs_process_async_call);
153+
INIT_WORK(&call->free_work, afs_deferred_free_worker);
152154
init_waitqueue_head(&call->waitq);
153155
spin_lock_init(&call->state_lock);
154156
call->iter = &call->def_iter;
@@ -159,6 +161,36 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
159161
return call;
160162
}
161163

164+
static void afs_free_call(struct afs_call *call)
165+
{
166+
struct afs_net *net = call->net;
167+
int o;
168+
169+
ASSERT(!work_pending(&call->async_work));
170+
171+
rxrpc_kernel_put_peer(call->peer);
172+
173+
if (call->rxcall) {
174+
rxrpc_kernel_shutdown_call(net->socket, call->rxcall);
175+
rxrpc_kernel_put_call(net->socket, call->rxcall);
176+
call->rxcall = NULL;
177+
}
178+
if (call->type->destructor)
179+
call->type->destructor(call);
180+
181+
afs_unuse_server_notime(call->net, call->server, afs_server_trace_put_call);
182+
kfree(call->request);
183+
184+
o = atomic_read(&net->nr_outstanding_calls);
185+
trace_afs_call(call->debug_id, afs_call_trace_free, 0, o,
186+
__builtin_return_address(0));
187+
kfree(call);
188+
189+
o = atomic_dec_return(&net->nr_outstanding_calls);
190+
if (o == 0)
191+
wake_up_var(&net->nr_outstanding_calls);
192+
}
193+
162194
/*
163195
* Dispose of a reference on a call.
164196
*/
@@ -173,32 +205,34 @@ void afs_put_call(struct afs_call *call)
173205
o = atomic_read(&net->nr_outstanding_calls);
174206
trace_afs_call(debug_id, afs_call_trace_put, r - 1, o,
175207
__builtin_return_address(0));
208+
if (zero)
209+
afs_free_call(call);
210+
}
176211

177-
if (zero) {
178-
ASSERT(!work_pending(&call->async_work));
179-
ASSERT(call->type->name != NULL);
180-
181-
rxrpc_kernel_put_peer(call->peer);
182-
183-
if (call->rxcall) {
184-
rxrpc_kernel_shutdown_call(net->socket, call->rxcall);
185-
rxrpc_kernel_put_call(net->socket, call->rxcall);
186-
call->rxcall = NULL;
187-
}
188-
if (call->type->destructor)
189-
call->type->destructor(call);
212+
static void afs_deferred_free_worker(struct work_struct *work)
213+
{
214+
struct afs_call *call = container_of(work, struct afs_call, free_work);
190215

191-
afs_unuse_server_notime(call->net, call->server, afs_server_trace_put_call);
192-
kfree(call->request);
216+
afs_free_call(call);
217+
}
193218

194-
trace_afs_call(call->debug_id, afs_call_trace_free, 0, o,
195-
__builtin_return_address(0));
196-
kfree(call);
219+
/*
220+
* Dispose of a reference on a call, deferring the cleanup to a workqueue
221+
* to avoid lock recursion.
222+
*/
223+
void afs_deferred_put_call(struct afs_call *call)
224+
{
225+
struct afs_net *net = call->net;
226+
unsigned int debug_id = call->debug_id;
227+
bool zero;
228+
int r, o;
197229

198-
o = atomic_dec_return(&net->nr_outstanding_calls);
199-
if (o == 0)
200-
wake_up_var(&net->nr_outstanding_calls);
201-
}
230+
zero = __refcount_dec_and_test(&call->ref, &r);
231+
o = atomic_read(&net->nr_outstanding_calls);
232+
trace_afs_call(debug_id, afs_call_trace_put, r - 1, o,
233+
__builtin_return_address(0));
234+
if (zero)
235+
schedule_work(&call->free_work);
202236
}
203237

204238
static struct afs_call *afs_get_call(struct afs_call *call,
@@ -640,7 +674,8 @@ static void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall,
640674
}
641675

642676
/*
643-
* wake up an asynchronous call
677+
* Wake up an asynchronous call. The caller is holding the call notify
678+
* spinlock around this, so we can't call afs_put_call().
644679
*/
645680
static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
646681
unsigned long call_user_ID)
@@ -657,7 +692,7 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
657692
__builtin_return_address(0));
658693

659694
if (!queue_work(afs_async_calls, &call->async_work))
660-
afs_put_call(call);
695+
afs_deferred_put_call(call);
661696
}
662697
}
663698

fs/namespace.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3944,7 +3944,9 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
39443944
new = copy_tree(old, old->mnt.mnt_root, copy_flags);
39453945
if (IS_ERR(new)) {
39463946
namespace_unlock();
3947-
free_mnt_ns(new_ns);
3947+
ns_free_inum(&new_ns->ns);
3948+
dec_mnt_namespaces(new_ns->ucounts);
3949+
mnt_ns_release(new_ns);
39483950
return ERR_CAST(new);
39493951
}
39503952
if (user_ns != ns->user_ns) {

fs/netfs/buffered_read.c

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ static int netfs_begin_cache_read(struct netfs_io_request *rreq, struct netfs_in
6767
* Decant the list of folios to read into a rolling buffer.
6868
*/
6969
static size_t netfs_load_buffer_from_ra(struct netfs_io_request *rreq,
70-
struct folio_queue *folioq)
70+
struct folio_queue *folioq,
71+
struct folio_batch *put_batch)
7172
{
7273
unsigned int order, nr;
7374
size_t size = 0;
@@ -82,6 +83,9 @@ static size_t netfs_load_buffer_from_ra(struct netfs_io_request *rreq,
8283
order = folio_order(folio);
8384
folioq->orders[i] = order;
8485
size += PAGE_SIZE << order;
86+
87+
if (!folio_batch_add(put_batch, folio))
88+
folio_batch_release(put_batch);
8589
}
8690

8791
for (int i = nr; i < folioq_nr_slots(folioq); i++)
@@ -120,6 +124,9 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq)
120124
* that we will need to release later - but we don't want to do
121125
* that until after we've started the I/O.
122126
*/
127+
struct folio_batch put_batch;
128+
129+
folio_batch_init(&put_batch);
123130
while (rreq->submitted < subreq->start + rsize) {
124131
struct folio_queue *tail = rreq->buffer_tail, *new;
125132
size_t added;
@@ -132,10 +139,11 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq)
132139
new->prev = tail;
133140
tail->next = new;
134141
rreq->buffer_tail = new;
135-
added = netfs_load_buffer_from_ra(rreq, new);
142+
added = netfs_load_buffer_from_ra(rreq, new, &put_batch);
136143
rreq->iter.count += added;
137144
rreq->submitted += added;
138145
}
146+
folio_batch_release(&put_batch);
139147
}
140148

141149
subreq->len = rsize;
@@ -348,6 +356,7 @@ static int netfs_wait_for_read(struct netfs_io_request *rreq)
348356
static int netfs_prime_buffer(struct netfs_io_request *rreq)
349357
{
350358
struct folio_queue *folioq;
359+
struct folio_batch put_batch;
351360
size_t added;
352361

353362
folioq = kmalloc(sizeof(*folioq), GFP_KERNEL);
@@ -360,39 +369,14 @@ static int netfs_prime_buffer(struct netfs_io_request *rreq)
360369
rreq->submitted = rreq->start;
361370
iov_iter_folio_queue(&rreq->iter, ITER_DEST, folioq, 0, 0, 0);
362371

363-
added = netfs_load_buffer_from_ra(rreq, folioq);
372+
folio_batch_init(&put_batch);
373+
added = netfs_load_buffer_from_ra(rreq, folioq, &put_batch);
374+
folio_batch_release(&put_batch);
364375
rreq->iter.count += added;
365376
rreq->submitted += added;
366377
return 0;
367378
}
368379

369-
/*
370-
* Drop the ref on each folio that we inherited from the VM readahead code. We
371-
* still have the folio locks to pin the page until we complete the I/O.
372-
*
373-
* Note that we can't just release the batch in each queue struct as we use the
374-
* occupancy count in other places.
375-
*/
376-
static void netfs_put_ra_refs(struct folio_queue *folioq)
377-
{
378-
struct folio_batch fbatch;
379-
380-
folio_batch_init(&fbatch);
381-
while (folioq) {
382-
for (unsigned int slot = 0; slot < folioq_count(folioq); slot++) {
383-
struct folio *folio = folioq_folio(folioq, slot);
384-
if (!folio)
385-
continue;
386-
trace_netfs_folio(folio, netfs_folio_trace_read_put);
387-
if (!folio_batch_add(&fbatch, folio))
388-
folio_batch_release(&fbatch);
389-
}
390-
folioq = folioq->next;
391-
}
392-
393-
folio_batch_release(&fbatch);
394-
}
395-
396380
/**
397381
* netfs_readahead - Helper to manage a read request
398382
* @ractl: The description of the readahead request
@@ -436,9 +420,6 @@ void netfs_readahead(struct readahead_control *ractl)
436420
goto cleanup_free;
437421
netfs_read_to_pagecache(rreq);
438422

439-
/* Release the folio refs whilst we're waiting for the I/O. */
440-
netfs_put_ra_refs(rreq->buffer);
441-
442423
netfs_put_request(rreq, true, netfs_rreq_trace_put_return);
443424
return;
444425

fs/netfs/locking.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ int netfs_start_io_write(struct inode *inode)
109109
up_write(&inode->i_rwsem);
110110
return -ERESTARTSYS;
111111
}
112+
downgrade_write(&inode->i_rwsem);
112113
return 0;
113114
}
114115
EXPORT_SYMBOL(netfs_start_io_write);
@@ -123,7 +124,7 @@ EXPORT_SYMBOL(netfs_start_io_write);
123124
void netfs_end_io_write(struct inode *inode)
124125
__releases(inode->i_rwsem)
125126
{
126-
up_write(&inode->i_rwsem);
127+
up_read(&inode->i_rwsem);
127128
}
128129
EXPORT_SYMBOL(netfs_end_io_write);
129130

fs/netfs/read_collect.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ static void netfs_unlock_read_folio(struct netfs_io_subrequest *subreq,
7777
folio_unlock(folio);
7878
}
7979
}
80+
81+
folioq_clear(folioq, slot);
8082
}
8183

8284
/*

fs/nilfs2/page.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ void nilfs_forget_buffer(struct buffer_head *bh)
7777
const unsigned long clear_bits =
7878
(BIT(BH_Uptodate) | BIT(BH_Dirty) | BIT(BH_Mapped) |
7979
BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) |
80-
BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected));
80+
BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected) |
81+
BIT(BH_Delay));
8182

8283
lock_buffer(bh);
8384
set_mask_bits(&bh->b_state, clear_bits, 0);
@@ -406,7 +407,8 @@ void nilfs_clear_folio_dirty(struct folio *folio)
406407
const unsigned long clear_bits =
407408
(BIT(BH_Uptodate) | BIT(BH_Dirty) | BIT(BH_Mapped) |
408409
BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) |
409-
BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected));
410+
BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected) |
411+
BIT(BH_Delay));
410412

411413
bh = head;
412414
do {

fs/ocfs2/file.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,9 +1129,12 @@ int ocfs2_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
11291129
trace_ocfs2_setattr(inode, dentry,
11301130
(unsigned long long)OCFS2_I(inode)->ip_blkno,
11311131
dentry->d_name.len, dentry->d_name.name,
1132-
attr->ia_valid, attr->ia_mode,
1133-
from_kuid(&init_user_ns, attr->ia_uid),
1134-
from_kgid(&init_user_ns, attr->ia_gid));
1132+
attr->ia_valid,
1133+
attr->ia_valid & ATTR_MODE ? attr->ia_mode : 0,
1134+
attr->ia_valid & ATTR_UID ?
1135+
from_kuid(&init_user_ns, attr->ia_uid) : 0,
1136+
attr->ia_valid & ATTR_GID ?
1137+
from_kgid(&init_user_ns, attr->ia_gid) : 0);
11351138

11361139
/* ensuring we don't even attempt to truncate a symlink */
11371140
if (S_ISLNK(inode->i_mode))

fs/open.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,8 @@ SYSCALL_DEFINE4(openat2, int, dfd, const char __user *, filename,
14571457

14581458
if (unlikely(usize < OPEN_HOW_SIZE_VER0))
14591459
return -EINVAL;
1460+
if (unlikely(usize > PAGE_SIZE))
1461+
return -E2BIG;
14601462

14611463
err = copy_struct_from_user(&tmp, sizeof(tmp), how, usize);
14621464
if (err)

0 commit comments

Comments
 (0)