2013-04-09 23:58:21

by J. Bruce Fields

[permalink] [raw]
Subject: finishing off 4.1 for 3.10...

The following close off 3 remaining 4.1 todo's and fix some
miscellaneous bugs and ugliness along the way.

I had two more todo's in mind before considering 4.1 no longer
experimental and turn it on by default:

- AUTH_GSS for the backchannel
- SP4_MACH_CRED state protection

In theory they're both mandatory, but I think I may just go ahead
without them, after making sure we return reasonable errors in both
cases and so on.

The last patch (implementing SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
hasn't gotten any real testing--I need to write a pynfs test for the
TEST_STATEID/FREE_STATEID behavior. So that may still need some more
revisions.

I think the others are ready if nobody sees problems.

--b.


2013-04-09 23:58:20

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 09/10] nfsd4: clean up validate_stateid

From: "J. Bruce Fields" <[email protected]>

The logic here is better expressed with a switch statement.

While we're here, CLOSED stateids (or stateids of an unkown type--which
would indicate a server bug) should probably return nfserr_bad_stateid,
though this behavior shouldn't affect any non-buggy client.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 67017fc..add9721 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3456,13 +3456,22 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
status = check_stateid_generation(stateid, &s->sc_stateid, 1);
if (status)
return status;
- if (!(s->sc_type & (NFS4_OPEN_STID | NFS4_LOCK_STID)))
+ switch (s->sc_type) {
+ case NFS4_DELEG_STID:
+ return nfs_ok;
+ case NFS4_OPEN_STID:
+ case NFS4_LOCK_STID:
+ ols = openlockstateid(s);
+ if (ols->st_stateowner->so_is_open_owner
+ && !(openowner(ols->st_stateowner)->oo_flags
+ & NFS4_OO_CONFIRMED))
+ return nfserr_bad_stateid;
return nfs_ok;
- ols = openlockstateid(s);
- if (ols->st_stateowner->so_is_open_owner
- && !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
+ default:
+ printk("unknown stateid type %x\n", s->sc_type);
+ case NFS4_CLOSED_STID:
return nfserr_bad_stateid;
- return nfs_ok;
+ }
}

static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
--
1.7.9.5


2013-04-15 02:07:10

by J. Bruce Fields

[permalink] [raw]
Subject: Re: finishing off 4.1 for 3.10...

On Tue, Apr 09, 2013 at 07:58:05PM -0400, J. Bruce Fields wrote:
> The following close off 3 remaining 4.1 todo's and fix some
> miscellaneous bugs and ugliness along the way.
>
> I had two more todo's in mind before considering 4.1 no longer
> experimental and turn it on by default:
>
> - AUTH_GSS for the backchannel
> - SP4_MACH_CRED state protection
>
> In theory they're both mandatory, but I think I may just go ahead
> without them, after making sure we return reasonable errors in both
> cases and so on.
>
> The last patch (implementing SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
> hasn't gotten any real testing--I need to write a pynfs test for the
> TEST_STATEID/FREE_STATEID behavior. So that may still need some more
> revisions.

Sure enough.... A revised patch is appended.

I've also added a pynfs test, and pushed out the result to

git://linux-nfs.org/~bfields/pynfs.git master

Along the way I noticed pynfs was using an out-of-date nfs4.x (which was
missing an error needed in this case) and had a crucial CB_SEQUENCE bug
(how did we not notice it was responding with the wrong sequence id?).
That (and another miscellaneous open/locking test) are included in the
above.

--b.

commit 4e05166c7148839be370ad8873d5835977c8f609
Author: J. Bruce Fields <[email protected]>
Date: Tue Apr 9 17:02:51 2013 -0400

nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED

A 4.1 server must notify a client that has had any state revoked using
the SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag. The client can figure
out exactly which state is the problem using CHECK_STATEID and then free
it using FREE_STATEID. The status flag will be unset once all such
revoked stateids are freed.

Our server's only recallable state is delegations. So we keep with each
4.1 client a list of delegations that have timed out and been recalled,
but haven't yet been freed by FREE_STATEID.

Signed-off-by: J. Bruce Fields <[email protected]>

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 986114c..b45a978 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -445,7 +445,6 @@ static void unhash_stid(struct nfs4_stid *s)
static void
unhash_delegation(struct nfs4_delegation *dp)
{
- unhash_stid(&dp->dl_stid);
list_del_init(&dp->dl_perclnt);
spin_lock(&recall_lock);
list_del_init(&dp->dl_perfile);
@@ -454,10 +453,37 @@ unhash_delegation(struct nfs4_delegation *dp)
nfs4_put_deleg_lease(dp->dl_file);
put_nfs4_file(dp->dl_file);
dp->dl_file = NULL;
+}
+
+
+
+static void destroy_revoked_delegation(struct nfs4_delegation *dp)
+{
+ list_del_init(&dp->dl_recall_lru);
remove_stid(&dp->dl_stid);
nfs4_put_delegation(dp);
}

+static void destroy_delegation(struct nfs4_delegation *dp)
+{
+ unhash_delegation(dp);
+ nfs4_put_delegation(dp);
+ remove_stid(&dp->dl_stid);
+}
+
+static void revoke_delegation(struct nfs4_delegation *dp)
+{
+ struct nfs4_client *clp = dp->dl_stid.sc_client;
+
+ if (clp->cl_minorversion == 0)
+ destroy_delegation(dp);
+ else {
+ unhash_delegation(dp);
+ dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
+ list_add(&dp->dl_recall_lru, &clp->cl_revoked);
+ }
+}
+
/*
* SETCLIENTID state
*/
@@ -1113,7 +1139,7 @@ destroy_client(struct nfs4_client *clp)
spin_unlock(&recall_lock);
while (!list_empty(&reaplist)) {
dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
- unhash_delegation(dp);
+ destroy_delegation(dp);
}
while (!list_empty(&clp->cl_openowners)) {
oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
@@ -1309,6 +1335,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_lru);
INIT_LIST_HEAD(&clp->cl_callbacks);
+ INIT_LIST_HEAD(&clp->cl_revoked);
spin_lock_init(&clp->cl_lock);
nfsd4_init_callback(&clp->cl_cb_null);
clp->cl_time = get_seconds();
@@ -2170,6 +2197,8 @@ out:
default:
seq->status_flags = 0;
}
+ if (!list_empty(&clp->cl_revoked))
+ seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
out_no_session:
kfree(conn);
spin_unlock(&nn->client_lock);
@@ -3296,7 +3325,7 @@ nfs4_laundromat(struct nfsd_net *nn)
spin_unlock(&recall_lock);
list_for_each_safe(pos, next, &reaplist) {
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
- unhash_delegation(dp);
+ revoke_delegation(dp);
}
test_val = nn->nfsd4_lease;
list_for_each_safe(pos, next, &nn->close_lru) {
@@ -3458,6 +3487,8 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
switch (s->sc_type) {
case NFS4_DELEG_STID:
return nfs_ok;
+ case NFS4_REVOKED_DELEG_STID:
+ return nfserr_deleg_revoked;
case NFS4_OPEN_STID:
case NFS4_LOCK_STID:
ols = openlockstateid(s);
@@ -3601,6 +3632,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
stateid_t *stateid = &free_stateid->fr_stateid;
struct nfs4_stid *s;
+ struct nfs4_delegation *dp;
struct nfs4_client *cl = cstate->session->se_client;
__be32 ret = nfserr_bad_stateid;

@@ -3622,6 +3654,11 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
else
ret = nfserr_locks_held;
break;
+ case NFS4_REVOKED_DELEG_STID:
+ dp = delegstateid(s);
+ destroy_revoked_delegation(dp);
+ ret = nfs_ok;
+ break;
default:
ret = nfserr_bad_stateid;
}
@@ -3646,10 +3683,12 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
status = nfsd4_check_seqid(cstate, sop, seqid);
if (status)
return status;
- if (stp->st_stid.sc_type == NFS4_CLOSED_STID)
+ if (stp->st_stid.sc_type == NFS4_CLOSED_STID
+ || stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
/*
* "Closed" stateid's exist *only* to return
- * nfserr_replay_me from the previous step.
+ * nfserr_replay_me from the previous step, and
+ * revoked delegations are kept only for free_stateid.
*/
return nfserr_bad_stateid;
status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
@@ -3912,7 +3951,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (status)
goto out;

- unhash_delegation(dp);
+ destroy_delegation(dp);
out:
nfs4_unlock_state();

@@ -4762,7 +4801,7 @@ u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max)
spin_unlock(&recall_lock);

list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
- unhash_delegation(dp);
+ revoke_delegation(dp);

return count;
}
@@ -5017,7 +5056,7 @@ nfs4_state_shutdown_net(struct net *net)
spin_unlock(&recall_lock);
list_for_each_safe(pos, next, &reaplist) {
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
- unhash_delegation(dp);
+ destroy_delegation(dp);
}

nfsd4_client_tracking_exit(net);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 13ec485..274e2a1 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -79,6 +79,8 @@ struct nfs4_stid {
#define NFS4_DELEG_STID 4
/* For an open stateid kept around *only* to process close replays: */
#define NFS4_CLOSED_STID 8
+/* For a deleg stateid kept around only to process free_stateid's: */
+#define NFS4_REVOKED_DELEG_STID 16
unsigned char sc_type;
stateid_t sc_stateid;
struct nfs4_client *sc_client;
@@ -238,6 +240,7 @@ struct nfs4_client {
struct list_head cl_openowners;
struct idr cl_stateids; /* stateid lookup */
struct list_head cl_delegations;
+ struct list_head cl_revoked; /* unacknowledged, revoked 4.1 state */
struct list_head cl_lru; /* tail queue */
struct xdr_netobj cl_name; /* id generated by client */
nfs4_verifier cl_verifier; /* generated by client */

2013-04-09 23:58:20

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 02/10] nfsd4: no need for replay_owner in sessions case

From: "J. Bruce Fields" <[email protected]>

The replay_owner will never be used in the sessions case.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4proc.c | 2 +-
fs/nfsd/nfs4state.c | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 609e1e2..c97bb42 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -413,7 +413,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
WARN_ON(status && open->op_created);
out:
nfsd4_cleanup_open_state(open, status);
- if (open->op_openowner)
+ if (open->op_openowner && !nfsd4_has_session(cstate))
cstate->replay_owner = &open->op_openowner->oo_owner;
nfsd4_bump_seqid(cstate, status);
if (!cstate->replay_owner)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1226ff6..16db25d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3666,7 +3666,8 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
if (status)
return status;
*stpp = openlockstateid(s);
- cstate->replay_owner = (*stpp)->st_stateowner;
+ if (!nfsd4_has_session(cstate))
+ cstate->replay_owner = (*stpp)->st_stateowner;

return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
}
@@ -3858,10 +3859,9 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
oo->oo_last_closed_stid = stp;

if (list_empty(&oo->oo_owner.so_stateids)) {
- if (cstate->minorversion) {
+ if (cstate->minorversion)
release_openowner(oo);
- cstate->replay_owner = NULL;
- } else {
+ else {
/*
* In the 4.0 case we need to keep the owners around a
* little while to handle CLOSE replay.
--
1.7.9.5


2013-04-09 23:58:21

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 03/10] nfsd4: more sessions/open-owner-replay cleanup

From: "J. Bruce Fields" <[email protected]>

More logic that's unnecessary in the 4.1 case.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4proc.c | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index c97bb42..5dee811 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -191,9 +191,18 @@ static __be32 nfsd_check_obj_isreg(struct svc_fh *fh)
return nfserr_symlink;
}

+static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh *resfh)
+{
+ if (nfsd4_has_session(cstate))
+ return;
+ fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
+ &resfh->fh_handle);
+}
+
static __be32
-do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
{
+ struct svc_fh *current_fh = &cstate->current_fh;
struct svc_fh *resfh;
int accmode;
__be32 status;
@@ -252,9 +261,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
if (is_create_with_attrs(open) && open->op_acl != NULL)
do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval);

- /* set reply cache */
- fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
- &resfh->fh_handle);
+ nfsd4_set_open_owner_reply_cache(cstate, open, resfh);
accmode = NFSD_MAY_NOP;
if (open->op_created)
accmode |= NFSD_MAY_OWNER_OVERRIDE;
@@ -268,8 +275,9 @@ out:
}

static __be32
-do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+do_open_fhandle(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
{
+ struct svc_fh *current_fh = &cstate->current_fh;
__be32 status;

/* We don't know the target directory, and therefore can not
@@ -278,9 +286,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_

memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));

- /* set replay cache */
- fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
- &current_fh->fh_handle);
+ nfsd4_set_open_owner_reply_cache(cstate, open, current_fh);

open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
(open->op_iattr.ia_size == 0);
@@ -372,8 +378,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
switch (open->op_claim_type) {
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
case NFS4_OPEN_CLAIM_NULL:
- status = do_open_lookup(rqstp, &cstate->current_fh,
- open);
+ status = do_open_lookup(rqstp, cstate, open);
if (status)
goto out;
break;
@@ -386,8 +391,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
case NFS4_OPEN_CLAIM_FH:
case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
- status = do_open_fhandle(rqstp, &cstate->current_fh,
- open);
+ status = do_open_fhandle(rqstp, cstate, open);
if (status)
goto out;
break;
--
1.7.9.5


2013-04-09 23:58:21

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 07/10] nfsd4: fix forechannel attribute negotiation

From: "J. Bruce Fields" <[email protected]>

Negotiation of the 4.1 session forechannel attributes is a mess. Fix:

- Move it all into check_forechannel_attrs instead of spreading
it between that, alloc_session, and init_forechannel_attrs.
- set a minimum "slotsize" so that our drc memory limits apply
even for small maxresponsesize_cached. This also fixes some
bugs when slotsize becomes <= 0.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 116 ++++++++++++++++++++++-----------------------------
1 file changed, 49 insertions(+), 67 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f1262f7..036d5f1 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -776,17 +776,15 @@ free_session_slots(struct nfsd4_session *ses)
* We don't actually need to cache the rpc and session headers, so we
* can allocate a little less for each slot:
*/
-static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
+static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca)
{
- return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
-}
-
-static int nfsd4_sanitize_slot_size(u32 size)
-{
- size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */
- size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE);
+ u32 size;

- return size;
+ if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ)
+ size = 0;
+ else
+ size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
+ return size + sizeof(struct nfsd4_slot);
}

/*
@@ -794,12 +792,12 @@ static int nfsd4_sanitize_slot_size(u32 size)
* re-negotiate active sessions and reduce their slot usage to make
* room for new connections. For now we just fail the create session.
*/
-static int nfsd4_get_drc_mem(int slotsize, u32 num)
+static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca)
{
+ u32 slotsize = slot_bytes(ca);
+ u32 num = ca->maxreqs;
int avail;

- num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION);
-
spin_lock(&nfsd_drc_lock);
avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION,
nfsd_drc_max_mem - nfsd_drc_mem_used);
@@ -810,15 +808,19 @@ static int nfsd4_get_drc_mem(int slotsize, u32 num)
return num;
}

-static void nfsd4_put_drc_mem(int slotsize, int num)
+static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
{
+ int slotsize = slot_bytes(ca);
+
spin_lock(&nfsd_drc_lock);
- nfsd_drc_mem_used -= slotsize * num;
+ nfsd_drc_mem_used -= slotsize * ca->maxreqs;
spin_unlock(&nfsd_drc_lock);
}

-static struct nfsd4_session *__alloc_session(int slotsize, int numslots)
+static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs)
{
+ int numslots = attrs->maxreqs;
+ int slotsize = slot_bytes(attrs);
struct nfsd4_session *new;
int mem, i;

@@ -831,8 +833,7 @@ static struct nfsd4_session *__alloc_session(int slotsize, int numslots)
return NULL;
/* allocate each struct nfsd4_slot and data cache in one piece */
for (i = 0; i < numslots; i++) {
- mem = sizeof(struct nfsd4_slot) + slotsize;
- new->se_slots[i] = kzalloc(mem, GFP_KERNEL);
+ new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL);
if (!new->se_slots[i])
goto out_free;
}
@@ -844,21 +845,6 @@ out_free:
return NULL;
}

-static void init_forechannel_attrs(struct nfsd4_channel_attrs *new,
- struct nfsd4_channel_attrs *req,
- int numslots, int slotsize,
- struct nfsd_net *nn)
-{
- u32 maxrpc = nn->nfsd_serv->sv_max_mesg;
-
- new->maxreqs = numslots;
- new->maxresp_cached = min_t(u32, req->maxresp_cached,
- slotsize + NFSD_MIN_HDR_SEQ_SZ);
- new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
- new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
- new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
-}
-
static void free_conn(struct nfsd4_conn *c)
{
svc_xprt_put(c->cn_xprt);
@@ -960,7 +946,6 @@ static void nfsd4_del_conns(struct nfsd4_session *s)

static void __free_session(struct nfsd4_session *ses)
{
- nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs);
free_session_slots(ses);
kfree(ses);
}
@@ -971,35 +956,10 @@ static void free_session(struct nfsd4_session *ses)

lockdep_assert_held(&nn->client_lock);
nfsd4_del_conns(ses);
+ nfsd4_put_drc_mem(&ses->se_fchannel);
__free_session(ses);
}

-static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan,
- struct nfsd_net *nn)
-{
- struct nfsd4_session *new;
- int numslots, slotsize;
- /*
- * Note decreasing slot size below client's request may
- * make it difficult for client to function correctly, whereas
- * decreasing the number of slots will (just?) affect
- * performance. When short on memory we therefore prefer to
- * decrease number of slots instead of their size.
- */
- slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
- numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
- if (numslots < 1)
- return NULL;
-
- new = __alloc_session(slotsize, numslots);
- if (!new) {
- nfsd4_put_drc_mem(slotsize, numslots);
- return NULL;
- }
- init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize, nn);
- return new;
-}
-
static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
{
int idx;
@@ -1022,7 +982,8 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
list_add(&new->se_perclnt, &clp->cl_sessions);
spin_unlock(&clp->cl_lock);
spin_unlock(&nn->client_lock);
-
+ memcpy(&new->se_fchannel, &cses->fore_channel,
+ sizeof(struct nfsd4_channel_attrs));
if (cses->flags & SESSION4_BACK_CHAN) {
struct sockaddr *sa = svc_addr(rqstp);
/*
@@ -1803,12 +1764,33 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
/* seqid, slotID, slotID, slotID, status */ \
5 ) * sizeof(__be32))

-static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca)
+static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn)
{
+ u32 maxrpc = nn->nfsd_serv->sv_max_mesg;
+
if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ)
return nfserr_toosmall;
if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ)
return nfserr_toosmall;
+ ca->headerpadsz = 0;
+ ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
+ ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
+ ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
+ ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
+ NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
+ ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);
+ /*
+ * Note decreasing slot size below client's request may make it
+ * difficult for client to function correctly, whereas
+ * decreasing the number of slots will (just?) affect
+ * performance. When short on memory we therefore prefer to
+ * decrease number of slots instead of their size. Clients that
+ * request larger slots than they need will get poor results:
+ */
+ ca->maxreqs = nfsd4_get_drc_mem(ca);
+ if (!ca->maxreqs)
+ return nfserr_jukebox;
+
return nfs_ok;
}

@@ -1827,13 +1809,13 @@ nfsd4_create_session(struct svc_rqst *rqstp,

if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
return nfserr_inval;
- status = check_forechannel_attrs(&cr_ses->fore_channel);
+ status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
if (status)
return status;
- new = alloc_session(&cr_ses->fore_channel, nn);
- if (!new)
- return nfserr_jukebox;
status = nfserr_jukebox;
+ new = alloc_session(&cr_ses->fore_channel);
+ if (!new)
+ goto out_release_drc_mem;
conn = alloc_conn_from_crses(rqstp, cr_ses);
if (!conn)
goto out_free_session;
@@ -1892,8 +1874,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,

memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
NFS4_MAX_SESSIONID_LEN);
- memcpy(&cr_ses->fore_channel, &new->se_fchannel,
- sizeof(struct nfsd4_channel_attrs));
cs_slot->sl_seqid++;
cr_ses->seqid = cs_slot->sl_seqid;

@@ -1906,6 +1886,8 @@ out_free_conn:
free_conn(conn);
out_free_session:
__free_session(new);
+out_release_drc_mem:
+ nfsd4_put_drc_mem(&cr_ses->fore_channel);
return status;
}

--
1.7.9.5


2013-04-09 23:58:20

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 06/10] nfsd4: cleanup check_forechannel_attrs

From: "J. Bruce Fields" <[email protected]>

Pass this struct by reference, not by value, and return an error instead
of a boolean to allow for future additions.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 7d2e3b5..f1262f7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1803,10 +1803,13 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
/* seqid, slotID, slotID, slotID, status */ \
5 ) * sizeof(__be32))

-static bool check_forechannel_attrs(struct nfsd4_channel_attrs fchannel)
+static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca)
{
- return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ
- || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ;
+ if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ)
+ return nfserr_toosmall;
+ if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ)
+ return nfserr_toosmall;
+ return nfs_ok;
}

__be32
@@ -1824,8 +1827,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,

if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
return nfserr_inval;
- if (check_forechannel_attrs(cr_ses->fore_channel))
- return nfserr_toosmall;
+ status = check_forechannel_attrs(&cr_ses->fore_channel);
+ if (status)
+ return status;
new = alloc_session(&cr_ses->fore_channel, nn);
if (!new)
return nfserr_jukebox;
--
1.7.9.5


2013-04-09 23:58:20

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 01/10] nfsd4: remove some redundant comments

From: "J. Bruce Fields" <[email protected]>

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 6 ------
1 file changed, 6 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9cb9f6e..1226ff6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4432,17 +4432,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
locku->lu_length);
nfs4_transform_lock_offset(file_lock);

- /*
- * Try to unlock the file in the VFS.
- */
err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);
if (err) {
dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
goto out_nfserr;
}
- /*
- * OK, unlock succeeded; the only thing left to do is update the stateid.
- */
update_stateid(&stp->st_stid.sc_stateid);
memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

--
1.7.9.5


2013-04-09 23:58:21

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 04/10] nfsd4: release lockowners on last unlock in 4.1 case

From: "J. Bruce Fields" <[email protected]>

In the 4.1 case we're supposed to release lockowners as soon as they're
no longer used.

It would probably be more efficient to reference count them, but that's
slightly fiddly due to the need to have callbacks from locks.c to take
into account lock merging and splitting.

For most cases just scanning the inode's lock list on unlock for
matching locks will be sufficient.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 16db25d..ff1577d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4387,6 +4387,7 @@ __be32
nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_locku *locku)
{
+ struct nfs4_lockowner *lo;
struct nfs4_ol_stateid *stp;
struct file *filp = NULL;
struct file_lock *file_lock = NULL;
@@ -4419,9 +4420,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_jukebox;
goto out;
}
+ lo = lockowner(stp->st_stateowner);
locks_init_lock(file_lock);
file_lock->fl_type = F_UNLCK;
- file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
+ file_lock->fl_owner = (fl_owner_t)lo;
file_lock->fl_pid = current->tgid;
file_lock->fl_file = filp;
file_lock->fl_flags = FL_POSIX;
@@ -4440,6 +4442,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
update_stateid(&stp->st_stid.sc_stateid);
memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

+ if (nfsd4_has_session(cstate) && !check_for_locks(stp->st_file, lo)) {
+ WARN_ON_ONCE(cstate->replay_owner);
+ release_lockowner(lo);
+ }
+
out:
nfsd4_bump_seqid(cstate, status);
if (!cstate->replay_owner)
--
1.7.9.5


2013-04-09 23:58:22

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 10/10] nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED

From: "J. Bruce Fields" <[email protected]>

A 4.1 server must notify a client that has had any state revoked using
the SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag. The client can figure
out exactly which state is the problem using CHECK_STATEID and then free
it using FREE_STATEID. The status flag will be unset once all such
revoked stateids are freed.

Our server's only recallable state is delegations. So we keep with each
4.1 client a list of delegations that have timed out and been recalled,
but haven't yet been freed by FREE_STATEID.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 55 +++++++++++++++++++++++++++++++++++++++++++--------
fs/nfsd/state.h | 3 +++
2 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index add9721..032e024 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -445,7 +445,6 @@ static void unhash_stid(struct nfs4_stid *s)
static void
unhash_delegation(struct nfs4_delegation *dp)
{
- unhash_stid(&dp->dl_stid);
list_del_init(&dp->dl_perclnt);
spin_lock(&recall_lock);
list_del_init(&dp->dl_perfile);
@@ -455,9 +454,36 @@ unhash_delegation(struct nfs4_delegation *dp)
put_nfs4_file(dp->dl_file);
dp->dl_file = NULL;
remove_stid(&dp->dl_stid);
+}
+
+
+
+static void destroy_revoked_delegation(struct nfs4_delegation *dp)
+{
+ unhash_stid(&dp->dl_stid);
+ list_del_init(&dp->dl_recall_lru);
nfs4_put_delegation(dp);
}

+static void destroy_delegation(struct nfs4_delegation *dp)
+{
+ unhash_stid(&dp->dl_stid);
+ unhash_delegation(dp);
+ nfs4_put_delegation(dp);
+}
+
+static void revoke_delegation(struct nfs4_delegation *dp)
+{
+ struct nfs4_client *clp = dp->dl_stid.sc_client;
+
+ if (clp->cl_minorversion == 0)
+ destroy_delegation(dp);
+ else {
+ dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
+ list_add(&dp->dl_recall_lru, &clp->cl_revoked);
+ }
+}
+
/*
* SETCLIENTID state
*/
@@ -1114,7 +1140,7 @@ destroy_client(struct nfs4_client *clp)
spin_unlock(&recall_lock);
while (!list_empty(&reaplist)) {
dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
- unhash_delegation(dp);
+ destroy_delegation(dp);
}
while (!list_empty(&clp->cl_openowners)) {
oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
@@ -1310,6 +1336,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_lru);
INIT_LIST_HEAD(&clp->cl_callbacks);
+ INIT_LIST_HEAD(&clp->cl_revoked);
spin_lock_init(&clp->cl_lock);
nfsd4_init_callback(&clp->cl_cb_null);
clp->cl_time = get_seconds();
@@ -2171,6 +2198,8 @@ out:
default:
seq->status_flags = 0;
}
+ if (!list_empty(&clp->cl_revoked))
+ seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
out_no_session:
kfree(conn);
spin_unlock(&nn->client_lock);
@@ -3297,7 +3326,7 @@ nfs4_laundromat(struct nfsd_net *nn)
spin_unlock(&recall_lock);
list_for_each_safe(pos, next, &reaplist) {
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
- unhash_delegation(dp);
+ revoke_delegation(dp);
}
test_val = nn->nfsd4_lease;
list_for_each_safe(pos, next, &nn->close_lru) {
@@ -3459,6 +3488,8 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
switch (s->sc_type) {
case NFS4_DELEG_STID:
return nfs_ok;
+ case NFS4_REVOKED_DELEG_STID:
+ return nfserr_deleg_revoked;
case NFS4_OPEN_STID:
case NFS4_LOCK_STID:
ols = openlockstateid(s);
@@ -3602,6 +3633,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
stateid_t *stateid = &free_stateid->fr_stateid;
struct nfs4_stid *s;
+ struct nfs4_delegation *dp;
struct nfs4_client *cl = cstate->session->se_client;
__be32 ret = nfserr_bad_stateid;

@@ -3623,6 +3655,11 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
else
ret = nfserr_locks_held;
break;
+ case NFS4_REVOKED_DELEG_STID:
+ dp = delegstateid(s);
+ destroy_revoked_delegation(dp);
+ ret = nfs_ok;
+ break;
default:
ret = nfserr_bad_stateid;
}
@@ -3647,10 +3684,12 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
status = nfsd4_check_seqid(cstate, sop, seqid);
if (status)
return status;
- if (stp->st_stid.sc_type == NFS4_CLOSED_STID)
+ if (stp->st_stid.sc_type == NFS4_CLOSED_STID
+ || stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
/*
* "Closed" stateid's exist *only* to return
- * nfserr_replay_me from the previous step.
+ * nfserr_replay_me from the previous step, and
+ * revoked delegations are kept only for free_stateid.
*/
return nfserr_bad_stateid;
status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
@@ -3913,7 +3952,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (status)
goto out;

- unhash_delegation(dp);
+ destroy_delegation(dp);
out:
nfs4_unlock_state();

@@ -4763,7 +4802,7 @@ u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max)
spin_unlock(&recall_lock);

list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
- unhash_delegation(dp);
+ revoke_delegation(dp);

return count;
}
@@ -5018,7 +5057,7 @@ nfs4_state_shutdown_net(struct net *net)
spin_unlock(&recall_lock);
list_for_each_safe(pos, next, &reaplist) {
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
- unhash_delegation(dp);
+ destroy_delegation(dp);
}

nfsd4_client_tracking_exit(net);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 13ec485..274e2a1 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -79,6 +79,8 @@ struct nfs4_stid {
#define NFS4_DELEG_STID 4
/* For an open stateid kept around *only* to process close replays: */
#define NFS4_CLOSED_STID 8
+/* For a deleg stateid kept around only to process free_stateid's: */
+#define NFS4_REVOKED_DELEG_STID 16
unsigned char sc_type;
stateid_t sc_stateid;
struct nfs4_client *sc_client;
@@ -238,6 +240,7 @@ struct nfs4_client {
struct list_head cl_openowners;
struct idr cl_stateids; /* stateid lookup */
struct list_head cl_delegations;
+ struct list_head cl_revoked; /* unacknowledged, revoked 4.1 state */
struct list_head cl_lru; /* tail queue */
struct xdr_netobj cl_name; /* id generated by client */
nfs4_verifier cl_verifier; /* generated by client */
--
1.7.9.5


2013-04-09 23:58:20

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 08/10] nfsd4: check backchannel attributes on create_session

From: "J. Bruce Fields" <[email protected]>

Make sure the client gives us an adequate backchannel.

Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4callback.c | 25 +------------------------
fs/nfsd/nfs4state.c | 25 +++++++++++++++++++++++++
fs/nfsd/xdr4cb.h | 23 +++++++++++++++++++++++
include/linux/sunrpc/msg_prot.h | 3 +++
4 files changed, 52 insertions(+), 24 deletions(-)
create mode 100644 fs/nfsd/xdr4cb.h

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index be3ff0f..7f05cd1 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -37,6 +37,7 @@
#include "nfsd.h"
#include "state.h"
#include "netns.h"
+#include "xdr4cb.h"

#define NFSDDBG_FACILITY NFSDDBG_PROC

@@ -53,30 +54,6 @@ enum {
NFSPROC4_CLNT_CB_SEQUENCE,
};

-#define NFS4_MAXTAGLEN 20
-
-#define NFS4_enc_cb_null_sz 0
-#define NFS4_dec_cb_null_sz 0
-#define cb_compound_enc_hdr_sz 4
-#define cb_compound_dec_hdr_sz (3 + (NFS4_MAXTAGLEN >> 2))
-#define sessionid_sz (NFS4_MAX_SESSIONID_LEN >> 2)
-#define cb_sequence_enc_sz (sessionid_sz + 4 + \
- 1 /* no referring calls list yet */)
-#define cb_sequence_dec_sz (op_dec_sz + sessionid_sz + 4)
-
-#define op_enc_sz 1
-#define op_dec_sz 2
-#define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2))
-#define enc_stateid_sz (NFS4_STATEID_SIZE >> 2)
-#define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \
- cb_sequence_enc_sz + \
- 1 + enc_stateid_sz + \
- enc_nfs4_fh_sz)
-
-#define NFS4_dec_cb_recall_sz (cb_compound_dec_hdr_sz + \
- cb_sequence_dec_sz + \
- op_dec_sz)
-
struct nfs4_cb_compound_hdr {
/* args */
u32 ident; /* minorversion 0 only */
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 036d5f1..67017fc 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -42,6 +42,7 @@
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/sunrpc/addr.h>
#include "xdr4.h"
+#include "xdr4cb.h"
#include "vfs.h"
#include "current_stateid.h"

@@ -1794,6 +1795,27 @@ static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfs
return nfs_ok;
}

+static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
+{
+ ca->headerpadsz = 0;
+
+ /*
+ * These RPC_MAX_HEADER macros are overkill, especially since we
+ * don't even do gss on the backchannel yet. But this is still
+ * less than 1k. Tighten up this estimate in the unlikely event
+ * it turns out to be a problem for some client:
+ */
+ if (ca->maxreq_sz < NFS4_enc_cb_recall_sz + RPC_MAX_HEADER_WITH_AUTH)
+ return nfserr_toosmall;
+ if (ca->maxresp_sz < NFS4_dec_cb_recall_sz + RPC_MAX_REPHEADER_WITH_AUTH)
+ return nfserr_toosmall;
+ ca->maxresp_cached = 0;
+ if (ca->maxops < 2)
+ return nfserr_toosmall;
+
+ return nfs_ok;
+}
+
__be32
nfsd4_create_session(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
@@ -1812,6 +1834,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
if (status)
return status;
+ status = check_backchannel_attrs(&cr_ses->back_channel);
+ if (status)
+ return status;
status = nfserr_jukebox;
new = alloc_session(&cr_ses->fore_channel);
if (!new)
diff --git a/fs/nfsd/xdr4cb.h b/fs/nfsd/xdr4cb.h
new file mode 100644
index 0000000..c5c55df
--- /dev/null
+++ b/fs/nfsd/xdr4cb.h
@@ -0,0 +1,23 @@
+#define NFS4_MAXTAGLEN 20
+
+#define NFS4_enc_cb_null_sz 0
+#define NFS4_dec_cb_null_sz 0
+#define cb_compound_enc_hdr_sz 4
+#define cb_compound_dec_hdr_sz (3 + (NFS4_MAXTAGLEN >> 2))
+#define sessionid_sz (NFS4_MAX_SESSIONID_LEN >> 2)
+#define cb_sequence_enc_sz (sessionid_sz + 4 + \
+ 1 /* no referring calls list yet */)
+#define cb_sequence_dec_sz (op_dec_sz + sessionid_sz + 4)
+
+#define op_enc_sz 1
+#define op_dec_sz 2
+#define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2))
+#define enc_stateid_sz (NFS4_STATEID_SIZE >> 2)
+#define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \
+ cb_sequence_enc_sz + \
+ 1 + enc_stateid_sz + \
+ enc_nfs4_fh_sz)
+
+#define NFS4_dec_cb_recall_sz (cb_compound_dec_hdr_sz + \
+ cb_sequence_dec_sz + \
+ op_dec_sz)
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
index c68a147..aadc6a0 100644
--- a/include/linux/sunrpc/msg_prot.h
+++ b/include/linux/sunrpc/msg_prot.h
@@ -138,6 +138,9 @@ typedef __be32 rpc_fraghdr;
#define RPC_MAX_HEADER_WITH_AUTH \
(RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))

+#define RPC_MAX_REPHEADER_WITH_AUTH \
+ (RPC_REPHDRSIZE + (2 + RPC_MAX_AUTH_SIZE/4))
+
/*
* RFC1833/RFC3530 rpcbind (v3+) well-known netid's.
*/
--
1.7.9.5


2013-04-09 23:58:21

by J. Bruce Fields

[permalink] [raw]
Subject: [PATCH 05/10] nfsd4: don't close read-write opens too soon

From: "J. Bruce Fields" <[email protected]>

Don't actually close any opens until we don't need them at all.

This means being left with write access when it's not really necessary,
but that's better than putting a file that might still have posix locks
held on it, as we have been.

Reported-by: Toralf Förster <[email protected]>
Cc: [email protected]
Signed-off-by: J. Bruce Fields <[email protected]>
---
fs/nfsd/nfs4state.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ff1577d..7d2e3b5 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -307,13 +307,7 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
{
if (atomic_dec_and_test(&fp->fi_access[oflag])) {
nfs4_file_put_fd(fp, oflag);
- /*
- * It's also safe to get rid of the RDWR open *if*
- * we no longer have need of the other kind of access
- * or if we already have the other kind of open:
- */
- if (fp->fi_fds[1-oflag]
- || atomic_read(&fp->fi_access[1 - oflag]) == 0)
+ if (atomic_read(&fp->fi_access[1 - oflag]) == 0)
nfs4_file_put_fd(fp, O_RDWR);
}
}
--
1.7.9.5