The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_vfsops.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: nfs_vfsops.c,v 1.203 2008/10/22 12:29:35 matt Exp $    */
    2 
    3 /*
    4  * Copyright (c) 1989, 1993, 1995
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Rick Macklem at The University of Guelph.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      @(#)nfs_vfsops.c        8.12 (Berkeley) 5/20/95
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: nfs_vfsops.c,v 1.203 2008/10/22 12:29:35 matt Exp $");
   39 
   40 #if defined(_KERNEL_OPT)
   41 #include "opt_compat_netbsd.h"
   42 #include "opt_nfs.h"
   43 #endif
   44 
   45 #include <sys/param.h>
   46 #include <sys/ioctl.h>
   47 #include <sys/signal.h>
   48 #include <sys/proc.h>
   49 #include <sys/namei.h>
   50 #include <sys/device.h>
   51 #include <sys/vnode.h>
   52 #include <sys/kernel.h>
   53 #include <sys/mount.h>
   54 #include <sys/buf.h>
   55 #include <sys/mbuf.h>
   56 #include <sys/dirent.h>
   57 #include <sys/socket.h>
   58 #include <sys/socketvar.h>
   59 #include <sys/sysctl.h>
   60 #include <sys/systm.h>
   61 #include <sys/timetc.h>
   62 #include <sys/kauth.h>
   63 #include <sys/module.h>
   64 
   65 #include <net/if.h>
   66 #include <net/route.h>
   67 #include <netinet/in.h>
   68 
   69 #include <nfs/rpcv2.h>
   70 #include <nfs/nfsproto.h>
   71 #include <nfs/nfsnode.h>
   72 #include <nfs/nfs.h>
   73 #include <nfs/nfsmount.h>
   74 #include <nfs/xdr_subs.h>
   75 #include <nfs/nfsm_subs.h>
   76 #include <nfs/nfsdiskless.h>
   77 #include <nfs/nfs_var.h>
   78 
   79 MODULE(MODULE_CLASS_VFS, nfs, NULL);
   80 
   81 extern struct nfsstats nfsstats;
   82 extern int nfs_ticks;
   83 
   84 /*
   85  * keep a count of the nfs mounts to generate ficticious drive names
   86  * for the per drive stats.
   87  */
   88 unsigned int nfs_mount_count = 0;
   89 
   90 /*
   91  * nfs vfs operations.
   92  */
   93 
   94 extern const struct vnodeopv_desc nfsv2_vnodeop_opv_desc;
   95 extern const struct vnodeopv_desc spec_nfsv2nodeop_opv_desc;
   96 extern const struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc;
   97 
   98 const struct vnodeopv_desc * const nfs_vnodeopv_descs[] = {
   99         &nfsv2_vnodeop_opv_desc,
  100         &spec_nfsv2nodeop_opv_desc,
  101         &fifo_nfsv2nodeop_opv_desc,
  102         NULL,
  103 };
  104 
  105 struct vfsops nfs_vfsops = {
  106         MOUNT_NFS,
  107         sizeof (struct nfs_args),
  108         nfs_mount,
  109         nfs_start,
  110         nfs_unmount,
  111         nfs_root,
  112         (void *)eopnotsupp,     /* vfs_quotactl */
  113         nfs_statvfs,
  114         nfs_sync,
  115         nfs_vget,
  116         nfs_fhtovp,
  117         nfs_vptofh,
  118         nfs_vfs_init,
  119         NULL,
  120         nfs_vfs_done,
  121         nfs_mountroot,
  122         (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
  123         vfs_stdextattrctl,
  124         (void *)eopnotsupp,     /* vfs_suspendctl */
  125         genfs_renamelock_enter,
  126         genfs_renamelock_exit,
  127         (void *)eopnotsupp,
  128         nfs_vnodeopv_descs,
  129         0,
  130         { NULL, NULL },
  131 };
  132 
  133 static int
  134 nfs_modcmd(modcmd_t cmd, void *arg)
  135 {
  136 
  137         switch (cmd) {
  138         case MODULE_CMD_INIT:
  139                 return vfs_attach(&nfs_vfsops);
  140         case MODULE_CMD_FINI:
  141                 return vfs_detach(&nfs_vfsops);
  142         default:
  143                 return ENOTTY;
  144         }
  145 }
  146 
  147 extern u_int32_t nfs_procids[NFS_NPROCS];
  148 extern u_int32_t nfs_prog, nfs_vers;
  149 
  150 static int nfs_mount_diskless __P((struct nfs_dlmount *, const char *,
  151     struct mount **, struct vnode **, struct lwp *));
  152 
  153 /*
  154  * nfs statvfs call
  155  */
  156 int
  157 nfs_statvfs(mp, sbp)
  158         struct mount *mp;
  159         struct statvfs *sbp;
  160 {
  161         struct lwp *l = curlwp;
  162         struct vnode *vp;
  163         struct nfs_statfs *sfp;
  164         char *cp;
  165         u_int32_t *tl;
  166         int32_t t1, t2;
  167         char *bpos, *dpos, *cp2;
  168         struct nfsmount *nmp = VFSTONFS(mp);
  169         int error = 0, retattr;
  170 #ifdef NFS_V2_ONLY
  171         const int v3 = 0;
  172 #else
  173         int v3 = (nmp->nm_flag & NFSMNT_NFSV3);
  174 #endif
  175         struct mbuf *mreq, *mrep = NULL, *md, *mb;
  176         kauth_cred_t cred;
  177         u_quad_t tquad;
  178         struct nfsnode *np;
  179 
  180 #ifndef nolint
  181         sfp = (struct nfs_statfs *)0;
  182 #endif
  183         vp = nmp->nm_vnode;
  184         np = VTONFS(vp);
  185         cred = kauth_cred_alloc();
  186 #ifndef NFS_V2_ONLY
  187         if (v3 && (nmp->nm_iflag & NFSMNT_GOTFSINFO) == 0)
  188                 (void)nfs_fsinfo(nmp, vp, cred, l);
  189 #endif
  190         nfsstats.rpccnt[NFSPROC_FSSTAT]++;
  191         nfsm_reqhead(np, NFSPROC_FSSTAT, NFSX_FH(v3));
  192         nfsm_fhtom(np, v3);
  193         nfsm_request(np, NFSPROC_FSSTAT, l, cred);
  194         if (v3)
  195                 nfsm_postop_attr(vp, retattr, 0);
  196         if (error) {
  197                 if (mrep != NULL) {
  198                         if (mrep->m_next != NULL)
  199                                 printf("nfs_vfsops: nfs_statvfs would lose buffers\n");
  200                         m_freem(mrep);
  201                 }
  202                 goto nfsmout;
  203         }
  204         nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
  205         sbp->f_flag = nmp->nm_flag;
  206         sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
  207         if (v3) {
  208                 sbp->f_frsize = sbp->f_bsize = NFS_FABLKSIZE;
  209                 tquad = fxdr_hyper(&sfp->sf_tbytes);
  210                 sbp->f_blocks = ((quad_t)tquad / (quad_t)NFS_FABLKSIZE);
  211                 tquad = fxdr_hyper(&sfp->sf_fbytes);
  212                 sbp->f_bfree = ((quad_t)tquad / (quad_t)NFS_FABLKSIZE);
  213                 tquad = fxdr_hyper(&sfp->sf_abytes);
  214                 tquad = ((quad_t)tquad / (quad_t)NFS_FABLKSIZE);
  215                 sbp->f_bresvd = sbp->f_bfree - tquad;
  216                 sbp->f_bavail = tquad;
  217 #ifdef COMPAT_20
  218                 /* Handle older NFS servers returning negative values */
  219                 if ((quad_t)sbp->f_bavail < 0)
  220                         sbp->f_bavail = 0;
  221 #endif
  222                 tquad = fxdr_hyper(&sfp->sf_tfiles);
  223                 sbp->f_files = tquad;
  224                 tquad = fxdr_hyper(&sfp->sf_ffiles);
  225                 sbp->f_ffree = tquad;
  226                 sbp->f_favail = tquad;
  227                 sbp->f_fresvd = 0;
  228                 sbp->f_namemax = MAXNAMLEN;
  229         } else {
  230                 sbp->f_bsize = NFS_FABLKSIZE;
  231                 sbp->f_frsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
  232                 sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
  233                 sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);
  234                 sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
  235                 sbp->f_fresvd = 0;
  236                 sbp->f_files = 0;
  237                 sbp->f_ffree = 0;
  238                 sbp->f_favail = 0;
  239                 sbp->f_fresvd = 0;
  240                 sbp->f_namemax = MAXNAMLEN;
  241         }
  242         copy_statvfs_info(sbp, mp);
  243         nfsm_reqdone;
  244         kauth_cred_free(cred);
  245         return (error);
  246 }
  247 
  248 #ifndef NFS_V2_ONLY
  249 /*
  250  * nfs version 3 fsinfo rpc call
  251  */
  252 int
  253 nfs_fsinfo(nmp, vp, cred, l)
  254         struct nfsmount *nmp;
  255         struct vnode *vp;
  256         kauth_cred_t cred;
  257         struct lwp *l;
  258 {
  259         struct nfsv3_fsinfo *fsp;
  260         char *cp;
  261         int32_t t1, t2;
  262         u_int32_t *tl, pref, xmax;
  263         char *bpos, *dpos, *cp2;
  264         int error = 0, retattr;
  265         struct mbuf *mreq, *mrep, *md, *mb;
  266         u_int64_t maxfsize;
  267         struct nfsnode *np = VTONFS(vp);
  268 
  269         nfsstats.rpccnt[NFSPROC_FSINFO]++;
  270         nfsm_reqhead(np, NFSPROC_FSINFO, NFSX_FH(1));
  271         nfsm_fhtom(np, 1);
  272         nfsm_request(np, NFSPROC_FSINFO, l, cred);
  273         nfsm_postop_attr(vp, retattr, 0);
  274         if (!error) {
  275                 nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
  276                 pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
  277                 if ((nmp->nm_flag & NFSMNT_WSIZE) == 0 &&
  278                     pref < nmp->nm_wsize && pref >= NFS_FABLKSIZE)
  279                         nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
  280                                 ~(NFS_FABLKSIZE - 1);
  281                 xmax = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
  282                 if (xmax < nmp->nm_wsize && xmax > 0) {
  283                         nmp->nm_wsize = xmax & ~(NFS_FABLKSIZE - 1);
  284                         if (nmp->nm_wsize == 0)
  285                                 nmp->nm_wsize = xmax;
  286                 }
  287                 pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
  288                 if ((nmp->nm_flag & NFSMNT_RSIZE) == 0 &&
  289                     pref < nmp->nm_rsize && pref >= NFS_FABLKSIZE)
  290                         nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
  291                                 ~(NFS_FABLKSIZE - 1);
  292                 xmax = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
  293                 if (xmax < nmp->nm_rsize && xmax > 0) {
  294                         nmp->nm_rsize = xmax & ~(NFS_FABLKSIZE - 1);
  295                         if (nmp->nm_rsize == 0)
  296                                 nmp->nm_rsize = xmax;
  297                 }
  298                 pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
  299                 if (pref < nmp->nm_readdirsize && pref >= NFS_DIRFRAGSIZ)
  300                         nmp->nm_readdirsize = (pref + NFS_DIRFRAGSIZ - 1) &
  301                                 ~(NFS_DIRFRAGSIZ - 1);
  302                 if (xmax < nmp->nm_readdirsize && xmax > 0) {
  303                         nmp->nm_readdirsize = xmax & ~(NFS_DIRFRAGSIZ - 1);
  304                         if (nmp->nm_readdirsize == 0)
  305                                 nmp->nm_readdirsize = xmax;
  306                 }
  307                 /* XXX */
  308                 nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1;
  309                 maxfsize = fxdr_hyper(&fsp->fs_maxfilesize);
  310                 if (maxfsize > 0 && maxfsize < nmp->nm_maxfilesize)
  311                         nmp->nm_maxfilesize = maxfsize;
  312                 nmp->nm_mountp->mnt_fs_bshift =
  313                     ffs(MIN(nmp->nm_rsize, nmp->nm_wsize)) - 1;
  314                 nmp->nm_iflag |= NFSMNT_GOTFSINFO;
  315         }
  316         nfsm_reqdone;
  317         return (error);
  318 }
  319 #endif
  320 
  321 /*
  322  * Mount a remote root fs via. NFS.  It goes like this:
  323  * - Call nfs_boot_init() to fill in the nfs_diskless struct
  324  * - build the rootfs mount point and call mountnfs() to do the rest.
  325  */
  326 int
  327 nfs_mountroot()
  328 {
  329         struct timespec ts;
  330         struct nfs_diskless *nd;
  331         struct vattr attr;
  332         struct mount *mp;
  333         struct vnode *vp;
  334         struct lwp *l;
  335         long n;
  336         int error;
  337 
  338         l = curlwp; /* XXX */
  339 
  340         if (device_class(root_device) != DV_IFNET)
  341                 return (ENODEV);
  342 
  343         /*
  344          * XXX time must be non-zero when we init the interface or else
  345          * the arp code will wedge.  [Fixed now in if_ether.c]
  346          * However, the NFS attribute cache gives false "hits" when the
  347          * current time < nfs_attrtimeo(nmp, np) so keep this in for now.
  348          */
  349         if (time_second < NFS_MAXATTRTIMO) {
  350                 ts.tv_sec = NFS_MAXATTRTIMO;
  351                 ts.tv_nsec = 0;
  352                 tc_setclock(&ts);
  353         }
  354 
  355         /*
  356          * Call nfs_boot_init() to fill in the nfs_diskless struct.
  357          * Side effect:  Finds and configures a network interface.
  358          */
  359         nd = kmem_zalloc(sizeof(*nd), KM_SLEEP);
  360         error = nfs_boot_init(nd, l);
  361         if (error) {
  362                 kmem_free(nd, sizeof(*nd));
  363                 return (error);
  364         }
  365 
  366         /*
  367          * Create the root mount point.
  368          */
  369         error = nfs_mount_diskless(&nd->nd_root, "/", &mp, &vp, l);
  370         if (error)
  371                 goto out;
  372         printf("root on %s\n", nd->nd_root.ndm_host);
  373 
  374         /*
  375          * Link it into the mount list.
  376          */
  377         mutex_enter(&mountlist_lock);
  378         CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
  379         mutex_exit(&mountlist_lock);
  380         rootvp = vp;
  381         mp->mnt_vnodecovered = NULLVP;
  382         vfs_unbusy(mp, false, NULL);
  383 
  384         /* Get root attributes (for the time). */
  385         error = VOP_GETATTR(vp, &attr, l->l_cred);
  386         if (error)
  387                 panic("nfs_mountroot: getattr for root");
  388         n = attr.va_atime.tv_sec;
  389 #ifdef  DEBUG
  390         printf("root time: 0x%lx\n", n);
  391 #endif
  392         setrootfstime(n);
  393 
  394 out:
  395         if (error)
  396                 nfs_boot_cleanup(nd, l);
  397         kmem_free(nd, sizeof(*nd));
  398         return (error);
  399 }
  400 
  401 /*
  402  * Internal version of mount system call for diskless setup.
  403  * Separate function because we used to call it twice.
  404  * (once for root and once for swap)
  405  */
  406 static int
  407 nfs_mount_diskless(ndmntp, mntname, mpp, vpp, l)
  408         struct nfs_dlmount *ndmntp;
  409         const char *mntname;    /* mount point name */
  410         struct mount **mpp;
  411         struct vnode **vpp;
  412         struct lwp *l;
  413 {
  414         struct mount *mp;
  415         struct mbuf *m;
  416         int error;
  417 
  418         vfs_rootmountalloc(MOUNT_NFS, mntname, &mp);
  419 
  420         mp->mnt_op = &nfs_vfsops;
  421 
  422         /*
  423          * Historical practice expects NFS root file systems to
  424          * be initially mounted r/w.
  425          */
  426         mp->mnt_flag &= ~MNT_RDONLY;
  427 
  428         /* Get mbuf for server sockaddr. */
  429         m = m_get(M_WAIT, MT_SONAME);
  430         if (m == NULL)
  431                 panic("nfs_mountroot: mget soname for %s", mntname);
  432         MCLAIM(m, &nfs_mowner);
  433         memcpy(mtod(m, void *), (void *)ndmntp->ndm_args.addr,
  434               (m->m_len = ndmntp->ndm_args.addr->sa_len));
  435 
  436         error = mountnfs(&ndmntp->ndm_args, mp, m, mntname,
  437                          ndmntp->ndm_args.hostname, vpp, l);
  438         if (error) {
  439                 vfs_unbusy(mp, false, NULL);
  440                 vfs_destroy(mp);
  441                 printf("nfs_mountroot: mount %s failed: %d\n",
  442                        mntname, error);
  443         } else
  444                 *mpp = mp;
  445 
  446         return (error);
  447 }
  448 
  449 void
  450 nfs_decode_args(nmp, argp, l)
  451         struct nfsmount *nmp;
  452         struct nfs_args *argp;
  453         struct lwp *l;
  454 {
  455         int s;
  456         int adjsock;
  457         int maxio;
  458 
  459         s = splsoftnet();
  460 
  461         /*
  462          * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
  463          * no sense in that context.
  464          */
  465         if (argp->sotype == SOCK_STREAM)
  466                 argp->flags &= ~NFSMNT_NOCONN;
  467 
  468         /*
  469          * Cookie translation is not needed for v2, silently ignore it.
  470          */
  471         if ((argp->flags & (NFSMNT_XLATECOOKIE|NFSMNT_NFSV3)) ==
  472             NFSMNT_XLATECOOKIE)
  473                 argp->flags &= ~NFSMNT_XLATECOOKIE;
  474 
  475         /* Re-bind if rsrvd port requested and wasn't on one */
  476         adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
  477                   && (argp->flags & NFSMNT_RESVPORT);
  478         /* Also re-bind if we're switching to/from a connected UDP socket */
  479         adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
  480                     (argp->flags & NFSMNT_NOCONN));
  481 
  482         /* Update flags. */
  483         nmp->nm_flag = argp->flags;
  484         splx(s);
  485 
  486         if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
  487                 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
  488                 if (nmp->nm_timeo < NFS_MINTIMEO)
  489                         nmp->nm_timeo = NFS_MINTIMEO;
  490                 else if (nmp->nm_timeo > NFS_MAXTIMEO)
  491                         nmp->nm_timeo = NFS_MAXTIMEO;
  492         }
  493 
  494         if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
  495                 nmp->nm_retry = argp->retrans;
  496                 if (nmp->nm_retry > NFS_MAXREXMIT)
  497                         nmp->nm_retry = NFS_MAXREXMIT;
  498         }
  499 
  500 #ifndef NFS_V2_ONLY
  501         if (argp->flags & NFSMNT_NFSV3) {
  502                 if (argp->sotype == SOCK_DGRAM)
  503                         maxio = NFS_MAXDGRAMDATA;
  504                 else
  505                         maxio = NFS_MAXDATA;
  506         } else
  507 #endif
  508                 maxio = NFS_V2MAXDATA;
  509 
  510         if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
  511                 int osize = nmp->nm_wsize;
  512                 nmp->nm_wsize = argp->wsize;
  513                 /* Round down to multiple of blocksize */
  514                 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
  515                 if (nmp->nm_wsize <= 0)
  516                         nmp->nm_wsize = NFS_FABLKSIZE;
  517                 adjsock |= (nmp->nm_wsize != osize);
  518         }
  519         if (nmp->nm_wsize > maxio)
  520                 nmp->nm_wsize = maxio;
  521         if (nmp->nm_wsize > MAXBSIZE)
  522                 nmp->nm_wsize = MAXBSIZE;
  523 
  524         if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
  525                 int osize = nmp->nm_rsize;
  526                 nmp->nm_rsize = argp->rsize;
  527                 /* Round down to multiple of blocksize */
  528                 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
  529                 if (nmp->nm_rsize <= 0)
  530                         nmp->nm_rsize = NFS_FABLKSIZE;
  531                 adjsock |= (nmp->nm_rsize != osize);
  532         }
  533         if (nmp->nm_rsize > maxio)
  534                 nmp->nm_rsize = maxio;
  535         if (nmp->nm_rsize > MAXBSIZE)
  536                 nmp->nm_rsize = MAXBSIZE;
  537 
  538         if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
  539                 nmp->nm_readdirsize = argp->readdirsize;
  540                 /* Round down to multiple of minimum blocksize */
  541                 nmp->nm_readdirsize &= ~(NFS_DIRFRAGSIZ - 1);
  542                 if (nmp->nm_readdirsize < NFS_DIRFRAGSIZ)
  543                         nmp->nm_readdirsize = NFS_DIRFRAGSIZ;
  544                 /* Bigger than buffer size makes no sense */
  545                 if (nmp->nm_readdirsize > NFS_DIRBLKSIZ)
  546                         nmp->nm_readdirsize = NFS_DIRBLKSIZ;
  547         } else if (argp->flags & NFSMNT_RSIZE)
  548                 nmp->nm_readdirsize = nmp->nm_rsize;
  549 
  550         if (nmp->nm_readdirsize > maxio)
  551                 nmp->nm_readdirsize = maxio;
  552 
  553         if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
  554                 argp->maxgrouplist <= NFS_MAXGRPS)
  555                 nmp->nm_numgrps = argp->maxgrouplist;
  556         if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
  557                 argp->readahead <= NFS_MAXRAHEAD)
  558                 nmp->nm_readahead = argp->readahead;
  559         if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
  560                 argp->deadthresh <= NFS_NEVERDEAD)
  561                 nmp->nm_deadthresh = argp->deadthresh;
  562 
  563         adjsock |= ((nmp->nm_sotype != argp->sotype) ||
  564                     (nmp->nm_soproto != argp->proto));
  565         nmp->nm_sotype = argp->sotype;
  566         nmp->nm_soproto = argp->proto;
  567 
  568         if (nmp->nm_so && adjsock) {
  569                 nfs_safedisconnect(nmp);
  570                 if (nmp->nm_sotype == SOCK_DGRAM)
  571                         while (nfs_connect(nmp, (struct nfsreq *)0, l)) {
  572                                 printf("nfs_args: retrying connect\n");
  573                                 kpause("nfscn3", false, hz, NULL);
  574                         }
  575         }
  576 }
  577 
  578 /*
  579  * VFS Operations.
  580  *
  581  * mount system call
  582  * It seems a bit dumb to copyinstr() the host and path here and then
  583  * memcpy() them in mountnfs(), but I wanted to detect errors before
  584  * doing the sockargs() call because sockargs() allocates an mbuf and
  585  * an error after that means that I have to release the mbuf.
  586  */
  587 /* ARGSUSED */
  588 int
  589 nfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
  590 {
  591         struct lwp *l = curlwp;
  592         int error;
  593         struct nfs_args *args = data;
  594         struct mbuf *nam;
  595         struct nfsmount *nmp = VFSTONFS(mp);
  596         struct sockaddr *sa;
  597         struct vnode *vp;
  598         char *pth, *hst;
  599         struct proc *p;
  600         size_t len;
  601         u_char *nfh;
  602 
  603         if (*data_len < sizeof *args)
  604                 return EINVAL;
  605 
  606         p = l->l_proc;
  607         if (mp->mnt_flag & MNT_GETARGS) {
  608 
  609                 if (nmp == NULL)
  610                         return (EIO);
  611                 if (args->addr != NULL) {
  612                         sa = mtod(nmp->nm_nam, struct sockaddr *);
  613                         error = copyout(sa, args->addr, sa->sa_len);
  614                         if (error)
  615                                 return (error);
  616                         args->addrlen = sa->sa_len;
  617                 } else
  618                         args->addrlen = 0;
  619 
  620                 args->version = NFS_ARGSVERSION;
  621                 args->sotype = nmp->nm_sotype;
  622                 args->proto = nmp->nm_soproto;
  623                 args->fh = NULL;
  624                 args->fhsize = 0;
  625                 args->flags = nmp->nm_flag;
  626                 args->wsize = nmp->nm_wsize;
  627                 args->rsize = nmp->nm_rsize;
  628                 args->readdirsize = nmp->nm_readdirsize;
  629                 args->timeo = nmp->nm_timeo;
  630                 args->retrans = nmp->nm_retry;
  631                 args->maxgrouplist = nmp->nm_numgrps;
  632                 args->readahead = nmp->nm_readahead;
  633                 args->leaseterm = 0; /* dummy */
  634                 args->deadthresh = nmp->nm_deadthresh;
  635                 args->hostname = NULL;
  636                 *data_len = sizeof *args;
  637                 return 0;
  638         }
  639 
  640         if (args->version != NFS_ARGSVERSION)
  641                 return (EPROGMISMATCH);
  642         if (args->flags & (NFSMNT_NQNFS|NFSMNT_KERB))
  643                 return (EPROGUNAVAIL);
  644 #ifdef NFS_V2_ONLY
  645         if (args->flags & NFSMNT_NFSV3)
  646                 return (EPROGMISMATCH);
  647 #endif
  648         if (mp->mnt_flag & MNT_UPDATE) {
  649                 if (nmp == NULL)
  650                         return (EIO);
  651                 /*
  652                  * When doing an update, we can't change from or to
  653                  * v3, or change cookie translation
  654                  */
  655                 args->flags = (args->flags & ~(NFSMNT_NFSV3|NFSMNT_XLATECOOKIE)) |
  656                     (nmp->nm_flag & (NFSMNT_NFSV3|NFSMNT_XLATECOOKIE));
  657                 nfs_decode_args(nmp, args, l);
  658                 return (0);
  659         }
  660         if (args->fhsize < 0 || args->fhsize > NFSX_V3FHMAX)
  661                 return (EINVAL);
  662         MALLOC(nfh, u_char *, NFSX_V3FHMAX, M_TEMP, M_WAITOK);
  663         error = copyin(args->fh, nfh, args->fhsize);
  664         if (error)
  665                 goto free_nfh;
  666         MALLOC(pth, char *, MNAMELEN, M_TEMP, M_WAITOK);
  667         error = copyinstr(path, pth, MNAMELEN - 1, &len);
  668         if (error)
  669                 goto free_pth;
  670         memset(&pth[len], 0, MNAMELEN - len);
  671         MALLOC(hst, char *, MNAMELEN, M_TEMP, M_WAITOK);
  672         error = copyinstr(args->hostname, hst, MNAMELEN - 1, &len);
  673         if (error)
  674                 goto free_hst;
  675         memset(&hst[len], 0, MNAMELEN - len);
  676         /* sockargs() call must be after above copyin() calls */
  677         error = sockargs(&nam, args->addr, args->addrlen, MT_SONAME);
  678         if (error)
  679                 goto free_hst;
  680         MCLAIM(nam, &nfs_mowner);
  681         args->fh = nfh;
  682         error = mountnfs(args, mp, nam, pth, hst, &vp, l);
  683 
  684 free_hst:
  685         FREE(hst, M_TEMP);
  686 free_pth:
  687         FREE(pth, M_TEMP);
  688 free_nfh:
  689         FREE(nfh, M_TEMP);
  690 
  691         return (error);
  692 }
  693 
  694 /*
  695  * Common code for mount and mountroot
  696  */
  697 int
  698 mountnfs(argp, mp, nam, pth, hst, vpp, l)
  699         struct nfs_args *argp;
  700         struct mount *mp;
  701         struct mbuf *nam;
  702         const char *pth, *hst;
  703         struct vnode **vpp;
  704         struct lwp *l;
  705 {
  706         struct nfsmount *nmp;
  707         struct nfsnode *np;
  708         struct vnode *vp;
  709         int error;
  710         struct vattr *attrs;
  711         kauth_cred_t cr;
  712         char iosname[IOSTATNAMELEN];
  713 
  714         /*
  715          * If the number of nfs iothreads to use has never
  716          * been set, create a reasonable number of them.
  717          */
  718 
  719         if (nfs_niothreads < 0) {
  720                 nfs_set_niothreads(NFS_DEFAULT_NIOTHREADS);
  721         }
  722 
  723         if (mp->mnt_flag & MNT_UPDATE) {
  724                 nmp = VFSTONFS(mp);
  725                 /* update paths, file handles, etc, here        XXX */
  726                 m_freem(nam);
  727                 return (0);
  728         } else {
  729                 nmp = kmem_zalloc(sizeof(*nmp), KM_SLEEP);
  730                 mp->mnt_data = nmp;
  731                 TAILQ_INIT(&nmp->nm_uidlruhead);
  732                 TAILQ_INIT(&nmp->nm_bufq);
  733                 rw_init(&nmp->nm_writeverflock);
  734                 mutex_init(&nmp->nm_lock, MUTEX_DEFAULT, IPL_NONE);
  735                 rw_init(&nmp->nm_rbtlock);
  736                 cv_init(&nmp->nm_rcvcv, "nfsrcv");
  737                 cv_init(&nmp->nm_sndcv, "nfssnd");
  738                 cv_init(&nmp->nm_aiocv, "nfsaio");
  739                 cv_init(&nmp->nm_disconcv, "nfsdis");
  740                 nfs_rbtinit(nmp);
  741         }
  742         vfs_getnewfsid(mp);
  743         nmp->nm_mountp = mp;
  744 
  745 #ifndef NFS_V2_ONLY
  746         if ((argp->flags & NFSMNT_NFSV3) == 0)
  747 #endif
  748         {
  749                 if (argp->fhsize != NFSX_V2FH) {
  750                         return EINVAL;
  751                 }
  752         }
  753 
  754         /*
  755          * V2 can only handle 32 bit filesizes. For v3, nfs_fsinfo
  756          * will overwrite this.
  757          */
  758         nmp->nm_maxfilesize = 0xffffffffLL;
  759 
  760         nmp->nm_timeo = NFS_TIMEO;
  761         nmp->nm_retry = NFS_RETRANS;
  762         nmp->nm_wsize = NFS_WSIZE;
  763         nmp->nm_rsize = NFS_RSIZE;
  764         nmp->nm_readdirsize = NFS_READDIRSIZE;
  765         nmp->nm_numgrps = NFS_MAXGRPS;
  766         nmp->nm_readahead = NFS_DEFRAHEAD;
  767         nmp->nm_deadthresh = NFS_DEFDEADTHRESH;
  768         error = set_statvfs_info(pth, UIO_SYSSPACE, hst, UIO_SYSSPACE,
  769             mp->mnt_op->vfs_name, mp, l);
  770         if (error)
  771                 goto bad;
  772         nmp->nm_nam = nam;
  773 
  774         /* Set up the sockets and per-host congestion */
  775         nmp->nm_sotype = argp->sotype;
  776         nmp->nm_soproto = argp->proto;
  777 
  778         nfs_decode_args(nmp, argp, l);
  779 
  780         mp->mnt_fs_bshift = ffs(MIN(nmp->nm_rsize, nmp->nm_wsize)) - 1;
  781         mp->mnt_dev_bshift = DEV_BSHIFT;
  782 
  783         /*
  784          * For Connection based sockets (TCP,...) defer the connect until
  785          * the first request, in case the server is not responding.
  786          */
  787         if (nmp->nm_sotype == SOCK_DGRAM &&
  788                 (error = nfs_connect(nmp, (struct nfsreq *)0, l)))
  789                 goto bad;
  790 
  791         /*
  792          * This is silly, but it has to be set so that vinifod() works.
  793          * We do not want to do an nfs_statvfs() here since we can get
  794          * stuck on a dead server and we are holding a lock on the mount
  795          * point.
  796          */
  797         mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
  798         error = nfs_nget(mp, (nfsfh_t *)argp->fh, argp->fhsize, &np);
  799         if (error)
  800                 goto bad;
  801         vp = NFSTOV(np);
  802         MALLOC(attrs, struct vattr *, sizeof(struct vattr), M_TEMP, M_WAITOK);
  803         VOP_GETATTR(vp, attrs, l->l_cred);
  804         if ((nmp->nm_flag & NFSMNT_NFSV3) && (vp->v_type == VDIR)) {
  805                 cr = kauth_cred_alloc();
  806                 kauth_cred_setuid(cr, attrs->va_uid);
  807                 kauth_cred_seteuid(cr, attrs->va_uid);
  808                 kauth_cred_setsvuid(cr, attrs->va_uid);
  809                 kauth_cred_setgid(cr, attrs->va_gid);
  810                 kauth_cred_setegid(cr, attrs->va_gid);
  811                 kauth_cred_setsvgid(cr, attrs->va_gid);
  812                 nfs_cookieheuristic(vp, &nmp->nm_iflag, l, cr);
  813                 kauth_cred_free(cr);
  814         }
  815         FREE(attrs, M_TEMP);
  816 
  817         /*
  818          * A reference count is needed on the nfsnode representing the
  819          * remote root.  If this object is not persistent, then backward
  820          * traversals of the mount point (i.e. "..") will not work if
  821          * the nfsnode gets flushed out of the cache. Ufs does not have
  822          * this problem, because one can identify root inodes by their
  823          * number == ROOTINO (2). So, just unlock, but no rele.
  824          */
  825 
  826         nmp->nm_vnode = vp;
  827         if (vp->v_type == VNON)
  828                 vp->v_type = VDIR;
  829         vp->v_vflag |= VV_ROOT;
  830         VOP_UNLOCK(vp, 0);
  831         *vpp = vp;
  832 
  833         snprintf(iosname, sizeof(iosname), "nfs%u", nfs_mount_count++);
  834         nmp->nm_stats = iostat_alloc(IOSTAT_NFS, nmp, iosname);
  835 
  836         return (0);
  837 bad:
  838         nfs_disconnect(nmp);
  839         rw_destroy(&nmp->nm_writeverflock);
  840         rw_destroy(&nmp->nm_rbtlock);
  841         mutex_destroy(&nmp->nm_lock);
  842         cv_destroy(&nmp->nm_rcvcv);
  843         cv_destroy(&nmp->nm_sndcv);
  844         cv_destroy(&nmp->nm_aiocv);
  845         cv_destroy(&nmp->nm_disconcv);
  846         kmem_free(nmp, sizeof(*nmp));
  847         m_freem(nam);
  848         return (error);
  849 }
  850 
  851 /*
  852  * unmount system call
  853  */
  854 int
  855 nfs_unmount(struct mount *mp, int mntflags)
  856 {
  857         struct nfsmount *nmp;
  858         struct vnode *vp;
  859         int error, flags = 0;
  860 
  861         if (mntflags & MNT_FORCE)
  862                 flags |= FORCECLOSE;
  863         nmp = VFSTONFS(mp);
  864         /*
  865          * Goes something like this..
  866          * - Check for activity on the root vnode (other than ourselves).
  867          * - Call vflush() to clear out vnodes for this file system,
  868          *   except for the root vnode.
  869          * - Decrement reference on the vnode representing remote root.
  870          * - Close the socket
  871          * - Free up the data structures
  872          */
  873         /*
  874          * We need to decrement the ref. count on the nfsnode representing
  875          * the remote root.  See comment in mountnfs().  The VFS unmount()
  876          * has done vput on this vnode, otherwise we would get deadlock!
  877          */
  878         vp = nmp->nm_vnode;
  879         error = vget(vp, LK_EXCLUSIVE | LK_RETRY);
  880         if (error != 0)
  881                 return error;
  882 
  883         if ((mntflags & MNT_FORCE) == 0 && vp->v_usecount > 2) {
  884                 vput(vp);
  885                 return (EBUSY);
  886         }
  887 
  888         error = vflush(mp, vp, flags);
  889         if (error) {
  890                 vput(vp);
  891                 return (error);
  892         }
  893 
  894         /*
  895          * We are now committed to the unmount; mark the mount structure
  896          * as doomed so that any sleepers kicked awake by nfs_disconnect
  897          * will go away cleanly.
  898          */
  899         nmp->nm_iflag |= NFSMNT_DISMNT;
  900 
  901         /*
  902          * Clean up the stats... note that we carefully avoid decrementing
  903          * nfs_mount_count here for good reason - we may not be unmounting
  904          * the last thing mounted.
  905          */
  906         iostat_free(nmp->nm_stats);
  907 
  908         /*
  909          * There are two reference counts to get rid of here
  910          * (see comment in mountnfs()).
  911          */
  912         vput(vp);
  913         vgone(vp);
  914         nfs_disconnect(nmp);
  915         m_freem(nmp->nm_nam);
  916 
  917         rw_destroy(&nmp->nm_writeverflock);
  918         rw_destroy(&nmp->nm_rbtlock);
  919         mutex_destroy(&nmp->nm_lock);
  920         cv_destroy(&nmp->nm_rcvcv);
  921         cv_destroy(&nmp->nm_sndcv);
  922         cv_destroy(&nmp->nm_aiocv);
  923         cv_destroy(&nmp->nm_disconcv);
  924         kmem_free(nmp, sizeof(*nmp));
  925         return (0);
  926 }
  927 
  928 /*
  929  * Return root of a filesystem
  930  */
  931 int
  932 nfs_root(mp, vpp)
  933         struct mount *mp;
  934         struct vnode **vpp;
  935 {
  936         struct vnode *vp;
  937         struct nfsmount *nmp;
  938         int error;
  939 
  940         nmp = VFSTONFS(mp);
  941         vp = nmp->nm_vnode;
  942         error = vget(vp, LK_EXCLUSIVE | LK_RETRY);
  943         if (error != 0)
  944                 return error;
  945         *vpp = vp;
  946         return (0);
  947 }
  948 
  949 extern int syncprt;
  950 
  951 /*
  952  * Flush out the buffer cache
  953  */
  954 /* ARGSUSED */
  955 int
  956 nfs_sync(mp, waitfor, cred)
  957         struct mount *mp;
  958         int waitfor;
  959         kauth_cred_t cred;
  960 {
  961         struct vnode *vp, *mvp;
  962         int error, allerror = 0;
  963 
  964         /*
  965          * Force stale buffer cache information to be flushed.
  966          */
  967         if ((mvp = vnalloc(mp)) == NULL)
  968                 return (ENOMEM);
  969 loop:
  970         /*
  971          * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
  972          * and vclean() can be called indirectly
  973          */
  974         mutex_enter(&mntvnode_lock);
  975         for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
  976                 vmark(mvp, vp);
  977                 if (vp->v_mount != mp || vismarker(vp))
  978                         continue;
  979                 mutex_enter(&vp->v_interlock);
  980                 /* XXX MNT_LAZY cannot be right? */
  981                 if (waitfor == MNT_LAZY || VOP_ISLOCKED(vp) ||
  982                     (LIST_EMPTY(&vp->v_dirtyblkhd) &&
  983                      UVM_OBJ_IS_CLEAN(&vp->v_uobj))) {
  984                         mutex_exit(&vp->v_interlock);
  985                         continue;
  986                 }
  987                 mutex_exit(&mntvnode_lock);
  988                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) {
  989                         (void)vunmark(mvp);
  990                         goto loop;
  991                 }
  992                 error = VOP_FSYNC(vp, cred,
  993                     waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0);
  994                 if (error)
  995                         allerror = error;
  996                 vput(vp);
  997                 mutex_enter(&mntvnode_lock);
  998         }
  999         mutex_exit(&mntvnode_lock);
 1000         vnfree(mvp);
 1001         return (allerror);
 1002 }
 1003 
 1004 /*
 1005  * NFS flat namespace lookup.
 1006  * Currently unsupported.
 1007  */
 1008 /* ARGSUSED */
 1009 int
 1010 nfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
 1011 {
 1012 
 1013         return (EOPNOTSUPP);
 1014 }
 1015 
 1016 /*
 1017  * Do that sysctl thang...
 1018  */
 1019 static int
 1020 sysctl_vfs_nfs_iothreads(SYSCTLFN_ARGS)
 1021 {
 1022         struct sysctlnode node;
 1023         int val;
 1024         int error;
 1025 
 1026         val = nfs_niothreads;
 1027         node = *rnode;
 1028         node.sysctl_data = &val;
 1029         error = sysctl_lookup(SYSCTLFN_CALL(&node));
 1030         if (error || newp == NULL)
 1031                 return error;
 1032 
 1033         return nfs_set_niothreads(val);
 1034 }
 1035 
 1036 SYSCTL_SETUP(sysctl_vfs_nfs_setup, "sysctl vfs.nfs subtree setup")
 1037 {
 1038 
 1039         sysctl_createv(clog, 0, NULL, NULL,
 1040                        CTLFLAG_PERMANENT,
 1041                        CTLTYPE_NODE, "vfs", NULL,
 1042                        NULL, 0, NULL, 0,
 1043                        CTL_VFS, CTL_EOL);
 1044         sysctl_createv(clog, 0, NULL, NULL,
 1045                        CTLFLAG_PERMANENT,
 1046                        CTLTYPE_NODE, "nfs",
 1047                        SYSCTL_DESCR("NFS vfs options"),
 1048                        NULL, 0, NULL, 0,
 1049                        CTL_VFS, 2, CTL_EOL);
 1050         /*
 1051          * XXX the "2" above could be dynamic, thereby eliminating one
 1052          * more instance of the "number to vfs" mapping problem, but
 1053          * "2" is the order as taken from sys/mount.h
 1054          */
 1055 
 1056         sysctl_createv(clog, 0, NULL, NULL,
 1057                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 1058                        CTLTYPE_STRUCT, "nfsstats",
 1059                        SYSCTL_DESCR("NFS operation statistics"),
 1060                        NULL, 0, &nfsstats, sizeof(nfsstats),
 1061                        CTL_VFS, 2, NFS_NFSSTATS, CTL_EOL);
 1062         sysctl_createv(clog, 0, NULL, NULL,
 1063                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 1064                        CTLTYPE_INT, "iothreads",
 1065                        SYSCTL_DESCR("Number of NFS client processes desired"),
 1066                        sysctl_vfs_nfs_iothreads, 0, NULL, 0,
 1067                        CTL_VFS, 2, NFS_IOTHREADS, CTL_EOL);
 1068 }
 1069 
 1070 /* ARGSUSED */
 1071 int
 1072 nfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp)
 1073 {
 1074         size_t fidsize;
 1075         size_t fhsize;
 1076         struct nfsnode *np;
 1077         int error;
 1078         struct vattr va;
 1079 
 1080         fidsize = fid->fid_len;
 1081         if (fidsize < sizeof(*fid)) {
 1082                 return EINVAL;
 1083         }
 1084         fhsize = fidsize - sizeof(*fid);
 1085         if ((fhsize % NFSX_UNSIGNED) != 0) {
 1086                 return EINVAL;
 1087         }
 1088         if ((VFSTONFS(mp)->nm_flag & NFSMNT_NFSV3) != 0) {
 1089                 if (fhsize > NFSX_V3FHMAX || fhsize == 0) {
 1090                         return EINVAL;
 1091                 }
 1092         } else {
 1093                 if (fhsize != NFSX_V2FH) {
 1094                         return EINVAL;
 1095                 }
 1096         }
 1097         error = nfs_nget(mp, (void *)fid->fid_data, fhsize, &np);
 1098         if (error) {
 1099                 return error;
 1100         }
 1101         *vpp = NFSTOV(np);
 1102         error = VOP_GETATTR(*vpp, &va, kauth_cred_get());
 1103         if (error != 0) {
 1104                 vput(*vpp);
 1105         }
 1106         return error;
 1107 }
 1108 
 1109 /* ARGSUSED */
 1110 int
 1111 nfs_vptofh(struct vnode *vp, struct fid *buf, size_t *bufsize)
 1112 {
 1113         struct nfsnode *np;
 1114         struct fid *fid;
 1115         size_t fidsize;
 1116         int error = 0;
 1117 
 1118         np = VTONFS(vp);
 1119         fidsize = sizeof(*fid) + np->n_fhsize;
 1120         if (*bufsize < fidsize) {
 1121                 error = E2BIG;
 1122         }
 1123         *bufsize = fidsize;
 1124         if (error == 0) {
 1125                 struct fid fid_store;
 1126 
 1127                 fid = &fid_store;
 1128                 memset(fid, 0, sizeof(*fid));
 1129                 fid->fid_len = fidsize;
 1130                 memcpy(buf, fid, sizeof(*fid));
 1131                 memcpy(buf->fid_data, np->n_fhp, np->n_fhsize);
 1132         }
 1133         return error;
 1134 }
 1135 
 1136 /*
 1137  * Vfs start routine, a no-op.
 1138  */
 1139 /* ARGSUSED */
 1140 int
 1141 nfs_start(struct mount *mp, int flags)
 1142 {
 1143 
 1144         return (0);
 1145 }

Cache object: 4453181ad3942eb0ed9144dcd3e3b3fa


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.