2022-04-23 21:28:03

by Dai Ngo

[permalink] [raw]
Subject: [PATCH RFC v21 2/7] NFSD: add support for share reservation conflict to courteous server

This patch allows expired client with open state to be in COURTESY
state. Share/access conflict with COURTESY client is resolved by
setting COURTESY client to EXPIRABLE state, schedule laundromat
to run and returning nfserr_jukebox to the request client.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fea5e24e7d94..b08c132648b9 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -700,6 +700,57 @@ run_laundromat(struct nfsd_net *nn, bool wait)
flush_workqueue(laundry_wq);
}

+/*
+ * Check if courtesy clients have conflicting access and resolve it if possible
+ *
+ * access: is op_share_access if share_access is true.
+ * Check if access mode, op_share_access, would conflict with
+ * the current deny mode of the file 'fp'.
+ * access: is op_share_deny if share_access is false.
+ * Check if the deny mode, op_share_deny, would conflict with
+ * current access of the file 'fp'.
+ * stp: skip checking this entry.
+ * new_stp: normal open, not open upgrade.
+ *
+ * Function returns:
+ * false - access/deny mode conflict with normal client.
+ * true - no conflict or conflict with courtesy client(s) is resolved.
+ */
+static bool
+nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp,
+ struct nfs4_ol_stateid *stp, u32 access, bool share_access)
+{
+ struct nfs4_ol_stateid *st;
+ bool conflict = true;
+ unsigned char bmap;
+ struct nfsd_net *nn;
+ struct nfs4_client *clp;
+
+ lockdep_assert_held(&fp->fi_lock);
+ list_for_each_entry(st, &fp->fi_stateids, st_perfile) {
+ /* ignore lock stateid */
+ if (st->st_openstp)
+ continue;
+ if (st == stp && new_stp)
+ continue;
+ /* check file access against deny mode or vice versa */
+ bmap = share_access ? st->st_deny_bmap : st->st_access_bmap;
+ if (!(access & bmap_to_share_mode(bmap)))
+ continue;
+ clp = st->st_stid.sc_client;
+ if (try_to_expire_client(clp))
+ continue;
+ conflict = false;
+ break;
+ }
+ if (conflict) {
+ clp = stp->st_stid.sc_client;
+ nn = net_generic(clp->net, nfsd_net_id);
+ run_laundromat(nn, false);
+ }
+ return conflict;
+}
+
static void
__nfs4_file_get_access(struct nfs4_file *fp, u32 access)
{
@@ -4995,13 +5046,14 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,

static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
- struct nfsd4_open *open)
+ struct nfsd4_open *open, bool new_stp)
{
struct nfsd_file *nf = NULL;
__be32 status;
int oflag = nfs4_access_to_omode(open->op_share_access);
int access = nfs4_access_to_access(open->op_share_access);
unsigned char old_access_bmap, old_deny_bmap;
+ struct nfs4_client *clp;

spin_lock(&fp->fi_lock);

@@ -5011,6 +5063,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
*/
status = nfs4_file_check_deny(fp, open->op_share_deny);
if (status != nfs_ok) {
+ if (status != nfserr_share_denied) {
+ spin_unlock(&fp->fi_lock);
+ goto out;
+ }
+ clp = stp->st_stid.sc_client;
+ if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
+ stp, open->op_share_deny, false))
+ status = nfserr_jukebox;
spin_unlock(&fp->fi_lock);
goto out;
}
@@ -5018,6 +5078,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
/* set access to the file */
status = nfs4_file_get_access(fp, open->op_share_access);
if (status != nfs_ok) {
+ if (status != nfserr_share_denied) {
+ spin_unlock(&fp->fi_lock);
+ goto out;
+ }
+ clp = stp->st_stid.sc_client;
+ if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
+ stp, open->op_share_access, true))
+ status = nfserr_jukebox;
spin_unlock(&fp->fi_lock);
goto out;
}
@@ -5064,21 +5132,29 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
}

static __be32
-nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
+nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp,
+ struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
+ struct nfsd4_open *open)
{
__be32 status;
unsigned char old_deny_bmap = stp->st_deny_bmap;

if (!test_access(open->op_share_access, stp))
- return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
+ return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false);

/* test and set deny mode */
spin_lock(&fp->fi_lock);
status = nfs4_file_check_deny(fp, open->op_share_deny);
if (status == nfs_ok) {
- set_deny(open->op_share_deny, stp);
- fp->fi_share_deny |=
+ if (status != nfserr_share_denied) {
+ set_deny(open->op_share_deny, stp);
+ fp->fi_share_deny |=
(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
+ } else {
+ if (nfs4_resolve_deny_conflicts_locked(fp, false,
+ stp, open->op_share_deny, false))
+ status = nfserr_jukebox;
+ }
}
spin_unlock(&fp->fi_lock);

@@ -5419,7 +5495,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
goto out;
}
} else {
- status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
+ status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true);
if (status) {
stp->st_stid.sc_type = NFS4_CLOSED_STID;
release_open_stateid(stp);
@@ -5653,12 +5729,35 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
}
#endif

+static bool
+nfs4_has_any_locks(struct nfs4_client *clp)
+{
+ int i;
+ struct nfs4_stateowner *so;
+
+ spin_lock(&clp->cl_lock);
+ for (i = 0; i < OWNER_HASH_SIZE; i++) {
+ list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i],
+ so_strhash) {
+ if (so->so_is_open_owner)
+ continue;
+ 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
--
2.9.5


2022-04-25 16:18:18

by Dai Ngo

[permalink] [raw]
Subject: Re: [PATCH RFC v21 2/7] NFSD: add support for share reservation conflict to courteous server


On 4/25/22 6:15 AM, Chuck Lever III wrote:
>
>> On Apr 23, 2022, at 2:44 PM, Dai Ngo <[email protected]> wrote:
>>
>> This patch allows expired client with open state to be in COURTESY
>> state. Share/access conflict with COURTESY client is resolved by
>> setting COURTESY client to EXPIRABLE state, schedule laundromat
>> to run and returning nfserr_jukebox to the request client.
>>
>> Signed-off-by: Dai Ngo <[email protected]>
>> ---
>> fs/nfsd/nfs4state.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++---
>> 1 file changed, 105 insertions(+), 6 deletions(-)
>>
>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>> index fea5e24e7d94..b08c132648b9 100644
>> --- a/fs/nfsd/nfs4state.c
>> +++ b/fs/nfsd/nfs4state.c
>> @@ -700,6 +700,57 @@ run_laundromat(struct nfsd_net *nn, bool wait)
>> flush_workqueue(laundry_wq);
>> }
>>
>> +/*
>> + * Check if courtesy clients have conflicting access and resolve it if possible
>> + *
>> + * access: is op_share_access if share_access is true.
>> + * Check if access mode, op_share_access, would conflict with
>> + * the current deny mode of the file 'fp'.
>> + * access: is op_share_deny if share_access is false.
>> + * Check if the deny mode, op_share_deny, would conflict with
>> + * current access of the file 'fp'.
>> + * stp: skip checking this entry.
>> + * new_stp: normal open, not open upgrade.
>> + *
>> + * Function returns:
>> + * false - access/deny mode conflict with normal client.
>> + * true - no conflict or conflict with courtesy client(s) is resolved.
>> + */
>> +static bool
>> +nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp,
>> + struct nfs4_ol_stateid *stp, u32 access, bool share_access)
>> +{
>> + struct nfs4_ol_stateid *st;
>> + bool conflict = true;
>> + unsigned char bmap;
>> + struct nfsd_net *nn;
>> + struct nfs4_client *clp;
>> +
>> + lockdep_assert_held(&fp->fi_lock);
>> + list_for_each_entry(st, &fp->fi_stateids, st_perfile) {
>> + /* ignore lock stateid */
>> + if (st->st_openstp)
>> + continue;
>> + if (st == stp && new_stp)
>> + continue;
>> + /* check file access against deny mode or vice versa */
>> + bmap = share_access ? st->st_deny_bmap : st->st_access_bmap;
>> + if (!(access & bmap_to_share_mode(bmap)))
>> + continue;
>> + clp = st->st_stid.sc_client;
>> + if (try_to_expire_client(clp))
>> + continue;
>> + conflict = false;
>> + break;
>> + }
>> + if (conflict) {
>> + clp = stp->st_stid.sc_client;
>> + nn = net_generic(clp->net, nfsd_net_id);
>> + run_laundromat(nn, false);
>> + }
>> + return conflict;
>> +}
>> +
>> static void
>> __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
>> {
>> @@ -4995,13 +5046,14 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
>>
>> static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
>> - struct nfsd4_open *open)
>> + struct nfsd4_open *open, bool new_stp)
>> {
>> struct nfsd_file *nf = NULL;
>> __be32 status;
>> int oflag = nfs4_access_to_omode(open->op_share_access);
>> int access = nfs4_access_to_access(open->op_share_access);
>> unsigned char old_access_bmap, old_deny_bmap;
>> + struct nfs4_client *clp;
>>
>> spin_lock(&fp->fi_lock);
>>
>> @@ -5011,6 +5063,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> */
>> status = nfs4_file_check_deny(fp, open->op_share_deny);
>> if (status != nfs_ok) {
>> + if (status != nfserr_share_denied) {
>> + spin_unlock(&fp->fi_lock);
>> + goto out;
>> + }
>> + clp = stp->st_stid.sc_client;
> @clp is set here, but the value is never used in this function,
> even in later patches. Possibly left over from the previous
> revision of this series?

Thanks Chuck, will fix in v22.
Kernel test robot also reported the problem.

-Dai

>
>
>> + if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
>> + stp, open->op_share_deny, false))
>> + status = nfserr_jukebox;
>> spin_unlock(&fp->fi_lock);
>> goto out;
>> }
>> @@ -5018,6 +5078,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> /* set access to the file */
>> status = nfs4_file_get_access(fp, open->op_share_access);
>> if (status != nfs_ok) {
>> + if (status != nfserr_share_denied) {
>> + spin_unlock(&fp->fi_lock);
>> + goto out;
>> + }
>> + clp = stp->st_stid.sc_client;
> Ditto.
>
>
>> + if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
>> + stp, open->op_share_access, true))
>> + status = nfserr_jukebox;
>> spin_unlock(&fp->fi_lock);
>> goto out;
>> }
>> @@ -5064,21 +5132,29 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> }
>>
>> static __be32
>> -nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
>> +nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp,
>> + struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
>> + struct nfsd4_open *open)
>> {
>> __be32 status;
>> unsigned char old_deny_bmap = stp->st_deny_bmap;
>>
>> if (!test_access(open->op_share_access, stp))
>> - return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
>> + return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false);
>>
>> /* test and set deny mode */
>> spin_lock(&fp->fi_lock);
>> status = nfs4_file_check_deny(fp, open->op_share_deny);
>> if (status == nfs_ok) {
>> - set_deny(open->op_share_deny, stp);
>> - fp->fi_share_deny |=
>> + if (status != nfserr_share_denied) {
>> + set_deny(open->op_share_deny, stp);
>> + fp->fi_share_deny |=
>> (open->op_share_deny & NFS4_SHARE_DENY_BOTH);
>> + } else {
>> + if (nfs4_resolve_deny_conflicts_locked(fp, false,
>> + stp, open->op_share_deny, false))
>> + status = nfserr_jukebox;
>> + }
>> }
>> spin_unlock(&fp->fi_lock);
>>
>> @@ -5419,7 +5495,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
>> goto out;
>> }
>> } else {
>> - status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
>> + status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true);
>> if (status) {
>> stp->st_stid.sc_type = NFS4_CLOSED_STID;
>> release_open_stateid(stp);
>> @@ -5653,12 +5729,35 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
>> }
>> #endif
>>
>> +static bool
>> +nfs4_has_any_locks(struct nfs4_client *clp)
>> +{
>> + int i;
>> + struct nfs4_stateowner *so;
>> +
>> + spin_lock(&clp->cl_lock);
>> + for (i = 0; i < OWNER_HASH_SIZE; i++) {
>> + list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i],
>> + so_strhash) {
>> + if (so->so_is_open_owner)
>> + continue;
>> + 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
>> --
>> 2.9.5
>>
> --
> Chuck Lever
>
>
>

2022-04-25 16:48:27

by Chuck Lever III

[permalink] [raw]
Subject: Re: [PATCH RFC v21 2/7] NFSD: add support for share reservation conflict to courteous server



> On Apr 23, 2022, at 2:44 PM, Dai Ngo <[email protected]> wrote:
>
> This patch allows expired client with open state to be in COURTESY
> state. Share/access conflict with COURTESY client is resolved by
> setting COURTESY client to EXPIRABLE state, schedule laundromat
> to run and returning nfserr_jukebox to the request client.
>
> Signed-off-by: Dai Ngo <[email protected]>
> ---
> fs/nfsd/nfs4state.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 105 insertions(+), 6 deletions(-)
>
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index fea5e24e7d94..b08c132648b9 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -700,6 +700,57 @@ run_laundromat(struct nfsd_net *nn, bool wait)
> flush_workqueue(laundry_wq);
> }
>
> +/*
> + * Check if courtesy clients have conflicting access and resolve it if possible
> + *
> + * access: is op_share_access if share_access is true.
> + * Check if access mode, op_share_access, would conflict with
> + * the current deny mode of the file 'fp'.
> + * access: is op_share_deny if share_access is false.
> + * Check if the deny mode, op_share_deny, would conflict with
> + * current access of the file 'fp'.
> + * stp: skip checking this entry.
> + * new_stp: normal open, not open upgrade.
> + *
> + * Function returns:
> + * false - access/deny mode conflict with normal client.
> + * true - no conflict or conflict with courtesy client(s) is resolved.
> + */
> +static bool
> +nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp,
> + struct nfs4_ol_stateid *stp, u32 access, bool share_access)
> +{
> + struct nfs4_ol_stateid *st;
> + bool conflict = true;
> + unsigned char bmap;
> + struct nfsd_net *nn;
> + struct nfs4_client *clp;
> +
> + lockdep_assert_held(&fp->fi_lock);
> + list_for_each_entry(st, &fp->fi_stateids, st_perfile) {
> + /* ignore lock stateid */
> + if (st->st_openstp)
> + continue;
> + if (st == stp && new_stp)
> + continue;
> + /* check file access against deny mode or vice versa */
> + bmap = share_access ? st->st_deny_bmap : st->st_access_bmap;
> + if (!(access & bmap_to_share_mode(bmap)))
> + continue;
> + clp = st->st_stid.sc_client;
> + if (try_to_expire_client(clp))
> + continue;
> + conflict = false;
> + break;
> + }
> + if (conflict) {
> + clp = stp->st_stid.sc_client;
> + nn = net_generic(clp->net, nfsd_net_id);
> + run_laundromat(nn, false);
> + }
> + return conflict;
> +}
> +
> static void
> __nfs4_file_get_access(struct nfs4_file *fp, u32 access)
> {
> @@ -4995,13 +5046,14 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
>
> static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
> struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
> - struct nfsd4_open *open)
> + struct nfsd4_open *open, bool new_stp)
> {
> struct nfsd_file *nf = NULL;
> __be32 status;
> int oflag = nfs4_access_to_omode(open->op_share_access);
> int access = nfs4_access_to_access(open->op_share_access);
> unsigned char old_access_bmap, old_deny_bmap;
> + struct nfs4_client *clp;
>
> spin_lock(&fp->fi_lock);
>
> @@ -5011,6 +5063,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
> */
> status = nfs4_file_check_deny(fp, open->op_share_deny);
> if (status != nfs_ok) {
> + if (status != nfserr_share_denied) {
> + spin_unlock(&fp->fi_lock);
> + goto out;
> + }
> + clp = stp->st_stid.sc_client;

@clp is set here, but the value is never used in this function,
even in later patches. Possibly left over from the previous
revision of this series?


> + if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
> + stp, open->op_share_deny, false))
> + status = nfserr_jukebox;
> spin_unlock(&fp->fi_lock);
> goto out;
> }
> @@ -5018,6 +5078,14 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
> /* set access to the file */
> status = nfs4_file_get_access(fp, open->op_share_access);
> if (status != nfs_ok) {
> + if (status != nfserr_share_denied) {
> + spin_unlock(&fp->fi_lock);
> + goto out;
> + }
> + clp = stp->st_stid.sc_client;

Ditto.


> + if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
> + stp, open->op_share_access, true))
> + status = nfserr_jukebox;
> spin_unlock(&fp->fi_lock);
> goto out;
> }
> @@ -5064,21 +5132,29 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
> }
>
> static __be32
> -nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
> +nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp,
> + struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
> + struct nfsd4_open *open)
> {
> __be32 status;
> unsigned char old_deny_bmap = stp->st_deny_bmap;
>
> if (!test_access(open->op_share_access, stp))
> - return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
> + return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false);
>
> /* test and set deny mode */
> spin_lock(&fp->fi_lock);
> status = nfs4_file_check_deny(fp, open->op_share_deny);
> if (status == nfs_ok) {
> - set_deny(open->op_share_deny, stp);
> - fp->fi_share_deny |=
> + if (status != nfserr_share_denied) {
> + set_deny(open->op_share_deny, stp);
> + fp->fi_share_deny |=
> (open->op_share_deny & NFS4_SHARE_DENY_BOTH);
> + } else {
> + if (nfs4_resolve_deny_conflicts_locked(fp, false,
> + stp, open->op_share_deny, false))
> + status = nfserr_jukebox;
> + }
> }
> spin_unlock(&fp->fi_lock);
>
> @@ -5419,7 +5495,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
> goto out;
> }
> } else {
> - status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
> + status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true);
> if (status) {
> stp->st_stid.sc_type = NFS4_CLOSED_STID;
> release_open_stateid(stp);
> @@ -5653,12 +5729,35 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
> }
> #endif
>
> +static bool
> +nfs4_has_any_locks(struct nfs4_client *clp)
> +{
> + int i;
> + struct nfs4_stateowner *so;
> +
> + spin_lock(&clp->cl_lock);
> + for (i = 0; i < OWNER_HASH_SIZE; i++) {
> + list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i],
> + so_strhash) {
> + if (so->so_is_open_owner)
> + continue;
> + 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
> --
> 2.9.5
>

--
Chuck Lever