diff options
| author | Trond Myklebust <trond.myklebust@fys.uio.no> | 2003-04-08 04:30:19 +0200 |
|---|---|---|
| committer | Trond Myklebust <trond.myklebust@fys.uio.no> | 2003-04-08 04:30:19 +0200 |
| commit | be6c1a46a0609afffd8926a2f533158a8481689c (patch) | |
| tree | fbb04bbf9781d99c37188f66f1f9cc0ecac0b202 | |
| parent | 45f3fae685e9579979b0dbed506c424688d72881 (diff) | |
Make NFSv4 'setattr()' method use the cached stateid if the file is
already open.
| -rw-r--r-- | fs/nfs/nfs4proc.c | 104 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 77 | ||||
| -rw-r--r-- | include/linux/nfs4.h | 1 | ||||
| -rw-r--r-- | include/linux/nfs_xdr.h | 11 |
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; |
