Commit 45f3fae6 authored by Trond Myklebust's avatar Trond Myklebust

Setup code to tear down the NFSv4 state once we're done with a file.

parent 62175be2
......@@ -80,19 +80,6 @@ nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported,
cp->req_nops++;
}
static void
nfs4_setup_close(struct nfs4_compound *cp, nfs4_stateid stateid, u32 seqid)
{
struct nfs4_close *close = GET_OP(cp, close);
close->cl_stateid = stateid;
close->cl_seqid = seqid;
OPNUM(cp) = OP_CLOSE;
cp->req_nops++;
cp->renew_index = cp->req_nops;
}
static void
nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name,
struct iattr *sattr, struct nfs4_change_info *info)
......@@ -710,16 +697,44 @@ do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
return nfs4_call_compound(&compound, NULL, 0);
}
static int
do_close(struct nfs_server *server, struct nfs_fh *fhandle, u32 seqid, char *stateid)
/*
* It is possible for data to be read/written from a mem-mapped file
* after the sys_close call (which hits the vfs layer as a flush).
* This means that we can't safely call nfsv4 close on a file until
* the inode is cleared. This in turn means that we are not good
* NFSv4 citizens - we do not indicate to the server to update the file's
* share state even when we are done with one of the three share
* stateid's in the inode.
*/
int
nfs4_do_close(struct inode *inode, struct nfs4_shareowner *sp)
{
struct nfs4_compound compound;
struct nfs4_op ops[2];
int status = 0;
struct nfs_closeargs arg = {
.fh = NFS_FH(inode),
};
struct nfs_closeres res = {
.status = 0,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE],
.rpc_argp = &arg,
.rpc_resp = &res,
};
nfs4_setup_compound(&compound, ops, server, "close");
nfs4_setup_putfh(&compound, fhandle);
nfs4_setup_close(&compound, stateid, seqid);
return nfs4_call_compound(&compound, NULL, 0);
memcpy(arg.stateid, sp->so_stateid, sizeof(nfs4_stateid));
/* Serialization for the sequence id */
down(&sp->so_sema);
arg.seqid = sp->so_seqid,
status = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0);
/* hmm. we are done with the inode, and in the process of freeing
* the shareowner. we keep this around to process errors
*/
nfs4_increment_seqid(status, sp);
up(&sp->so_sema);
return status;
}
static int
......@@ -820,6 +835,12 @@ nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
return nfs4_call_compound(&compound, NULL, 0);
}
/*
* The file is not closed if it is opened due to the a request to change
* the size of the file. The open call will not be needed once the
* VFS layer lookup-intents are implemented.
* Close is called when the inode is destroyed.
*/
static int
nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
struct iattr *sattr)
......@@ -851,15 +872,12 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
*/
if (fattr->fileid != NFS_FILEID(inode)) {
printk(KERN_WARNING "nfs: raced in setattr, returning -EIO\n");
do_close(NFS_SERVER(inode), NFS_FH(inode), sp->so_seqid, sp->so_stateid);
return -EIO;
}
}
status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr,
fake == 1? zero_stateid: sp->so_stateid);
if (size_change)
do_close(NFS_SERVER(inode), NFS_FH(inode), sp->so_seqid, sp->so_stateid);
return status;
}
......@@ -1059,8 +1077,7 @@ nfs4_proc_write(struct inode *inode, struct rpc_cred *cred,
* conditions due to the lookup, create, and open VFS calls from sys_open()
* placed on the wire.
*
* Given the above sorry state of affairs, I'm simply sending an OPEN, a
* possible SETATTR, and then a CLOSE
* Given the above sorry state of affairs, I'm simply sending an OPEN.
* The file will be opened again in the subsequent VFS open call
* (nfs4_proc_file_open).
*
......
......@@ -124,7 +124,7 @@ nfs4_get_shareowner(struct inode *dir)
}
/*
* Called for each inode shareowner in nfs_clear_inode,
* Called for each non-null inode shareowner in nfs_clear_inode,
* or if nfs4_do_open fails.
*/
void
......@@ -132,6 +132,8 @@ nfs4_put_shareowner(struct inode *inode, struct nfs4_shareowner *sp)
{
if (!sp)
return;
if (sp->so_flags & O_ACCMODE)
nfs4_do_close(inode, sp);
kfree(sp);
}
......
......@@ -144,6 +144,13 @@ extern int nfs_stat_to_errno(int);
#define NFS4_dec_open_confirm_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
op_decode_hdr_maxsz + 4
#define NFS4_enc_close_sz compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
op_encode_hdr_maxsz + 5
#define NFS4_dec_close_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
op_decode_hdr_maxsz + 4
......@@ -378,14 +385,14 @@ encode_access(struct xdr_stream *xdr, struct nfs4_access *access)
}
static int
encode_close(struct xdr_stream *xdr, struct nfs4_close *close)
encode_close(struct xdr_stream *xdr, struct nfs_closeargs *arg)
{
uint32_t *p;
RESERVE_SPACE(8+sizeof(nfs4_stateid));
WRITE32(OP_CLOSE);
WRITE32(close->cl_seqid);
WRITEMEM(close->cl_stateid, sizeof(nfs4_stateid));
WRITE32(arg->seqid);
WRITEMEM(arg->stateid, sizeof(nfs4_stateid));
return 0;
}
......@@ -858,9 +865,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs
case OP_ACCESS:
status = encode_access(xdr, &cp->ops[i].u.access);
break;
case OP_CLOSE:
status = encode_close(xdr, &cp->ops[i].u.close);
break;
case OP_CREATE:
status = encode_create(xdr, &cp->ops[i].u.create);
break;
......@@ -940,6 +944,28 @@ nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *c
cp->timestamp = jiffies;
return status;
}
/*
* Encode a CLOSE request
*/
static int
nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
.nops = 2,
};
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh);
if(status)
goto out;
status = encode_close(&xdr, args);
out:
return status;
}
/*
* Encode an OPEN request
*/
......@@ -1229,7 +1255,7 @@ decode_access(struct xdr_stream *xdr, struct nfs4_access *access)
}
static int
decode_close(struct xdr_stream *xdr, struct nfs4_close *close)
decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
{
uint32_t *p;
int status;
......@@ -1238,7 +1264,7 @@ decode_close(struct xdr_stream *xdr, struct nfs4_close *close)
if (status)
return status;
READ_BUF(sizeof(nfs4_stateid));
COPYMEM(close->cl_stateid, sizeof(nfs4_stateid));
COPYMEM(res->stateid, sizeof(nfs4_stateid));
return 0;
}
......@@ -2076,9 +2102,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs
case OP_ACCESS:
status = decode_access(xdr, &op->u.access);
break;
case OP_CLOSE:
status = decode_close(xdr, &op->u.close);
break;
case OP_CREATE:
status = decode_create(xdr, &op->u.create);
break;
......@@ -2165,6 +2188,27 @@ nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_compound
return status;
}
/*
* Decode CLOSE response
*/
static int
nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
status = decode_compound_hdr(&xdr, &hdr);
if (status)
goto out;
status = decode_putfh(&xdr);
if (status)
goto out;
status = decode_close(&xdr, res);
out:
return status;
}
/*
* Decode OPEN response
......@@ -2374,6 +2418,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(COMMIT, enc_commit, dec_commit),
PROC(OPEN, enc_open, dec_open),
PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm),
PROC(CLOSE, enc_close, dec_close),
};
struct rpc_version nfs_version4 = {
......
......@@ -208,6 +208,7 @@ enum {
NFSPROC4_CLNT_COMMIT,
NFSPROC4_CLNT_OPEN,
NFSPROC4_CLNT_OPEN_CONFIRM,
NFSPROC4_CLNT_CLOSE,
};
#endif
......
......@@ -491,6 +491,7 @@ struct nfs4_shareowner {
/* nfs4proc.c */
extern int nfs4_proc_renew(struct nfs_server *server);
extern int nfs4_do_close(struct inode *inode, struct nfs4_shareowner *sp);
/* nfs4renewd.c */
extern int nfs4_init_renewd(struct nfs_server *server);
......
......@@ -131,6 +131,20 @@ struct nfs_open_confirmres {
nfs4_stateid stateid;
};
/*
* Arguments to the close call.
*/
struct nfs_closeargs {
struct nfs_fh * fh;
nfs4_stateid stateid;
__u32 seqid;
};
struct nfs_closeres {
__u32 status;
nfs4_stateid stateid;
};
/*
* Arguments to the read call.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment