summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@fys.uio.no>2003-04-08 04:30:19 +0200
committerTrond Myklebust <trond.myklebust@fys.uio.no>2003-04-08 04:30:19 +0200
commitbe6c1a46a0609afffd8926a2f533158a8481689c (patch)
treefbb04bbf9781d99c37188f66f1f9cc0ecac0b202
parent45f3fae685e9579979b0dbed506c424688d72881 (diff)
Make NFSv4 'setattr()' method use the cached stateid if the file is
already open.
-rw-r--r--fs/nfs/nfs4proc.c104
-rw-r--r--fs/nfs/nfs4xdr.c77
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs_xdr.h11
4 files changed, 134 insertions, 59 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 98e7cc17329e..f302bd233380 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -462,18 +462,6 @@ nfs4_setup_savefh(struct nfs4_compound *cp)
}
static void
-nfs4_setup_setattr(struct nfs4_compound *cp, char *stateid, struct iattr *iap)
-{
- struct nfs4_setattr *setattr = GET_OP(cp, setattr);
-
- setattr->st_stateid = stateid;
- setattr->st_iap = iap;
-
- OPNUM(cp) = OP_SETATTR;
- cp->req_nops++;
-}
-
-static void
nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short port)
{
struct nfs4_setclientid *setclientid = GET_OP(cp, setclientid);
@@ -681,20 +669,39 @@ out:
return status;
}
-static int
-do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
- struct nfs_fh *fhandle, struct iattr *sattr, char *stateid)
-{
- struct nfs4_compound compound;
- struct nfs4_op ops[3];
- u32 bmres[2];
-
- fattr->valid = 0;
- nfs4_setup_compound(&compound, ops, server, "setattr");
- nfs4_setup_putfh(&compound, fhandle);
- nfs4_setup_setattr(&compound, stateid, sattr);
- nfs4_setup_getattr(&compound, fattr, bmres);
- return nfs4_call_compound(&compound, NULL, 0);
+int
+nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
+ struct nfs_fh *fhandle, struct iattr *sattr,
+ struct nfs4_shareowner *sp)
+{
+ u32 g_bmres[2];
+ struct nfs4_getattr getattr = {
+ .gt_bmval = nfs4_fattr_bitmap,
+ .gt_attrs = fattr,
+ .gt_bmres = g_bmres,
+ };
+ struct nfs_setattrargs arg = {
+ .fh = fhandle,
+ .iap = sattr,
+ .attr = &getattr,
+ };
+ struct nfs_setattrres res = {
+ .attr = &getattr,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+ .rpc_argp = &arg,
+ .rpc_resp = &res,
+ };
+
+ fattr->valid = 0;
+
+ if (sp)
+ memcpy(arg.stateid, sp->so_stateid, sizeof(nfs4_stateid));
+ else
+ memcpy(arg.stateid, zero_stateid, sizeof(nfs4_stateid));
+
+ return(rpc_call_sync(server->client, &msg, 0));
}
/*
@@ -839,7 +846,18 @@ nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
* 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.
+ * If we haven't opened the file for O_WRONLY, we
+ * need to in the size_change case to obtain a stateid.
+ *
+ * Got race?
+ * Because OPEN is always done by name in nfsv4, it is
+ * possible that we opened a different file by the same
+ * name. We can recognize this race condition, but we
+ * can't do anything about it besides returning an error.
+ *
+ * This will be fixed with VFS changes (lookup-intent).
*/
static int
nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
@@ -847,37 +865,31 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
{
struct inode * inode = dentry->d_inode;
int size_change = sattr->ia_valid & ATTR_SIZE;
- struct nfs_fh throwaway_fh;
struct nfs4_shareowner *sp = NULL;
- int status, fake = 1;
+ int status;
fattr->valid = 0;
if (size_change) {
+ if (NFS_I(inode)->wo_owner) {
+ /* file is already open for O_WRONLY */
+ sp = NFS_I(inode)->wo_owner;
+ goto no_open;
+ }
status = nfs4_do_open(dentry->d_parent->d_inode,
- &dentry->d_name,
- O_WRONLY, NULL, fattr,
- &throwaway_fh,&sp);
+ &dentry->d_name, O_WRONLY, NULL, fattr,
+ NULL, &sp);
if (status)
return status;
- fake = 0;
- /*
- * Because OPEN is always done by name in nfsv4, it is
- * possible that we opened a different file by the same
- * name. We can recognize this race condition, but we
- * can't do anything about it besides returning an error.
- *
- * XXX: Should we compare filehandles too, as in
- * nfs_find_actor()?
- */
+
if (fattr->fileid != NFS_FILEID(inode)) {
printk(KERN_WARNING "nfs: raced in setattr, returning -EIO\n");
return -EIO;
}
}
-
- status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr,
- fake == 1? zero_stateid: sp->so_stateid);
+no_open:
+ status = nfs4_do_setattr(NFS_SERVER(inode), fattr,
+ NFS_FH(inode), sattr, sp);
return status;
}
@@ -1097,8 +1109,8 @@ nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
status = nfs4_do_open(dir, name, oflags, sattr, fattr, fhandle, &sp);
if (!status) {
if (flags & O_EXCL) {
- status = do_setattr(NFS_SERVER(dir), fattr,
- fhandle, sattr, sp->so_stateid);
+ status = nfs4_do_setattr(NFS_SERVER(dir), fattr,
+ fhandle, sattr, sp);
/* XXX should i bother closing the file? */
}
}
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 7bd0e88ebd02..ef6e32ce91be 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -150,8 +150,14 @@ extern int nfs_stat_to_errno(int);
#define NFS4_dec_close_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
op_decode_hdr_maxsz + 4
-
-
+#define NFS4_enc_setattr_sz compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ op_encode_hdr_maxsz + 4 + \
+ nfs4_fattr_bitmap_maxsz + \
+ encode_getattr_maxsz
+#define NFS4_dec_setattr_sz compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ op_decode_hdr_maxsz + 3
static struct {
@@ -771,16 +777,16 @@ encode_savefh(struct xdr_stream *xdr)
}
static int
-encode_setattr(struct xdr_stream *xdr, struct nfs4_setattr *setattr)
+encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg)
{
int status;
uint32_t *p;
RESERVE_SPACE(4+sizeof(nfs4_stateid));
WRITE32(OP_SETATTR);
- WRITEMEM(setattr->st_stateid, sizeof(nfs4_stateid));
+ WRITEMEM(arg->stateid, sizeof(nfs4_stateid));
- if ((status = encode_attrs(xdr, setattr->st_iap)))
+ if ((status = encode_attrs(xdr, arg->iap)))
return status;
return 0;
@@ -907,9 +913,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs
case OP_SAVEFH:
status = encode_savefh(xdr);
break;
- case OP_SETATTR:
- status = encode_setattr(xdr, &cp->ops[i].u.setattr);
- break;
case OP_SETCLIENTID:
status = encode_setclientid(xdr, &cp->ops[i].u.setclientid);
break;
@@ -1062,6 +1065,31 @@ out:
}
/*
+ * Encode an SETATTR request
+ */
+static int
+nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 3,
+ };
+ 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_setattr(&xdr, args);
+ if(status)
+ goto out;
+ status = encode_getattr(&xdr, args->attr);
+out:
+ return status;
+}
+
+/*
* Encode a WRITE request
*/
static int
@@ -1991,7 +2019,7 @@ decode_savefh(struct xdr_stream *xdr)
}
static int
-decode_setattr(struct xdr_stream *xdr)
+decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
{
uint32_t *p;
uint32_t bmlen;
@@ -2144,9 +2172,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs
case OP_SAVEFH:
status = decode_savefh(xdr);
break;
- case OP_SETATTR:
- status = decode_setattr(xdr);
- break;
case OP_SETCLIENTID:
status = decode_setclientid(xdr, &op->u.setclientid);
break;
@@ -2274,6 +2299,31 @@ out:
return status;
}
+/*
+ * Decode SETATTR response
+ */
+static int
+nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *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_setattr(&xdr, res);
+ if (status)
+ goto out;
+ status = decode_getattr(&xdr, res->attr);
+out:
+ return status;
+}
+
/*
* Decode Read response
@@ -2418,7 +2468,8 @@ 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),
+ PROC(CLOSE, enc_close, dec_close),
+ PROC(SETATTR, enc_setattr, dec_setattr),
};
struct rpc_version nfs_version4 = {
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index ace7f169b5dc..de82796383bf 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -209,6 +209,7 @@ enum {
NFSPROC4_CLNT_OPEN,
NFSPROC4_CLNT_OPEN_CONFIRM,
NFSPROC4_CLNT_CLOSE,
+ NFSPROC4_CLNT_SETATTR,
};
#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 1b1db6599e6e..7c37e245e732 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -241,6 +241,17 @@ struct nfs_renameargs {
unsigned int tolen;
};
+struct nfs_setattrargs {
+ struct nfs_fh * fh;
+ nfs4_stateid stateid;
+ struct iattr * iap;
+ struct nfs4_getattr * attr;
+};
+
+struct nfs_setattrres {
+ struct nfs4_getattr * attr;
+};
+
struct nfs_linkargs {
struct nfs_fh * fromfh;
struct nfs_fh * tofh;