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, ...@@ -80,19 +80,6 @@ nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported,
cp->req_nops++; 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 static void
nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name, nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name,
struct iattr *sattr, struct nfs4_change_info *info) struct iattr *sattr, struct nfs4_change_info *info)
...@@ -710,16 +697,44 @@ do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, ...@@ -710,16 +697,44 @@ do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
return nfs4_call_compound(&compound, NULL, 0); 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; int status = 0;
struct nfs4_op ops[2]; struct nfs_closeargs arg = {
.fh = NFS_FH(inode),
nfs4_setup_compound(&compound, ops, server, "close"); };
nfs4_setup_putfh(&compound, fhandle); struct nfs_closeres res = {
nfs4_setup_close(&compound, stateid, seqid); .status = 0,
return nfs4_call_compound(&compound, NULL, 0); };
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE],
.rpc_argp = &arg,
.rpc_resp = &res,
};
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 static int
...@@ -820,6 +835,12 @@ nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) ...@@ -820,6 +835,12 @@ nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
return nfs4_call_compound(&compound, NULL, 0); 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 static int
nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
struct iattr *sattr) struct iattr *sattr)
...@@ -851,15 +872,12 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, ...@@ -851,15 +872,12 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
*/ */
if (fattr->fileid != NFS_FILEID(inode)) { if (fattr->fileid != NFS_FILEID(inode)) {
printk(KERN_WARNING "nfs: raced in setattr, returning -EIO\n"); 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; return -EIO;
} }
} }
status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr, status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr,
fake == 1? zero_stateid: sp->so_stateid); 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; return status;
} }
...@@ -1059,8 +1077,7 @@ nfs4_proc_write(struct inode *inode, struct rpc_cred *cred, ...@@ -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() * conditions due to the lookup, create, and open VFS calls from sys_open()
* placed on the wire. * placed on the wire.
* *
* Given the above sorry state of affairs, I'm simply sending an OPEN, a * Given the above sorry state of affairs, I'm simply sending an OPEN.
* possible SETATTR, and then a CLOSE
* The file will be opened again in the subsequent VFS open call * The file will be opened again in the subsequent VFS open call
* (nfs4_proc_file_open). * (nfs4_proc_file_open).
* *
......
...@@ -124,7 +124,7 @@ nfs4_get_shareowner(struct inode *dir) ...@@ -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. * or if nfs4_do_open fails.
*/ */
void void
...@@ -132,6 +132,8 @@ nfs4_put_shareowner(struct inode *inode, struct nfs4_shareowner *sp) ...@@ -132,6 +132,8 @@ nfs4_put_shareowner(struct inode *inode, struct nfs4_shareowner *sp)
{ {
if (!sp) if (!sp)
return; return;
if (sp->so_flags & O_ACCMODE)
nfs4_do_close(inode, sp);
kfree(sp); kfree(sp);
} }
......
...@@ -144,6 +144,13 @@ extern int nfs_stat_to_errno(int); ...@@ -144,6 +144,13 @@ extern int nfs_stat_to_errno(int);
#define NFS4_dec_open_confirm_sz compound_decode_hdr_maxsz + \ #define NFS4_dec_open_confirm_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \ decode_putfh_maxsz + \
op_decode_hdr_maxsz + 4 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) ...@@ -378,14 +385,14 @@ encode_access(struct xdr_stream *xdr, struct nfs4_access *access)
} }
static int 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; uint32_t *p;
RESERVE_SPACE(8+sizeof(nfs4_stateid)); RESERVE_SPACE(8+sizeof(nfs4_stateid));
WRITE32(OP_CLOSE); WRITE32(OP_CLOSE);
WRITE32(close->cl_seqid); WRITE32(arg->seqid);
WRITEMEM(close->cl_stateid, sizeof(nfs4_stateid)); WRITEMEM(arg->stateid, sizeof(nfs4_stateid));
return 0; return 0;
} }
...@@ -858,9 +865,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs ...@@ -858,9 +865,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs
case OP_ACCESS: case OP_ACCESS:
status = encode_access(xdr, &cp->ops[i].u.access); status = encode_access(xdr, &cp->ops[i].u.access);
break; break;
case OP_CLOSE:
status = encode_close(xdr, &cp->ops[i].u.close);
break;
case OP_CREATE: case OP_CREATE:
status = encode_create(xdr, &cp->ops[i].u.create); status = encode_create(xdr, &cp->ops[i].u.create);
break; break;
...@@ -940,6 +944,28 @@ nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *c ...@@ -940,6 +944,28 @@ nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *c
cp->timestamp = jiffies; cp->timestamp = jiffies;
return status; 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 * Encode an OPEN request
*/ */
...@@ -1229,7 +1255,7 @@ decode_access(struct xdr_stream *xdr, struct nfs4_access *access) ...@@ -1229,7 +1255,7 @@ decode_access(struct xdr_stream *xdr, struct nfs4_access *access)
} }
static int 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; uint32_t *p;
int status; int status;
...@@ -1238,7 +1264,7 @@ decode_close(struct xdr_stream *xdr, struct nfs4_close *close) ...@@ -1238,7 +1264,7 @@ decode_close(struct xdr_stream *xdr, struct nfs4_close *close)
if (status) if (status)
return status; return status;
READ_BUF(sizeof(nfs4_stateid)); READ_BUF(sizeof(nfs4_stateid));
COPYMEM(close->cl_stateid, sizeof(nfs4_stateid)); COPYMEM(res->stateid, sizeof(nfs4_stateid));
return 0; return 0;
} }
...@@ -2076,9 +2102,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs ...@@ -2076,9 +2102,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs
case OP_ACCESS: case OP_ACCESS:
status = decode_access(xdr, &op->u.access); status = decode_access(xdr, &op->u.access);
break; break;
case OP_CLOSE:
status = decode_close(xdr, &op->u.close);
break;
case OP_CREATE: case OP_CREATE:
status = decode_create(xdr, &op->u.create); status = decode_create(xdr, &op->u.create);
break; break;
...@@ -2165,6 +2188,27 @@ nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_compound ...@@ -2165,6 +2188,27 @@ nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_compound
return status; 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 * Decode OPEN response
...@@ -2374,6 +2418,7 @@ struct rpc_procinfo nfs4_procedures[] = { ...@@ -2374,6 +2418,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(COMMIT, enc_commit, dec_commit), PROC(COMMIT, enc_commit, dec_commit),
PROC(OPEN, enc_open, dec_open), PROC(OPEN, enc_open, dec_open),
PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm), PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm),
PROC(CLOSE, enc_close, dec_close),
}; };
struct rpc_version nfs_version4 = { struct rpc_version nfs_version4 = {
......
...@@ -208,6 +208,7 @@ enum { ...@@ -208,6 +208,7 @@ enum {
NFSPROC4_CLNT_COMMIT, NFSPROC4_CLNT_COMMIT,
NFSPROC4_CLNT_OPEN, NFSPROC4_CLNT_OPEN,
NFSPROC4_CLNT_OPEN_CONFIRM, NFSPROC4_CLNT_OPEN_CONFIRM,
NFSPROC4_CLNT_CLOSE,
}; };
#endif #endif
......
...@@ -491,6 +491,7 @@ struct nfs4_shareowner { ...@@ -491,6 +491,7 @@ struct nfs4_shareowner {
/* nfs4proc.c */ /* nfs4proc.c */
extern int nfs4_proc_renew(struct nfs_server *server); extern int nfs4_proc_renew(struct nfs_server *server);
extern int nfs4_do_close(struct inode *inode, struct nfs4_shareowner *sp);
/* nfs4renewd.c */ /* nfs4renewd.c */
extern int nfs4_init_renewd(struct nfs_server *server); extern int nfs4_init_renewd(struct nfs_server *server);
......
...@@ -131,6 +131,20 @@ struct nfs_open_confirmres { ...@@ -131,6 +131,20 @@ struct nfs_open_confirmres {
nfs4_stateid stateid; 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. * 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