NFSv4: Ensure we do not reuse open owner names
The NFSv4 spec is ambiguous about whether or not it is permissible to reuse open owner names, so play it safe. This patch adds a timestamp to the state_owner structure, and combines that with the IDA based uniquifier. Fixes a regression whereby the Linux server returns NFS4ERR_BAD_SEQID. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
98a2139f4f
commit
95b72eb0bd
@ -59,6 +59,7 @@ struct nfs_unique_id {
|
|||||||
|
|
||||||
#define NFS_SEQID_CONFIRMED 1
|
#define NFS_SEQID_CONFIRMED 1
|
||||||
struct nfs_seqid_counter {
|
struct nfs_seqid_counter {
|
||||||
|
ktime_t create_time;
|
||||||
int owner_id;
|
int owner_id;
|
||||||
int flags;
|
int flags;
|
||||||
u32 counter;
|
u32 counter;
|
||||||
|
@ -838,7 +838,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
|
|||||||
p->o_arg.open_flags = flags;
|
p->o_arg.open_flags = flags;
|
||||||
p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
|
p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
|
||||||
p->o_arg.clientid = server->nfs_client->cl_clientid;
|
p->o_arg.clientid = server->nfs_client->cl_clientid;
|
||||||
p->o_arg.id = sp->so_seqid.owner_id;
|
p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
|
||||||
|
p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
|
||||||
p->o_arg.name = &dentry->d_name;
|
p->o_arg.name = &dentry->d_name;
|
||||||
p->o_arg.server = server;
|
p->o_arg.server = server;
|
||||||
p->o_arg.bitmask = server->attr_bitmask;
|
p->o_arg.bitmask = server->attr_bitmask;
|
||||||
@ -1466,8 +1467,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
|
|||||||
goto unlock_no_action;
|
goto unlock_no_action;
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
/* Update sequence id. */
|
/* Update client id. */
|
||||||
data->o_arg.id = sp->so_seqid.owner_id;
|
|
||||||
data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
|
data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
|
||||||
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
|
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
|
||||||
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
|
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
|
||||||
|
@ -393,6 +393,7 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
|
|||||||
static void
|
static void
|
||||||
nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
|
nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
|
||||||
{
|
{
|
||||||
|
sc->create_time = ktime_get();
|
||||||
sc->flags = 0;
|
sc->flags = 0;
|
||||||
sc->counter = 0;
|
sc->counter = 0;
|
||||||
spin_lock_init(&sc->lock);
|
spin_lock_init(&sc->lock);
|
||||||
|
@ -74,7 +74,7 @@ static int nfs4_stat_to_errno(int);
|
|||||||
/* lock,open owner id:
|
/* lock,open owner id:
|
||||||
* we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2)
|
* we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2)
|
||||||
*/
|
*/
|
||||||
#define open_owner_id_maxsz (1 + 1 + 4)
|
#define open_owner_id_maxsz (1 + 2 + 1 + 1 + 2)
|
||||||
#define lock_owner_id_maxsz (1 + 1 + 4)
|
#define lock_owner_id_maxsz (1 + 1 + 4)
|
||||||
#define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
|
#define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
|
||||||
#define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2))
|
#define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2))
|
||||||
@ -1340,12 +1340,13 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
|
|||||||
*/
|
*/
|
||||||
encode_nfs4_seqid(xdr, arg->seqid);
|
encode_nfs4_seqid(xdr, arg->seqid);
|
||||||
encode_share_access(xdr, arg->fmode);
|
encode_share_access(xdr, arg->fmode);
|
||||||
p = reserve_space(xdr, 32);
|
p = reserve_space(xdr, 36);
|
||||||
p = xdr_encode_hyper(p, arg->clientid);
|
p = xdr_encode_hyper(p, arg->clientid);
|
||||||
*p++ = cpu_to_be32(20);
|
*p++ = cpu_to_be32(24);
|
||||||
p = xdr_encode_opaque_fixed(p, "open id:", 8);
|
p = xdr_encode_opaque_fixed(p, "open id:", 8);
|
||||||
*p++ = cpu_to_be32(arg->server->s_dev);
|
*p++ = cpu_to_be32(arg->server->s_dev);
|
||||||
xdr_encode_hyper(p, arg->id);
|
*p++ = cpu_to_be32(arg->id.uniquifier);
|
||||||
|
xdr_encode_hyper(p, arg->id.create_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
|
static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
|
||||||
|
@ -312,6 +312,11 @@ struct nfs4_layoutreturn {
|
|||||||
int rpc_status;
|
int rpc_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct stateowner_id {
|
||||||
|
__u64 create_time;
|
||||||
|
__u32 uniquifier;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arguments to the open call.
|
* Arguments to the open call.
|
||||||
*/
|
*/
|
||||||
@ -321,7 +326,7 @@ struct nfs_openargs {
|
|||||||
int open_flags;
|
int open_flags;
|
||||||
fmode_t fmode;
|
fmode_t fmode;
|
||||||
__u64 clientid;
|
__u64 clientid;
|
||||||
__u64 id;
|
struct stateowner_id id;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
struct iattr * attrs; /* UNCHECKED, GUARDED */
|
struct iattr * attrs; /* UNCHECKED, GUARDED */
|
||||||
|
Loading…
Reference in New Issue
Block a user