Date: Tue, 24 Apr 2012 00:13:59 +0000 (UTC) From: Rick Macklem <rmacklem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r234626 - in projects/nfsv4.1-client/sys/fs: nfs nfsclient Message-ID: <201204240013.q3O0Dxhj021779@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rmacklem Date: Tue Apr 24 00:13:59 2012 New Revision: 234626 URL: http://svn.freebsd.org/changeset/base/234626 Log: Fix up layout recall, layout commit and layout return so that they seem to work ok. I'm still not clear w.r.t. exactly what RFC5661 requires them to do, so much more testing will be needed. Modified: projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clbio.c projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clstate.c projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clvnops.c projects/nfsv4.1-client/sys/fs/nfsclient/nfsnode.h Modified: projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h ============================================================================== --- projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h Mon Apr 23 23:57:24 2012 (r234625) +++ projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h Tue Apr 24 00:13:59 2012 (r234626) @@ -450,11 +450,12 @@ int nfsrpc_layoutget(struct nfsmount *, struct ucred *, NFSPROC_T *, void *); int nfsrpc_getdeviceinfo(struct nfsmount *, uint8_t *, int, uint32_t *, struct nfscldevinfo **, struct ucred *, NFSPROC_T *); -int nfsrpc_layoutcommit(vnode_t, off_t, uint64_t, int, nfsv4stateid_t *, int, - off_t, int, struct timespec, int, int, uint8_t *, int *, uint64_t *, +int nfsrpc_layoutcommit(struct nfsmount *, uint8_t *, int, int, + uint64_t, uint64_t, nfsv4stateid_t *, int, int, uint8_t *, struct ucred *, NFSPROC_T *, void *); -int nfsrpc_layoutreturn(vnode_t, int, int, int, int, off_t, uint64_t, - nfsv4stateid_t *, int, uint32_t *, struct ucred *, NFSPROC_T *, void *); +int nfsrpc_layoutreturn(struct nfsmount *, uint8_t *, int, int, int, uint32_t, + int, uint64_t, uint64_t, nfsv4stateid_t *, int, uint32_t *, struct ucred *, + NFSPROC_T *, void *); int nfsrpc_reclaimcomplete(struct nfsmount *, struct ucred *, NFSPROC_T *); int nfscl_doiods(vnode_t, struct uio *, int *, int *, uint32_t, struct ucred *, NFSPROC_T *); @@ -520,17 +521,21 @@ void nfscl_deleggetmodtime(vnode_t, stru int nfscl_tryclose(struct nfsclopen *, struct ucred *, struct nfsmount *, NFSPROC_T *); void nfscl_cleanup(NFSPROC_T *); -int nfscl_layout(struct nfsmount *, u_int8_t *, int, nfsv4stateid_t *, int, - struct nfsclflayouthead *, struct nfscllayout **, struct ucred *, +int nfscl_layout(struct nfsmount *, vnode_t, u_int8_t *, int, nfsv4stateid_t *, + int, struct nfsclflayouthead *, struct nfscllayout **, struct ucred *, NFSPROC_T *); -struct nfscllayout *nfscl_getlayout(struct nfsclclient *, uint8_t *, int); +struct nfscllayout *nfscl_getlayout(struct nfsclclient *, uint8_t *, int, + int *); void nfscl_rellayout(struct nfscllayout *); -struct nfscldevinfo *nfscl_getdevinfo(struct nfsclclient *, uint8_t *); +struct nfscldevinfo *nfscl_getdevinfo(struct nfsclclient *, uint8_t *, + struct nfscldevinfo *); void nfscl_reldevinfo(struct nfscldevinfo *); -void nfscl_adddevinfo(struct nfsmount *, struct nfscldevinfo *); +int nfscl_adddevinfo(struct nfsmount *, struct nfscldevinfo *, + struct nfsclflayout *); void nfscl_freelayout(struct nfscllayout *); void nfscl_freeflayout(struct nfsclflayout *); void nfscl_freedevinfo(struct nfscldevinfo *); +int nfscl_layoutcommit(vnode_t, NFSPROC_T *); /* nfs_clport.c */ int nfscl_nget(mount_t, vnode_t, struct nfsfh *, Modified: projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h ============================================================================== --- projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h Mon Apr 23 23:57:24 2012 (r234625) +++ projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h Tue Apr 24 00:13:59 2012 (r234626) @@ -43,18 +43,14 @@ LIST_HEAD(nfscldeleghash, nfscldeleg); TAILQ_HEAD(nfscllayouthead, nfscllayout); LIST_HEAD(nfscllayouthash, nfscllayout); LIST_HEAD(nfsclflayouthead, nfsclflayout); -TAILQ_HEAD(nfscldevinfohead, nfscldevinfo); -LIST_HEAD(nfscldevinfohash, nfscldevinfo); +LIST_HEAD(nfscldevinfohead, nfscldevinfo); +LIST_HEAD(nfsclrecalllayouthead, nfsclrecalllayout); #define NFSCLDELEGHASHSIZE 256 #define NFSCLDELEGHASH(c, f, l) \ (&((c)->nfsc_deleghash[ncl_hash((f), (l)) % NFSCLDELEGHASHSIZE])) #define NFSCLLAYOUTHASHSIZE 256 #define NFSCLLAYOUTHASH(c, f, l) \ (&((c)->nfsc_layouthash[ncl_hash((f), (l)) % NFSCLLAYOUTHASHSIZE])) -#define NFSCLDEVINFOHASHSIZE 16 -#define NFSCLDEVINFOHASH(c, f) \ - (&((c)->nfsc_devinfohash[ncl_hash((f), NFSX_V4DEVICEID) % \ - NFSCLDEVINFOHASHSIZE])) /* Structure for NFSv4.1 session stuff. */ struct nfsclsession { @@ -100,7 +96,6 @@ struct nfsclclient { struct nfscllayouthead nfsc_layout; struct nfscllayouthash nfsc_layouthash[NFSCLLAYOUTHASHSIZE]; struct nfscldevinfohead nfsc_devinfo; - struct nfscldevinfohash nfsc_devinfohash[NFSCLDEVINFOHASHSIZE]; struct nfsv4lock nfsc_lock; struct proc *nfsc_renewthread; struct nfsmount *nfsc_nmp; @@ -234,16 +229,31 @@ struct nfscllayout { TAILQ_ENTRY(nfscllayout) nfsly_list; LIST_ENTRY(nfscllayout) nfsly_hash; nfsv4stateid_t nfsly_stateid; + uint64_t nfsly_filesid[2]; struct nfsclflayouthead nfsly_flayread; struct nfsclflayouthead nfsly_flayrw; + struct nfsclrecalllayouthead nfsly_recall; + time_t nfsly_timestamp; struct nfsclclient *nfsly_clp; uint32_t nfsly_refcnt; - uint16_t nfsly_retonclose; + uint16_t nfsly_flags; uint16_t nfsly_fhlen; uint8_t nfsly_fh[1]; }; /* + * Flags for nfsly_flags. + */ +#define NFSLY_FILES 0x0001 +#define NFSLY_BLOCK 0x0002 +#define NFSLY_OBJECT 0x0004 +#define NFSLY_RECALL 0x0008 +#define NFSLY_RECALLFILE 0x0010 +#define NFSLY_RECALLFSID 0x0020 +#define NFSLY_RECALLALL 0x0040 +#define NFSLY_RETONCLOSE 0x0080 + +/* * MALLOC'd to the correct length to accommodate the file handle list. * These hang off of nfsly_flayread and nfsly_flayrw, sorted in increasing * offset order. @@ -256,14 +266,34 @@ struct nfsclflayout { uint64_t nfsfl_off; uint64_t nfsfl_end; uint64_t nfsfl_patoff; + struct nfscldevinfo *nfsfl_devp; uint32_t nfsfl_iomode; uint32_t nfsfl_util; uint32_t nfsfl_stripe1; - uint32_t nfsfl_fhcnt; + uint16_t nfsfl_flags; + uint16_t nfsfl_fhcnt; struct nfsfh *nfsfl_fh[1]; /* FH list for DS */ }; /* + * Flags for nfsfl_flags. + */ +#define NFSFL_RECALL 0x0001 /* File layout has been recalled */ +#define NFSFL_WRITTEN 0x0002 /* Has been used to write to a DS. */ + +/* + * Structure that is used to store a LAYOUTRECALL. + */ +struct nfsclrecalllayout { + LIST_ENTRY(nfsclrecalllayout) nfsrecly_list; + uint64_t nfsrecly_off; + uint64_t nfsrecly_len; + int nfsrecly_recalltype; + uint32_t nfsrecly_iomode; + uint32_t nfsrecly_stateseqid; +}; + +/* * Stores the NFSv4.1 Device Info. Malloc'd to the correct length to * store the list of network connections and list of indices. * nfsdi_data[] is allocated the following way: @@ -273,11 +303,11 @@ struct nfsclflayout { * indices select which address.) */ struct nfscldevinfo { - TAILQ_ENTRY(nfscldevinfo) nfsdi_list; - LIST_ENTRY(nfscldevinfo) nfsdi_hash; + LIST_ENTRY(nfscldevinfo) nfsdi_list; uint8_t nfsdi_deviceid[NFSX_V4DEVICEID]; struct nfsclclient *nfsdi_clp; uint32_t nfsdi_refcnt; + uint32_t nfsdi_layoutrefs; uint16_t nfsdi_stripecnt; uint16_t nfsdi_addrcnt; struct nfsclds *nfsdi_data[0]; Modified: projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clbio.c ============================================================================== --- projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clbio.c Mon Apr 23 23:57:24 2012 (r234625) +++ projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clbio.c Tue Apr 24 00:13:59 2012 (r234626) @@ -1343,6 +1343,8 @@ ncl_vinvalbuf(struct vnode *vp, int flag goto out; error = vinvalbuf(vp, flags, 0, slptimeo); } + if (NFSHASPNFS(nmp)) + nfscl_layoutcommit(vp, td); mtx_lock(&np->n_mtx); if (np->n_directio_asyncwr == 0) np->n_flag &= ~NMODIFIED; Modified: projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c ============================================================================== --- projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c Mon Apr 23 23:57:24 2012 (r234625) +++ projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c Tue Apr 24 00:13:59 2012 (r234626) @@ -98,8 +98,9 @@ static int nfsrpc_locku(struct nfsrv_des u_int32_t, struct ucred *, NFSPROC_T *, int); static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, struct acl *, nfsv4stateid_t *, void *); -static int nfsrpc_getlayout(struct nfsmount *, struct nfsfh *, int, uint32_t *, - nfsv4stateid_t *, struct ucred *, NFSPROC_T *); +static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int, + uint32_t *, nfsv4stateid_t *, struct nfscllayout **, struct ucred *, + NFSPROC_T *); static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_storage *, struct nfsclds **, NFSPROC_T *); static void nfscl_initsessionslots(struct nfsclsession *); @@ -253,8 +254,6 @@ nfsrpc_open(vnode_t vp, int amode, struc struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); u_int32_t mode, clidrev; int ret, newone, error, expireret = 0, retrycnt; - int iomode; - nfsv4stateid_t stateid; /* * For NFSv4, Open Ops are only done on Regular Files. @@ -262,13 +261,10 @@ nfsrpc_open(vnode_t vp, int amode, struc if (vnode_vtype(vp) != VREG) return (0); mode = 0; - iomode = NFSLAYOUTIOMODE_READ; if (amode & FREAD) mode |= NFSV4OPEN_ACCESSREAD; - if (amode & FWRITE) { + if (amode & FWRITE) mode |= NFSV4OPEN_ACCESSWRITE; - iomode = NFSLAYOUTIOMODE_RW; - } nfhp = np->n_fhp; retrycnt = 0; @@ -320,17 +316,6 @@ else printf(" fhl=0\n"); op->nfso_own->nfsow_clp, nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); } - - /* Try and get a Layout, if it is supported. */ - if (error == 0 && NFSHASPNFS(nmp) && - nfscl_enablecallb != 0 && nfs_numnfscbd > 0) { - stateid.seqid = op->nfso_stateid.seqid; - stateid.other[0] = op->nfso_stateid.other[0]; - stateid.other[1] = op->nfso_stateid.other[1]; - stateid.other[2] = op->nfso_stateid.other[2]; - (void)nfsrpc_getlayout(nmp, nfhp, iomode, - NULL, &stateid, cred, p); - } } else { error = EIO; } @@ -4450,9 +4435,10 @@ printf("servlen=%d\n", len); dsp->nfsclds_sess.nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); v41flags = fxdr_unsigned(uint32_t, *tl); -printf("v41fl=0x%x\n", v41flags); +printf("v41fl=0x%x nmfl=0x%x\n", v41flags, nmp->nm_flag); if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 && NFSHASPNFSOPT(nmp)) { +printf("set PNFS\n"); NFSLOCKMNT(nmp); nmp->nm_state |= NFSSTA_PNFS; NFSUNLOCKMNT(nmp); @@ -4651,7 +4637,8 @@ nfsrpc_layoutget(struct nfsmount *nmp, u tl += 2; txdr_hyper(minlen, tl); tl += 2; - *tl++ = stateidp->seqid; + *tl++ = txdr_unsigned(stateidp->seqid); +printf("layget seq=%d\n", stateidp->seqid); *tl++ = stateidp->other[0]; *tl++ = stateidp->other[1]; *tl++ = stateidp->other[2]; @@ -4667,8 +4654,8 @@ nfsrpc_layoutget(struct nfsmount *nmp, u *retonclosep = 1; else *retonclosep = 0; -printf("retonclose=%d\n", *retonclosep); - stateidp->seqid = *tl++; + stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); +printf("retoncls=%d stseq=%d\n", *retonclosep, stateidp->seqid); stateidp->other[0] = *tl++; stateidp->other[1] = *tl++; stateidp->other[2] = *tl++; @@ -4698,6 +4685,7 @@ printf("fhcnt=%d\n", fhcnt); else flp = malloc(sizeof(*flp), M_NFSFLAYOUT, M_WAITOK); + flp->nfsfl_flags = 0; flp->nfsfl_fhcnt = 0; flp->nfsfl_off = fxdr_hyper(tl); tl += 2; retlen = fxdr_hyper(tl); tl += 2; @@ -4934,21 +4922,20 @@ nfsmout: * Do the NFSv4.1 LayoutCommit. */ int -nfsrpc_layoutcommit(vnode_t vp, off_t offset, uint64_t len, int reclaim, - nfsv4stateid_t *stateidp, int newoff, off_t newoffset, int newtime, - struct timespec newtimespec, int layouttype, int layoutupdatecnt, - uint8_t *layp, int *sizechangedp, uint64_t *newsizep, struct ucred *cred, - NFSPROC_T *p, void *stuff) +nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, + uint64_t off, uint64_t len, nfsv4stateid_t *stateidp, int layouttype, + int layoutupdatecnt, uint8_t *layp, struct ucred *cred, NFSPROC_T *p, + void *stuff) { uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; int error, outcnt, i; uint8_t *cp; - NFSCL_REQSTART(nd, NFSPROC_LAYOUTCOMMIT, vp); - NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + + nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL); + NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 2 * NFSX_HYPER + NFSX_STATEID); - txdr_hyper(offset, tl); + txdr_hyper(off, tl); tl += 2; txdr_hyper(len, tl); tl += 2; @@ -4956,25 +4943,12 @@ nfsrpc_layoutcommit(vnode_t vp, off_t of *tl++ = newnfs_true; else *tl++ = newnfs_false; - *tl++ = stateidp->seqid; + *tl++ = txdr_unsigned(stateidp->seqid); *tl++ = stateidp->other[0]; *tl++ = stateidp->other[1]; *tl++ = stateidp->other[2]; - if (newoff != 0) { - *tl = newnfs_true; - NFSM_BUILD(tl, uint32_t *, NFSX_HYPER); - txdr_hyper(newoffset, tl); - } else - *tl = newnfs_false; - if (newtime != 0) { - NFSM_BUILD(tl, uint32_t *, NFSX_V4SETTIME + 2 * NFSX_UNSIGNED); - *tl++ = newnfs_true; - txdr_nfsv4time(&newtimespec, tl); - tl += NFSX_V4TIME / NFSX_UNSIGNED; - } else { - NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); - *tl++ = newnfs_false; - } + *tl++ = newnfs_false; + *tl++ = newnfs_false; *tl++ = txdr_unsigned(layouttype); *tl = txdr_unsigned(layoutupdatecnt); if (layoutupdatecnt > 0) { @@ -4988,20 +4962,11 @@ nfsrpc_layoutcommit(vnode_t vp, off_t of *cp++ = 0x0; } nd->nd_flag |= ND_USEGSSNAME; - error = nfscl_request(nd, vp, p, cred, stuff); + error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, + NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); - if (nd->nd_repstat == 0) { - NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); - if (*tl != 0) { - NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER); - *sizechangedp = 1; - *newsizep = fxdr_hyper(tl); - } else - *sizechangedp = 0; - } else - error = nd->nd_repstat; -nfsmout: + error = nd->nd_repstat; mbuf_freem(nd->nd_mrep); return (error); } @@ -5010,9 +4975,9 @@ nfsmout: * Do the NFSv4.1 LayoutReturn. */ int -nfsrpc_layoutreturn(vnode_t vp, int reclaim, int layouttype, int iomode, - int layoutreturn, off_t offset, uint64_t len, nfsv4stateid_t *stateidp, - int layoutcnt, uint32_t *layp, +nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, + int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, + uint64_t len, nfsv4stateid_t *stateidp, int layoutcnt, uint32_t *layp, struct ucred *cred, NFSPROC_T *p, void *stuff) { uint32_t *tl; @@ -5020,7 +4985,7 @@ nfsrpc_layoutreturn(vnode_t vp, int recl int error, outcnt, i; uint8_t *cp; - NFSCL_REQSTART(nd, NFSPROC_LAYOUTRETURN, vp); + nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL); NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); if (reclaim != 0) *tl++ = newnfs_true; @@ -5036,7 +5001,8 @@ nfsrpc_layoutreturn(vnode_t vp, int recl tl += 2; txdr_hyper(len, tl); tl += 2; - *tl++ = stateidp->seqid; +printf("layret stseq=%d\n", stateidp->seqid); + *tl++ = txdr_unsigned(stateidp->seqid); *tl++ = stateidp->other[0]; *tl++ = stateidp->other[1]; *tl++ = stateidp->other[2]; @@ -5051,14 +5017,15 @@ nfsrpc_layoutreturn(vnode_t vp, int recl } } nd->nd_flag |= ND_USEGSSNAME; - error = nfscl_request(nd, vp, p, cred, stuff); + error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, + NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); if (error != 0) return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); if (*tl != 0) { NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); - stateidp->seqid = *tl++; + stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); stateidp->other[0] = *tl++; stateidp->other[1] = *tl++; stateidp->other[2] = *tl; @@ -5071,42 +5038,58 @@ nfsmout: } /* - * Called from nfsrpc_open() to acquire a layout and associated device - * info. A separate function mostly to avoid excessive indentation in - * nfsrpc_open(). The open has already acquired a reference cnt on the client. + * Acquire a layout and devinfo, if possible. The caller must have acquired + * a reference count on the nfsclclient structure before calling this. + * Return the layout in lypp with a reference count on it, if successful. */ static int -nfsrpc_getlayout(struct nfsmount *nmp, struct nfsfh *nfhp, int iomode, - uint32_t *notifybitsp, nfsv4stateid_t *stateidp, struct ucred *cred, - NFSPROC_T *p) +nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, + int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, + struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) { struct nfscllayout *lyp; struct nfsclflayout *flp; struct nfscldevinfo *dip; struct nfsclflayouthead flh; - int error = 0, retonclose; + int error = 0, recalled, retonclose; - lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len); + *lypp = NULL; + lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, + &recalled); if (lyp == NULL) { + if (recalled != 0) + return (EIO); LIST_INIT(&flh); error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, nfhp->nfh_len, iomode, (uint64_t)0, INT64_MAX, (uint64_t)0, stateidp, &retonclose, &flh, cred, p, NULL); if (error == 0) LIST_FOREACH(flp, &flh, nfsfl_list) { - error = nfsrpc_getdeviceinfo(nmp, - flp->nfsfl_dev, NFSLAYOUT_NFSV4_1_FILES, - notifybitsp, &dip, cred, p); - if (error != 0) - break; - nfscl_adddevinfo(nmp, dip); + error = nfscl_adddevinfo(nmp, NULL, flp); + if (error != 0) { + error = nfsrpc_getdeviceinfo(nmp, + flp->nfsfl_dev, + NFSLAYOUT_NFSV4_1_FILES, + notifybitsp, &dip, cred, p); + if (error != 0) + break; + error = nfscl_adddevinfo(nmp, dip, flp); + if (error != 0) + printf( + "getlayout: cannot add\n"); + } } if (error == 0) - error = nfscl_layout(nmp, nfhp->nfh_fh, nfhp->nfh_len, - stateidp, retonclose, &flh, &lyp, cred, p); + error = nfscl_layout(nmp, vp, nfhp->nfh_fh, + nfhp->nfh_len, stateidp, retonclose, &flh, &lyp, + cred, p); + } + if (lyp != NULL) { + if (error == 0) + *lypp = lyp; + else + nfscl_rellayout(lyp); } - if (lyp != NULL) - nfscl_rellayout(lyp); return (error); } @@ -5303,33 +5286,49 @@ nfscl_doiods(vnode_t vp, struct uio *uio nfsv4stateid_t stateid; struct ucred *newcred; uint64_t len, off, oresid, xfer; - int eof, error; + int eof, error, iolaymode, recalled; void *lckp; - if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0) + if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || + (np->n_flag & NNOLAYOUT) != 0) return (EIO); /* Now, get a reference cnt on the clientid for this mount. */ if (nfscl_getref(nmp) == 0) return (EIO); - /* Search for a layout for this file. */ - layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, - np->n_fhp->nfh_len); - if (layp == NULL) { - nfscl_relref(nmp); - return (EIO); - } - /* Find an appropriate stateid. */ newcred = NFSNEWCRED(cred); error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, rwaccess, 1, newcred, p, &stateid, &lckp); if (error != 0) { +if (error == 2) printf("rwacc=0x%x\n", rwaccess); NFSFREECRED(newcred); - nfscl_rellayout(layp); nfscl_relref(nmp); return (error); } + /* Search for a layout for this file. */ + layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, + np->n_fhp->nfh_len, &recalled); + if (layp == NULL) { + /* Try and get a Layout, if it is supported. */ + stateid.seqid = 0; + iolaymode = (rwaccess == NFSV4OPEN_ACCESSWRITE) ? + NFSLAYOUTIOMODE_RW : NFSLAYOUTIOMODE_READ; + error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, + NULL, &stateid, &layp, newcred, p); + if (error != 0) { + NFSLOCKNODE(np); + np->n_flag |= NNOLAYOUT; + NFSUNLOCKNODE(np); + if (lckp != NULL) + nfscl_lockderef(lckp); + NFSFREECRED(newcred); + if (layp != NULL) + nfscl_rellayout(layp); + nfscl_relref(nmp); + return (error); + } + } /* * Loop around finding a layout that works for the first part of @@ -5345,7 +5344,8 @@ nfscl_doiods(vnode_t vp, struct uio *uio oresid = xfer = (uint64_t)uiop->uio_resid; if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) xfer = rflp->nfsfl_end - rflp->nfsfl_off; - dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev); + dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev, + rflp->nfsfl_devp); if (dip != NULL) { error = nfscl_doflayoutio(vp, uiop, iomode, must_commit, &eof, &stateid, rwaccess, dip, @@ -5463,10 +5463,16 @@ nfscl_doflayoutio(vnode_t vp, struct uio if (rwflag == FREAD) error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, io_off, xfer, fhp, cred, p); - else + else { error = nfsrpc_writeds(vp, uiop, iomode, must_commit, stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, cred, p); + if (error == 0) { + NFSLOCKCLSTATE(); + flp->nfsfl_flags |= NFSFL_WRITTEN; + NFSUNLOCKCLSTATE(); + } + } if (error == 0) { transfer = stripe_unit_size; stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; Modified: projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clstate.c ============================================================================== --- projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clstate.c Mon Apr 23 23:57:24 2012 (r234625) +++ projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clstate.c Tue Apr 24 00:13:59 2012 (r234626) @@ -156,6 +156,13 @@ static void nfscl_emptylockowner(struct struct nfscllockownerfhhead *); static void nfscl_mergeflayouts(struct nfsclflayouthead *, struct nfsclflayouthead *); +static int nfscl_layoutrecall(int, struct nfscllayout *, uint32_t, uint64_t, + uint64_t, uint32_t, struct nfsclrecalllayout *); +static int nfscl_seq(uint32_t, uint32_t); +static void nfscl_layoutreturn(struct nfsmount *, struct nfscllayout *, + struct ucred *, NFSPROC_T *); +static void nfscl_dolayoutcommit(struct nfsmount *, struct nfscllayout *, + struct nfsclflayout *, struct ucred *, NFSPROC_T *); static short nfscberr_null[] = { 0, @@ -762,13 +769,11 @@ nfscl_getcl(struct mount *mp, struct ucr LIST_INIT(&clp->nfsc_owner); TAILQ_INIT(&clp->nfsc_deleg); TAILQ_INIT(&clp->nfsc_layout); - TAILQ_INIT(&clp->nfsc_devinfo); + LIST_INIT(&clp->nfsc_devinfo); for (i = 0; i < NFSCLDELEGHASHSIZE; i++) LIST_INIT(&clp->nfsc_deleghash[i]); for (i = 0; i < NFSCLLAYOUTHASHSIZE; i++) LIST_INIT(&clp->nfsc_layouthash[i]); - for (i = 0; i < NFSCLDEVINFOHASHSIZE; i++) - LIST_INIT(&clp->nfsc_devinfohash[i]); clp->nfsc_flags = NFSCLFLAGS_INITED; clp->nfsc_clientidrev = 1; clp->nfsc_cbident = nfscl_nextcbident(); @@ -2432,6 +2437,10 @@ nfscl_renewthread(struct nfsclclient *cl static time_t prevsec = 0; struct nfscllockownerfh *lfhp, *nlfhp; struct nfscllockownerfhhead lfh; + struct nfscllayout *lyp, *nlyp; + struct nfsclflayout *flp; + struct nfscldevinfo *dip, *ndip; + struct nfscllayouthead rlh; cred = newnfs_getcred(); NFSLOCKCLSTATE(); @@ -2577,8 +2586,90 @@ tryagain: } if (igotlock) nfsv4_unlock(&clp->nfsc_lock, 0); + + /* + * Do the recall on any layouts. To avoid trouble, always + * come back up here after having slept. + */ + TAILQ_INIT(&rlh); +tryagain2: + TAILQ_FOREACH_SAFE(lyp, &clp->nfsc_layout, nfsly_list, nlyp) { + if ((lyp->nfsly_flags & NFSLY_RECALL) != 0) { + /* + * Wait for outstanding I/O ops to be done. + */ + if (lyp->nfsly_refcnt > 0) { +printf("layrec io=%d\n", lyp->nfsly_refcnt); + (void)mtx_sleep(&lyp->nfsly_refcnt, + NFSCLSTATEMUTEXPTR, PZERO, "nfslyd", + 0); + goto tryagain2; + } + + /* Handle any layout commits. */ + LIST_FOREACH(flp, &lyp->nfsly_flayrw, + nfsfl_list) { + if ((flp->nfsfl_flags & NFSFL_WRITTEN) + != 0) { + lyp->nfsly_refcnt++; + flp->nfsfl_flags &= + ~NFSFL_WRITTEN; + NFSUNLOCKCLSTATE(); +printf("do layoutcommit\n"); + nfscl_dolayoutcommit( + clp->nfsc_nmp, lyp, flp, + cred, p); + NFSLOCKCLSTATE(); + lyp->nfsly_refcnt--; + if (lyp->nfsly_refcnt == 0) + wakeup( + &lyp->nfsly_refcnt); + goto tryagain2; + } + } + + /* Move the layout to the recall list. */ + TAILQ_REMOVE(&clp->nfsc_layout, lyp, + nfsly_list); + LIST_REMOVE(lyp, nfsly_hash); + TAILQ_INSERT_HEAD(&rlh, lyp, nfsly_list); + } + } +#ifdef notyet + /* Now, look for stale layouts. */ + lyp = TAILQ_LAST(&clp->nfsc_layout, nfscllayouthead); + while (lyp != NULL) { + nlyp = TAILQ_PREV(lyp, nfscllayouthead, nfsly_list); + if (lyp->nfsly_timestamp < NFSD_MONOSEC && + (lyp->nfsly_flags & NFSLY_RECALL) == 0 && + lyp->nfsly_refcnt == 0) { +printf("ret stale lay=%d\n", nfscl_layoutcnt); + } + lyp = nlyp; + } +#endif + + /* + * Free up any unreferenced device info structures. + */ + LIST_FOREACH_SAFE(dip, &clp->nfsc_devinfo, nfsdi_list, ndip) { + if (dip->nfsdi_layoutrefs == 0 && + dip->nfsdi_refcnt == 0) { +printf("freeing devinfo\n"); + LIST_REMOVE(dip, nfsdi_list); + nfscl_freedevinfo(dip); + } + } NFSUNLOCKCLSTATE(); + /* Do layout return(s), as required. */ + TAILQ_FOREACH_SAFE(lyp, &rlh, nfsly_list, nlyp) { + TAILQ_REMOVE(&rlh, lyp, nfsly_list); +printf("ret layout\n"); + nfscl_layoutreturn(clp->nfsc_nmp, lyp, cred, p); + nfscl_freelayout(lyp); + } + /* * Delegreturn any delegations cleaned out or recalled. */ @@ -3031,6 +3122,11 @@ nfscl_docb(struct nfsrv_descript *nd, NF uint32_t seqid, slotid = 0, highslot, cachethis; uint8_t sessionid[NFSX_V4SESSIONID]; struct mbuf *rep; + struct nfscllayout *lyp; + uint64_t filesid[2], len, off; + int changed, gotone, laytype, recalltype; + uint32_t iomode; + struct nfsclrecalllayout *recallp = NULL; gotseq_ok = 0; nfsrvd_rephead(nd); @@ -3186,6 +3282,129 @@ printf("cbrecall\n"); if (nfhp != NULL) FREE((caddr_t)nfhp, M_NFSFH); break; + case NFSV4OP_CBLAYOUTRECALL: +printf("cblayrec\n"); + nfhp = NULL; + NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); + laytype = fxdr_unsigned(int, *tl++); + iomode = fxdr_unsigned(uint32_t, *tl++); + if (newnfs_true == *tl++) + changed = 1; + else + changed = 0; + recalltype = fxdr_unsigned(int, *tl); + recallp = malloc(sizeof(*recallp), M_NFSLAYRECALL, + M_WAITOK); + if (laytype != NFSLAYOUT_NFSV4_1_FILES) + error = NFSERR_NOMATCHLAYOUT; + else if (recalltype == NFSLAYOUTRETURN_FILE) { + error = nfsm_getfh(nd, &nfhp); +printf("retfile getfh=%d\n", error); + if (error != 0) + goto nfsmout; + NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER + + NFSX_STATEID); + off = fxdr_hyper(tl); tl += 2; + len = fxdr_hyper(tl); tl += 2; + stateid.seqid = fxdr_unsigned(uint32_t, *tl++); + NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); + if (minorvers == NFSV4_MINORVERSION) + error = NFSERR_NOTSUPP; + else if (i == 0) + error = NFSERR_OPNOTINSESS; + if (error == 0) { + NFSLOCKCLSTATE(); + clp = nfscl_getclntsess(sessionid); +printf("cbly clp=%p\n", clp); + if (clp != NULL) { + lyp = nfscl_findlayout(clp, + nfhp->nfh_fh, + nfhp->nfh_len); +printf("cblyp=%p\n", lyp); + if (lyp != NULL && + (lyp->nfsly_flags & + NFSLY_FILES) != 0 && + !NFSBCMP(stateid.other, + lyp->nfsly_stateid.other, + NFSX_STATEIDOTHER)) { + error = + nfscl_layoutrecall( + recalltype, + lyp, iomode, off, + len, stateid.seqid, + recallp); + recallp = NULL; + wakeup(clp); +printf("aft layrec=%d\n", error); + } else + error = + NFSERR_NOMATCHLAYOUT; + } else + error = NFSERR_NOMATCHLAYOUT; + NFSUNLOCKCLSTATE(); + } + free(nfhp, M_NFSFH); + } else if (recalltype == NFSLAYOUTRETURN_FSID) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER); + filesid[0] = fxdr_hyper(tl); tl += 2; + filesid[1] = fxdr_hyper(tl); tl += 2; + gotone = 0; + NFSLOCKCLSTATE(); + clp = nfscl_getclntsess(sessionid); + if (clp != NULL) { + TAILQ_FOREACH(lyp, &clp->nfsc_layout, + nfsly_list) { + if (lyp->nfsly_filesid[0] == + filesid[0] && + lyp->nfsly_filesid[1] == + filesid[1]) { + error = + nfscl_layoutrecall( + recalltype, + lyp, iomode, 0, + UINT64_MAX, + lyp->nfsly_stateid.seqid, + recallp); + recallp = NULL; + gotone = 1; + } + } + if (gotone != 0) + wakeup(clp); + else + error = NFSERR_NOMATCHLAYOUT; + } else + error = NFSERR_NOMATCHLAYOUT; + NFSUNLOCKCLSTATE(); + } else if (recalltype == NFSLAYOUTRETURN_ALL) { + gotone = 0; + NFSLOCKCLSTATE(); + clp = nfscl_getclntsess(sessionid); + if (clp != NULL) { + TAILQ_FOREACH(lyp, &clp->nfsc_layout, + nfsly_list) { + error = nfscl_layoutrecall( + recalltype, lyp, iomode, 0, + UINT64_MAX, + lyp->nfsly_stateid.seqid, + recallp); + recallp = NULL; + gotone = 1; + } + if (gotone != 0) + wakeup(clp); + else + error = NFSERR_NOMATCHLAYOUT; + } else + error = NFSERR_NOMATCHLAYOUT; + NFSUNLOCKCLSTATE(); + } else + error = NFSERR_NOMATCHLAYOUT; + if (recallp != NULL) { + free(recallp, M_NFSLAYRECALL); + recallp = NULL; + } + break; case NFSV4OP_CBSEQUENCE: NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 5 * NFSX_UNSIGNED); @@ -3267,6 +3486,8 @@ printf("unsupp callback %d\n", op); *repp = 0; /* NFS4_OK */ } nfsmout: + if (recallp != NULL) + free(recallp, M_NFSLAYRECALL); if (error) { if (error == EBADRPC || error == NFSERR_BADXDR) nd->nd_repstat = NFSERR_BADXDR; @@ -4413,7 +4634,7 @@ nfscl_errmap(struct nfsrv_descript *nd) * Called to find/add a layout to a client. */ APPLESTATIC int -nfscl_layout(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, +nfscl_layout(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen, nfsv4stateid_t *stateidp, int retonclose, struct nfsclflayouthead *fhlp, struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) @@ -4421,6 +4642,7 @@ nfscl_layout(struct nfsmount *nmp, u_int struct nfsclclient *clp; struct nfscllayout *lyp, *tlyp; struct nfsclflayout *flp; + struct nfsnode *np = VTONFS(vp); *lypp = NULL; tlyp = malloc(sizeof(*tlyp) + fhlen - 1, M_NFSLAYOUT, M_WAITOK); @@ -4442,22 +4664,27 @@ nfscl_layout(struct nfsmount *nmp, u_int lyp->nfsly_stateid.other[2] = stateidp->other[2]; LIST_INIT(&lyp->nfsly_flayread); LIST_INIT(&lyp->nfsly_flayrw); + LIST_INIT(&lyp->nfsly_recall); + lyp->nfsly_filesid[0] = np->n_vattr.na_filesid[0]; + lyp->nfsly_filesid[1] = np->n_vattr.na_filesid[1]; lyp->nfsly_clp = clp; - lyp->nfsly_retonclose = retonclose; + lyp->nfsly_flags = (retonclose != 0) ? + (NFSLY_FILES | NFSLY_RETONCLOSE) : NFSLY_FILES; lyp->nfsly_refcnt = 1; /* Return with a reference cnt. */ lyp->nfsly_fhlen = fhlen; NFSBCOPY(fhp, lyp->nfsly_fh, fhlen); TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list); LIST_INSERT_HEAD(NFSCLLAYOUTHASH(clp, fhp, fhlen), lyp, nfsly_hash); -#ifdef notyet lyp->nfsly_timestamp = NFSD_MONOSEC + 120; -#endif nfscl_layoutcnt++; } else { lyp->nfsly_refcnt++; + if (retonclose != 0) + lyp->nfsly_flags |= NFSLY_RETONCLOSE; TAILQ_REMOVE(&clp->nfsc_layout, lyp, nfsly_list); TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list); + lyp->nfsly_timestamp = NFSD_MONOSEC + 120; } /* Merge the new list of File Layouts into the list. */ @@ -4476,20 +4703,27 @@ nfscl_layout(struct nfsmount *nmp, u_int } /* - * Search for a layout by MDS file handle. If one is found, lock it it and + * Search for a layout by MDS file handle. If one is found, ref cnt it and * return a pointer to it. */ struct nfscllayout * -nfscl_getlayout(struct nfsclclient *clp, uint8_t *fhp, int fhlen) +nfscl_getlayout(struct nfsclclient *clp, uint8_t *fhp, int fhlen, + int *recalledp) { struct nfscllayout *lyp; + *recalledp = 0; NFSLOCKCLSTATE(); lyp = nfscl_findlayout(clp, fhp, fhlen); if (lyp != NULL) { - lyp->nfsly_refcnt++; - TAILQ_REMOVE(&clp->nfsc_layout, lyp, nfsly_list); - TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list); + if ((lyp->nfsly_flags & NFSLY_RECALL) == 0) { + lyp->nfsly_refcnt++; + TAILQ_REMOVE(&clp->nfsc_layout, lyp, nfsly_list); + TAILQ_INSERT_HEAD(&clp->nfsc_layout, lyp, nfsly_list); + } else { + lyp = NULL; + *recalledp = 1; + } } NFSUNLOCKCLSTATE(); return (lyp); @@ -4514,17 +4748,15 @@ nfscl_rellayout(struct nfscllayout *lyp) * acquiring a reference count on it. */ struct nfscldevinfo * -nfscl_getdevinfo(struct nfsclclient *clp, uint8_t *deviceid) +nfscl_getdevinfo(struct nfsclclient *clp, uint8_t *deviceid, + struct nfscldevinfo *dip) { - struct nfscldevinfo *dip; NFSLOCKCLSTATE(); - dip = nfscl_finddevinfo(clp, deviceid); - if (dip != NULL) { + if (dip == NULL) + dip = nfscl_finddevinfo(clp, deviceid); + if (dip != NULL) dip->nfsdi_refcnt++; - TAILQ_REMOVE(&clp->nfsc_devinfo, dip, nfsdi_list); - TAILQ_INSERT_HEAD(&clp->nfsc_devinfo, dip, nfsdi_list); - } NFSUNLOCKCLSTATE(); return (dip); } @@ -4576,7 +4808,7 @@ nfscl_finddevinfo(struct nfsclclient *cl { struct nfscldevinfo *dip; - LIST_FOREACH(dip, NFSCLDEVINFOHASH(clp, deviceid), nfsdi_hash) + LIST_FOREACH(dip, &clp->nfsc_devinfo, nfsdi_list) if (NFSBCMP(dip->nfsdi_deviceid, deviceid, NFSX_V4DEVICEID) == 0) break; @@ -4610,10 +4842,11 @@ nfscl_mergeflayouts(struct nfsclflayouth /* * Add this nfscldevinfo to the client, if it doesn't already exist. - * This function consumes the structure pointed at by dip. + * This function consumes the structure pointed at by dip, if not NULL. */ -APPLESTATIC void -nfscl_adddevinfo(struct nfsmount *nmp, struct nfscldevinfo *dip) +APPLESTATIC int +nfscl_adddevinfo(struct nfsmount *nmp, struct nfscldevinfo *dip, + struct nfsclflayout *flp) { struct nfsclclient *clp; struct nfscldevinfo *tdip; @@ -4622,20 +4855,29 @@ nfscl_adddevinfo(struct nfsmount *nmp, s clp = nmp->nm_clp; if (clp == NULL) { NFSUNLOCKCLSTATE(); - free(dip, M_NFSDEVINFO); - return; + if (dip != NULL) + free(dip, M_NFSDEVINFO); + return (ENODEV); } - tdip = nfscl_finddevinfo(clp, dip->nfsdi_deviceid); + tdip = nfscl_finddevinfo(clp, flp->nfsfl_dev); if (tdip != NULL) { + tdip->nfsdi_layoutrefs++; + flp->nfsfl_devp = tdip; nfscl_reldevinfo_locked(tdip); NFSUNLOCKCLSTATE(); - free(dip, M_NFSDEVINFO); - return; + if (dip != NULL) + free(dip, M_NFSDEVINFO); + return (0); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201204240013.q3O0Dxhj021779>