Date: Sat, 29 Dec 2012 02:10:55 +0000 (UTC) From: Rick Macklem <rmacklem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r244805 - in projects/nfsv4-packrats/sys: conf fs/nfs fs/nfsclient modules/nfscl nfs Message-ID: <201212290210.qBT2Atnd050518@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rmacklem Date: Sat Dec 29 02:10:55 2012 New Revision: 244805 URL: http://svnweb.freebsd.org/changeset/base/244805 Log: Put the current kernel patch for packrats in the project tree. Added: projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clpackrat.c (contents, props changed) Modified: projects/nfsv4-packrats/sys/conf/files projects/nfsv4-packrats/sys/fs/nfs/nfs_commonport.c projects/nfsv4-packrats/sys/fs/nfs/nfs_var.h projects/nfsv4-packrats/sys/fs/nfs/nfsclstate.h projects/nfsv4-packrats/sys/fs/nfs/nfsport.h projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clbio.c projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clport.c projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clrpcops.c projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clstate.c projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clvnops.c projects/nfsv4-packrats/sys/fs/nfsclient/nfsnode.h projects/nfsv4-packrats/sys/modules/nfscl/Makefile projects/nfsv4-packrats/sys/nfs/nfs_nfssvc.c projects/nfsv4-packrats/sys/nfs/nfssvc.h Modified: projects/nfsv4-packrats/sys/conf/files ============================================================================== --- projects/nfsv4-packrats/sys/conf/files Sat Dec 29 00:30:30 2012 (r244804) +++ projects/nfsv4-packrats/sys/conf/files Sat Dec 29 02:10:55 2012 (r244805) @@ -2388,6 +2388,7 @@ fs/nfsclient/nfs_clcomsubs.c optional nf fs/nfsclient/nfs_clsubs.c optional nfscl fs/nfsclient/nfs_clstate.c optional nfscl fs/nfsclient/nfs_clkrpc.c optional nfscl +fs/nfsclient/nfs_clpackrat.c optional nfscl fs/nfsclient/nfs_clrpcops.c optional nfscl fs/nfsclient/nfs_clvnops.c optional nfscl fs/nfsclient/nfs_clnode.c optional nfscl Modified: projects/nfsv4-packrats/sys/fs/nfs/nfs_commonport.c ============================================================================== --- projects/nfsv4-packrats/sys/fs/nfs/nfs_commonport.c Sat Dec 29 00:30:30 2012 (r244804) +++ projects/nfsv4-packrats/sys/fs/nfs/nfs_commonport.c Sat Dec 29 02:10:55 2012 (r244805) @@ -112,6 +112,7 @@ MALLOC_DEFINE(M_NEWNFSDEVINFO, "NFSCL de MALLOC_DEFINE(M_NEWNFSSOCKREQ, "NFSCL sockreq", "NFS Sock Req"); MALLOC_DEFINE(M_NEWNFSCLDS, "NFSCL session", "NFSv4.1 Session"); MALLOC_DEFINE(M_NEWNFSLAYRECALL, "NFSCL layrecall", "NFSv4.1 Layout Recall"); +MALLOC_DEFINE(M_NEWNFSLDIRTY, "NFSCL ldirty", "NFSCL deleg locally dirty"); /* * Definition of mutex locks. Modified: projects/nfsv4-packrats/sys/fs/nfs/nfs_var.h ============================================================================== --- projects/nfsv4-packrats/sys/fs/nfs/nfs_var.h Sat Dec 29 00:30:30 2012 (r244804) +++ projects/nfsv4-packrats/sys/fs/nfs/nfs_var.h Sat Dec 29 02:10:55 2012 (r244805) @@ -522,7 +522,7 @@ int nfscl_renamedeleg(vnode_t, nfsv4stat void nfscl_reclaimnode(vnode_t); void nfscl_newnode(vnode_t); void nfscl_delegmodtime(vnode_t); -void nfscl_deleggetmodtime(vnode_t, struct timespec *); +void nfscl_deleggetmod(vnode_t, struct timespec *, uint64_t *); int nfscl_tryclose(struct nfsclopen *, struct ucred *, struct nfsmount *, NFSPROC_T *); void nfscl_cleanup(NFSPROC_T *); @@ -541,6 +541,7 @@ void nfscl_freelayout(struct nfscllayout void nfscl_freeflayout(struct nfsclflayout *); void nfscl_freedevinfo(struct nfscldevinfo *); int nfscl_layoutcommit(vnode_t, NFSPROC_T *); +struct nfscldeleg *nfscl_finddeleg(struct nfsclclient *, u_int8_t *, int); /* nfs_clport.c */ int nfscl_nget(mount_t, vnode_t, struct nfsfh *, @@ -655,3 +656,16 @@ void nfsrvd_init(int); int nfscbd_addsock(struct file *); int nfscbd_nfsd(NFSPROC_T *, struct nfsd_nfscbd_args *); +/* nfs_clpackrat.c */ +void nfscl_packratsetup(struct nfscldeleg *, struct nfsmount *, struct ucred *, + NFSPROC_T *); +void nfscl_packratopen(vnode_t, NFSPROC_T *); +void nfscl_packratclose(vnode_t, NFSPROC_T *); +int nfscbd_packrat(char *); +int nfscl_packratread(vnode_t, struct uio *, int, struct ucred *, int *); +int nfscl_packratwrite(vnode_t, struct uio *, int, struct ucred *, + NFSPROC_T *, int *); +int nfscl_deleglocalflush(struct nfscldeleg *, struct nfsmount *, NFSPROC_T *, + int, int); +void nfscl_packratsetsize(vnode_t, uint64_t); + Modified: projects/nfsv4-packrats/sys/fs/nfs/nfsclstate.h ============================================================================== --- projects/nfsv4-packrats/sys/fs/nfs/nfsclstate.h Sat Dec 29 00:30:30 2012 (r244804) +++ projects/nfsv4-packrats/sys/fs/nfs/nfsclstate.h Sat Dec 29 02:10:55 2012 (r244805) @@ -136,6 +136,15 @@ struct nfsclowner { }; /* + * List entry for dirty byte ranges for nfscldeleg. + */ +struct nfsldirty { + LIST_ENTRY(nfsldirty) nfsw_list; + uint64_t nfsw_first; + uint64_t nfsw_end; +}; + +/* * MALLOC'd to the correct length to accommodate the file handle. */ struct nfscldeleg { @@ -153,21 +162,41 @@ struct nfscldeleg { u_int64_t nfsdl_size; /* saved copy of file size */ u_int64_t nfsdl_change; /* and change attribute */ struct timespec nfsdl_modtime; /* local modify time */ + u_int64_t nfsdl_opensize; /* size at open */ + u_int64_t nfsdl_localsize;/* locally stored file size */ + LIST_HEAD(, nfsldirty) nfsdl_ldirty; /* locally mod. ranges */ + u_int32_t nfsdl_localiocnt; /* Local I/Os in prog */ + vnode_t nfsdl_filevp; /* Local copy of file */ + vnode_t nfsdl_delegvp; /* Delegation record file */ + struct proc *nfsdl_packratthread; /* Packrat copy thread */ u_int16_t nfsdl_fhlen; - u_int8_t nfsdl_flags; + u_int16_t nfsdl_flags; u_int8_t nfsdl_fh[1]; /* must be last */ }; /* * nfsdl_flags bits. */ -#define NFSCLDL_READ 0x01 -#define NFSCLDL_WRITE 0x02 -#define NFSCLDL_RECALL 0x04 -#define NFSCLDL_NEEDRECLAIM 0x08 -#define NFSCLDL_ZAPPED 0x10 -#define NFSCLDL_MODTIMESET 0x20 -#define NFSCLDL_DELEGRET 0x40 +#define NFSCLDL_READ 0x0001 +#define NFSCLDL_WRITE 0x0002 +#define NFSCLDL_RECALL 0x0004 +#define NFSCLDL_NEEDRECLAIM 0x0008 +#define NFSCLDL_ZAPPED 0x0010 +#define NFSCLDL_MODTIMESET 0x0020 +#define NFSCLDL_DELEGRET 0x0040 +#define NFSCLDL_COPYINPROG 0x0080 +#define NFSCLDL_LOCALSIZESET 0x0100 +#define NFSCLDL_HASCOPY 0x0200 +#define NFSCLDL_WAITRECALL 0x0400 + +/* + * Maximum length of a local filename used by the packrat daemons. + * 1 - indicates the type of file. + * 1 - indicates IPv4 vs IPv6 host address. + * 32 - maximum IP host address length. + * 174 - the maximum length of the file handle in ascii. + */ +#define NFSPCKRAT_MAXFILELEN (1 + 1 + 32 + 174) /* * MALLOC'd to the correct length to accommodate the file handle. Modified: projects/nfsv4-packrats/sys/fs/nfs/nfsport.h ============================================================================== --- projects/nfsv4-packrats/sys/fs/nfs/nfsport.h Sat Dec 29 00:30:30 2012 (r244804) +++ projects/nfsv4-packrats/sys/fs/nfs/nfsport.h Sat Dec 29 02:10:55 2012 (r244805) @@ -743,6 +743,7 @@ MALLOC_DECLARE(M_NEWNFSDEVINFO); MALLOC_DECLARE(M_NEWNFSSOCKREQ); MALLOC_DECLARE(M_NEWNFSCLDS); MALLOC_DECLARE(M_NEWNFSLAYRECALL); +MALLOC_DECLARE(M_NEWNFSLDIRTY); #define M_NFSRVCACHE M_NEWNFSRVCACHE #define M_NFSDCLIENT M_NEWNFSDCLIENT #define M_NFSDSTATE M_NEWNFSDSTATE @@ -768,6 +769,7 @@ MALLOC_DECLARE(M_NEWNFSLAYRECALL); #define M_NFSSOCKREQ M_NEWNFSSOCKREQ #define M_NFSCLDS M_NEWNFSCLDS #define M_NFSLAYRECALL M_NEWNFSLAYRECALL +#define M_NFSLDIRTY M_NEWNFSLDIRTY #define NFSINT_SIGMASK(set) \ (SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) || \ Modified: projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clbio.c ============================================================================== --- projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clbio.c Sat Dec 29 00:30:30 2012 (r244804) +++ projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clbio.c Sat Dec 29 02:10:55 2012 (r244805) @@ -82,7 +82,7 @@ static int nfs_directio_write(struct vno int ncl_getpages(struct vop_getpages_args *ap) { - int i, error, nextoff, size, toff, count, npages; + int i, error, nextoff, size, toff, count, npages, didread; struct uio uio; struct iovec iov; vm_offset_t kva; @@ -169,7 +169,9 @@ ncl_getpages(struct vop_getpages_args *a uio.uio_rw = UIO_READ; uio.uio_td = td; - error = ncl_readrpc(vp, &uio, cred); + error = nfscl_packratread(vp, &uio, 0, cred, &didread); + if (didread == 0) + error = ncl_readrpc(vp, &uio, cred); pmap_qremove(kva, npages); relpbuf(bp, &ncl_pbuf_freecnt); @@ -245,7 +247,7 @@ ncl_putpages(struct vop_putpages_args *a struct iovec iov; vm_offset_t kva; struct buf *bp; - int iomode, must_commit, i, error, npages, count; + int iomode, must_commit, i, error, npages, count, didwrite; off_t offset; int *rtvals; struct vnode *vp; @@ -325,7 +327,9 @@ ncl_putpages(struct vop_putpages_args *a else iomode = NFSWRITE_FILESYNC; - error = ncl_writerpc(vp, &uio, cred, &iomode, &must_commit, 0); + error = nfscl_packratwrite(vp, &uio, 0, cred, NULL, &didwrite); + if (didwrite == 0) + error = ncl_writerpc(vp, &uio, cred, &iomode, &must_commit, 0); crfree(cred); pmap_qremove(kva, npages); @@ -873,7 +877,7 @@ ncl_write(struct vop_write_args *ap) struct vattr vattr; struct nfsmount *nmp = VFSTONFS(vp->v_mount); daddr_t lbn; - int bcount; + int bcount, didwrite; int bp_cached, n, on, error = 0, error1; size_t orig_resid, local_resid; off_t orig_size, tmp_off; @@ -902,6 +906,14 @@ ncl_write(struct vop_write_args *ap) mtx_unlock(&nmp->nm_mtx); /* + * Do the write locally if there is a write delegation and packrats + * have created a locally cached copy. + */ + error = nfscl_packratwrite(vp, uio, ioflag, cred, td, &didwrite); + if (didwrite != 0) + return (error); + + /* * Synchronously flush pending buffers if we are in synchronous * mode or if we are appending. */ @@ -1374,7 +1386,7 @@ ncl_vinvalbuf(struct vnode *vp, int flag if (NFSHASPNFS(nmp)) nfscl_layoutcommit(vp, td); mtx_lock(&np->n_mtx); - if (np->n_directio_asyncwr == 0) + if (np->n_directio_asyncwr == 0 && (np->n_flag & NLOCALCACHE) == 0) np->n_flag &= ~NMODIFIED; mtx_unlock(&np->n_mtx); out: @@ -1548,7 +1560,8 @@ ncl_doio_directwrite(struct buf *bp) mtx_lock(&np->n_mtx); np->n_directio_asyncwr--; if (np->n_directio_asyncwr == 0) { - np->n_flag &= ~NMODIFIED; + if ((np->n_flag & NLOCALCACHE) == 0) + np->n_flag &= ~NMODIFIED; if ((np->n_flag & NFSYNCWAIT)) { np->n_flag &= ~NFSYNCWAIT; wakeup((caddr_t)&np->n_directio_asyncwr); Added: projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clpackrat.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/nfsv4-packrats/sys/fs/nfsclient/nfs_clpackrat.c Sat Dec 29 02:10:55 2012 (r244805) @@ -0,0 +1,1211 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <fs/nfs/nfsport.h> +#include <fs/nfsclient/nfs.h> + +/* + * These functions provide the packrat support for the NFSv4 client. That + * is, they implement agressive client side whole file caching to a directory + * on stable storage, such as a disk. + */ +#ifndef APPLEKEXT +NFSCLSTATEMUTEX; +static char nfscl_packratpath[MAXPATHLEN + 1]; +static int nfscl_packratpathlen = 0; +static uint64_t nfscl_packratmaxsize = 10000000; +#endif /* !APPLEKEXT */ + +#define NFS_PACKRATIOSIZE NFS_MAXBSIZE + +static vnode_t nfscl_openfile(char *, boolean_t, struct ucred *, NFSPROC_T *); +static void nfscl_closefile(vnode_t, char *, boolean_t, struct ucred *, + NFSPROC_T *); +static void start_packrat(void *); +static void nfscl_start_packratthread(struct nfscldeleg *); +static void nfscl_packratthread(struct nfscldeleg *, NFSPROC_T *); +static int nfsrpc_readdp(struct nfscldeleg *, struct uio *, struct ucred *, + NFSPROC_T *); +static int nfsrpc_readrpcdp(struct nfscldeleg *, struct uio *, struct ucred *, + NFSPROC_T *); +static void nfscl_fhtofilename(u_int8_t *, u_int16_t, char *); +static void nfscl_packratbreakdown(struct nfscldeleg *, struct nfsmount *, + struct ucred *, NFSPROC_T *); +static void nfscl_updatewrite(struct nfscldeleg *, struct nfsldirty *); +static int nfscl_localwrite(struct nfscldeleg *, uint64_t, int, + struct ucred *, struct ucred *, NFSPROC_T *, int); +static int nfsrpc_writedp(struct nfscldeleg *, uint8_t *, off_t, int, + struct ucred *, NFSPROC_T *, int); +static int nfsrpc_writerpcdp(struct nfscldeleg *, uint8_t *, off_t, int, + struct ucred *, NFSPROC_T *); +static void nfscl_truncdirty(struct nfscldeleg *, uint64_t); +static int nfscl_packrathostaddr(struct nfsmount *, char *, int); +static void nfscl_packratgetvp(struct nfscldeleg *, struct nfsmount *, char *, + int, struct ucred *, NFSPROC_T *); + +/* + * This function opens/creates a file for reading and writing, returning the + * vnode pointer for it. + */ +static vnode_t +nfscl_openfile(char *path, boolean_t createit, struct ucred *cred, NFSPROC_T *p) +{ + struct nameidata nd; + int error, fmode; + + NDINIT_AT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, + path, AT_FDCWD, p); + if (createit) + fmode = O_CREAT | O_TRUNC | O_RDWR; + else + fmode = O_RDWR; + error = vn_open_cred(&nd, &fmode, 0600, VN_OPEN_NOAUDIT, cred, NULL); + if (error == 0) + NDFREE(&nd, NDF_ONLY_PNBUF); + else if (nd.ni_vp != NULL) + panic("nfsclopenf"); + return (nd.ni_vp); +} + +/* + * This function closes and removes a file that was previously created/opened + * by nfscl_openfile(). + */ +static void +nfscl_closefile(vnode_t vp, char *path, boolean_t unlinkit, struct ucred *cred, + NFSPROC_T *p) +{ + + (void) vn_close(vp, FREAD | FWRITE, cred, p); + if (unlinkit) + (void) kern_unlinkat(p, AT_FDCWD, path, UIO_SYSSPACE, 0); +} + +/* + * Start up a packrat thread to copy the file to local disk. + */ +static void +start_packrat(void *arg) +{ + struct nfscldeleg *dp; + struct thread *td; + + dp = (struct nfscldeleg *)arg; + td = TAILQ_FIRST(&dp->nfsdl_packratthread->p_threads); + nfscl_packratthread(dp, td); + kproc_exit(0); +} + +static void +nfscl_start_packratthread(struct nfscldeleg *dp) +{ + + kproc_create(start_packrat, (void *)dp, &dp->nfsdl_packratthread, 0, 0, + "nfspackrat"); +} + +/* + * This is the body of the packrat copy thread. Just copy the file to the + * local one on disk. + */ +static void +nfscl_packratthread(struct nfscldeleg *dp, NFSPROC_T *td) +{ + struct uio uio; + struct iovec io; + struct ucred *incred, *outcred; + char *iobuf; + int resid, error; + off_t off; + + incred = newnfs_getcred(); + outcred = newnfs_getcred(); + newnfs_copycred(&dp->nfsdl_cred, incred); + iobuf = (char *)malloc(NFS_PACKRATIOSIZE, M_TEMP, M_WAITOK); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_offset = 0; + + /* Loop around until eof */ + do { + off = uio.uio_offset; + uio.uio_resid = NFS_PACKRATIOSIZE; + io.iov_len = NFS_PACKRATIOSIZE; + io.iov_base = iobuf; + uio.uio_iovcnt = 1; + uio.uio_iov = &io; + uio.uio_td = td; + error = nfsrpc_readdp(dp, &uio, incred, td); + + /* and then write to the disk file */ + if (error == 0 && uio.uio_resid < NFS_PACKRATIOSIZE) { + error = vn_rdwr(UIO_WRITE, dp->nfsdl_filevp, + iobuf, NFS_PACKRATIOSIZE - uio.uio_resid, + off, UIO_SYSSPACE, IO_NOMACCHECK, outcred, + NOCRED, &resid, td); + if (error == 0) { + dp->nfsdl_localsize = uio.uio_offset; + wakeup(&dp->nfsdl_localsize); + } + } + } while (error == 0 && uio.uio_resid < NFS_PACKRATIOSIZE); + free(iobuf, M_TEMP); + + if (error == 0) { + vnode_pager_setsize(dp->nfsdl_filevp, dp->nfsdl_localsize); + NFSLOCKCLSTATE(); + dp->nfsdl_flags &= ~NFSCLDL_COPYINPROG; + dp->nfsdl_flags |= NFSCLDL_HASCOPY; + wakeup(&dp->nfsdl_flags); + wakeup(&dp->nfsdl_localsize); + NFSUNLOCKCLSTATE(); + } else + nfscl_packratbreakdown(dp, dp->nfsdl_clp->nfsc_nmp, outcred, + td); + NFSFREECRED(incred); + NFSFREECRED(outcred); +} + +/* + * Read operation against an NFSv4 delegation. + */ +static int +nfsrpc_readdp(struct nfscldeleg *dp, struct uio *uiop, struct ucred *cred, + NFSPROC_T *p) +{ + int error, expireret = 0, retrycnt; + u_int32_t clidrev = 0; + + clidrev = dp->nfsdl_clp->nfsc_clientidrev; + retrycnt = 0; + do { + error = nfsrpc_readrpcdp(dp, uiop, cred, p); + if (error == NFSERR_STALESTATEID) + nfscl_initiate_recovery(dp->nfsdl_clp); + if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || + error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || + error == NFSERR_OLDSTATEID) { + (void) nfs_catnap(PZERO, error, "nfs_readdp"); + } else if ((error == NFSERR_EXPIRED || + error == NFSERR_BADSTATEID) && clidrev != 0) { + expireret = nfscl_hasexpired(dp->nfsdl_clp, clidrev, p); + } + retrycnt++; + } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || + error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || + (error == NFSERR_OLDSTATEID && retrycnt < 20) || + ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && + expireret == 0 && clidrev != 0 && retrycnt < 4)); + if (error && retrycnt >= 4) + error = EIO; + return (error); +} + +/* + * The actual read RPC for the above. + */ +static int +nfsrpc_readrpcdp(struct nfscldeleg *dp, struct uio *uiop, struct ucred *cred, + NFSPROC_T *p) +{ + u_int32_t *tl; + int error = 0, len, retlen, tsiz, eof = 0; + struct nfsrv_descript nfsd; + struct nfsrv_descript *nd = &nfsd; + struct nfsmount *nmp; + + nmp = dp->nfsdl_clp->nfsc_nmp; + if (nmp == NULL) + return (0); + tsiz = uio_uio_resid(uiop); + nd->nd_mrep = NULL; + while (tsiz > 0) { + len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; + nfscl_reqstart(nd, NFSPROC_READ, nmp, dp->nfsdl_fh, + dp->nfsdl_fhlen, NULL, NULL); + nfsm_stateidtom(nd, &dp->nfsdl_stateid, NFSSTATEID_PUTSTATEID); + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); + txdr_hyper(uiop->uio_offset, tl); + *(tl + 2) = txdr_unsigned(len); + 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 || error != 0) { + if (error == 0) + error = nd->nd_repstat; + goto nfsmout; + } + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + eof = fxdr_unsigned(int, *tl); + NFSM_STRSIZ(retlen, nmp->nm_rsize); + error = nfsm_mbufuio(nd, uiop, retlen); + if (error) + goto nfsmout; + mbuf_freem(nd->nd_mrep); + nd->nd_mrep = NULL; + tsiz -= retlen; + if (eof || retlen == 0) + tsiz = 0; + } + return (0); +nfsmout: + if (nd->nd_mrep != NULL) + mbuf_freem(nd->nd_mrep); + return (error); +} + +static u_int8_t *not64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$%"; +static u_int8_t *hexval = "0123456789abcdef"; +/* + * This function generates a file name for the file handle passed in as an + * argument. Since the file handle can be up to 128 bytes and a file name is + * limited to 255 in length, a simple hexadecimal representation doesn't + * work. + * The name looks like this: + * - 2 hex digits for the file handle length + * - fhlen/3 sequences of four characters, where each ascii character + * represents 6 bits (4 digits representing the 3 bytes) + * - 0 to 2 bytes represented as hexadecimal + * As such, a 128 byte fh creates a 174 byte file name. + * The name argument must point to sufficient storage. + */ +static void +nfscl_fhtofilename(u_int8_t *fh, u_int16_t fhlen, char *name) +{ + + *name++ = hexval[fhlen & 0xf]; + *name++ = hexval[fhlen >> 4]; + + /* + * Now loop around for the fh bytes until < 3 left. + */ + while (fhlen >= 3) { + *name++ = not64[*fh & 0x3f]; + *name++ = not64[((*fh & 0xc0) >> 2) | (*(fh + 1) & 0xf)]; + *name++ = not64[(*(fh + 1) >> 4) | ((*(fh + 2) & 0xc0) >> 2)]; + *name++ = not64[*(fh + 2) & 0x3f]; + fh += 3; + fhlen -= 3; + } + + /* + * and then do the last 0 to 2 bytes as hexadecimal. + */ + while (fhlen > 0) { + *name++ = hexval[*fh & 0xf]; + *name++ = hexval[*fh >> 4]; + fh++; + fhlen--; + } + *name = '\0'; +} + +/* + * Set up a new delegation for packrat support. + */ +void +nfscl_packratsetup(struct nfscldeleg *dp, struct nfsmount *nmp, + struct ucred *cred, NFSPROC_T *p) +{ + vnode_t delegvp, filevp; + char fname[MAXPATHLEN + 1]; + int pathlen, pathlen2; + + NFSLOCKCLSTATE(); + if (nfscl_packratpathlen == 0 || + dp->nfsdl_opensize > nfscl_packratmaxsize) { + dp->nfsdl_flags &= ~NFSCLDL_COPYINPROG; + wakeup(&dp->nfsdl_flags); + NFSUNLOCKCLSTATE(); + return; + } + pathlen = nfscl_packratpathlen; + bcopy(nfscl_packratpath, &fname[0], pathlen); + NFSUNLOCKCLSTATE(); + + /* + * The appropriate fields of the delegation structure are already + * initialized, so create the files and, if that is successful, + * fire up a packrat thread for it. + */ + pathlen2 = pathlen; + fname[pathlen++] = 'D'; + pathlen = nfscl_packrathostaddr(nmp, &fname[0], pathlen); + if (pathlen == 0) { + NFSLOCKCLSTATE(); + dp->nfsdl_flags &= ~NFSCLDL_COPYINPROG; + wakeup(&dp->nfsdl_flags); + NFSUNLOCKCLSTATE(); + return; + } + nfscl_fhtofilename(dp->nfsdl_fh, dp->nfsdl_fhlen, &fname[pathlen]); + delegvp = nfscl_openfile(fname, TRUE, cred, p); + if (delegvp == NULL) { + NFSLOCKCLSTATE(); + dp->nfsdl_flags &= ~NFSCLDL_COPYINPROG; + wakeup(&dp->nfsdl_flags); + NFSUNLOCKCLSTATE(); + return; + } + VOP_UNLOCK(delegvp, 0); + fname[pathlen2] = 'F'; + filevp = nfscl_openfile(fname, TRUE, cred, p); + if (filevp == NULL) { + nfscl_closefile(delegvp, fname, TRUE, cred, p); + NFSLOCKCLSTATE(); + dp->nfsdl_flags &= ~NFSCLDL_COPYINPROG; + wakeup(&dp->nfsdl_flags); + NFSUNLOCKCLSTATE(); + return; + } + VOP_UNLOCK(filevp, 0); + + NFSLOCKCLSTATE(); + dp->nfsdl_delegvp = delegvp; + dp->nfsdl_filevp = filevp; + dp->nfsdl_localsize = 0; + NFSUNLOCKCLSTATE(); + + nfscl_start_packratthread(dp); +} + +/* + * Reopen the locally cached copy of the file, created by nfscl_packratsetup(). + */ +void +nfscl_packratopen(vnode_t vp, NFSPROC_T *p) +{ + struct nfsclclient *clp; + struct nfscldeleg *dp; + struct nfsnode *np = VTONFS(vp); + struct nfsmount *nmp; + struct ucred *cred; + char fname[MAXPATHLEN + 1]; + int pathlen; + + nmp = VFSTONFS(vnode_mount(vp)); + NFSLOCKCLSTATE(); + if (nfscl_packratpathlen == 0 || (nmp->nm_flag & NFSMNT_NFSV4) == 0) { + NFSUNLOCKCLSTATE(); + return; + } + clp = nfscl_findcl(nmp); + if (clp == NULL) { + NFSUNLOCKCLSTATE(); + return; + } + dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); + if (dp == NULL || (dp->nfsdl_flags & + (NFSCLDL_RECALL | NFSCLDL_WRITE | NFSCLDL_HASCOPY)) != + (NFSCLDL_WRITE | NFSCLDL_HASCOPY) || + dp->nfsdl_filevp != NULL) { + NFSUNLOCKCLSTATE(); + return; + } + + /* Now, try and reopen them. */ + pathlen = nfscl_packratpathlen; + bcopy(nfscl_packratpath, &fname[0], pathlen); + NFSUNLOCKCLSTATE(); + + cred = newnfs_getcred(); + nfscl_packratgetvp(dp, nmp, fname, pathlen, cred, p); + NFSFREECRED(cred); +} + +/* + * Do the actual reopens to get the vnodes. + */ +static void +nfscl_packratgetvp(struct nfscldeleg *dp, struct nfsmount *nmp, char *fname, + int pathlen, struct ucred *cred, NFSPROC_T *p) +{ + vnode_t delegvp, filevp; + boolean_t closethem; + int pathlen2; + + /* + * The appropriate fields of the delegation structure are already + * initialized, so create the files and, if that is successful, + * fire up a packrat thread for it. + */ + pathlen2 = pathlen; + fname[pathlen++] = 'D'; + pathlen = nfscl_packrathostaddr(nmp, &fname[0], pathlen); + if (pathlen == 0) + return; + nfscl_fhtofilename(dp->nfsdl_fh, dp->nfsdl_fhlen, &fname[pathlen]); + delegvp = nfscl_openfile(fname, FALSE, cred, p); + if (delegvp == NULL) + return; + VOP_UNLOCK(delegvp, 0); + fname[pathlen2] = 'F'; + filevp = nfscl_openfile(fname, FALSE, cred, p); + if (filevp == NULL) { + nfscl_closefile(delegvp, fname, FALSE, cred, p); + return; + } + VOP_UNLOCK(filevp, 0); + + NFSLOCKCLSTATE(); + if (dp->nfsdl_delegvp == NULL) { + dp->nfsdl_delegvp = delegvp; + dp->nfsdl_filevp = filevp; + closethem = FALSE; + } else + closethem = TRUE; + NFSUNLOCKCLSTATE(); + + if (closethem) { + fname[pathlen2] = 'D'; + nfscl_closefile(delegvp, fname, FALSE, cred, p); + fname[pathlen2] = 'F'; + nfscl_closefile(filevp, fname, FALSE, cred, p); + } +} + +/* + * Get rid of the local files related to a delegation. + */ +static void +nfscl_packratbreakdown(struct nfscldeleg *dp, struct nfsmount *nmp, + struct ucred *cred, NFSPROC_T *p) +{ + vnode_t delegvp, filevp; + char fname[MAXPATHLEN + 1]; + int pathlen, pathlen2; + + /* + * Get the vnode pointers out of the delegation structure and + * null them out. + */ + NFSLOCKCLSTATE(); + pathlen = nfscl_packratpathlen; + if (pathlen > 0) + bcopy(nfscl_packratpath, &fname[0], pathlen); + delegvp = dp->nfsdl_delegvp; + filevp = dp->nfsdl_filevp; + dp->nfsdl_delegvp = NULL; + dp->nfsdl_filevp = NULL; + pathlen2 = pathlen; + if (pathlen > 0) { + fname[pathlen++] = 'D'; + pathlen = nfscl_packrathostaddr(nmp, &fname[0], pathlen); + } + if (pathlen > 0) + nfscl_fhtofilename(dp->nfsdl_fh, dp->nfsdl_fhlen, + &fname[pathlen]); + while (dp->nfsdl_localiocnt > 0) + (void) nfsmsleep(&dp->nfsdl_localiocnt, NFSCLSTATEMUTEXPTR, + PZERO, "nfspckbr", NULL); + if ((dp->nfsdl_flags & NFSCLDL_COPYINPROG) != 0) { + dp->nfsdl_flags &= ~NFSCLDL_COPYINPROG; + wakeup(&dp->nfsdl_flags); + } + NFSUNLOCKCLSTATE(); + if (pathlen == 0) + return; + + /* + * Close/remove the 2 files. + */ + if (delegvp != NULL) + nfscl_closefile(delegvp, fname, TRUE, cred, p); + fname[pathlen2] = 'F'; + if (filevp != NULL) + nfscl_closefile(filevp, fname, TRUE, cred, p); +} + +/* + * Close the local files related to a delegation in order to release the + * vnodes. + */ +void +nfscl_packratclose(vnode_t vp, NFSPROC_T *p) +{ + struct nfsclclient *clp; + struct nfscldeleg *dp; + struct nfsnode *np = VTONFS(vp); + struct nfsmount *nmp; + struct ucred *cred; + vnode_t delegvp, filevp; + char fname[MAXPATHLEN + 1]; + int pathlen, pathlen2; + + nmp = VFSTONFS(vnode_mount(vp)); + NFSLOCKCLSTATE(); + if (nfscl_packratpathlen == 0 || (nmp->nm_flag & NFSMNT_NFSV4) == 0 || + vp->v_usecount > 1) { + NFSUNLOCKCLSTATE(); + return; + } + clp = nfscl_findcl(nmp); + if (clp == NULL) { + NFSUNLOCKCLSTATE(); + return; + } + dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); + if (dp == NULL || (dp->nfsdl_flags & + (NFSCLDL_RECALL | NFSCLDL_WRITE | NFSCLDL_HASCOPY)) != + (NFSCLDL_WRITE | NFSCLDL_HASCOPY) || + dp->nfsdl_filevp == NULL) { + NFSUNLOCKCLSTATE(); + return; + } + pathlen = nfscl_packratpathlen; + bcopy(nfscl_packratpath, &fname[0], pathlen); + delegvp = dp->nfsdl_delegvp; + filevp = dp->nfsdl_filevp; + dp->nfsdl_delegvp = NULL; + dp->nfsdl_filevp = NULL; + while (dp->nfsdl_localiocnt > 0) + (void) nfsmsleep(&dp->nfsdl_localiocnt, NFSCLSTATEMUTEXPTR, + PZERO, "nfspckbr", NULL); + NFSUNLOCKCLSTATE(); + pathlen2 = pathlen; + fname[pathlen++] = 'D'; + pathlen = nfscl_packrathostaddr(nmp, &fname[0], pathlen); + if (pathlen == 0) + return; + nfscl_fhtofilename(np->n_fhp->nfh_fh, np->n_fhp->nfh_len, + &fname[pathlen]); + + /* + * Close the 2 files. + */ + cred = newnfs_getcred(); + nfscl_closefile(delegvp, fname, FALSE, cred, p); + fname[pathlen2] = 'F'; + nfscl_closefile(filevp, fname, FALSE, cred, p); + NFSFREECRED(cred); +} + +/* + * Set up the packrat directory. + */ +int +nfscbd_packrat(char *pathbuf) +{ + int pathlen; + + pathlen = strlen(pathbuf); + if (pathlen < 1 || pathbuf[pathlen - 1] != '/') + return (EINVAL); + NFSLOCKCLSTATE(); + strcpy(nfscl_packratpath, pathbuf); + nfscl_packratpathlen = pathlen; + NFSUNLOCKCLSTATE(); + return (0); +} + +/* + * Do a read via a local cached copy, if possible. + * Return whether or not the local read was possible via "didread". + */ +int +nfscl_packratread(vnode_t vp, struct uio *uio, int ioflag, struct ucred *cred, + int *didread) +{ + struct nfsclclient *clp; + struct nfscldeleg *dp; + struct nfsnode *np = VTONFS(vp); + struct nfsmount *nmp; + vnode_t filevp; + int error; + ssize_t tresid; + + *didread = 0; + nmp = VFSTONFS(vnode_mount(vp)); + NFSLOCKCLSTATE(); + if (nfscl_packratpathlen == 0 || (nmp->nm_flag & NFSMNT_NFSV4) == 0) { + NFSUNLOCKCLSTATE(); + return (0); + } + clp = nfscl_findcl(nmp); + if (clp == NULL) { + NFSUNLOCKCLSTATE(); + return (0); + } + dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); + if (dp == NULL || (dp->nfsdl_flags & + (NFSCLDL_RECALL | NFSCLDL_WRITE)) != NFSCLDL_WRITE || + dp->nfsdl_filevp == NULL || + ((dp->nfsdl_flags & NFSCLDL_COPYINPROG) != 0 && + uio->uio_offset + uio->uio_resid > dp->nfsdl_localsize)) { + if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_RECALL) != 0) { + dp->nfsdl_flags |= NFSCLDL_WAITRECALL; + (void) nfsmsleep(&dp->nfsdl_ldirty, NFSCLSTATEMUTEXPTR, + PZERO, "nfspkrc", NULL); + } + NFSUNLOCKCLSTATE(); + NFSLOCKNODE(np); + NFSINVALATTRCACHE(np); + np->n_flag &= ~NLOCALCACHE; + NFSUNLOCKNODE(np); + return (0); + } + + *didread = 1; + if (uio->uio_offset >= dp->nfsdl_localsize) { + NFSUNLOCKCLSTATE(); + return (0); + } + if (uio->uio_offset + uio->uio_resid > dp->nfsdl_localsize) { + tresid = uio->uio_resid; + uio->uio_resid = dp->nfsdl_localsize - uio->uio_offset; + tresid -= uio->uio_resid; + } else + tresid = 0; + dp->nfsdl_localiocnt++; + filevp = dp->nfsdl_filevp; + NFSUNLOCKCLSTATE(); + error = 0; + vn_lock(filevp, LK_SHARED | LK_RETRY); + VI_LOCK(filevp); + if ((filevp->v_iflag & VI_DOOMED) != 0) + error = ENOENT; + VI_UNLOCK(filevp); + if (error == 0) + error = VOP_READ(filevp, uio, ioflag, cred); + VOP_UNLOCK(filevp, 0); + uio->uio_resid += tresid; + NFSLOCKCLSTATE(); + dp->nfsdl_localiocnt--; + if (dp->nfsdl_localiocnt == 0) + wakeup(&dp->nfsdl_localiocnt); + NFSUNLOCKCLSTATE(); + return (error); +} + +/* + * Do a write into a local copy cached on disk, if possible. + * Return whether or not the local write was possible via "didwrite". + */ +int +nfscl_packratwrite(vnode_t vp, struct uio *uio, int ioflag, struct ucred *cred, + NFSPROC_T *p, int *didwrite) +{ + struct nfsclclient *clp; + struct nfscldeleg *dp; + struct nfsnode *np = VTONFS(vp); + struct nfsmount *nmp; + struct mount *mp; + struct nfsldirty *wp; + vnode_t filevp; + uint64_t end; + int error; + off_t setsize; + + *didwrite = 0; + nmp = VFSTONFS(vnode_mount(vp)); + NFSLOCKCLSTATE(); + if (nfscl_packratpathlen == 0 || (nmp->nm_flag & NFSMNT_NFSV4) == 0) { + NFSUNLOCKCLSTATE(); + NFSLOCKNODE(np); + np->n_flag &= ~NLOCALCACHE; + NFSUNLOCKNODE(np); + return (0); + } + clp = nfscl_findcl(nmp); + if (clp == NULL) { + NFSUNLOCKCLSTATE(); + NFSLOCKNODE(np); + np->n_flag &= ~NLOCALCACHE; + NFSUNLOCKNODE(np); + return (0); + } + dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len); + if (dp == NULL || (dp->nfsdl_flags & + (NFSCLDL_RECALL | NFSCLDL_WRITE)) != NFSCLDL_WRITE || + dp->nfsdl_filevp == NULL) { + if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_RECALL) != 0) { + dp->nfsdl_flags |= NFSCLDL_WAITRECALL; + (void) nfsmsleep(&dp->nfsdl_ldirty, NFSCLSTATEMUTEXPTR, + PZERO, "nfspkwc", NULL); + } + NFSUNLOCKCLSTATE(); + NFSLOCKNODE(np); + np->n_flag &= ~NLOCALCACHE; + NFSUNLOCKNODE(np); + return (0); + } + + /* + * We can now try and do the write. It cannot be done until the + * local copy has been read in to past the point at which we + * are writing, so we must loop until enough reading has been + * completed. + */ + end = (uint64_t)uio->uio_offset + uio->uio_resid; + while ((dp->nfsdl_flags & NFSCLDL_COPYINPROG) != 0 && + (end > dp->nfsdl_localsize || (ioflag & IO_APPEND) != 0)) + (void) nfsmsleep(&dp->nfsdl_localsize, NFSCLSTATEMUTEXPTR, + PZERO, "nfspckw", NULL); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201212290210.qBT2Atnd050518>