diff -u --recursive --new-file linux-2.5.59-03-nfsv4-closestate/fs/nfs/nfs4proc.c linux-2.5.59-04-nfsv4-setattrstate/fs/nfs/nfs4proc.c --- linux-2.5.59-03-nfsv4-closestate/fs/nfs/nfs4proc.c 2003-01-17 14:16:07.000000000 +0100 +++ linux-2.5.59-04-nfsv4-setattrstate/fs/nfs/nfs4proc.c 2003-01-17 14:16:31.000000000 +0100 @@ -462,18 +462,6 @@ } 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); @@ -677,20 +665,46 @@ 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]; +int +nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, + struct nfs_fh *fhandle, struct iattr *sattr, + struct nfs4_shareowner *sp) +{ + u32 s_bmres[2]; + u32 g_bmres[2]; + struct nfs_fattr r_fattr; + struct nfs4_getattr a_getattr = { + .gt_bmval = nfs4_fattr_bitmap, + .gt_attrs = fattr, + .gt_bmres = g_bmres, + }; + struct nfs4_getattr r_getattr = { + .gt_bmval = nfs4_fattr_bitmap, + .gt_attrs = &r_fattr, + .gt_bmres = s_bmres, + }; + struct nfs_setattrargs arg = { + .fh = fhandle, + .iap = sattr, + .attr = &a_getattr, + }; + struct nfs_setattrres res ={ + .attr = &r_getattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], + .rpc_argp = &arg, + .rpc_resp = &res, + }; - 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); + 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)); } /* @@ -834,46 +848,52 @@ * 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 NFS4_SHARE_ACCESS_WRITE, 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, - struct iattr *sattr) + struct iattr *sattr) { - 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; - - fattr->valid = 0; - - if (size_change) { - status = nfs4_do_open(dentry->d_parent->d_inode, - &dentry->d_name, - NFS4_SHARE_ACCESS_WRITE, NULL, fattr, - &throwaway_fh,&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); - return status; + struct inode * inode = dentry->d_inode; + int size_change = sattr->ia_valid & ATTR_SIZE; + struct nfs4_shareowner *sp = NULL; + int status; + + fattr->valid = 0; + + if (size_change) { + if(NFS_I(inode)->wo_owner) { + /* file is already open for NFS4_SHARE_ACCESS_WRITE */ + sp = NFS_I(inode)->wo_owner; + goto no_open; + } + status = nfs4_do_open(dentry->d_parent->d_inode, + &dentry->d_name, + NFS4_SHARE_ACCESS_WRITE, NULL, fattr, + NULL, &sp); + if (status) + return status; + + if (fattr->fileid != NFS_FILEID(inode)) { + printk(KERN_WARNING "nfs: raced in setattr, returning -EIO\n"); + return -EIO; + } + } +no_open: + status = nfs4_do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), + sattr, sp); + return status; } static int @@ -1092,8 +1112,8 @@ 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 -u --recursive --new-file linux-2.5.59-03-nfsv4-closestate/fs/nfs/nfs4xdr.c linux-2.5.59-04-nfsv4-setattrstate/fs/nfs/nfs4xdr.c --- linux-2.5.59-03-nfsv4-closestate/fs/nfs/nfs4xdr.c 2003-01-17 14:16:07.000000000 +0100 +++ linux-2.5.59-04-nfsv4-setattrstate/fs/nfs/nfs4xdr.c 2003-01-17 14:16:31.000000000 +0100 @@ -156,8 +156,14 @@ #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 { @@ -768,16 +774,16 @@ } 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; @@ -904,9 +910,6 @@ 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; @@ -1059,6 +1062,31 @@ } /* + * 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 @@ -1987,7 +2015,7 @@ } static int -decode_setattr(struct xdr_stream *xdr) +decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) { uint32_t *p; uint32_t bmlen; @@ -2140,9 +2168,6 @@ 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; @@ -2270,6 +2295,31 @@ 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 @@ -2417,7 +2467,8 @@ 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 -u --recursive --new-file linux-2.5.59-03-nfsv4-closestate/include/linux/nfs4.h linux-2.5.59-04-nfsv4-setattrstate/include/linux/nfs4.h --- linux-2.5.59-03-nfsv4-closestate/include/linux/nfs4.h 2003-01-17 14:16:07.000000000 +0100 +++ linux-2.5.59-04-nfsv4-setattrstate/include/linux/nfs4.h 2003-01-17 14:16:31.000000000 +0100 @@ -209,6 +209,7 @@ NFSPROC4_CLNT_OPEN, NFSPROC4_CLNT_OPEN_CONFIRM, NFSPROC4_CLNT_CLOSE, + NFSPROC4_CLNT_SETATTR, }; #endif diff -u --recursive --new-file linux-2.5.59-03-nfsv4-closestate/include/linux/nfs_xdr.h linux-2.5.59-04-nfsv4-setattrstate/include/linux/nfs_xdr.h --- linux-2.5.59-03-nfsv4-closestate/include/linux/nfs_xdr.h 2003-01-17 14:16:07.000000000 +0100 +++ linux-2.5.59-04-nfsv4-setattrstate/include/linux/nfs_xdr.h 2003-01-17 14:16:31.000000000 +0100 @@ -241,6 +241,17 @@ 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;