summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@fys.uio.no>2003-04-08 04:27:37 +0200
committerTrond Myklebust <trond.myklebust@fys.uio.no>2003-04-08 04:27:37 +0200
commit45f3fae685e9579979b0dbed506c424688d72881 (patch)
treeeef8b81a6e74125a4c8b93b6b2fcf0372dc46075
parent62175be2bd850d3c2db5065fb3ef4dff3272c068 (diff)
Setup code to tear down the NFSv4 state once we're done with a file.
-rw-r--r--fs/nfs/nfs4proc.c71
-rw-r--r--fs/nfs/nfs4state.c4
-rw-r--r--fs/nfs/nfs4xdr.c67
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nfs_xdr.h14
6 files changed, 119 insertions, 39 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 15ce5d40f2c2..98e7cc17329e 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -81,19 +81,6 @@ nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported,
}
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];
-
- 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);
+ 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,
+ };
+
+ 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).
*
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 059880274526..8243f6d7398d 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -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);
}
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 319d16b0bd01..7bd0e88ebd02 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -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;
@@ -941,6 +945,28 @@ nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *c
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
*/
static int
@@ -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 @@ out:
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 = {
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 02c77391d6f8..ace7f169b5dc 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -208,6 +208,7 @@ enum {
NFSPROC4_CLNT_COMMIT,
NFSPROC4_CLNT_OPEN,
NFSPROC4_CLNT_OPEN_CONFIRM,
+ NFSPROC4_CLNT_CLOSE,
};
#endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 7d53fd8a8710..3d7525998534 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -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);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 2d1544931139..1b1db6599e6e 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -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.