2022-04-24 01:34:15

by Dai Ngo

[permalink] [raw]
Subject: [PATCH RFC v21 6/7] NFSD: add support for lock conflict to courteous server

This patch allows expired client with lock state to be in COURTESY
state. Lock conflict with COURTESY client is resolved by the fs/lock
code using the lm_lock_expirable and lm_expire_lock callback in the
struct lock_manager_operations.

If conflict client is in COURTESY state, set it to EXPIRABLE and
schedule the laundromat to run immediately to expire the client. The
callback lm_expire_lock waits for the laundromat to flush its work
queue before returning to caller.

Signed-off-by: Dai Ngo <[email protected]>
---
fs/nfsd/nfs4state.c | 82 +++++++++++++++++++++++++++++++++--------------------
1 file changed, 52 insertions(+), 30 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b70ba2eb5665..f6aef1a7cc02 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5729,11 +5729,31 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
}
#endif

+/* Check if any lock belonging to this lockowner has any blockers */
static bool
-nfs4_has_any_locks(struct nfs4_client *clp)
+nfs4_lockowner_has_blockers(struct nfs4_lockowner *lo)
+{
+ struct file_lock_context *ctx;
+ struct nfs4_ol_stateid *stp;
+ struct nfs4_file *nf;
+
+ list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) {
+ nf = stp->st_stid.sc_file;
+ ctx = nf->fi_inode->i_flctx;
+ if (!ctx)
+ continue;
+ if (locks_owner_has_blockers(ctx, lo))
+ return true;
+ }
+ return false;
+}
+
+static bool
+nfs4_anylock_blockers(struct nfs4_client *clp)
{
int i;
struct nfs4_stateowner *so;
+ struct nfs4_lockowner *lo;

spin_lock(&clp->cl_lock);
for (i = 0; i < OWNER_HASH_SIZE; i++) {
@@ -5741,40 +5761,17 @@ nfs4_has_any_locks(struct nfs4_client *clp)
so_strhash) {
if (so->so_is_open_owner)
continue;
- spin_unlock(&clp->cl_lock);
- return true;
+ lo = lockowner(so);
+ if (nfs4_lockowner_has_blockers(lo)) {
+ spin_unlock(&clp->cl_lock);
+ return true;
+ }
}
}
spin_unlock(&clp->cl_lock);
return false;
}

-/*
- * place holder for now, no check for lock blockers yet
- */
-static bool
-nfs4_anylock_blockers(struct nfs4_client *clp)
-{
- /* not allow locks yet */
- if (nfs4_has_any_locks(clp))
- return true;
- /*
- * don't want to check for delegation conflict here since
- * we need the state_lock for it. The laundromat willexpire
- * COURTESY later when checking for delegation recall timeout.
- */
- return false;
-}
-
-static bool client_has_state_tmp(struct nfs4_client *clp)
-{
- if (!list_empty(&clp->cl_delegations) &&
- !client_has_openowners(clp) &&
- list_empty(&clp->async_copies))
- return true;
- return false;
-}
-
static void
nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
struct laundry_time *lt)
@@ -5791,7 +5788,7 @@ nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
goto exp_client;
if (!state_expired(lt, clp->cl_time))
break;
- if (!client_has_state_tmp(clp))
+ if (!client_has_state(clp))
goto exp_client;
cour = (clp->cl_state == NFSD4_COURTESY);
if (cour && ktime_get_boottime_seconds() >=
@@ -6747,6 +6744,28 @@ nfsd4_lm_put_owner(fl_owner_t owner)
nfs4_put_stateowner(&lo->lo_owner);
}

+/* return pointer to struct nfs4_client if client is expirable */
+static void *
+nfsd4_lm_lock_expirable(struct file_lock *cfl)
+{
+ struct nfs4_lockowner *lo = (struct nfs4_lockowner *)cfl->fl_owner;
+ struct nfs4_client *clp = lo->lo_owner.so_client;
+
+ if (try_to_expire_client(clp))
+ return clp;
+ return NULL;
+}
+
+/* schedule laundromat to run immediately and wait for it to complete */
+static void
+nfsd4_lm_expire_lock(void *data)
+{
+ struct nfs4_client *clp = (struct nfs4_client *)data;
+ struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+ run_laundromat(nn, true);
+}
+
static void
nfsd4_lm_notify(struct file_lock *fl)
{
@@ -6773,9 +6792,12 @@ nfsd4_lm_notify(struct file_lock *fl)
}

static const struct lock_manager_operations nfsd_posix_mng_ops = {
+ .lm_mod_owner = THIS_MODULE,
.lm_notify = nfsd4_lm_notify,
.lm_get_owner = nfsd4_lm_get_owner,
.lm_put_owner = nfsd4_lm_put_owner,
+ .lm_lock_expirable = nfsd4_lm_lock_expirable,
+ .lm_expire_lock = nfsd4_lm_expire_lock,
};

static inline void
--
2.9.5