Skip to content

Commit 4039fbe

Browse files
Christoph HellwigAnna Schumaker
authored andcommitted
NFS: fix delayed delegation return handling
Rework this code that was totally busted at least as of my most recent changes. Introduce a separate list for delayed delegations so that they can't get lost and don't clutter up the returns list. Add a missing spin_unlock in the helper marking it as a regular pending return. Fixes: 0ebe655 ("NFS: add a separate delegation return list") Reported-by: Chris Mason <clm@meta.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
1 parent 94b8886 commit 4039fbe

5 files changed

Lines changed: 15 additions & 22 deletions

File tree

fs/nfs/client.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,7 @@ struct nfs_server *nfs_alloc_server(void)
10631063
spin_lock_init(&server->delegations_lock);
10641064
INIT_LIST_HEAD(&server->delegations_return);
10651065
INIT_LIST_HEAD(&server->delegations_lru);
1066+
INIT_LIST_HEAD(&server->delegations_delayed);
10661067
INIT_LIST_HEAD(&server->layouts);
10671068
INIT_LIST_HEAD(&server->state_owners_lru);
10681069
INIT_LIST_HEAD(&server->ss_copies);

fs/nfs/delegation.c

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -336,10 +336,8 @@ nfs_start_delegation_return(struct nfs_inode *nfsi)
336336

337337
spin_lock(&delegation->lock);
338338
if (delegation->inode &&
339-
!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
340-
clear_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags);
339+
!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
341340
return_now = true;
342-
}
343341
spin_unlock(&delegation->lock);
344342

345343
if (!return_now) {
@@ -586,8 +584,11 @@ static int nfs_end_delegation_return(struct inode *inode,
586584
out_return:
587585
return nfs_do_return_delegation(inode, delegation, issync);
588586
delay:
589-
set_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags);
590-
set_bit(NFS4SERV_DELEGRETURN_DELAYED, &server->delegation_flags);
587+
spin_lock(&server->delegations_lock);
588+
if (list_empty(&delegation->entry))
589+
refcount_inc(&delegation->refcount);
590+
list_move_tail(&delegation->entry, &server->delegations_return);
591+
spin_unlock(&server->delegations_lock);
591592
set_bit(NFS4CLNT_DELEGRETURN_DELAYED, &server->nfs_client->cl_state);
592593
abort:
593594
clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
@@ -616,22 +617,16 @@ static int nfs_return_one_delegation(struct nfs_server *server)
616617
spin_unlock(&delegation->lock);
617618
goto out_put_delegation;
618619
}
619-
if (test_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags) ||
620-
test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) ||
620+
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) ||
621621
test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
622622
spin_unlock(&delegation->lock);
623623
goto out_put_inode;
624624
}
625-
clear_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags);
626625
spin_unlock(&delegation->lock);
627626

628627
nfs_clear_verifier_delegated(inode);
629628

630629
err = nfs_end_delegation_return(inode, delegation, false);
631-
if (err) {
632-
nfs_mark_return_delegation(server, delegation);
633-
goto out_put_inode;
634-
}
635630

636631
out_put_inode:
637632
iput(inode);
@@ -708,19 +703,18 @@ static void nfs_delegation_add_lru(struct nfs_server *server,
708703

709704
static bool nfs_server_clear_delayed_delegations(struct nfs_server *server)
710705
{
711-
struct nfs_delegation *d;
712706
bool ret = false;
713707

714-
if (!test_and_clear_bit(NFS4SERV_DELEGRETURN_DELAYED,
715-
&server->delegation_flags))
708+
if (list_empty_careful(&server->delegations_delayed))
716709
return false;
717710

718711
spin_lock(&server->delegations_lock);
719-
list_for_each_entry_rcu(d, &server->delegations_return, entry) {
720-
if (test_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags))
721-
clear_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags);
712+
if (!list_empty(&server->delegations_delayed)) {
713+
list_splice_tail_init(&server->delegations_delayed,
714+
&server->delegations_return);
722715
ret = true;
723716
}
717+
spin_unlock(&server->delegations_lock);
724718

725719
return ret;
726720
}

fs/nfs/delegation.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ enum {
3737
NFS_DELEGATION_RETURNING,
3838
NFS_DELEGATION_REVOKED,
3939
NFS_DELEGATION_TEST_EXPIRED,
40-
NFS_DELEGATION_RETURN_DELAYED,
4140
NFS_DELEGATION_DELEGTIME,
4241
};
4342

fs/nfs/nfs4trace.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -991,8 +991,7 @@ DEFINE_NFS4_SET_DELEGATION_EVENT(nfs4_detach_delegation);
991991
{ BIT(NFS_DELEGATION_REFERENCED), "REFERENCED" }, \
992992
{ BIT(NFS_DELEGATION_RETURNING), "RETURNING" }, \
993993
{ BIT(NFS_DELEGATION_REVOKED), "REVOKED" }, \
994-
{ BIT(NFS_DELEGATION_TEST_EXPIRED), "TEST_EXPIRED" }, \
995-
{ BIT(NFS_DELEGATION_RETURN_DELAYED), "RETURN_DELAYED" })
994+
{ BIT(NFS_DELEGATION_TEST_EXPIRED), "TEST_EXPIRED" })
996995

997996
DECLARE_EVENT_CLASS(nfs4_delegation_event,
998997
TP_PROTO(

include/linux/nfs_fs_sb.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ struct nfs_server {
260260
spinlock_t delegations_lock;
261261
struct list_head delegations_return;
262262
struct list_head delegations_lru;
263+
struct list_head delegations_delayed;
263264
atomic_long_t nr_active_delegations;
264265
unsigned int delegation_hash_mask;
265266
struct hlist_head *delegation_hash_table;
@@ -268,7 +269,6 @@ struct nfs_server {
268269

269270
unsigned long delegation_flags;
270271
#define NFS4SERV_DELEGATION_EXPIRED (1)
271-
#define NFS4SERV_DELEGRETURN_DELAYED (2)
272272
unsigned long delegation_gen;
273273
unsigned long mig_gen;
274274
unsigned long mig_status;

0 commit comments

Comments
 (0)