]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nfsserver/nfs_nfsdport.c
nfsd: fix NFS server for ERELOOKUP
[FreeBSD/FreeBSD.git] / sys / fs / nfsserver / nfs_nfsdport.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1989, 1993
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  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/capsicum.h>
40 #include <sys/extattr.h>
41
42 /*
43  * Functions that perform the vfs operations required by the routines in
44  * nfsd_serv.c. It is hoped that this change will make the server more
45  * portable.
46  */
47
48 #include <fs/nfs/nfsport.h>
49 #include <security/mac/mac_framework.h>
50 #include <sys/filio.h>
51 #include <sys/hash.h>
52 #include <sys/sysctl.h>
53 #include <nlm/nlm_prot.h>
54 #include <nlm/nlm.h>
55
56 FEATURE(nfsd, "NFSv4 server");
57
58 extern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
59 extern int nfsrv_useacl;
60 extern int newnfs_numnfsd;
61 extern struct mount nfsv4root_mnt;
62 extern struct nfsrv_stablefirst nfsrv_stablefirst;
63 extern void (*nfsd_call_servertimer)(void);
64 extern SVCPOOL  *nfsrvd_pool;
65 extern struct nfsv4lock nfsd_suspend_lock;
66 extern struct nfsclienthashhead *nfsclienthash;
67 extern struct nfslockhashhead *nfslockhash;
68 extern struct nfssessionhash *nfssessionhash;
69 extern int nfsrv_sessionhashsize;
70 extern struct nfsstatsv1 nfsstatsv1;
71 extern struct nfslayouthash *nfslayouthash;
72 extern int nfsrv_layouthashsize;
73 extern struct mtx nfsrv_dslock_mtx;
74 extern int nfs_pnfsiothreads;
75 extern struct nfsdontlisthead nfsrv_dontlisthead;
76 extern volatile int nfsrv_dontlistlen;
77 extern volatile int nfsrv_devidcnt;
78 extern int nfsrv_maxpnfsmirror;
79 struct vfsoptlist nfsv4root_opt, nfsv4root_newopt;
80 NFSDLOCKMUTEX;
81 NFSSTATESPINLOCK;
82 struct nfsrchash_bucket nfsrchash_table[NFSRVCACHE_HASHSIZE];
83 struct nfsrchash_bucket nfsrcahash_table[NFSRVCACHE_HASHSIZE];
84 struct mtx nfsrc_udpmtx;
85 struct mtx nfs_v4root_mutex;
86 struct mtx nfsrv_dontlistlock_mtx;
87 struct mtx nfsrv_recalllock_mtx;
88 struct nfsrvfh nfs_rootfh, nfs_pubfh;
89 int nfs_pubfhset = 0, nfs_rootfhset = 0;
90 struct proc *nfsd_master_proc = NULL;
91 int nfsd_debuglevel = 0;
92 static pid_t nfsd_master_pid = (pid_t)-1;
93 static char nfsd_master_comm[MAXCOMLEN + 1];
94 static struct timeval nfsd_master_start;
95 static uint32_t nfsv4_sysid = 0;
96 static fhandle_t zerofh;
97
98 static int nfssvc_srvcall(struct thread *, struct nfssvc_args *,
99     struct ucred *);
100
101 int nfsrv_enable_crossmntpt = 1;
102 static int nfs_commit_blks;
103 static int nfs_commit_miss;
104 extern int nfsrv_issuedelegs;
105 extern int nfsrv_dolocallocks;
106 extern int nfsd_enable_stringtouid;
107 extern struct nfsdevicehead nfsrv_devidhead;
108
109 static int nfsrv_createiovec(int, struct mbuf **, struct mbuf **,
110     struct iovec **);
111 static int nfsrv_createiovec_extpgs(int, int, struct mbuf **,
112     struct mbuf **, struct iovec **);
113 static int nfsrv_createiovecw(int, struct mbuf *, char *, struct iovec **,
114     int *);
115 static void nfsrv_pnfscreate(struct vnode *, struct vattr *, struct ucred *,
116     NFSPROC_T *);
117 static void nfsrv_pnfsremovesetup(struct vnode *, NFSPROC_T *, struct vnode **,
118     int *, char *, fhandle_t *);
119 static void nfsrv_pnfsremove(struct vnode **, int, char *, fhandle_t *,
120     NFSPROC_T *);
121 static int nfsrv_proxyds(struct vnode *, off_t, int, struct ucred *,
122     struct thread *, int, struct mbuf **, char *, struct mbuf **,
123     struct nfsvattr *, struct acl *, off_t *, int, bool *);
124 static int nfsrv_setextattr(struct vnode *, struct nfsvattr *, NFSPROC_T *);
125 static int nfsrv_readdsrpc(fhandle_t *, off_t, int, struct ucred *,
126     NFSPROC_T *, struct nfsmount *, struct mbuf **, struct mbuf **);
127 static int nfsrv_writedsrpc(fhandle_t *, off_t, int, struct ucred *,
128     NFSPROC_T *, struct vnode *, struct nfsmount **, int, struct mbuf **,
129     char *, int *);
130 static int nfsrv_allocatedsrpc(fhandle_t *, off_t, off_t, struct ucred *,
131     NFSPROC_T *, struct vnode *, struct nfsmount **, int, int *);
132 static int nfsrv_setacldsrpc(fhandle_t *, struct ucred *, NFSPROC_T *,
133     struct vnode *, struct nfsmount **, int, struct acl *, int *);
134 static int nfsrv_setattrdsrpc(fhandle_t *, struct ucred *, NFSPROC_T *,
135     struct vnode *, struct nfsmount **, int, struct nfsvattr *, int *);
136 static int nfsrv_getattrdsrpc(fhandle_t *, struct ucred *, NFSPROC_T *,
137     struct vnode *, struct nfsmount *, struct nfsvattr *);
138 static int nfsrv_seekdsrpc(fhandle_t *, off_t *, int, bool *, struct ucred *,
139     NFSPROC_T *, struct nfsmount *);
140 static int nfsrv_putfhname(fhandle_t *, char *);
141 static int nfsrv_pnfslookupds(struct vnode *, struct vnode *,
142     struct pnfsdsfile *, struct vnode **, NFSPROC_T *);
143 static void nfsrv_pnfssetfh(struct vnode *, struct pnfsdsfile *, char *, char *,
144     struct vnode *, NFSPROC_T *);
145 static int nfsrv_dsremove(struct vnode *, char *, struct ucred *, NFSPROC_T *);
146 static int nfsrv_dssetacl(struct vnode *, struct acl *, struct ucred *,
147     NFSPROC_T *);
148 static int nfsrv_pnfsstatfs(struct statfs *, struct mount *);
149
150 int nfs_pnfsio(task_fn_t *, void *);
151
152 SYSCTL_NODE(_vfs, OID_AUTO, nfsd, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
153     "NFS server");
154 SYSCTL_INT(_vfs_nfsd, OID_AUTO, mirrormnt, CTLFLAG_RW,
155     &nfsrv_enable_crossmntpt, 0, "Enable nfsd to cross mount points");
156 SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks,
157     0, "");
158 SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss,
159     0, "");
160 SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW,
161     &nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations");
162 SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLFLAG_RW,
163     &nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files");
164 SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW, &nfsd_debuglevel,
165     0, "Debug level for NFS server");
166 SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, CTLFLAG_RW,
167     &nfsd_enable_stringtouid, 0, "Enable nfsd to accept numeric owner_names");
168 static int nfsrv_pnfsgetdsattr = 1;
169 SYSCTL_INT(_vfs_nfsd, OID_AUTO, pnfsgetdsattr, CTLFLAG_RW,
170     &nfsrv_pnfsgetdsattr, 0, "When set getattr gets DS attributes via RPC");
171
172 /*
173  * nfsrv_dsdirsize can only be increased and only when the nfsd threads are
174  * not running.
175  * The dsN subdirectories for the increased values must have been created
176  * on all DS servers before this increase is done.
177  */
178 u_int   nfsrv_dsdirsize = 20;
179 static int
180 sysctl_dsdirsize(SYSCTL_HANDLER_ARGS)
181 {
182         int error, newdsdirsize;
183
184         newdsdirsize = nfsrv_dsdirsize;
185         error = sysctl_handle_int(oidp, &newdsdirsize, 0, req);
186         if (error != 0 || req->newptr == NULL)
187                 return (error);
188         if (newdsdirsize <= nfsrv_dsdirsize || newdsdirsize > 10000 ||
189             newnfs_numnfsd != 0)
190                 return (EINVAL);
191         nfsrv_dsdirsize = newdsdirsize;
192         return (0);
193 }
194 SYSCTL_PROC(_vfs_nfsd, OID_AUTO, dsdirsize,
195     CTLTYPE_UINT | CTLFLAG_MPSAFE | CTLFLAG_RW, 0, sizeof(nfsrv_dsdirsize),
196     sysctl_dsdirsize, "IU", "Number of dsN subdirs on the DS servers");
197
198 #define MAX_REORDERED_RPC       16
199 #define NUM_HEURISTIC           1031
200 #define NHUSE_INIT              64
201 #define NHUSE_INC               16
202 #define NHUSE_MAX               2048
203
204 static struct nfsheur {
205         struct vnode *nh_vp;    /* vp to match (unreferenced pointer) */
206         off_t nh_nextoff;       /* next offset for sequential detection */
207         int nh_use;             /* use count for selection */
208         int nh_seqcount;        /* heuristic */
209 } nfsheur[NUM_HEURISTIC];
210
211 /*
212  * Heuristic to detect sequential operation.
213  */
214 static struct nfsheur *
215 nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp)
216 {
217         struct nfsheur *nh;
218         int hi, try;
219
220         /* Locate best candidate. */
221         try = 32;
222         hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC;
223         nh = &nfsheur[hi];
224         while (try--) {
225                 if (nfsheur[hi].nh_vp == vp) {
226                         nh = &nfsheur[hi];
227                         break;
228                 }
229                 if (nfsheur[hi].nh_use > 0)
230                         --nfsheur[hi].nh_use;
231                 hi = (hi + 1) % NUM_HEURISTIC;
232                 if (nfsheur[hi].nh_use < nh->nh_use)
233                         nh = &nfsheur[hi];
234         }
235
236         /* Initialize hint if this is a new file. */
237         if (nh->nh_vp != vp) {
238                 nh->nh_vp = vp;
239                 nh->nh_nextoff = uio->uio_offset;
240                 nh->nh_use = NHUSE_INIT;
241                 if (uio->uio_offset == 0)
242                         nh->nh_seqcount = 4;
243                 else
244                         nh->nh_seqcount = 1;
245         }
246
247         /* Calculate heuristic. */
248         if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) ||
249             uio->uio_offset == nh->nh_nextoff) {
250                 /* See comments in vfs_vnops.c:sequential_heuristic(). */
251                 nh->nh_seqcount += howmany(uio->uio_resid, 16384);
252                 if (nh->nh_seqcount > IO_SEQMAX)
253                         nh->nh_seqcount = IO_SEQMAX;
254         } else if (qabs(uio->uio_offset - nh->nh_nextoff) <= MAX_REORDERED_RPC *
255             imax(vp->v_mount->mnt_stat.f_iosize, uio->uio_resid)) {
256                 /* Probably a reordered RPC, leave seqcount alone. */
257         } else if (nh->nh_seqcount > 1) {
258                 nh->nh_seqcount /= 2;
259         } else {
260                 nh->nh_seqcount = 0;
261         }
262         nh->nh_use += NHUSE_INC;
263         if (nh->nh_use > NHUSE_MAX)
264                 nh->nh_use = NHUSE_MAX;
265         return (nh);
266 }
267
268 /*
269  * Get attributes into nfsvattr structure.
270  */
271 int
272 nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap,
273     struct nfsrv_descript *nd, struct thread *p, int vpislocked,
274     nfsattrbit_t *attrbitp)
275 {
276         int error, gotattr, lockedit = 0;
277         struct nfsvattr na;
278
279         if (vpislocked == 0) {
280                 /*
281                  * When vpislocked == 0, the vnode is either exclusively
282                  * locked by this thread or not locked by this thread.
283                  * As such, shared lock it, if not exclusively locked.
284                  */
285                 if (NFSVOPISLOCKED(vp) != LK_EXCLUSIVE) {
286                         lockedit = 1;
287                         NFSVOPLOCK(vp, LK_SHARED | LK_RETRY);
288                 }
289         }
290
291         /*
292          * Acquire the Change, Size, TimeAccess, TimeModify and SpaceUsed
293          * attributes, as required.
294          * This needs to be done for regular files if:
295          * - non-NFSv4 RPCs or
296          * - when attrbitp == NULL or
297          * - an NFSv4 RPC with any of the above attributes in attrbitp.
298          * A return of 0 for nfsrv_proxyds() indicates that it has acquired
299          * these attributes.  nfsrv_proxyds() will return an error if the
300          * server is not a pNFS one.
301          */
302         gotattr = 0;
303         if (vp->v_type == VREG && nfsrv_devidcnt > 0 && (attrbitp == NULL ||
304             (nd->nd_flag & ND_NFSV4) == 0 ||
305             NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_CHANGE) ||
306             NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE) ||
307             NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEACCESS) ||
308             NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEMODIFY) ||
309             NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SPACEUSED))) {
310                 error = nfsrv_proxyds(vp, 0, 0, nd->nd_cred, p,
311                     NFSPROC_GETATTR, NULL, NULL, NULL, &na, NULL, NULL, 0,
312                     NULL);
313                 if (error == 0)
314                         gotattr = 1;
315         }
316
317         error = VOP_GETATTR(vp, &nvap->na_vattr, nd->nd_cred);
318         if (lockedit != 0)
319                 NFSVOPUNLOCK(vp);
320
321         /*
322          * If we got the Change, Size and Modify Time from the DS,
323          * replace them.
324          */
325         if (gotattr != 0) {
326                 nvap->na_atime = na.na_atime;
327                 nvap->na_mtime = na.na_mtime;
328                 nvap->na_filerev = na.na_filerev;
329                 nvap->na_size = na.na_size;
330                 nvap->na_bytes = na.na_bytes;
331         }
332         NFSD_DEBUG(4, "nfsvno_getattr: gotattr=%d err=%d chg=%ju\n", gotattr,
333             error, (uintmax_t)na.na_filerev);
334
335         NFSEXITCODE(error);
336         return (error);
337 }
338
339 /*
340  * Get a file handle for a vnode.
341  */
342 int
343 nfsvno_getfh(struct vnode *vp, fhandle_t *fhp, struct thread *p)
344 {
345         int error;
346
347         NFSBZERO((caddr_t)fhp, sizeof(fhandle_t));
348         fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
349         error = VOP_VPTOFH(vp, &fhp->fh_fid);
350
351         NFSEXITCODE(error);
352         return (error);
353 }
354
355 /*
356  * Perform access checking for vnodes obtained from file handles that would
357  * refer to files already opened by a Unix client. You cannot just use
358  * vn_writechk() and VOP_ACCESSX() for two reasons.
359  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write
360  *     case.
361  * 2 - The owner is to be given access irrespective of mode bits for some
362  *     operations, so that processes that chmod after opening a file don't
363  *     break.
364  */
365 int
366 nfsvno_accchk(struct vnode *vp, accmode_t accmode, struct ucred *cred,
367     struct nfsexstuff *exp, struct thread *p, int override, int vpislocked,
368     u_int32_t *supportedtypep)
369 {
370         struct vattr vattr;
371         int error = 0, getret = 0;
372
373         if (vpislocked == 0) {
374                 if (NFSVOPLOCK(vp, LK_SHARED) != 0) {
375                         error = EPERM;
376                         goto out;
377                 }
378         }
379         if (accmode & VWRITE) {
380                 /* Just vn_writechk() changed to check rdonly */
381                 /*
382                  * Disallow write attempts on read-only file systems;
383                  * unless the file is a socket or a block or character
384                  * device resident on the file system.
385                  */
386                 if (NFSVNO_EXRDONLY(exp) ||
387                     (vp->v_mount->mnt_flag & MNT_RDONLY)) {
388                         switch (vp->v_type) {
389                         case VREG:
390                         case VDIR:
391                         case VLNK:
392                                 error = EROFS;
393                         default:
394                                 break;
395                         }
396                 }
397                 /*
398                  * If there's shared text associated with
399                  * the inode, try to free it up once.  If
400                  * we fail, we can't allow writing.
401                  */
402                 if (VOP_IS_TEXT(vp) && error == 0)
403                         error = ETXTBSY;
404         }
405         if (error != 0) {
406                 if (vpislocked == 0)
407                         NFSVOPUNLOCK(vp);
408                 goto out;
409         }
410
411         /*
412          * Should the override still be applied when ACLs are enabled?
413          */
414         error = VOP_ACCESSX(vp, accmode, cred, p);
415         if (error != 0 && (accmode & (VDELETE | VDELETE_CHILD))) {
416                 /*
417                  * Try again with VEXPLICIT_DENY, to see if the test for
418                  * deletion is supported.
419                  */
420                 error = VOP_ACCESSX(vp, accmode | VEXPLICIT_DENY, cred, p);
421                 if (error == 0) {
422                         if (vp->v_type == VDIR) {
423                                 accmode &= ~(VDELETE | VDELETE_CHILD);
424                                 accmode |= VWRITE;
425                                 error = VOP_ACCESSX(vp, accmode, cred, p);
426                         } else if (supportedtypep != NULL) {
427                                 *supportedtypep &= ~NFSACCESS_DELETE;
428                         }
429                 }
430         }
431
432         /*
433          * Allow certain operations for the owner (reads and writes
434          * on files that are already open).
435          */
436         if (override != NFSACCCHK_NOOVERRIDE &&
437             (error == EPERM || error == EACCES)) {
438                 if (cred->cr_uid == 0 && (override & NFSACCCHK_ALLOWROOT))
439                         error = 0;
440                 else if (override & NFSACCCHK_ALLOWOWNER) {
441                         getret = VOP_GETATTR(vp, &vattr, cred);
442                         if (getret == 0 && cred->cr_uid == vattr.va_uid)
443                                 error = 0;
444                 }
445         }
446         if (vpislocked == 0)
447                 NFSVOPUNLOCK(vp);
448
449 out:
450         NFSEXITCODE(error);
451         return (error);
452 }
453
454 /*
455  * Set attribute(s) vnop.
456  */
457 int
458 nfsvno_setattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred,
459     struct thread *p, struct nfsexstuff *exp)
460 {
461         u_quad_t savsize = 0;
462         int error, savedit;
463         time_t savbtime;
464
465         /*
466          * If this is an exported file system and a pNFS service is running,
467          * don't VOP_SETATTR() of size for the MDS file system.
468          */
469         savedit = 0;
470         error = 0;
471         if (vp->v_type == VREG && (vp->v_mount->mnt_flag & MNT_EXPORTED) != 0 &&
472             nfsrv_devidcnt != 0 && nvap->na_vattr.va_size != VNOVAL &&
473             nvap->na_vattr.va_size > 0) {
474                 savsize = nvap->na_vattr.va_size;
475                 nvap->na_vattr.va_size = VNOVAL;
476                 if (nvap->na_vattr.va_uid != (uid_t)VNOVAL ||
477                     nvap->na_vattr.va_gid != (gid_t)VNOVAL ||
478                     nvap->na_vattr.va_mode != (mode_t)VNOVAL ||
479                     nvap->na_vattr.va_atime.tv_sec != VNOVAL ||
480                     nvap->na_vattr.va_mtime.tv_sec != VNOVAL)
481                         savedit = 1;
482                 else
483                         savedit = 2;
484         }
485         if (savedit != 2)
486                 error = VOP_SETATTR(vp, &nvap->na_vattr, cred);
487         if (savedit != 0)
488                 nvap->na_vattr.va_size = savsize;
489         if (error == 0 && (nvap->na_vattr.va_uid != (uid_t)VNOVAL ||
490             nvap->na_vattr.va_gid != (gid_t)VNOVAL ||
491             nvap->na_vattr.va_size != VNOVAL ||
492             nvap->na_vattr.va_mode != (mode_t)VNOVAL ||
493             nvap->na_vattr.va_atime.tv_sec != VNOVAL ||
494             nvap->na_vattr.va_mtime.tv_sec != VNOVAL)) {
495                 /* Never modify birthtime on a DS file. */
496                 savbtime = nvap->na_vattr.va_birthtime.tv_sec;
497                 nvap->na_vattr.va_birthtime.tv_sec = VNOVAL;
498                 /* For a pNFS server, set the attributes on the DS file. */
499                 error = nfsrv_proxyds(vp, 0, 0, cred, p, NFSPROC_SETATTR,
500                     NULL, NULL, NULL, nvap, NULL, NULL, 0, NULL);
501                 nvap->na_vattr.va_birthtime.tv_sec = savbtime;
502                 if (error == ENOENT)
503                         error = 0;
504         }
505         NFSEXITCODE(error);
506         return (error);
507 }
508
509 /*
510  * Set up nameidata for a lookup() call and do it.
511  */
512 int
513 nfsvno_namei(struct nfsrv_descript *nd, struct nameidata *ndp,
514     struct vnode *dp, int islocked, struct nfsexstuff *exp, struct thread *p,
515     struct vnode **retdirp)
516 {
517         struct componentname *cnp = &ndp->ni_cnd;
518         int i;
519         struct iovec aiov;
520         struct uio auio;
521         int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0, linklen;
522         int error = 0;
523         char *cp;
524
525         *retdirp = NULL;
526         cnp->cn_nameptr = cnp->cn_pnbuf;
527         ndp->ni_lcf = 0;
528         /*
529          * Extract and set starting directory.
530          */
531         if (dp->v_type != VDIR) {
532                 if (islocked)
533                         vput(dp);
534                 else
535                         vrele(dp);
536                 nfsvno_relpathbuf(ndp);
537                 error = ENOTDIR;
538                 goto out1;
539         }
540         if (islocked)
541                 NFSVOPUNLOCK(dp);
542         VREF(dp);
543         *retdirp = dp;
544         if (NFSVNO_EXRDONLY(exp))
545                 cnp->cn_flags |= RDONLY;
546         ndp->ni_segflg = UIO_SYSSPACE;
547
548         if (nd->nd_flag & ND_PUBLOOKUP) {
549                 ndp->ni_loopcnt = 0;
550                 if (cnp->cn_pnbuf[0] == '/') {
551                         vrele(dp);
552                         /*
553                          * Check for degenerate pathnames here, since lookup()
554                          * panics on them.
555                          */
556                         for (i = 1; i < ndp->ni_pathlen; i++)
557                                 if (cnp->cn_pnbuf[i] != '/')
558                                         break;
559                         if (i == ndp->ni_pathlen) {
560                                 error = NFSERR_ACCES;
561                                 goto out;
562                         }
563                         dp = rootvnode;
564                         VREF(dp);
565                 }
566         } else if ((nfsrv_enable_crossmntpt == 0 && NFSVNO_EXPORTED(exp)) ||
567             (nd->nd_flag & ND_NFSV4) == 0) {
568                 /*
569                  * Only cross mount points for NFSv4 when doing a
570                  * mount while traversing the file system above
571                  * the mount point, unless nfsrv_enable_crossmntpt is set.
572                  */
573                 cnp->cn_flags |= NOCROSSMOUNT;
574         }
575
576         /*
577          * Initialize for scan, set ni_startdir and bump ref on dp again
578          * because lookup() will dereference ni_startdir.
579          */
580
581         cnp->cn_thread = p;
582         ndp->ni_startdir = dp;
583         ndp->ni_rootdir = rootvnode;
584         ndp->ni_topdir = NULL;
585
586         if (!lockleaf)
587                 cnp->cn_flags |= LOCKLEAF;
588         for (;;) {
589                 cnp->cn_nameptr = cnp->cn_pnbuf;
590                 /*
591                  * Call lookup() to do the real work.  If an error occurs,
592                  * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
593                  * we do not have to dereference anything before returning.
594                  * In either case ni_startdir will be dereferenced and NULLed
595                  * out.
596                  */
597                 error = lookup(ndp);
598                 if (error)
599                         break;
600
601                 /*
602                  * Check for encountering a symbolic link.  Trivial
603                  * termination occurs if no symlink encountered.
604                  */
605                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
606                         if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
607                                 nfsvno_relpathbuf(ndp);
608                         if (ndp->ni_vp && !lockleaf)
609                                 NFSVOPUNLOCK(ndp->ni_vp);
610                         break;
611                 }
612
613                 /*
614                  * Validate symlink
615                  */
616                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
617                         NFSVOPUNLOCK(ndp->ni_dvp);
618                 if (!(nd->nd_flag & ND_PUBLOOKUP)) {
619                         error = EINVAL;
620                         goto badlink2;
621                 }
622
623                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
624                         error = ELOOP;
625                         goto badlink2;
626                 }
627                 if (ndp->ni_pathlen > 1)
628                         cp = uma_zalloc(namei_zone, M_WAITOK);
629                 else
630                         cp = cnp->cn_pnbuf;
631                 aiov.iov_base = cp;
632                 aiov.iov_len = MAXPATHLEN;
633                 auio.uio_iov = &aiov;
634                 auio.uio_iovcnt = 1;
635                 auio.uio_offset = 0;
636                 auio.uio_rw = UIO_READ;
637                 auio.uio_segflg = UIO_SYSSPACE;
638                 auio.uio_td = NULL;
639                 auio.uio_resid = MAXPATHLEN;
640                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
641                 if (error) {
642                 badlink1:
643                         if (ndp->ni_pathlen > 1)
644                                 uma_zfree(namei_zone, cp);
645                 badlink2:
646                         vrele(ndp->ni_dvp);
647                         vput(ndp->ni_vp);
648                         break;
649                 }
650                 linklen = MAXPATHLEN - auio.uio_resid;
651                 if (linklen == 0) {
652                         error = ENOENT;
653                         goto badlink1;
654                 }
655                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
656                         error = ENAMETOOLONG;
657                         goto badlink1;
658                 }
659
660                 /*
661                  * Adjust or replace path
662                  */
663                 if (ndp->ni_pathlen > 1) {
664                         NFSBCOPY(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
665                         uma_zfree(namei_zone, cnp->cn_pnbuf);
666                         cnp->cn_pnbuf = cp;
667                 } else
668                         cnp->cn_pnbuf[linklen] = '\0';
669                 ndp->ni_pathlen += linklen;
670
671                 /*
672                  * Cleanup refs for next loop and check if root directory
673                  * should replace current directory.  Normally ni_dvp
674                  * becomes the new base directory and is cleaned up when
675                  * we loop.  Explicitly null pointers after invalidation
676                  * to clarify operation.
677                  */
678                 vput(ndp->ni_vp);
679                 ndp->ni_vp = NULL;
680
681                 if (cnp->cn_pnbuf[0] == '/') {
682                         vrele(ndp->ni_dvp);
683                         ndp->ni_dvp = ndp->ni_rootdir;
684                         VREF(ndp->ni_dvp);
685                 }
686                 ndp->ni_startdir = ndp->ni_dvp;
687                 ndp->ni_dvp = NULL;
688         }
689         if (!lockleaf)
690                 cnp->cn_flags &= ~LOCKLEAF;
691
692 out:
693         if (error) {
694                 nfsvno_relpathbuf(ndp);
695                 ndp->ni_vp = NULL;
696                 ndp->ni_dvp = NULL;
697                 ndp->ni_startdir = NULL;
698         } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
699                 ndp->ni_dvp = NULL;
700         }
701
702 out1:
703         NFSEXITCODE2(error, nd);
704         return (error);
705 }
706
707 /*
708  * Set up a pathname buffer and return a pointer to it and, optionally
709  * set a hash pointer.
710  */
711 void
712 nfsvno_setpathbuf(struct nameidata *ndp, char **bufpp, u_long **hashpp)
713 {
714         struct componentname *cnp = &ndp->ni_cnd;
715
716         cnp->cn_flags |= (NOMACCHECK | HASBUF);
717         cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
718         if (hashpp != NULL)
719                 *hashpp = NULL;
720         *bufpp = cnp->cn_pnbuf;
721 }
722
723 /*
724  * Release the above path buffer, if not released by nfsvno_namei().
725  */
726 void
727 nfsvno_relpathbuf(struct nameidata *ndp)
728 {
729
730         if ((ndp->ni_cnd.cn_flags & HASBUF) == 0)
731                 panic("nfsrelpath");
732         uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf);
733         ndp->ni_cnd.cn_flags &= ~HASBUF;
734 }
735
736 /*
737  * Readlink vnode op into an mbuf list.
738  */
739 int
740 nfsvno_readlink(struct vnode *vp, struct ucred *cred, int maxextsiz,
741     struct thread *p, struct mbuf **mpp, struct mbuf **mpendp, int *lenp)
742 {
743         struct iovec *iv;
744         struct uio io, *uiop = &io;
745         struct mbuf *mp, *mp3;
746         int len, tlen, error = 0;
747
748         len = NFS_MAXPATHLEN;
749         if (maxextsiz > 0)
750                 uiop->uio_iovcnt = nfsrv_createiovec_extpgs(len, maxextsiz,
751                     &mp3, &mp, &iv);
752         else
753                 uiop->uio_iovcnt = nfsrv_createiovec(len, &mp3, &mp, &iv);
754         uiop->uio_iov = iv;
755         uiop->uio_offset = 0;
756         uiop->uio_resid = len;
757         uiop->uio_rw = UIO_READ;
758         uiop->uio_segflg = UIO_SYSSPACE;
759         uiop->uio_td = NULL;
760         error = VOP_READLINK(vp, uiop, cred);
761         free(iv, M_TEMP);
762         if (error) {
763                 m_freem(mp3);
764                 *lenp = 0;
765                 goto out;
766         }
767         if (uiop->uio_resid > 0) {
768                 len -= uiop->uio_resid;
769                 tlen = NFSM_RNDUP(len);
770                 if (tlen == 0) {
771                         m_freem(mp3);
772                         mp3 = mp = NULL;
773                 } else if (tlen != NFS_MAXPATHLEN || tlen != len)
774                         mp = nfsrv_adj(mp3, NFS_MAXPATHLEN - tlen,
775                             tlen - len);
776         }
777         *lenp = len;
778         *mpp = mp3;
779         *mpendp = mp;
780
781 out:
782         NFSEXITCODE(error);
783         return (error);
784 }
785
786 /*
787  * Create an mbuf chain and an associated iovec that can be used to Read
788  * or Getextattr of data.
789  * Upon success, return pointers to the first and last mbufs in the chain
790  * plus the malloc'd iovec and its iovlen.
791  */
792 static int
793 nfsrv_createiovec(int len, struct mbuf **mpp, struct mbuf **mpendp,
794     struct iovec **ivp)
795 {
796         struct mbuf *m, *m2 = NULL, *m3;
797         struct iovec *iv;
798         int i, left, siz;
799
800         left = len;
801         m3 = NULL;
802         /*
803          * Generate the mbuf list with the uio_iov ref. to it.
804          */
805         i = 0;
806         while (left > 0) {
807                 NFSMGET(m);
808                 MCLGET(m, M_WAITOK);
809                 m->m_len = 0;
810                 siz = min(M_TRAILINGSPACE(m), left);
811                 left -= siz;
812                 i++;
813                 if (m3)
814                         m2->m_next = m;
815                 else
816                         m3 = m;
817                 m2 = m;
818         }
819         *ivp = iv = malloc(i * sizeof (struct iovec), M_TEMP, M_WAITOK);
820         m = m3;
821         left = len;
822         i = 0;
823         while (left > 0) {
824                 if (m == NULL)
825                         panic("nfsrv_createiovec iov");
826                 siz = min(M_TRAILINGSPACE(m), left);
827                 if (siz > 0) {
828                         iv->iov_base = mtod(m, caddr_t) + m->m_len;
829                         iv->iov_len = siz;
830                         m->m_len += siz;
831                         left -= siz;
832                         iv++;
833                         i++;
834                 }
835                 m = m->m_next;
836         }
837         *mpp = m3;
838         *mpendp = m2;
839         return (i);
840 }
841
842 /*
843  * Create an mbuf chain and an associated iovec that can be used to Read
844  * or Getextattr of data.
845  * Upon success, return pointers to the first and last mbufs in the chain
846  * plus the malloc'd iovec and its iovlen.
847  * Same as above, but creates ext_pgs mbuf(s).
848  */
849 static int
850 nfsrv_createiovec_extpgs(int len, int maxextsiz, struct mbuf **mpp,
851     struct mbuf **mpendp, struct iovec **ivp)
852 {
853         struct mbuf *m, *m2 = NULL, *m3;
854         struct iovec *iv;
855         int i, left, pgno, siz;
856
857         left = len;
858         m3 = NULL;
859         /*
860          * Generate the mbuf list with the uio_iov ref. to it.
861          */
862         i = 0;
863         while (left > 0) {
864                 siz = min(left, maxextsiz);
865                 m = mb_alloc_ext_plus_pages(siz, M_WAITOK);
866                 left -= siz;
867                 i += m->m_epg_npgs;
868                 if (m3 != NULL)
869                         m2->m_next = m;
870                 else
871                         m3 = m;
872                 m2 = m;
873         }
874         *ivp = iv = malloc(i * sizeof (struct iovec), M_TEMP, M_WAITOK);
875         m = m3;
876         left = len;
877         i = 0;
878         pgno = 0;
879         while (left > 0) {
880                 if (m == NULL)
881                         panic("nfsvno_createiovec_extpgs iov");
882                 siz = min(PAGE_SIZE, left);
883                 if (siz > 0) {
884                         iv->iov_base = (void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]);
885                         iv->iov_len = siz;
886                         m->m_len += siz;
887                         if (pgno == m->m_epg_npgs - 1)
888                                 m->m_epg_last_len = siz;
889                         left -= siz;
890                         iv++;
891                         i++;
892                         pgno++;
893                 }
894                 if (pgno == m->m_epg_npgs && left > 0) {
895                         m = m->m_next;
896                         if (m == NULL)
897                                 panic("nfsvno_createiovec_extpgs iov");
898                         pgno = 0;
899                 }
900         }
901         *mpp = m3;
902         *mpendp = m2;
903         return (i);
904 }
905
906 /*
907  * Read vnode op call into mbuf list.
908  */
909 int
910 nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred,
911     int maxextsiz, struct thread *p, struct mbuf **mpp,
912     struct mbuf **mpendp)
913 {
914         struct mbuf *m;
915         struct iovec *iv;
916         int error = 0, len, tlen, ioflag = 0;
917         struct mbuf *m3;
918         struct uio io, *uiop = &io;
919         struct nfsheur *nh;
920
921         /*
922          * Attempt to read from a DS file. A return of ENOENT implies
923          * there is no DS file to read.
924          */
925         error = nfsrv_proxyds(vp, off, cnt, cred, p, NFSPROC_READDS, mpp,
926             NULL, mpendp, NULL, NULL, NULL, 0, NULL);
927         if (error != ENOENT)
928                 return (error);
929
930         len = NFSM_RNDUP(cnt);
931         if (maxextsiz > 0)
932                 uiop->uio_iovcnt = nfsrv_createiovec_extpgs(len, maxextsiz,
933                     &m3, &m, &iv);
934         else
935                 uiop->uio_iovcnt = nfsrv_createiovec(len, &m3, &m, &iv);
936         uiop->uio_iov = iv;
937         uiop->uio_offset = off;
938         uiop->uio_resid = len;
939         uiop->uio_rw = UIO_READ;
940         uiop->uio_segflg = UIO_SYSSPACE;
941         uiop->uio_td = NULL;
942         nh = nfsrv_sequential_heuristic(uiop, vp);
943         ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
944         /* XXX KDM make this more systematic? */
945         nfsstatsv1.srvbytes[NFSV4OP_READ] += uiop->uio_resid;
946         error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
947         free(iv, M_TEMP);
948         if (error) {
949                 m_freem(m3);
950                 *mpp = NULL;
951                 goto out;
952         }
953         nh->nh_nextoff = uiop->uio_offset;
954         tlen = len - uiop->uio_resid;
955         cnt = cnt < tlen ? cnt : tlen;
956         tlen = NFSM_RNDUP(cnt);
957         if (tlen == 0) {
958                 m_freem(m3);
959                 m3 = m = NULL;
960         } else if (len != tlen || tlen != cnt)
961                 m = nfsrv_adj(m3, len - tlen, tlen - cnt);
962         *mpp = m3;
963         *mpendp = m;
964
965 out:
966         NFSEXITCODE(error);
967         return (error);
968 }
969
970 /*
971  * Create the iovec for the mbuf chain passed in as an argument.
972  * The "cp" argument is where the data starts within the first mbuf in
973  * the chain. It returns the iovec and the iovcnt.
974  */
975 static int
976 nfsrv_createiovecw(int retlen, struct mbuf *m, char *cp, struct iovec **ivpp,
977     int *iovcntp)
978 {
979         struct mbuf *mp;
980         struct iovec *ivp;
981         int cnt, i, len;
982
983         /*
984          * Loop through the mbuf chain, counting how many mbufs are a
985          * part of this write operation, so the iovec size is known.
986          */
987         cnt = 0;
988         len = retlen;
989         mp = m;
990         i = mtod(mp, caddr_t) + mp->m_len - cp;
991         while (len > 0) {
992                 if (i > 0) {
993                         len -= i;
994                         cnt++;
995                 }
996                 mp = mp->m_next;
997                 if (!mp) {
998                         if (len > 0)
999                                 return (EBADRPC);
1000                 } else
1001                         i = mp->m_len;
1002         }
1003
1004         /* Now, create the iovec. */
1005         mp = m;
1006         *ivpp = ivp = malloc(cnt * sizeof (struct iovec), M_TEMP,
1007             M_WAITOK);
1008         *iovcntp = cnt;
1009         i = mtod(mp, caddr_t) + mp->m_len - cp;
1010         len = retlen;
1011         while (len > 0) {
1012                 if (mp == NULL)
1013                         panic("nfsrv_createiovecw");
1014                 if (i > 0) {
1015                         i = min(i, len);
1016                         ivp->iov_base = cp;
1017                         ivp->iov_len = i;
1018                         ivp++;
1019                         len -= i;
1020                 }
1021                 mp = mp->m_next;
1022                 if (mp) {
1023                         i = mp->m_len;
1024                         cp = mtod(mp, caddr_t);
1025                 }
1026         }
1027         return (0);
1028 }
1029
1030 /*
1031  * Write vnode op from an mbuf list.
1032  */
1033 int
1034 nfsvno_write(struct vnode *vp, off_t off, int retlen, int *stable,
1035     struct mbuf *mp, char *cp, struct ucred *cred, struct thread *p)
1036 {
1037         struct iovec *iv;
1038         int cnt, ioflags, error;
1039         struct uio io, *uiop = &io;
1040         struct nfsheur *nh;
1041
1042         /*
1043          * Attempt to write to a DS file. A return of ENOENT implies
1044          * there is no DS file to write.
1045          */
1046         error = nfsrv_proxyds(vp, off, retlen, cred, p, NFSPROC_WRITEDS,
1047             &mp, cp, NULL, NULL, NULL, NULL, 0, NULL);
1048         if (error != ENOENT) {
1049                 *stable = NFSWRITE_FILESYNC;
1050                 return (error);
1051         }
1052
1053         if (*stable == NFSWRITE_UNSTABLE)
1054                 ioflags = IO_NODELOCKED;
1055         else
1056                 ioflags = (IO_SYNC | IO_NODELOCKED);
1057         error = nfsrv_createiovecw(retlen, mp, cp, &iv, &cnt);
1058         if (error != 0)
1059                 return (error);
1060         uiop->uio_iov = iv;
1061         uiop->uio_iovcnt = cnt;
1062         uiop->uio_resid = retlen;
1063         uiop->uio_rw = UIO_WRITE;
1064         uiop->uio_segflg = UIO_SYSSPACE;
1065         NFSUIOPROC(uiop, p);
1066         uiop->uio_offset = off;
1067         nh = nfsrv_sequential_heuristic(uiop, vp);
1068         ioflags |= nh->nh_seqcount << IO_SEQSHIFT;
1069         /* XXX KDM make this more systematic? */
1070         nfsstatsv1.srvbytes[NFSV4OP_WRITE] += uiop->uio_resid;
1071         error = VOP_WRITE(vp, uiop, ioflags, cred);
1072         if (error == 0)
1073                 nh->nh_nextoff = uiop->uio_offset;
1074         free(iv, M_TEMP);
1075
1076         NFSEXITCODE(error);
1077         return (error);
1078 }
1079
1080 /*
1081  * Common code for creating a regular file (plus special files for V2).
1082  */
1083 int
1084 nfsvno_createsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1085     struct vnode **vpp, struct nfsvattr *nvap, int *exclusive_flagp,
1086     int32_t *cverf, NFSDEV_T rdev, struct nfsexstuff *exp)
1087 {
1088         u_quad_t tempsize;
1089         int error;
1090         struct thread *p = curthread;
1091
1092         error = nd->nd_repstat;
1093         if (!error && ndp->ni_vp == NULL) {
1094                 if (nvap->na_type == VREG || nvap->na_type == VSOCK) {
1095                         vrele(ndp->ni_startdir);
1096                         error = VOP_CREATE(ndp->ni_dvp,
1097                             &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr);
1098                         /* For a pNFS server, create the data file on a DS. */
1099                         if (error == 0 && nvap->na_type == VREG) {
1100                                 /*
1101                                  * Create a data file on a DS for a pNFS server.
1102                                  * This function just returns if not
1103                                  * running a pNFS DS or the creation fails.
1104                                  */
1105                                 nfsrv_pnfscreate(ndp->ni_vp, &nvap->na_vattr,
1106                                     nd->nd_cred, p);
1107                         }
1108                         vput(ndp->ni_dvp);
1109                         nfsvno_relpathbuf(ndp);
1110                         if (!error) {
1111                                 if (*exclusive_flagp) {
1112                                         *exclusive_flagp = 0;
1113                                         NFSVNO_ATTRINIT(nvap);
1114                                         nvap->na_atime.tv_sec = cverf[0];
1115                                         nvap->na_atime.tv_nsec = cverf[1];
1116                                         error = VOP_SETATTR(ndp->ni_vp,
1117                                             &nvap->na_vattr, nd->nd_cred);
1118                                         if (error != 0) {
1119                                                 vput(ndp->ni_vp);
1120                                                 ndp->ni_vp = NULL;
1121                                                 error = NFSERR_NOTSUPP;
1122                                         }
1123                                 }
1124                         }
1125                 /*
1126                  * NFS V2 Only. nfsrvd_mknod() does this for V3.
1127                  * (This implies, just get out on an error.)
1128                  */
1129                 } else if (nvap->na_type == VCHR || nvap->na_type == VBLK ||
1130                         nvap->na_type == VFIFO) {
1131                         if (nvap->na_type == VCHR && rdev == 0xffffffff)
1132                                 nvap->na_type = VFIFO;
1133                         if (nvap->na_type != VFIFO &&
1134                             (error = priv_check_cred(nd->nd_cred, PRIV_VFS_MKNOD_DEV))) {
1135                                 vrele(ndp->ni_startdir);
1136                                 nfsvno_relpathbuf(ndp);
1137                                 vput(ndp->ni_dvp);
1138                                 goto out;
1139                         }
1140                         nvap->na_rdev = rdev;
1141                         error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp,
1142                             &ndp->ni_cnd, &nvap->na_vattr);
1143                         vput(ndp->ni_dvp);
1144                         nfsvno_relpathbuf(ndp);
1145                         vrele(ndp->ni_startdir);
1146                         if (error)
1147                                 goto out;
1148                 } else {
1149                         vrele(ndp->ni_startdir);
1150                         nfsvno_relpathbuf(ndp);
1151                         vput(ndp->ni_dvp);
1152                         error = ENXIO;
1153                         goto out;
1154                 }
1155                 *vpp = ndp->ni_vp;
1156         } else {
1157                 /*
1158                  * Handle cases where error is already set and/or
1159                  * the file exists.
1160                  * 1 - clean up the lookup
1161                  * 2 - iff !error and na_size set, truncate it
1162                  */
1163                 vrele(ndp->ni_startdir);
1164                 nfsvno_relpathbuf(ndp);
1165                 *vpp = ndp->ni_vp;
1166                 if (ndp->ni_dvp == *vpp)
1167                         vrele(ndp->ni_dvp);
1168                 else
1169                         vput(ndp->ni_dvp);
1170                 if (!error && nvap->na_size != VNOVAL) {
1171                         error = nfsvno_accchk(*vpp, VWRITE,
1172                             nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
1173                             NFSACCCHK_VPISLOCKED, NULL);
1174                         if (!error) {
1175                                 tempsize = nvap->na_size;
1176                                 NFSVNO_ATTRINIT(nvap);
1177                                 nvap->na_size = tempsize;
1178                                 error = VOP_SETATTR(*vpp,
1179                                     &nvap->na_vattr, nd->nd_cred);
1180                         }
1181                 }
1182                 if (error)
1183                         vput(*vpp);
1184         }
1185
1186 out:
1187         NFSEXITCODE(error);
1188         return (error);
1189 }
1190
1191 /*
1192  * Do a mknod vnode op.
1193  */
1194 int
1195 nfsvno_mknod(struct nameidata *ndp, struct nfsvattr *nvap, struct ucred *cred,
1196     struct thread *p)
1197 {
1198         int error = 0;
1199         enum vtype vtyp;
1200
1201         vtyp = nvap->na_type;
1202         /*
1203          * Iff doesn't exist, create it.
1204          */
1205         if (ndp->ni_vp) {
1206                 vrele(ndp->ni_startdir);
1207                 nfsvno_relpathbuf(ndp);
1208                 vput(ndp->ni_dvp);
1209                 vrele(ndp->ni_vp);
1210                 error = EEXIST;
1211                 goto out;
1212         }
1213         if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1214                 vrele(ndp->ni_startdir);
1215                 nfsvno_relpathbuf(ndp);
1216                 vput(ndp->ni_dvp);
1217                 error = NFSERR_BADTYPE;
1218                 goto out;
1219         }
1220         if (vtyp == VSOCK) {
1221                 vrele(ndp->ni_startdir);
1222                 error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
1223                     &ndp->ni_cnd, &nvap->na_vattr);
1224                 vput(ndp->ni_dvp);
1225                 nfsvno_relpathbuf(ndp);
1226         } else {
1227                 if (nvap->na_type != VFIFO &&
1228                     (error = priv_check_cred(cred, PRIV_VFS_MKNOD_DEV))) {
1229                         vrele(ndp->ni_startdir);
1230                         nfsvno_relpathbuf(ndp);
1231                         vput(ndp->ni_dvp);
1232                         goto out;
1233                 }
1234                 error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp,
1235                     &ndp->ni_cnd, &nvap->na_vattr);
1236                 vput(ndp->ni_dvp);
1237                 nfsvno_relpathbuf(ndp);
1238                 vrele(ndp->ni_startdir);
1239                 /*
1240                  * Since VOP_MKNOD returns the ni_vp, I can't
1241                  * see any reason to do the lookup.
1242                  */
1243         }
1244
1245 out:
1246         NFSEXITCODE(error);
1247         return (error);
1248 }
1249
1250 /*
1251  * Mkdir vnode op.
1252  */
1253 int
1254 nfsvno_mkdir(struct nameidata *ndp, struct nfsvattr *nvap, uid_t saved_uid,
1255     struct ucred *cred, struct thread *p, struct nfsexstuff *exp)
1256 {
1257         int error = 0;
1258
1259         if (ndp->ni_vp != NULL) {
1260                 if (ndp->ni_dvp == ndp->ni_vp)
1261                         vrele(ndp->ni_dvp);
1262                 else
1263                         vput(ndp->ni_dvp);
1264                 vrele(ndp->ni_vp);
1265                 nfsvno_relpathbuf(ndp);
1266                 error = EEXIST;
1267                 goto out;
1268         }
1269         error = VOP_MKDIR(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd,
1270             &nvap->na_vattr);
1271         vput(ndp->ni_dvp);
1272         nfsvno_relpathbuf(ndp);
1273
1274 out:
1275         NFSEXITCODE(error);
1276         return (error);
1277 }
1278
1279 /*
1280  * symlink vnode op.
1281  */
1282 int
1283 nfsvno_symlink(struct nameidata *ndp, struct nfsvattr *nvap, char *pathcp,
1284     int pathlen, int not_v2, uid_t saved_uid, struct ucred *cred, struct thread *p,
1285     struct nfsexstuff *exp)
1286 {
1287         int error = 0;
1288
1289         if (ndp->ni_vp) {
1290                 vrele(ndp->ni_startdir);
1291                 nfsvno_relpathbuf(ndp);
1292                 if (ndp->ni_dvp == ndp->ni_vp)
1293                         vrele(ndp->ni_dvp);
1294                 else
1295                         vput(ndp->ni_dvp);
1296                 vrele(ndp->ni_vp);
1297                 error = EEXIST;
1298                 goto out;
1299         }
1300
1301         error = VOP_SYMLINK(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd,
1302             &nvap->na_vattr, pathcp);
1303         vput(ndp->ni_dvp);
1304         vrele(ndp->ni_startdir);
1305         nfsvno_relpathbuf(ndp);
1306         /*
1307          * Although FreeBSD still had the lookup code in
1308          * it for 7/current, there doesn't seem to be any
1309          * point, since VOP_SYMLINK() returns the ni_vp.
1310          * Just vput it for v2.
1311          */
1312         if (!not_v2 && !error)
1313                 vput(ndp->ni_vp);
1314
1315 out:
1316         NFSEXITCODE(error);
1317         return (error);
1318 }
1319
1320 /*
1321  * Parse symbolic link arguments.
1322  * This function has an ugly side effect. It will malloc() an area for
1323  * the symlink and set iov_base to point to it, only if it succeeds.
1324  * So, if it returns with uiop->uio_iov->iov_base != NULL, that must
1325  * be FREE'd later.
1326  */
1327 int
1328 nfsvno_getsymlink(struct nfsrv_descript *nd, struct nfsvattr *nvap,
1329     struct thread *p, char **pathcpp, int *lenp)
1330 {
1331         u_int32_t *tl;
1332         char *pathcp = NULL;
1333         int error = 0, len;
1334         struct nfsv2_sattr *sp;
1335
1336         *pathcpp = NULL;
1337         *lenp = 0;
1338         if ((nd->nd_flag & ND_NFSV3) &&
1339             (error = nfsrv_sattr(nd, NULL, nvap, NULL, NULL, p)))
1340                 goto nfsmout;
1341         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1342         len = fxdr_unsigned(int, *tl);
1343         if (len > NFS_MAXPATHLEN || len <= 0) {
1344                 error = EBADRPC;
1345                 goto nfsmout;
1346         }
1347         pathcp = malloc(len + 1, M_TEMP, M_WAITOK);
1348         error = nfsrv_mtostr(nd, pathcp, len);
1349         if (error)
1350                 goto nfsmout;
1351         if (nd->nd_flag & ND_NFSV2) {
1352                 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1353                 nvap->na_mode = fxdr_unsigned(u_int16_t, sp->sa_mode);
1354         }
1355         *pathcpp = pathcp;
1356         *lenp = len;
1357         NFSEXITCODE2(0, nd);
1358         return (0);
1359 nfsmout:
1360         if (pathcp)
1361                 free(pathcp, M_TEMP);
1362         NFSEXITCODE2(error, nd);
1363         return (error);
1364 }
1365
1366 /*
1367  * Remove a non-directory object.
1368  */
1369 int
1370 nfsvno_removesub(struct nameidata *ndp, int is_v4, struct ucred *cred,
1371     struct thread *p, struct nfsexstuff *exp)
1372 {
1373         struct vnode *vp, *dsdvp[NFSDEV_MAXMIRRORS];
1374         int error = 0, mirrorcnt;
1375         char fname[PNFS_FILENAME_LEN + 1];
1376         fhandle_t fh;
1377
1378         vp = ndp->ni_vp;
1379         dsdvp[0] = NULL;
1380         if (vp->v_type == VDIR)
1381                 error = NFSERR_ISDIR;
1382         else if (is_v4)
1383                 error = nfsrv_checkremove(vp, 1, NULL, (nfsquad_t)((u_quad_t)0),
1384                     p);
1385         if (error == 0)
1386                 nfsrv_pnfsremovesetup(vp, p, dsdvp, &mirrorcnt, fname, &fh);
1387         if (!error)
1388                 error = VOP_REMOVE(ndp->ni_dvp, vp, &ndp->ni_cnd);
1389         if (error == 0 && dsdvp[0] != NULL)
1390                 nfsrv_pnfsremove(dsdvp, mirrorcnt, fname, &fh, p);
1391         if (ndp->ni_dvp == vp)
1392                 vrele(ndp->ni_dvp);
1393         else
1394                 vput(ndp->ni_dvp);
1395         vput(vp);
1396         if ((ndp->ni_cnd.cn_flags & SAVENAME) != 0)
1397                 nfsvno_relpathbuf(ndp);
1398         NFSEXITCODE(error);
1399         return (error);
1400 }
1401
1402 /*
1403  * Remove a directory.
1404  */
1405 int
1406 nfsvno_rmdirsub(struct nameidata *ndp, int is_v4, struct ucred *cred,
1407     struct thread *p, struct nfsexstuff *exp)
1408 {
1409         struct vnode *vp;
1410         int error = 0;
1411
1412         vp = ndp->ni_vp;
1413         if (vp->v_type != VDIR) {
1414                 error = ENOTDIR;
1415                 goto out;
1416         }
1417         /*
1418          * No rmdir "." please.
1419          */
1420         if (ndp->ni_dvp == vp) {
1421                 error = EINVAL;
1422                 goto out;
1423         }
1424         /*
1425          * The root of a mounted filesystem cannot be deleted.
1426          */
1427         if (vp->v_vflag & VV_ROOT)
1428                 error = EBUSY;
1429 out:
1430         if (!error)
1431                 error = VOP_RMDIR(ndp->ni_dvp, vp, &ndp->ni_cnd);
1432         if (ndp->ni_dvp == vp)
1433                 vrele(ndp->ni_dvp);
1434         else
1435                 vput(ndp->ni_dvp);
1436         vput(vp);
1437         if ((ndp->ni_cnd.cn_flags & SAVENAME) != 0)
1438                 nfsvno_relpathbuf(ndp);
1439         NFSEXITCODE(error);
1440         return (error);
1441 }
1442
1443 /*
1444  * Rename vnode op.
1445  */
1446 int
1447 nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp,
1448     u_int32_t ndstat, u_int32_t ndflag, struct ucred *cred, struct thread *p)
1449 {
1450         struct vnode *fvp, *tvp, *tdvp, *dsdvp[NFSDEV_MAXMIRRORS];
1451         int error = 0, mirrorcnt;
1452         char fname[PNFS_FILENAME_LEN + 1];
1453         fhandle_t fh;
1454
1455         dsdvp[0] = NULL;
1456         fvp = fromndp->ni_vp;
1457         if (ndstat) {
1458                 vrele(fromndp->ni_dvp);
1459                 vrele(fvp);
1460                 error = ndstat;
1461                 goto out1;
1462         }
1463         tdvp = tondp->ni_dvp;
1464         tvp = tondp->ni_vp;
1465         if (tvp != NULL) {
1466                 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1467                         error = (ndflag & ND_NFSV2) ? EISDIR : EEXIST;
1468                         goto out;
1469                 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1470                         error = (ndflag & ND_NFSV2) ? ENOTDIR : EEXIST;
1471                         goto out;
1472                 }
1473                 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
1474                         error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV;
1475                         goto out;
1476                 }
1477
1478                 /*
1479                  * A rename to '.' or '..' results in a prematurely
1480                  * unlocked vnode on FreeBSD5, so I'm just going to fail that
1481                  * here.
1482                  */
1483                 if ((tondp->ni_cnd.cn_namelen == 1 &&
1484                      tondp->ni_cnd.cn_nameptr[0] == '.') ||
1485                     (tondp->ni_cnd.cn_namelen == 2 &&
1486                      tondp->ni_cnd.cn_nameptr[0] == '.' &&
1487                      tondp->ni_cnd.cn_nameptr[1] == '.')) {
1488                         error = EINVAL;
1489                         goto out;
1490                 }
1491         }
1492         if (fvp->v_type == VDIR && fvp->v_mountedhere) {
1493                 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV;
1494                 goto out;
1495         }
1496         if (fvp->v_mount != tdvp->v_mount) {
1497                 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV;
1498                 goto out;
1499         }
1500         if (fvp == tdvp) {
1501                 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EINVAL;
1502                 goto out;
1503         }
1504         if (fvp == tvp) {
1505                 /*
1506                  * If source and destination are the same, there is nothing to
1507                  * do. Set error to -1 to indicate this.
1508                  */
1509                 error = -1;
1510                 goto out;
1511         }
1512         if (ndflag & ND_NFSV4) {
1513                 if (NFSVOPLOCK(fvp, LK_EXCLUSIVE) == 0) {
1514                         error = nfsrv_checkremove(fvp, 0, NULL,
1515                             (nfsquad_t)((u_quad_t)0), p);
1516                         NFSVOPUNLOCK(fvp);
1517                 } else
1518                         error = EPERM;
1519                 if (tvp && !error)
1520                         error = nfsrv_checkremove(tvp, 1, NULL,
1521                             (nfsquad_t)((u_quad_t)0), p);
1522         } else {
1523                 /*
1524                  * For NFSv2 and NFSv3, try to get rid of the delegation, so
1525                  * that the NFSv4 client won't be confused by the rename.
1526                  * Since nfsd_recalldelegation() can only be called on an
1527                  * unlocked vnode at this point and fvp is the file that will
1528                  * still exist after the rename, just do fvp.
1529                  */
1530                 nfsd_recalldelegation(fvp, p);
1531         }
1532         if (error == 0 && tvp != NULL) {
1533                 nfsrv_pnfsremovesetup(tvp, p, dsdvp, &mirrorcnt, fname, &fh);
1534                 NFSD_DEBUG(4, "nfsvno_rename: pnfsremovesetup"
1535                     " dsdvp=%p\n", dsdvp[0]);
1536         }
1537 out:
1538         if (!error) {
1539                 error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp,
1540                     &fromndp->ni_cnd, tondp->ni_dvp, tondp->ni_vp,
1541                     &tondp->ni_cnd);
1542         } else {
1543                 if (tdvp == tvp)
1544                         vrele(tdvp);
1545                 else
1546                         vput(tdvp);
1547                 if (tvp)
1548                         vput(tvp);
1549                 vrele(fromndp->ni_dvp);
1550                 vrele(fvp);
1551                 if (error == -1)
1552                         error = 0;
1553         }
1554
1555         /*
1556          * If dsdvp[0] != NULL, it was set up by nfsrv_pnfsremovesetup() and
1557          * if the rename succeeded, the DS file for the tvp needs to be
1558          * removed.
1559          */
1560         if (error == 0 && dsdvp[0] != NULL) {
1561                 nfsrv_pnfsremove(dsdvp, mirrorcnt, fname, &fh, p);
1562                 NFSD_DEBUG(4, "nfsvno_rename: pnfsremove\n");
1563         }
1564
1565         vrele(tondp->ni_startdir);
1566         nfsvno_relpathbuf(tondp);
1567 out1:
1568         vrele(fromndp->ni_startdir);
1569         nfsvno_relpathbuf(fromndp);
1570         NFSEXITCODE(error);
1571         return (error);
1572 }
1573
1574 /*
1575  * Link vnode op.
1576  */
1577 int
1578 nfsvno_link(struct nameidata *ndp, struct vnode *vp, struct ucred *cred,
1579     struct thread *p, struct nfsexstuff *exp)
1580 {
1581         struct vnode *xp;
1582         int error = 0;
1583
1584         xp = ndp->ni_vp;
1585         if (xp != NULL) {
1586                 error = EEXIST;
1587         } else {
1588                 xp = ndp->ni_dvp;
1589                 if (vp->v_mount != xp->v_mount)
1590                         error = EXDEV;
1591         }
1592         if (!error) {
1593                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
1594                 if (!VN_IS_DOOMED(vp))
1595                         error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd);
1596                 else
1597                         error = EPERM;
1598                 if (ndp->ni_dvp == vp)
1599                         vrele(ndp->ni_dvp);
1600                 else
1601                         vput(ndp->ni_dvp);
1602                 NFSVOPUNLOCK(vp);
1603         } else {
1604                 if (ndp->ni_dvp == ndp->ni_vp)
1605                         vrele(ndp->ni_dvp);
1606                 else
1607                         vput(ndp->ni_dvp);
1608                 if (ndp->ni_vp)
1609                         vrele(ndp->ni_vp);
1610         }
1611         nfsvno_relpathbuf(ndp);
1612         NFSEXITCODE(error);
1613         return (error);
1614 }
1615
1616 /*
1617  * Do the fsync() appropriate for the commit.
1618  */
1619 int
1620 nfsvno_fsync(struct vnode *vp, u_int64_t off, int cnt, struct ucred *cred,
1621     struct thread *td)
1622 {
1623         int error = 0;
1624
1625         /*
1626          * RFC 1813 3.3.21: if count is 0, a flush from offset to the end of
1627          * file is done.  At this time VOP_FSYNC does not accept offset and
1628          * byte count parameters so call VOP_FSYNC the whole file for now.
1629          * The same is true for NFSv4: RFC 3530 Sec. 14.2.3.
1630          * File systems that do not use the buffer cache (as indicated
1631          * by MNTK_USES_BCACHE not being set) must use VOP_FSYNC().
1632          */
1633         if (cnt == 0 || cnt > MAX_COMMIT_COUNT ||
1634             (vp->v_mount->mnt_kern_flag & MNTK_USES_BCACHE) == 0) {
1635                 /*
1636                  * Give up and do the whole thing
1637                  */
1638                 if (vp->v_object && vm_object_mightbedirty(vp->v_object)) {
1639                         VM_OBJECT_WLOCK(vp->v_object);
1640                         vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC);
1641                         VM_OBJECT_WUNLOCK(vp->v_object);
1642                 }
1643                 error = VOP_FSYNC(vp, MNT_WAIT, td);
1644         } else {
1645                 /*
1646                  * Locate and synchronously write any buffers that fall
1647                  * into the requested range.  Note:  we are assuming that
1648                  * f_iosize is a power of 2.
1649                  */
1650                 int iosize = vp->v_mount->mnt_stat.f_iosize;
1651                 int iomask = iosize - 1;
1652                 struct bufobj *bo;
1653                 daddr_t lblkno;
1654
1655                 /*
1656                  * Align to iosize boundary, super-align to page boundary.
1657                  */
1658                 if (off & iomask) {
1659                         cnt += off & iomask;
1660                         off &= ~(u_quad_t)iomask;
1661                 }
1662                 if (off & PAGE_MASK) {
1663                         cnt += off & PAGE_MASK;
1664                         off &= ~(u_quad_t)PAGE_MASK;
1665                 }
1666                 lblkno = off / iosize;
1667
1668                 if (vp->v_object && vm_object_mightbedirty(vp->v_object)) {
1669                         VM_OBJECT_WLOCK(vp->v_object);
1670                         vm_object_page_clean(vp->v_object, off, off + cnt,
1671                             OBJPC_SYNC);
1672                         VM_OBJECT_WUNLOCK(vp->v_object);
1673                 }
1674
1675                 bo = &vp->v_bufobj;
1676                 BO_LOCK(bo);
1677                 while (cnt > 0) {
1678                         struct buf *bp;
1679
1680                         /*
1681                          * If we have a buffer and it is marked B_DELWRI we
1682                          * have to lock and write it.  Otherwise the prior
1683                          * write is assumed to have already been committed.
1684                          *
1685                          * gbincore() can return invalid buffers now so we
1686                          * have to check that bit as well (though B_DELWRI
1687                          * should not be set if B_INVAL is set there could be
1688                          * a race here since we haven't locked the buffer).
1689                          */
1690                         if ((bp = gbincore(&vp->v_bufobj, lblkno)) != NULL) {
1691                                 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL |
1692                                     LK_INTERLOCK, BO_LOCKPTR(bo)) == ENOLCK) {
1693                                         BO_LOCK(bo);
1694                                         continue; /* retry */
1695                                 }
1696                                 if ((bp->b_flags & (B_DELWRI|B_INVAL)) ==
1697                                     B_DELWRI) {
1698                                         bremfree(bp);
1699                                         bp->b_flags &= ~B_ASYNC;
1700                                         bwrite(bp);
1701                                         ++nfs_commit_miss;
1702                                 } else
1703                                         BUF_UNLOCK(bp);
1704                                 BO_LOCK(bo);
1705                         }
1706                         ++nfs_commit_blks;
1707                         if (cnt < iosize)
1708                                 break;
1709                         cnt -= iosize;
1710                         ++lblkno;
1711                 }
1712                 BO_UNLOCK(bo);
1713         }
1714         NFSEXITCODE(error);
1715         return (error);
1716 }
1717
1718 /*
1719  * Statfs vnode op.
1720  */
1721 int
1722 nfsvno_statfs(struct vnode *vp, struct statfs *sf)
1723 {
1724         struct statfs *tsf;
1725         int error;
1726
1727         tsf = NULL;
1728         if (nfsrv_devidcnt > 0) {
1729                 /* For a pNFS service, get the DS numbers. */
1730                 tsf = malloc(sizeof(*tsf), M_TEMP, M_WAITOK | M_ZERO);
1731                 error = nfsrv_pnfsstatfs(tsf, vp->v_mount);
1732                 if (error != 0) {
1733                         free(tsf, M_TEMP);
1734                         tsf = NULL;
1735                 }
1736         }
1737         error = VFS_STATFS(vp->v_mount, sf);
1738         if (error == 0) {
1739                 if (tsf != NULL) {
1740                         sf->f_blocks = tsf->f_blocks;
1741                         sf->f_bavail = tsf->f_bavail;
1742                         sf->f_bfree = tsf->f_bfree;
1743                         sf->f_bsize = tsf->f_bsize;
1744                 }
1745                 /*
1746                  * Since NFS handles these values as unsigned on the
1747                  * wire, there is no way to represent negative values,
1748                  * so set them to 0. Without this, they will appear
1749                  * to be very large positive values for clients like
1750                  * Solaris10.
1751                  */
1752                 if (sf->f_bavail < 0)
1753                         sf->f_bavail = 0;
1754                 if (sf->f_ffree < 0)
1755                         sf->f_ffree = 0;
1756         }
1757         free(tsf, M_TEMP);
1758         NFSEXITCODE(error);
1759         return (error);
1760 }
1761
1762 /*
1763  * Do the vnode op stuff for Open. Similar to nfsvno_createsub(), but
1764  * must handle nfsrv_opencheck() calls after any other access checks.
1765  */
1766 void
1767 nfsvno_open(struct nfsrv_descript *nd, struct nameidata *ndp,
1768     nfsquad_t clientid, nfsv4stateid_t *stateidp, struct nfsstate *stp,
1769     int *exclusive_flagp, struct nfsvattr *nvap, int32_t *cverf, int create,
1770     NFSACL_T *aclp, nfsattrbit_t *attrbitp, struct ucred *cred,
1771     struct nfsexstuff *exp, struct vnode **vpp)
1772 {
1773         struct vnode *vp = NULL;
1774         u_quad_t tempsize;
1775         struct nfsexstuff nes;
1776         struct thread *p = curthread;
1777
1778         if (ndp->ni_vp == NULL)
1779                 nd->nd_repstat = nfsrv_opencheck(clientid,
1780                     stateidp, stp, NULL, nd, p, nd->nd_repstat);
1781         if (!nd->nd_repstat) {
1782                 if (ndp->ni_vp == NULL) {
1783                         vrele(ndp->ni_startdir);
1784                         nd->nd_repstat = VOP_CREATE(ndp->ni_dvp,
1785                             &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr);
1786                         /* For a pNFS server, create the data file on a DS. */
1787                         if (nd->nd_repstat == 0) {
1788                                 /*
1789                                  * Create a data file on a DS for a pNFS server.
1790                                  * This function just returns if not
1791                                  * running a pNFS DS or the creation fails.
1792                                  */
1793                                 nfsrv_pnfscreate(ndp->ni_vp, &nvap->na_vattr,
1794                                     cred, p);
1795                         }
1796                         vput(ndp->ni_dvp);
1797                         nfsvno_relpathbuf(ndp);
1798                         if (!nd->nd_repstat) {
1799                                 if (*exclusive_flagp) {
1800                                         *exclusive_flagp = 0;
1801                                         NFSVNO_ATTRINIT(nvap);
1802                                         nvap->na_atime.tv_sec = cverf[0];
1803                                         nvap->na_atime.tv_nsec = cverf[1];
1804                                         nd->nd_repstat = VOP_SETATTR(ndp->ni_vp,
1805                                             &nvap->na_vattr, cred);
1806                                         if (nd->nd_repstat != 0) {
1807                                                 vput(ndp->ni_vp);
1808                                                 ndp->ni_vp = NULL;
1809                                                 nd->nd_repstat = NFSERR_NOTSUPP;
1810                                         } else
1811                                                 NFSSETBIT_ATTRBIT(attrbitp,
1812                                                     NFSATTRBIT_TIMEACCESS);
1813                                 } else {
1814                                         nfsrv_fixattr(nd, ndp->ni_vp, nvap,
1815                                             aclp, p, attrbitp, exp);
1816                                 }
1817                         }
1818                         vp = ndp->ni_vp;
1819                 } else {
1820                         if (ndp->ni_startdir)
1821                                 vrele(ndp->ni_startdir);
1822                         nfsvno_relpathbuf(ndp);
1823                         vp = ndp->ni_vp;
1824                         if (create == NFSV4OPEN_CREATE) {
1825                                 if (ndp->ni_dvp == vp)
1826                                         vrele(ndp->ni_dvp);
1827                                 else
1828                                         vput(ndp->ni_dvp);
1829                         }
1830                         if (NFSVNO_ISSETSIZE(nvap) && vp->v_type == VREG) {
1831                                 if (ndp->ni_cnd.cn_flags & RDONLY)
1832                                         NFSVNO_SETEXRDONLY(&nes);
1833                                 else
1834                                         NFSVNO_EXINIT(&nes);
1835                                 nd->nd_repstat = nfsvno_accchk(vp, 
1836                                     VWRITE, cred, &nes, p,
1837                                     NFSACCCHK_NOOVERRIDE,
1838                                     NFSACCCHK_VPISLOCKED, NULL);
1839                                 nd->nd_repstat = nfsrv_opencheck(clientid,
1840                                     stateidp, stp, vp, nd, p, nd->nd_repstat);
1841                                 if (!nd->nd_repstat) {
1842                                         tempsize = nvap->na_size;
1843                                         NFSVNO_ATTRINIT(nvap);
1844                                         nvap->na_size = tempsize;
1845                                         nd->nd_repstat = VOP_SETATTR(vp,
1846                                             &nvap->na_vattr, cred);
1847                                 }
1848                         } else if (vp->v_type == VREG) {
1849                                 nd->nd_repstat = nfsrv_opencheck(clientid,
1850                                     stateidp, stp, vp, nd, p, nd->nd_repstat);
1851                         }
1852                 }
1853         } else {
1854                 if (ndp->ni_cnd.cn_flags & HASBUF)
1855                         nfsvno_relpathbuf(ndp);
1856                 if (ndp->ni_startdir && create == NFSV4OPEN_CREATE) {
1857                         vrele(ndp->ni_startdir);
1858                         if (ndp->ni_dvp == ndp->ni_vp)
1859                                 vrele(ndp->ni_dvp);
1860                         else
1861                                 vput(ndp->ni_dvp);
1862                         if (ndp->ni_vp)
1863                                 vput(ndp->ni_vp);
1864                 }
1865         }
1866         *vpp = vp;
1867
1868         NFSEXITCODE2(0, nd);
1869 }
1870
1871 /*
1872  * Updates the file rev and sets the mtime and ctime
1873  * to the current clock time, returning the va_filerev and va_Xtime
1874  * values.
1875  * Return ESTALE to indicate the vnode is VIRF_DOOMED.
1876  */
1877 int
1878 nfsvno_updfilerev(struct vnode *vp, struct nfsvattr *nvap,
1879     struct nfsrv_descript *nd, struct thread *p)
1880 {
1881         struct vattr va;
1882
1883         VATTR_NULL(&va);
1884         vfs_timestamp(&va.va_mtime);
1885         if (NFSVOPISLOCKED(vp) != LK_EXCLUSIVE) {
1886                 NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
1887                 if (VN_IS_DOOMED(vp))
1888                         return (ESTALE);
1889         }
1890         (void) VOP_SETATTR(vp, &va, nd->nd_cred);
1891         (void) nfsvno_getattr(vp, nvap, nd, p, 1, NULL);
1892         return (0);
1893 }
1894
1895 /*
1896  * Glue routine to nfsv4_fillattr().
1897  */
1898 int
1899 nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
1900     struct nfsvattr *nvap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
1901     struct ucred *cred, struct thread *p, int isdgram, int reterr,
1902     int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1903 {
1904         struct statfs *sf;
1905         int error;
1906
1907         sf = NULL;
1908         if (nfsrv_devidcnt > 0 &&
1909             (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SPACEAVAIL) ||
1910              NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SPACEFREE) ||
1911              NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SPACETOTAL))) {
1912                 sf = malloc(sizeof(*sf), M_TEMP, M_WAITOK | M_ZERO);
1913                 error = nfsrv_pnfsstatfs(sf, mp);
1914                 if (error != 0) {
1915                         free(sf, M_TEMP);
1916                         sf = NULL;
1917                 }
1918         }
1919         error = nfsv4_fillattr(nd, mp, vp, NULL, &nvap->na_vattr, fhp, rderror,
1920             attrbitp, cred, p, isdgram, reterr, supports_nfsv4acls, at_root,
1921             mounted_on_fileno, sf);
1922         free(sf, M_TEMP);
1923         NFSEXITCODE2(0, nd);
1924         return (error);
1925 }
1926
1927 /* Since the Readdir vnode ops vary, put the entire functions in here. */
1928 /*
1929  * nfs readdir service
1930  * - mallocs what it thinks is enough to read
1931  *      count rounded up to a multiple of DIRBLKSIZ <= NFS_MAXREADDIR
1932  * - calls VOP_READDIR()
1933  * - loops around building the reply
1934  *      if the output generated exceeds count break out of loop
1935  *      The NFSM_CLGET macro is used here so that the reply will be packed
1936  *      tightly in mbuf clusters.
1937  * - it trims out records with d_fileno == 0
1938  *      this doesn't matter for Unix clients, but they might confuse clients
1939  *      for other os'.
1940  * - it trims out records with d_type == DT_WHT
1941  *      these cannot be seen through NFS (unless we extend the protocol)
1942  *     The alternate call nfsrvd_readdirplus() does lookups as well.
1943  * PS: The NFS protocol spec. does not clarify what the "count" byte
1944  *      argument is a count of.. just name strings and file id's or the
1945  *      entire reply rpc or ...
1946  *      I tried just file name and id sizes and it confused the Sun client,
1947  *      so I am using the full rpc size now. The "paranoia.." comment refers
1948  *      to including the status longwords that are not a part of the dir.
1949  *      "entry" structures, but are in the rpc.
1950  */
1951 int
1952 nfsrvd_readdir(struct nfsrv_descript *nd, int isdgram,
1953     struct vnode *vp, struct nfsexstuff *exp)
1954 {
1955         struct dirent *dp;
1956         u_int32_t *tl;
1957         int dirlen;
1958         char *cpos, *cend, *rbuf;
1959         struct nfsvattr at;
1960         int nlen, error = 0, getret = 1;
1961         int siz, cnt, fullsiz, eofflag, ncookies;
1962         u_int64_t off, toff, verf __unused;
1963         u_long *cookies = NULL, *cookiep;
1964         struct uio io;
1965         struct iovec iv;
1966         int is_ufs;
1967         struct thread *p = curthread;
1968
1969         if (nd->nd_repstat) {
1970                 nfsrv_postopattr(nd, getret, &at);
1971                 goto out;
1972         }
1973         if (nd->nd_flag & ND_NFSV2) {
1974                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1975                 off = fxdr_unsigned(u_quad_t, *tl++);
1976         } else {
1977                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1978                 off = fxdr_hyper(tl);
1979                 tl += 2;
1980                 verf = fxdr_hyper(tl);
1981                 tl += 2;
1982         }
1983         toff = off;
1984         cnt = fxdr_unsigned(int, *tl);
1985         if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0)
1986                 cnt = NFS_SRVMAXDATA(nd);
1987         siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
1988         fullsiz = siz;
1989         if (nd->nd_flag & ND_NFSV3) {
1990                 nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd, p, 1,
1991                     NULL);
1992 #if 0
1993                 /*
1994                  * va_filerev is not sufficient as a cookie verifier,
1995                  * since it is not supposed to change when entries are
1996                  * removed/added unless that offset cookies returned to
1997                  * the client are no longer valid.
1998                  */
1999                 if (!nd->nd_repstat && toff && verf != at.na_filerev)
2000                         nd->nd_repstat = NFSERR_BAD_COOKIE;
2001 #endif
2002         }
2003         if (!nd->nd_repstat && vp->v_type != VDIR)
2004                 nd->nd_repstat = NFSERR_NOTDIR;
2005         if (nd->nd_repstat == 0 && cnt == 0) {
2006                 if (nd->nd_flag & ND_NFSV2)
2007                         /* NFSv2 does not have NFSERR_TOOSMALL */
2008                         nd->nd_repstat = EPERM;
2009                 else
2010                         nd->nd_repstat = NFSERR_TOOSMALL;
2011         }
2012         if (!nd->nd_repstat)
2013                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2014                     nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
2015                     NFSACCCHK_VPISLOCKED, NULL);
2016         if (nd->nd_repstat) {
2017                 vput(vp);
2018                 if (nd->nd_flag & ND_NFSV3)
2019                         nfsrv_postopattr(nd, getret, &at);
2020                 goto out;
2021         }
2022         is_ufs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "ufs") == 0;
2023         rbuf = malloc(siz, M_TEMP, M_WAITOK);
2024 again:
2025         eofflag = 0;
2026         if (cookies) {
2027                 free(cookies, M_TEMP);
2028                 cookies = NULL;
2029         }
2030
2031         iv.iov_base = rbuf;
2032         iv.iov_len = siz;
2033         io.uio_iov = &iv;
2034         io.uio_iovcnt = 1;
2035         io.uio_offset = (off_t)off;
2036         io.uio_resid = siz;
2037         io.uio_segflg = UIO_SYSSPACE;
2038         io.uio_rw = UIO_READ;
2039         io.uio_td = NULL;
2040         nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies,
2041             &cookies);
2042         off = (u_int64_t)io.uio_offset;
2043         if (io.uio_resid)
2044                 siz -= io.uio_resid;
2045
2046         if (!cookies && !nd->nd_repstat)
2047                 nd->nd_repstat = NFSERR_PERM;
2048         if (nd->nd_flag & ND_NFSV3) {
2049                 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2050                 if (!nd->nd_repstat)
2051                         nd->nd_repstat = getret;
2052         }
2053
2054         /*
2055          * Handles the failed cases. nd->nd_repstat == 0 past here.
2056          */
2057         if (nd->nd_repstat) {
2058                 vput(vp);
2059                 free(rbuf, M_TEMP);
2060                 if (cookies)
2061                         free(cookies, M_TEMP);
2062                 if (nd->nd_flag & ND_NFSV3)
2063                         nfsrv_postopattr(nd, getret, &at);
2064                 goto out;
2065         }
2066         /*
2067          * If nothing read, return eof
2068          * rpc reply
2069          */
2070         if (siz == 0) {
2071                 vput(vp);
2072                 if (nd->nd_flag & ND_NFSV2) {
2073                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2074                 } else {
2075                         nfsrv_postopattr(nd, getret, &at);
2076                         NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2077                         txdr_hyper(at.na_filerev, tl);
2078                         tl += 2;
2079                 }
2080                 *tl++ = newnfs_false;
2081                 *tl = newnfs_true;
2082                 free(rbuf, M_TEMP);
2083                 free(cookies, M_TEMP);
2084                 goto out;
2085         }
2086
2087         /*
2088          * Check for degenerate cases of nothing useful read.
2089          * If so go try again
2090          */
2091         cpos = rbuf;
2092         cend = rbuf + siz;
2093         dp = (struct dirent *)cpos;
2094         cookiep = cookies;
2095
2096         /*
2097          * For some reason FreeBSD's ufs_readdir() chooses to back the
2098          * directory offset up to a block boundary, so it is necessary to
2099          * skip over the records that precede the requested offset. This
2100          * requires the assumption that file offset cookies monotonically
2101          * increase.
2102          */
2103         while (cpos < cend && ncookies > 0 &&
2104             (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
2105              (is_ufs == 1 && ((u_quad_t)(*cookiep)) <= toff))) {
2106                 cpos += dp->d_reclen;
2107                 dp = (struct dirent *)cpos;
2108                 cookiep++;
2109                 ncookies--;
2110         }
2111         if (cpos >= cend || ncookies == 0) {
2112                 siz = fullsiz;
2113                 toff = off;
2114                 goto again;
2115         }
2116         vput(vp);
2117
2118         /*
2119          * If cnt > MCLBYTES and the reply will not be saved, use
2120          * ext_pgs mbufs for TLS.
2121          * For NFSv4.0, we do not know for sure if the reply will
2122          * be saved, so do not use ext_pgs mbufs for NFSv4.0.
2123          */
2124         if (cnt > MCLBYTES && siz > MCLBYTES &&
2125             (nd->nd_flag & (ND_TLS | ND_EXTPG | ND_SAVEREPLY)) == ND_TLS &&
2126             (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4)
2127                 nd->nd_flag |= ND_EXTPG;
2128
2129         /*
2130          * dirlen is the size of the reply, including all XDR and must
2131          * not exceed cnt. For NFSv2, RFC1094 didn't clearly indicate
2132          * if the XDR should be included in "count", but to be safe, we do.
2133          * (Include the two booleans at the end of the reply in dirlen now.)
2134          */
2135         if (nd->nd_flag & ND_NFSV3) {
2136                 nfsrv_postopattr(nd, getret, &at);
2137                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2138                 txdr_hyper(at.na_filerev, tl);
2139                 dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED;
2140         } else {
2141                 dirlen = 2 * NFSX_UNSIGNED;
2142         }
2143
2144         /* Loop through the records and build reply */
2145         while (cpos < cend && ncookies > 0) {
2146                 nlen = dp->d_namlen;
2147                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT &&
2148                         nlen <= NFS_MAXNAMLEN) {
2149                         if (nd->nd_flag & ND_NFSV3)
2150                                 dirlen += (6*NFSX_UNSIGNED + NFSM_RNDUP(nlen));
2151                         else
2152                                 dirlen += (4*NFSX_UNSIGNED + NFSM_RNDUP(nlen));
2153                         if (dirlen > cnt) {
2154                                 eofflag = 0;
2155                                 break;
2156                         }
2157
2158                         /*
2159                          * Build the directory record xdr from
2160                          * the dirent entry.
2161                          */
2162                         if (nd->nd_flag & ND_NFSV3) {
2163                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2164                                 *tl++ = newnfs_true;
2165                                 *tl++ = 0;
2166                         } else {
2167                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2168                                 *tl++ = newnfs_true;
2169                         }
2170                         *tl = txdr_unsigned(dp->d_fileno);
2171                         (void) nfsm_strtom(nd, dp->d_name, nlen);
2172                         if (nd->nd_flag & ND_NFSV3) {
2173                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2174                                 *tl++ = 0;
2175                         } else
2176                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2177                         *tl = txdr_unsigned(*cookiep);
2178                 }
2179                 cpos += dp->d_reclen;
2180                 dp = (struct dirent *)cpos;
2181                 cookiep++;
2182                 ncookies--;
2183         }
2184         if (cpos < cend)
2185                 eofflag = 0;
2186         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2187         *tl++ = newnfs_false;
2188         if (eofflag)
2189                 *tl = newnfs_true;
2190         else
2191                 *tl = newnfs_false;
2192         free(rbuf, M_TEMP);
2193         free(cookies, M_TEMP);
2194
2195 out:
2196         NFSEXITCODE2(0, nd);
2197         return (0);
2198 nfsmout:
2199         vput(vp);
2200         NFSEXITCODE2(error, nd);
2201         return (error);
2202 }
2203
2204 /*
2205  * Readdirplus for V3 and Readdir for V4.
2206  */
2207 int
2208 nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
2209     struct vnode *vp, struct nfsexstuff *exp)
2210 {
2211         struct dirent *dp;
2212         u_int32_t *tl;
2213         int dirlen;
2214         char *cpos, *cend, *rbuf;
2215         struct vnode *nvp;
2216         fhandle_t nfh;
2217         struct nfsvattr nva, at, *nvap = &nva;
2218         struct mbuf *mb0, *mb1;
2219         struct nfsreferral *refp;
2220         int nlen, r, error = 0, getret = 1, usevget = 1;
2221         int siz, cnt, fullsiz, eofflag, ncookies, entrycnt;
2222         caddr_t bpos0, bpos1;
2223         u_int64_t off, toff, verf;
2224         u_long *cookies = NULL, *cookiep;
2225         nfsattrbit_t attrbits, rderrbits, savbits;
2226         struct uio io;
2227         struct iovec iv;
2228         struct componentname cn;
2229         int at_root, is_ufs, is_zfs, needs_unbusy, supports_nfsv4acls;
2230         struct mount *mp, *new_mp;
2231         uint64_t mounted_on_fileno;
2232         struct thread *p = curthread;
2233         int bextpg0, bextpg1, bextpgsiz0, bextpgsiz1;
2234
2235         if (nd->nd_repstat) {
2236                 nfsrv_postopattr(nd, getret, &at);
2237                 goto out;
2238         }
2239         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2240         off = fxdr_hyper(tl);
2241         toff = off;
2242         tl += 2;
2243         verf = fxdr_hyper(tl);
2244         tl += 2;
2245         siz = fxdr_unsigned(int, *tl++);
2246         cnt = fxdr_unsigned(int, *tl);
2247
2248         /*
2249          * Use the server's maximum data transfer size as the upper bound
2250          * on reply datalen.
2251          */
2252         if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0)
2253                 cnt = NFS_SRVMAXDATA(nd);
2254
2255         /*
2256          * siz is a "hint" of how much directory information (name, fileid,
2257          * cookie) should be in the reply. At least one client "hints" 0,
2258          * so I set it to cnt for that case. I also round it up to the
2259          * next multiple of DIRBLKSIZ.
2260          * Since the size of a Readdirplus directory entry reply will always
2261          * be greater than a directory entry returned by VOP_READDIR(), it
2262          * does not make sense to read more than NFS_SRVMAXDATA() via
2263          * VOP_READDIR().
2264          */
2265         if (siz <= 0)
2266                 siz = cnt;
2267         else if (siz > NFS_SRVMAXDATA(nd))
2268                 siz = NFS_SRVMAXDATA(nd);
2269         siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2270
2271         if (nd->nd_flag & ND_NFSV4) {
2272                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2273                 if (error)
2274                         goto nfsmout;
2275                 NFSSET_ATTRBIT(&savbits, &attrbits);
2276                 NFSCLRNOTFILLABLE_ATTRBIT(&attrbits, nd);
2277                 NFSZERO_ATTRBIT(&rderrbits);
2278                 NFSSETBIT_ATTRBIT(&rderrbits, NFSATTRBIT_RDATTRERROR);
2279         } else {
2280                 NFSZERO_ATTRBIT(&attrbits);
2281         }
2282         fullsiz = siz;
2283         nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2284 #if 0
2285         if (!nd->nd_repstat) {
2286             if (off && verf != at.na_filerev) {
2287                 /*
2288                  * va_filerev is not sufficient as a cookie verifier,
2289                  * since it is not supposed to change when entries are
2290                  * removed/added unless that offset cookies returned to
2291                  * the client are no longer valid.
2292                  */
2293                 if (nd->nd_flag & ND_NFSV4) {
2294                         nd->nd_repstat = NFSERR_NOTSAME;
2295                 } else {
2296                         nd->nd_repstat = NFSERR_BAD_COOKIE;
2297                 }
2298             }
2299         }
2300 #endif
2301         if (!nd->nd_repstat && vp->v_type != VDIR)
2302                 nd->nd_repstat = NFSERR_NOTDIR;
2303         if (!nd->nd_repstat && cnt == 0)
2304                 nd->nd_repstat = NFSERR_TOOSMALL;
2305         if (!nd->nd_repstat)
2306                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2307                     nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
2308                     NFSACCCHK_VPISLOCKED, NULL);
2309         if (nd->nd_repstat) {
2310                 vput(vp);
2311                 if (nd->nd_flag & ND_NFSV3)
2312                         nfsrv_postopattr(nd, getret, &at);
2313                 goto out;
2314         }
2315         is_ufs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "ufs") == 0;
2316         is_zfs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "zfs") == 0;
2317
2318         rbuf = malloc(siz, M_TEMP, M_WAITOK);
2319 again:
2320         eofflag = 0;
2321         if (cookies) {
2322                 free(cookies, M_TEMP);
2323                 cookies = NULL;
2324         }
2325
2326         iv.iov_base = rbuf;
2327         iv.iov_len = siz;
2328         io.uio_iov = &iv;
2329         io.uio_iovcnt = 1;
2330         io.uio_offset = (off_t)off;
2331         io.uio_resid = siz;
2332         io.uio_segflg = UIO_SYSSPACE;
2333         io.uio_rw = UIO_READ;
2334         io.uio_td = NULL;
2335         nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies,
2336             &cookies);
2337         off = (u_int64_t)io.uio_offset;
2338         if (io.uio_resid)
2339                 siz -= io.uio_resid;
2340
2341         getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2342
2343         if (!cookies && !nd->nd_repstat)
2344                 nd->nd_repstat = NFSERR_PERM;
2345         if (!nd->nd_repstat)
2346                 nd->nd_repstat = getret;
2347         if (nd->nd_repstat) {
2348                 vput(vp);
2349                 if (cookies)
2350                         free(cookies, M_TEMP);
2351                 free(rbuf, M_TEMP);
2352                 if (nd->nd_flag & ND_NFSV3)
2353                         nfsrv_postopattr(nd, getret, &at);
2354                 goto out;
2355         }
2356         /*
2357          * If nothing read, return eof
2358          * rpc reply
2359          */
2360         if (siz == 0) {
2361                 vput(vp);
2362                 if (nd->nd_flag & ND_NFSV3)
2363                         nfsrv_postopattr(nd, getret, &at);
2364                 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2365                 txdr_hyper(at.na_filerev, tl);
2366                 tl += 2;
2367                 *tl++ = newnfs_false;
2368                 *tl = newnfs_true;
2369                 free(cookies, M_TEMP);
2370                 free(rbuf, M_TEMP);
2371                 goto out;
2372         }
2373
2374         /*
2375          * Check for degenerate cases of nothing useful read.
2376          * If so go try again
2377          */
2378         cpos = rbuf;
2379         cend = rbuf + siz;
2380         dp = (struct dirent *)cpos;
2381         cookiep = cookies;
2382
2383         /*
2384          * For some reason FreeBSD's ufs_readdir() chooses to back the
2385          * directory offset up to a block boundary, so it is necessary to
2386          * skip over the records that precede the requested offset. This
2387          * requires the assumption that file offset cookies monotonically
2388          * increase.
2389          */
2390         while (cpos < cend && ncookies > 0 &&
2391           (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
2392            (is_ufs == 1 && ((u_quad_t)(*cookiep)) <= toff) ||
2393            ((nd->nd_flag & ND_NFSV4) &&
2394             ((dp->d_namlen == 1 && dp->d_name[0] == '.') ||
2395              (dp->d_namlen==2 && dp->d_name[0]=='.' && dp->d_name[1]=='.'))))) {
2396                 cpos += dp->d_reclen;
2397                 dp = (struct dirent *)cpos;
2398                 cookiep++;
2399                 ncookies--;
2400         }
2401         if (cpos >= cend || ncookies == 0) {
2402                 siz = fullsiz;
2403                 toff = off;
2404                 goto again;
2405         }
2406
2407         /*
2408          * Busy the file system so that the mount point won't go away
2409          * and, as such, VFS_VGET() can be used safely.
2410          */
2411         mp = vp->v_mount;
2412         vfs_ref(mp);
2413         NFSVOPUNLOCK(vp);
2414         nd->nd_repstat = vfs_busy(mp, 0);
2415         vfs_rel(mp);
2416         if (nd->nd_repstat != 0) {
2417                 vrele(vp);
2418                 free(cookies, M_TEMP);
2419                 free(rbuf, M_TEMP);
2420                 if (nd->nd_flag & ND_NFSV3)
2421                         nfsrv_postopattr(nd, getret, &at);
2422                 goto out;
2423         }
2424
2425         /*
2426          * Check to see if entries in this directory can be safely acquired
2427          * via VFS_VGET() or if a switch to VOP_LOOKUP() is required.
2428          * ZFS snapshot directories need VOP_LOOKUP(), so that any
2429          * automount of the snapshot directory that is required will
2430          * be done.
2431          * This needs to be done here for NFSv4, since NFSv4 never does
2432          * a VFS_VGET() for "." or "..".
2433          */
2434         if (is_zfs == 1) {
2435                 r = VFS_VGET(mp, at.na_fileid, LK_SHARED, &nvp);
2436                 if (r == EOPNOTSUPP) {
2437                         usevget = 0;
2438                         cn.cn_nameiop = LOOKUP;
2439                         cn.cn_lkflags = LK_SHARED | LK_RETRY;
2440                         cn.cn_cred = nd->nd_cred;
2441                         cn.cn_thread = p;
2442                 } else if (r == 0)
2443                         vput(nvp);
2444         }
2445
2446         /*
2447          * If the reply is likely to exceed MCLBYTES and the reply will
2448          * not be saved, use ext_pgs mbufs for TLS.
2449          * It is difficult to predict how large each entry will be and
2450          * how many entries have been read, so just assume the directory
2451          * entries grow by a factor of 4 when attributes are included.
2452          * For NFSv4.0, we do not know for sure if the reply will
2453          * be saved, so do not use ext_pgs mbufs for NFSv4.0.
2454          */
2455         if (cnt > MCLBYTES && siz > MCLBYTES / 4 &&
2456             (nd->nd_flag & (ND_TLS | ND_EXTPG | ND_SAVEREPLY)) == ND_TLS &&
2457             (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4)
2458                 nd->nd_flag |= ND_EXTPG;
2459
2460         /*
2461          * Save this position, in case there is an error before one entry
2462          * is created.
2463          */
2464         mb0 = nd->nd_mb;
2465         bpos0 = nd->nd_bpos;
2466         bextpg0 = nd->nd_bextpg;
2467         bextpgsiz0 = nd->nd_bextpgsiz;
2468
2469         /*
2470          * Fill in the first part of the reply.
2471          * dirlen is the reply length in bytes and cannot exceed cnt.
2472          * (Include the two booleans at the end of the reply in dirlen now,
2473          *  so we recognize when we have exceeded cnt.)
2474          */
2475         if (nd->nd_flag & ND_NFSV3) {
2476                 dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED;
2477                 nfsrv_postopattr(nd, getret, &at);
2478         } else {
2479                 dirlen = NFSX_VERF + 2 * NFSX_UNSIGNED;
2480         }
2481         NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2482         txdr_hyper(at.na_filerev, tl);
2483
2484         /*
2485          * Save this position, in case there is an empty reply needed.
2486          */
2487         mb1 = nd->nd_mb;
2488         bpos1 = nd->nd_bpos;
2489         bextpg1 = nd->nd_bextpg;
2490         bextpgsiz1 = nd->nd_bextpgsiz;
2491
2492         /* Loop through the records and build reply */
2493         entrycnt = 0;
2494         while (cpos < cend && ncookies > 0 && dirlen < cnt) {
2495                 nlen = dp->d_namlen;
2496                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT &&
2497                     nlen <= NFS_MAXNAMLEN &&
2498                     ((nd->nd_flag & ND_NFSV3) || nlen > 2 ||
2499                      (nlen==2 && (dp->d_name[0]!='.' || dp->d_name[1]!='.'))
2500                       || (nlen == 1 && dp->d_name[0] != '.'))) {
2501                         /*
2502                          * Save the current position in the reply, in case
2503                          * this entry exceeds cnt.
2504                          */
2505                         mb1 = nd->nd_mb;
2506                         bpos1 = nd->nd_bpos;
2507                         bextpg1 = nd->nd_bextpg;
2508                         bextpgsiz1 = nd->nd_bextpgsiz;
2509
2510                         /*
2511                          * For readdir_and_lookup get the vnode using
2512                          * the file number.
2513                          */
2514                         nvp = NULL;
2515                         refp = NULL;
2516                         r = 0;
2517                         at_root = 0;
2518                         needs_unbusy = 0;
2519                         new_mp = mp;
2520                         mounted_on_fileno = (uint64_t)dp->d_fileno;
2521                         if ((nd->nd_flag & ND_NFSV3) ||
2522                             NFSNONZERO_ATTRBIT(&savbits)) {
2523                                 if (nd->nd_flag & ND_NFSV4)
2524                                         refp = nfsv4root_getreferral(NULL,
2525                                             vp, dp->d_fileno);
2526                                 if (refp == NULL) {
2527                                         if (usevget)
2528                                                 r = VFS_VGET(mp, dp->d_fileno,
2529                                                     LK_SHARED, &nvp);
2530                                         else
2531                                                 r = EOPNOTSUPP;
2532                                         if (r == EOPNOTSUPP) {
2533                                                 if (usevget) {
2534                                                         usevget = 0;
2535                                                         cn.cn_nameiop = LOOKUP;
2536                                                         cn.cn_lkflags =
2537                                                             LK_SHARED |
2538                                                             LK_RETRY;
2539                                                         cn.cn_cred =
2540                                                             nd->nd_cred;
2541                                                         cn.cn_thread = p;
2542                                                 }
2543                                                 cn.cn_nameptr = dp->d_name;
2544                                                 cn.cn_namelen = nlen;
2545                                                 cn.cn_flags = ISLASTCN |
2546                                                     NOFOLLOW | LOCKLEAF;
2547                                                 if (nlen == 2 &&
2548                                                     dp->d_name[0] == '.' &&
2549                                                     dp->d_name[1] == '.')
2550                                                         cn.cn_flags |=
2551                                                             ISDOTDOT;
2552                                                 if (NFSVOPLOCK(vp, LK_SHARED)
2553                                                     != 0) {
2554                                                         nd->nd_repstat = EPERM;
2555                                                         break;
2556                                                 }
2557                                                 if ((vp->v_vflag & VV_ROOT) != 0
2558                                                     && (cn.cn_flags & ISDOTDOT)
2559                                                     != 0) {
2560                                                         vref(vp);
2561                                                         nvp = vp;
2562                                                         r = 0;
2563                                                 } else {
2564                                                         r = VOP_LOOKUP(vp, &nvp,
2565                                                             &cn);
2566                                                         if (vp != nvp)
2567                                                                 NFSVOPUNLOCK(vp);
2568                                                 }
2569                                         }
2570
2571                                         /*
2572                                          * For NFSv4, check to see if nvp is
2573                                          * a mount point and get the mount
2574                                          * point vnode, as required.
2575                                          */
2576                                         if (r == 0 &&
2577                                             nfsrv_enable_crossmntpt != 0 &&
2578                                             (nd->nd_flag & ND_NFSV4) != 0 &&
2579                                             nvp->v_type == VDIR &&
2580                                             nvp->v_mountedhere != NULL) {
2581                                                 new_mp = nvp->v_mountedhere;
2582                                                 r = vfs_busy(new_mp, 0);
2583                                                 vput(nvp);
2584                                                 nvp = NULL;
2585                                                 if (r == 0) {
2586                                                         r = VFS_ROOT(new_mp,
2587                                                             LK_SHARED, &nvp);
2588                                                         needs_unbusy = 1;
2589                                                         if (r == 0)
2590                                                                 at_root = 1;
2591                                                 }
2592                                         }
2593                                 }
2594
2595                                 /*
2596                                  * If we failed to look up the entry, then it
2597                                  * has become invalid, most likely removed.
2598                                  */
2599                                 if (r != 0) {
2600                                         if (needs_unbusy)
2601                                                 vfs_unbusy(new_mp);
2602                                         goto invalid;
2603                                 }
2604                                 KASSERT(refp != NULL || nvp != NULL,
2605                                     ("%s: undetected lookup error", __func__));
2606
2607                                 if (refp == NULL &&
2608                                     ((nd->nd_flag & ND_NFSV3) ||
2609                                      NFSNONZERO_ATTRBIT(&attrbits))) {
2610                                         r = nfsvno_getfh(nvp, &nfh, p);
2611                                         if (!r)
2612                                             r = nfsvno_getattr(nvp, nvap, nd, p,
2613                                                 1, &attrbits);
2614                                         if (r == 0 && is_zfs == 1 &&
2615                                             nfsrv_enable_crossmntpt != 0 &&
2616                                             (nd->nd_flag & ND_NFSV4) != 0 &&
2617                                             nvp->v_type == VDIR &&
2618                                             vp->v_mount != nvp->v_mount) {
2619                                             /*
2620                                              * For a ZFS snapshot, there is a
2621                                              * pseudo mount that does not set
2622                                              * v_mountedhere, so it needs to
2623                                              * be detected via a different
2624                                              * mount structure.
2625                                              */
2626                                             at_root = 1;
2627                                             if (new_mp == mp)
2628                                                 new_mp = nvp->v_mount;
2629                                         }
2630                                 }
2631
2632                                 /*
2633                                  * If we failed to get attributes of the entry,
2634                                  * then just skip it for NFSv3 (the traditional
2635                                  * behavior in the old NFS server).
2636                                  * For NFSv4 the behavior is controlled by
2637                                  * RDATTRERROR: we either ignore the error or
2638                                  * fail the request.
2639                                  * Note that RDATTRERROR is never set for NFSv3.
2640                                  */
2641                                 if (r != 0) {
2642                                         if (!NFSISSET_ATTRBIT(&attrbits,
2643                                             NFSATTRBIT_RDATTRERROR)) {
2644                                                 vput(nvp);
2645                                                 if (needs_unbusy != 0)
2646                                                         vfs_unbusy(new_mp);
2647                                                 if ((nd->nd_flag & ND_NFSV3))
2648                                                         goto invalid;
2649                                                 nd->nd_repstat = r;
2650                                                 break;
2651                                         }
2652                                 }
2653                         }
2654
2655                         /*
2656                          * Build the directory record xdr
2657                          */
2658                         if (nd->nd_flag & ND_NFSV3) {
2659                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2660                                 *tl++ = newnfs_true;
2661                                 *tl++ = 0;
2662                                 *tl = txdr_unsigned(dp->d_fileno);
2663                                 dirlen += nfsm_strtom(nd, dp->d_name, nlen);
2664                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2665                                 *tl++ = 0;
2666                                 *tl = txdr_unsigned(*cookiep);
2667                                 nfsrv_postopattr(nd, 0, nvap);
2668                                 dirlen += nfsm_fhtom(nd,(u_int8_t *)&nfh,0,1);
2669                                 dirlen += (5*NFSX_UNSIGNED+NFSX_V3POSTOPATTR);
2670                                 if (nvp != NULL)
2671                                         vput(nvp);
2672                         } else {
2673                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2674                                 *tl++ = newnfs_true;
2675                                 *tl++ = 0;
2676                                 *tl = txdr_unsigned(*cookiep);
2677                                 dirlen += nfsm_strtom(nd, dp->d_name, nlen);
2678                                 if (nvp != NULL) {
2679                                         supports_nfsv4acls =
2680                                             nfs_supportsnfsv4acls(nvp);
2681                                         NFSVOPUNLOCK(nvp);
2682                                 } else
2683                                         supports_nfsv4acls = 0;
2684                                 if (refp != NULL) {
2685                                         dirlen += nfsrv_putreferralattr(nd,
2686                                             &savbits, refp, 0,
2687                                             &nd->nd_repstat);
2688                                         if (nd->nd_repstat) {
2689                                                 if (nvp != NULL)
2690                                                         vrele(nvp);
2691                                                 if (needs_unbusy != 0)
2692                                                         vfs_unbusy(new_mp);
2693                                                 break;
2694                                         }
2695                                 } else if (r) {
2696                                         dirlen += nfsvno_fillattr(nd, new_mp,
2697                                             nvp, nvap, &nfh, r, &rderrbits,
2698                                             nd->nd_cred, p, isdgram, 0,
2699                                             supports_nfsv4acls, at_root,
2700                                             mounted_on_fileno);
2701                                 } else {
2702                                         dirlen += nfsvno_fillattr(nd, new_mp,
2703                                             nvp, nvap, &nfh, r, &attrbits,
2704                                             nd->nd_cred, p, isdgram, 0,
2705                                             supports_nfsv4acls, at_root,
2706                                             mounted_on_fileno);
2707                                 }
2708                                 if (nvp != NULL)
2709                                         vrele(nvp);
2710                                 dirlen += (3 * NFSX_UNSIGNED);
2711                         }
2712                         if (needs_unbusy != 0)
2713                                 vfs_unbusy(new_mp);
2714                         if (dirlen <= cnt)
2715                                 entrycnt++;
2716                 }
2717 invalid:
2718                 cpos += dp->d_reclen;
2719                 dp = (struct dirent *)cpos;
2720                 cookiep++;
2721                 ncookies--;
2722         }
2723         vrele(vp);
2724         vfs_unbusy(mp);
2725
2726         /*
2727          * If dirlen > cnt, we must strip off the last entry. If that
2728          * results in an empty reply, report NFSERR_TOOSMALL.
2729          */
2730         if (dirlen > cnt || nd->nd_repstat) {
2731                 if (!nd->nd_repstat && entrycnt == 0)
2732                         nd->nd_repstat = NFSERR_TOOSMALL;
2733                 if (nd->nd_repstat) {
2734                         nfsm_trimtrailing(nd, mb0, bpos0, bextpg0, bextpgsiz0);
2735                         if (nd->nd_flag & ND_NFSV3)
2736                                 nfsrv_postopattr(nd, getret, &at);
2737                 } else
2738                         nfsm_trimtrailing(nd, mb1, bpos1, bextpg1, bextpgsiz1);
2739                 eofflag = 0;
2740         } else if (cpos < cend)
2741                 eofflag = 0;
2742         if (!nd->nd_repstat) {
2743                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2744                 *tl++ = newnfs_false;
2745                 if (eofflag)
2746                         *tl = newnfs_true;
2747                 else
2748                         *tl = newnfs_false;
2749         }
2750         free(cookies, M_TEMP);
2751         free(rbuf, M_TEMP);
2752
2753 out:
2754         NFSEXITCODE2(0, nd);
2755         return (0);
2756 nfsmout:
2757         vput(vp);
2758         NFSEXITCODE2(error, nd);
2759         return (error);
2760 }
2761
2762 /*
2763  * Get the settable attributes out of the mbuf list.
2764  * (Return 0 or EBADRPC)
2765  */
2766 int
2767 nfsrv_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
2768     nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p)
2769 {
2770         u_int32_t *tl;
2771         struct nfsv2_sattr *sp;
2772         int error = 0, toclient = 0;
2773
2774         switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
2775         case ND_NFSV2:
2776                 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2777                 /*
2778                  * Some old clients didn't fill in the high order 16bits.
2779                  * --> check the low order 2 bytes for 0xffff
2780                  */
2781                 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
2782                         nvap->na_mode = nfstov_mode(sp->sa_mode);
2783                 if (sp->sa_uid != newnfs_xdrneg1)
2784                         nvap->na_uid = fxdr_unsigned(uid_t, sp->sa_uid);
2785                 if (sp->sa_gid != newnfs_xdrneg1)
2786                         nvap->na_gid = fxdr_unsigned(gid_t, sp->sa_gid);
2787                 if (sp->sa_size != newnfs_xdrneg1)
2788                         nvap->na_size = fxdr_unsigned(u_quad_t, sp->sa_size);
2789                 if (sp->sa_atime.nfsv2_sec != newnfs_xdrneg1) {
2790 #ifdef notyet
2791                         fxdr_nfsv2time(&sp->sa_atime, &nvap->na_atime);
2792 #else
2793                         nvap->na_atime.tv_sec =
2794                                 fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec);
2795                         nvap->na_atime.tv_nsec = 0;
2796 #endif
2797                 }
2798                 if (sp->sa_mtime.nfsv2_sec != newnfs_xdrneg1)
2799                         fxdr_nfsv2time(&sp->sa_mtime, &nvap->na_mtime);
2800                 break;
2801         case ND_NFSV3:
2802                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2803                 if (*tl == newnfs_true) {
2804                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2805                         nvap->na_mode = nfstov_mode(*tl);
2806                 }
2807                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2808                 if (*tl == newnfs_true) {
2809                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2810                         nvap->na_uid = fxdr_unsigned(uid_t, *tl);
2811                 }
2812                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2813                 if (*tl == newnfs_true) {
2814                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2815                         nvap->na_gid = fxdr_unsigned(gid_t, *tl);
2816                 }
2817                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2818                 if (*tl == newnfs_true) {
2819                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2820                         nvap->na_size = fxdr_hyper(tl);
2821                 }
2822                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2823                 switch (fxdr_unsigned(int, *tl)) {
2824                 case NFSV3SATTRTIME_TOCLIENT:
2825                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2826                         fxdr_nfsv3time(tl, &nvap->na_atime);
2827                         toclient = 1;
2828                         break;
2829                 case NFSV3SATTRTIME_TOSERVER:
2830                         vfs_timestamp(&nvap->na_atime);
2831                         nvap->na_vaflags |= VA_UTIMES_NULL;
2832                         break;
2833                 }
2834                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2835                 switch (fxdr_unsigned(int, *tl)) {
2836                 case NFSV3SATTRTIME_TOCLIENT:
2837                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2838                         fxdr_nfsv3time(tl, &nvap->na_mtime);
2839                         nvap->na_vaflags &= ~VA_UTIMES_NULL;
2840                         break;
2841                 case NFSV3SATTRTIME_TOSERVER:
2842                         vfs_timestamp(&nvap->na_mtime);
2843                         if (!toclient)
2844                                 nvap->na_vaflags |= VA_UTIMES_NULL;
2845                         break;
2846                 }
2847                 break;
2848         case ND_NFSV4:
2849                 error = nfsv4_sattr(nd, vp, nvap, attrbitp, aclp, p);
2850         }
2851 nfsmout:
2852         NFSEXITCODE2(error, nd);
2853         return (error);
2854 }
2855
2856 /*
2857  * Handle the setable attributes for V4.
2858  * Returns NFSERR_BADXDR if it can't be parsed, 0 otherwise.
2859  */
2860 int
2861 nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
2862     nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p)
2863 {
2864         u_int32_t *tl;
2865         int attrsum = 0;
2866         int i, j;
2867         int error, attrsize, bitpos, aclsize, aceerr, retnotsup = 0;
2868         int moderet, toclient = 0;
2869         u_char *cp, namestr[NFSV4_SMALLSTR + 1];
2870         uid_t uid;
2871         gid_t gid;
2872         u_short mode, mask;             /* Same type as va_mode. */
2873         struct vattr va;
2874
2875         error = nfsrv_getattrbits(nd, attrbitp, NULL, &retnotsup);
2876         if (error)
2877                 goto nfsmout;
2878         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2879         attrsize = fxdr_unsigned(int, *tl);
2880
2881         /*
2882          * Loop around getting the setable attributes. If an unsupported
2883          * one is found, set nd_repstat == NFSERR_ATTRNOTSUPP and return.
2884          */
2885         if (retnotsup) {
2886                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
2887                 bitpos = NFSATTRBIT_MAX;
2888         } else {
2889                 bitpos = 0;
2890         }
2891         moderet = 0;
2892         for (; bitpos < NFSATTRBIT_MAX; bitpos++) {
2893             if (attrsum > attrsize) {
2894                 error = NFSERR_BADXDR;
2895                 goto nfsmout;
2896             }
2897             if (NFSISSET_ATTRBIT(attrbitp, bitpos))
2898                 switch (bitpos) {
2899                 case NFSATTRBIT_SIZE:
2900                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2901                      if (vp != NULL && vp->v_type != VREG) {
2902                             error = (vp->v_type == VDIR) ? NFSERR_ISDIR :
2903                                 NFSERR_INVAL;
2904                             goto nfsmout;
2905                         }
2906                         nvap->na_size = fxdr_hyper(tl);
2907                         attrsum += NFSX_HYPER;
2908                         break;
2909                 case NFSATTRBIT_ACL:
2910                         error = nfsrv_dissectacl(nd, aclp, &aceerr, &aclsize,
2911                             p);
2912                         if (error)
2913                                 goto nfsmout;
2914                         if (aceerr && !nd->nd_repstat)
2915                                 nd->nd_repstat = aceerr;
2916                         attrsum += aclsize;
2917                         break;
2918                 case NFSATTRBIT_ARCHIVE:
2919                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2920                         if (!nd->nd_repstat)
2921                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
2922                         attrsum += NFSX_UNSIGNED;
2923                         break;
2924                 case NFSATTRBIT_HIDDEN:
2925                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2926                         if (!nd->nd_repstat)
2927                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
2928                         attrsum += NFSX_UNSIGNED;
2929                         break;
2930                 case NFSATTRBIT_MIMETYPE:
2931                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2932                         i = fxdr_unsigned(int, *tl);
2933                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
2934                         if (error)
2935                                 goto nfsmout;
2936                         if (!nd->nd_repstat)
2937                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
2938                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
2939                         break;
2940                 case NFSATTRBIT_MODE:
2941                         moderet = NFSERR_INVAL; /* Can't do MODESETMASKED. */
2942                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2943                         nvap->na_mode = nfstov_mode(*tl);
2944                         attrsum += NFSX_UNSIGNED;
2945                         break;
2946                 case NFSATTRBIT_OWNER:
2947                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2948                         j = fxdr_unsigned(int, *tl);
2949                         if (j < 0) {
2950                                 error = NFSERR_BADXDR;
2951                                 goto nfsmout;
2952                         }
2953                         if (j > NFSV4_SMALLSTR)
2954                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
2955                         else
2956                                 cp = namestr;
2957                         error = nfsrv_mtostr(nd, cp, j);
2958                         if (error) {
2959                                 if (j > NFSV4_SMALLSTR)
2960                                         free(cp, M_NFSSTRING);
2961                                 goto nfsmout;
2962                         }
2963                         if (!nd->nd_repstat) {
2964                                 nd->nd_repstat = nfsv4_strtouid(nd, cp, j,
2965                                     &uid);
2966                                 if (!nd->nd_repstat)
2967                                         nvap->na_uid = uid;
2968                         }
2969                         if (j > NFSV4_SMALLSTR)
2970                                 free(cp, M_NFSSTRING);
2971                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
2972                         break;
2973                 case NFSATTRBIT_OWNERGROUP:
2974                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2975                         j = fxdr_unsigned(int, *tl);
2976                         if (j < 0) {
2977                                 error = NFSERR_BADXDR;
2978                                 goto nfsmout;
2979                         }
2980                         if (j > NFSV4_SMALLSTR)
2981                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
2982                         else
2983                                 cp = namestr;
2984                         error = nfsrv_mtostr(nd, cp, j);
2985                         if (error) {
2986                                 if (j > NFSV4_SMALLSTR)
2987                                         free(cp, M_NFSSTRING);
2988                                 goto nfsmout;
2989                         }
2990                         if (!nd->nd_repstat) {
2991                                 nd->nd_repstat = nfsv4_strtogid(nd, cp, j,
2992                                     &gid);
2993                                 if (!nd->nd_repstat)
2994                                         nvap->na_gid = gid;
2995                         }
2996                         if (j > NFSV4_SMALLSTR)
2997                                 free(cp, M_NFSSTRING);
2998                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
2999                         break;
3000                 case NFSATTRBIT_SYSTEM:
3001                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3002                         if (!nd->nd_repstat)
3003                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
3004                         attrsum += NFSX_UNSIGNED;
3005                         break;
3006                 case NFSATTRBIT_TIMEACCESSSET:
3007                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3008                         attrsum += NFSX_UNSIGNED;
3009                         if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) {
3010                             NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
3011                             fxdr_nfsv4time(tl, &nvap->na_atime);
3012                             toclient = 1;
3013                             attrsum += NFSX_V4TIME;
3014                         } else {
3015                             vfs_timestamp(&nvap->na_atime);
3016                             nvap->na_vaflags |= VA_UTIMES_NULL;
3017                         }
3018                         break;
3019                 case NFSATTRBIT_TIMEBACKUP:
3020                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
3021                         if (!nd->nd_repstat)
3022                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
3023                         attrsum += NFSX_V4TIME;
3024                         break;
3025                 case NFSATTRBIT_TIMECREATE:
3026                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
3027                         fxdr_nfsv4time(tl, &nvap->na_btime);
3028                         attrsum += NFSX_V4TIME;
3029                         break;
3030                 case NFSATTRBIT_TIMEMODIFYSET:
3031                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3032                         attrsum += NFSX_UNSIGNED;
3033                         if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) {
3034                             NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
3035                             fxdr_nfsv4time(tl, &nvap->na_mtime);
3036                             nvap->na_vaflags &= ~VA_UTIMES_NULL;
3037                             attrsum += NFSX_V4TIME;
3038                         } else {
3039                             vfs_timestamp(&nvap->na_mtime);
3040                             if (!toclient)
3041                                 nvap->na_vaflags |= VA_UTIMES_NULL;
3042                         }
3043                         break;
3044                 case NFSATTRBIT_MODESETMASKED:
3045                         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3046                         mode = fxdr_unsigned(u_short, *tl++);
3047                         mask = fxdr_unsigned(u_short, *tl);
3048                         /*
3049                          * vp == NULL implies an Open/Create operation.
3050                          * This attribute can only be used for Setattr and
3051                          * only for NFSv4.1 or higher.
3052                          * If moderet != 0, a mode attribute has also been
3053                          * specified and this attribute cannot be done in the
3054                          * same Setattr operation.
3055                          */
3056                         if ((nd->nd_flag & ND_NFSV41) == 0)
3057                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
3058                         else if ((mode & ~07777) != 0 || (mask & ~07777) != 0 ||
3059                             vp == NULL)
3060                                 nd->nd_repstat = NFSERR_INVAL;
3061                         else if (moderet == 0)
3062                                 moderet = VOP_GETATTR(vp, &va, nd->nd_cred);
3063                         if (moderet == 0)
3064                                 nvap->na_mode = (mode & mask) |
3065                                     (va.va_mode & ~mask);
3066                         else
3067                                 nd->nd_repstat = moderet;
3068                         attrsum += 2 * NFSX_UNSIGNED;
3069                         break;
3070                 default:
3071                         nd->nd_repstat = NFSERR_ATTRNOTSUPP;
3072                         /*
3073                          * set bitpos so we drop out of the loop.
3074                          */
3075                         bitpos = NFSATTRBIT_MAX;
3076                         break;
3077                 }
3078         }
3079
3080         /*
3081          * some clients pad the attrlist, so we need to skip over the
3082          * padding.
3083          */
3084         if (attrsum > attrsize) {
3085                 error = NFSERR_BADXDR;
3086         } else {
3087                 attrsize = NFSM_RNDUP(attrsize);
3088                 if (attrsum < attrsize)
3089                         error = nfsm_advance(nd, attrsize - attrsum, -1);
3090         }
3091 nfsmout:
3092         NFSEXITCODE2(error, nd);
3093         return (error);
3094 }
3095
3096 /*
3097  * Check/setup export credentials.
3098  */
3099 int
3100 nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp,
3101     struct ucred *credanon)
3102 {
3103         int error = 0;
3104
3105         /*
3106          * Check/setup credentials.
3107          */
3108         if (nd->nd_flag & ND_GSS)
3109                 exp->nes_exflag &= ~MNT_EXPORTANON;
3110
3111         /*
3112          * Check to see if the operation is allowed for this security flavor.
3113          * RFC2623 suggests that the NFSv3 Fsinfo RPC be allowed to
3114          * AUTH_NONE or AUTH_SYS for file systems requiring RPCSEC_GSS.
3115          * Also, allow Secinfo, so that it can acquire the correct flavor(s).
3116          */
3117         if (nfsvno_testexp(nd, exp) &&
3118             nd->nd_procnum != NFSV4OP_SECINFO &&
3119             nd->nd_procnum != NFSPROC_FSINFO) {
3120                 if (nd->nd_flag & ND_NFSV4)
3121                         error = NFSERR_WRONGSEC;
3122                 else
3123                         error = (NFSERR_AUTHERR | AUTH_TOOWEAK);
3124                 goto out;
3125         }
3126
3127         /*
3128          * Check to see if the file system is exported V4 only.
3129          */
3130         if (NFSVNO_EXV4ONLY(exp) && !(nd->nd_flag & ND_NFSV4)) {
3131                 error = NFSERR_PROGNOTV4;
3132                 goto out;
3133         }
3134
3135         /*
3136          * Now, map the user credentials.
3137          * (Note that ND_AUTHNONE will only be set for an NFSv3
3138          *  Fsinfo RPC. If set for anything else, this code might need
3139          *  to change.)
3140          */
3141         if (NFSVNO_EXPORTED(exp)) {
3142                 if (((nd->nd_flag & ND_GSS) == 0 && nd->nd_cred->cr_uid == 0) ||
3143                      NFSVNO_EXPORTANON(exp) ||
3144                      (nd->nd_flag & ND_AUTHNONE) != 0) {
3145                         nd->nd_cred->cr_uid = credanon->cr_uid;
3146                         nd->nd_cred->cr_gid = credanon->cr_gid;
3147                         crsetgroups(nd->nd_cred, credanon->cr_ngroups,
3148                             credanon->cr_groups);
3149                 } else if ((nd->nd_flag & ND_GSS) == 0) {
3150                         /*
3151                          * If using AUTH_SYS, call nfsrv_getgrpscred() to see
3152                          * if there is a replacement credential with a group
3153                          * list set up by "nfsuserd -manage-gids".
3154                          * If there is no replacement, nfsrv_getgrpscred()
3155                          * simply returns its argument.
3156                          */
3157                         nd->nd_cred = nfsrv_getgrpscred(nd->nd_cred);
3158                 }
3159         }
3160
3161 out:
3162         NFSEXITCODE2(error, nd);
3163         return (error);
3164 }
3165
3166 /*
3167  * Check exports.
3168  */
3169 int
3170 nfsvno_checkexp(struct mount *mp, struct sockaddr *nam, struct nfsexstuff *exp,
3171     struct ucred **credp)
3172 {
3173         int error;
3174
3175         error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp,
3176             &exp->nes_numsecflavor, exp->nes_secflavors);
3177         if (error) {
3178                 if (nfs_rootfhset) {
3179                         exp->nes_exflag = 0;
3180                         exp->nes_numsecflavor = 0;
3181                         error = 0;
3182                 }
3183         } else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor >
3184             MAXSECFLAVORS) {
3185                 printf("nfsvno_checkexp: numsecflavors out of range\n");
3186                 exp->nes_numsecflavor = 0;
3187                 error = EACCES;
3188         }
3189         NFSEXITCODE(error);
3190         return (error);
3191 }
3192
3193 /*
3194  * Get a vnode for a file handle and export stuff.
3195  */
3196 int
3197 nfsvno_fhtovp(struct mount *mp, fhandle_t *fhp, struct sockaddr *nam,
3198     int lktype, struct vnode **vpp, struct nfsexstuff *exp,
3199     struct ucred **credp)
3200 {
3201         int error;
3202
3203         *credp = NULL;
3204         exp->nes_numsecflavor = 0;
3205         error = VFS_FHTOVP(mp, &fhp->fh_fid, lktype, vpp);
3206         if (error != 0)
3207                 /* Make sure the server replies ESTALE to the client. */
3208                 error = ESTALE;
3209         if (nam && !error) {
3210                 error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp,
3211                     &exp->nes_numsecflavor, exp->nes_secflavors);
3212                 if (error) {
3213                         if (nfs_rootfhset) {
3214                                 exp->nes_exflag = 0;
3215                                 exp->nes_numsecflavor = 0;
3216                                 error = 0;
3217                         } else {
3218                                 vput(*vpp);
3219                         }
3220                 } else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor >
3221                     MAXSECFLAVORS) {
3222                         printf("nfsvno_fhtovp: numsecflavors out of range\n");
3223                         exp->nes_numsecflavor = 0;
3224                         error = EACCES;
3225                         vput(*vpp);
3226                 }
3227         }
3228         NFSEXITCODE(error);
3229         return (error);
3230 }
3231
3232 /*
3233  * nfsd_fhtovp() - convert a fh to a vnode ptr
3234  *      - look up fsid in mount list (if not found ret error)
3235  *      - get vp and export rights by calling nfsvno_fhtovp()
3236  *      - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
3237  *        for AUTH_SYS
3238  *      - if mpp != NULL, return the mount point so that it can
3239  *        be used for vn_finished_write() by the caller
3240  */
3241 void
3242 nfsd_fhtovp(struct nfsrv_descript *nd, struct nfsrvfh *nfp, int lktype,
3243     struct vnode **vpp, struct nfsexstuff *exp,
3244     struct mount **mpp, int startwrite)
3245 {
3246         struct mount *mp;
3247         struct ucred *credanon;
3248         fhandle_t *fhp;
3249
3250         fhp = (fhandle_t *)nfp->nfsrvfh_data;
3251         /*
3252          * Check for the special case of the nfsv4root_fh.
3253          */
3254         mp = vfs_busyfs(&fhp->fh_fsid);
3255         if (mpp != NULL)
3256                 *mpp = mp;
3257         if (mp == NULL) {
3258                 *vpp = NULL;
3259                 nd->nd_repstat = ESTALE;
3260                 goto out;
3261         }
3262
3263         if (startwrite) {
3264                 vn_start_write(NULL, mpp, V_WAIT);
3265                 if (lktype == LK_SHARED && !(MNT_SHARED_WRITES(mp)))
3266                         lktype = LK_EXCLUSIVE;
3267         }
3268         nd->nd_repstat = nfsvno_fhtovp(mp, fhp, nd->nd_nam, lktype, vpp, exp,
3269             &credanon);
3270         vfs_unbusy(mp);
3271
3272         /*
3273          * For NFSv4 without a pseudo root fs, unexported file handles
3274          * can be returned, so that Lookup works everywhere.
3275          */
3276         if (!nd->nd_repstat && exp->nes_exflag == 0 &&
3277             !(nd->nd_flag & ND_NFSV4)) {
3278                 vput(*vpp);
3279                 nd->nd_repstat = EACCES;
3280         }
3281
3282         /*
3283          * If TLS is required by the export, check the flags in nd_flag.
3284          */
3285         if (nd->nd_repstat == 0 && ((NFSVNO_EXTLS(exp) &&
3286             (nd->nd_flag & ND_TLS) == 0) ||
3287              (NFSVNO_EXTLSCERT(exp) &&
3288               (nd->nd_flag & ND_TLSCERT) == 0) ||
3289              (NFSVNO_EXTLSCERTUSER(exp) &&
3290               (nd->nd_flag & ND_TLSCERTUSER) == 0))) {
3291                 vput(*vpp);
3292                 nd->nd_repstat = NFSERR_ACCES;
3293         }
3294
3295         /*
3296          * Personally, I've never seen any point in requiring a
3297          * reserved port#, since only in the rare case where the
3298          * clients are all boxes with secure system privileges,
3299          * does it provide any enhanced security, but... some people
3300          * believe it to be useful and keep putting this code back in.
3301          * (There is also some "security checker" out there that
3302          *  complains if the nfs server doesn't enforce this.)
3303          * However, note the following:
3304          * RFC3530 (NFSv4) specifies that a reserved port# not be
3305          *      required.
3306          * RFC2623 recommends that, if a reserved port# is checked for,
3307          *      that there be a way to turn that off--> ifdef'd.
3308          */
3309 #ifdef NFS_REQRSVPORT
3310         if (!nd->nd_repstat) {
3311                 struct sockaddr_in *saddr;
3312                 struct sockaddr_in6 *saddr6;
3313
3314                 saddr = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
3315                 saddr6 = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in6 *);
3316                 if (!(nd->nd_flag & ND_NFSV4) &&
3317                     ((saddr->sin_family == AF_INET &&
3318                       ntohs(saddr->sin_port) >= IPPORT_RESERVED) ||
3319                      (saddr6->sin6_family == AF_INET6 &&
3320                       ntohs(saddr6->sin6_port) >= IPPORT_RESERVED))) {
3321                         vput(*vpp);
3322                         nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
3323                 }
3324         }
3325 #endif  /* NFS_REQRSVPORT */
3326
3327         /*
3328          * Check/setup credentials.
3329          */
3330         if (!nd->nd_repstat) {
3331                 nd->nd_saveduid = nd->nd_cred->cr_uid;
3332                 nd->nd_repstat = nfsd_excred(nd, exp, credanon);
3333                 if (nd->nd_repstat)
3334                         vput(*vpp);
3335         }
3336         if (credanon != NULL)
3337                 crfree(credanon);
3338         if (nd->nd_repstat) {
3339                 if (startwrite)
3340                         vn_finished_write(mp);
3341                 *vpp = NULL;
3342                 if (mpp != NULL)
3343                         *mpp = NULL;
3344         }
3345
3346 out:
3347         NFSEXITCODE2(0, nd);
3348 }
3349
3350 /*
3351  * glue for fp.
3352  */
3353 static int
3354 fp_getfvp(struct thread *p, int fd, struct file **fpp, struct vnode **vpp)
3355 {
3356         struct filedesc *fdp;
3357         struct file *fp;
3358         int error = 0;
3359
3360         fdp = p->td_proc->p_fd;
3361         if (fd < 0 || fd >= fdp->fd_nfiles ||
3362             (fp = fdp->fd_ofiles[fd].fde_file) == NULL) {
3363                 error = EBADF;
3364                 goto out;
3365         }
3366         *fpp = fp;
3367
3368 out:
3369         NFSEXITCODE(error);
3370         return (error);
3371 }
3372
3373 /*
3374  * Called from nfssvc() to update the exports list. Just call
3375  * vfs_export(). This has to be done, since the v4 root fake fs isn't
3376  * in the mount list.
3377  */
3378 int
3379 nfsrv_v4rootexport(void *argp, struct ucred *cred, struct thread *p)
3380 {
3381         struct nfsex_args *nfsexargp = (struct nfsex_args *)argp;
3382         int error = 0;
3383         struct nameidata nd;
3384         fhandle_t fh;
3385
3386         error = vfs_export(&nfsv4root_mnt, &nfsexargp->export);
3387         if ((nfsexargp->export.ex_flags & MNT_DELEXPORT) != 0)
3388                 nfs_rootfhset = 0;
3389         else if (error == 0) {
3390                 if (nfsexargp->fspec == NULL) {
3391                         error = EPERM;
3392                         goto out;
3393                 }
3394                 /*
3395                  * If fspec != NULL, this is the v4root path.
3396                  */
3397                 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
3398                     nfsexargp->fspec, p);
3399                 if ((error = namei(&nd)) != 0)
3400                         goto out;
3401                 error = nfsvno_getfh(nd.ni_vp, &fh, p);
3402                 vrele(nd.ni_vp);
3403                 if (!error) {
3404                         nfs_rootfh.nfsrvfh_len = NFSX_MYFH;
3405                         NFSBCOPY((caddr_t)&fh,
3406                             nfs_rootfh.nfsrvfh_data,
3407                             sizeof (fhandle_t));
3408                         nfs_rootfhset = 1;
3409                 }
3410         }
3411
3412 out:
3413         NFSEXITCODE(error);
3414         return (error);
3415 }
3416
3417 /*
3418  * This function needs to test to see if the system is near its limit
3419  * for memory allocation via malloc() or mget() and return True iff
3420  * either of these resources are near their limit.
3421  * XXX (For now, this is just a stub.)
3422  */
3423 int nfsrv_testmalloclimit = 0;
3424 int
3425 nfsrv_mallocmget_limit(void)
3426 {
3427         static int printmesg = 0;
3428         static int testval = 1;
3429
3430         if (nfsrv_testmalloclimit && (testval++ % 1000) == 0) {
3431                 if ((printmesg++ % 100) == 0)
3432                         printf("nfsd: malloc/mget near limit\n");
3433                 return (1);
3434         }
3435         return (0);
3436 }
3437
3438 /*
3439  * BSD specific initialization of a mount point.
3440  */
3441 void
3442 nfsd_mntinit(void)
3443 {
3444         static int inited = 0;
3445
3446         if (inited)
3447                 return;
3448         inited = 1;
3449         nfsv4root_mnt.mnt_flag = (MNT_RDONLY | MNT_EXPORTED);
3450         TAILQ_INIT(&nfsv4root_mnt.mnt_nvnodelist);
3451         TAILQ_INIT(&nfsv4root_mnt.mnt_lazyvnodelist);
3452         nfsv4root_mnt.mnt_export = NULL;
3453         TAILQ_INIT(&nfsv4root_opt);
3454         TAILQ_INIT(&nfsv4root_newopt);
3455         nfsv4root_mnt.mnt_opt = &nfsv4root_opt;
3456         nfsv4root_mnt.mnt_optnew = &nfsv4root_newopt;
3457         nfsv4root_mnt.mnt_nvnodelistsize = 0;
3458         nfsv4root_mnt.mnt_lazyvnodelistsize = 0;
3459 }
3460
3461 /*
3462  * Get a vnode for a file handle, without checking exports, etc.
3463  */
3464 struct vnode *
3465 nfsvno_getvp(fhandle_t *fhp)
3466 {
3467         struct mount *mp;
3468         struct vnode *vp;
3469         int error;
3470
3471         mp = vfs_busyfs(&fhp->fh_fsid);
3472         if (mp == NULL)
3473                 return (NULL);
3474         error = VFS_FHTOVP(mp, &fhp->fh_fid, LK_EXCLUSIVE, &vp);
3475         vfs_unbusy(mp);
3476         if (error)
3477                 return (NULL);
3478         return (vp);
3479 }
3480
3481 /*
3482  * Do a local VOP_ADVLOCK().
3483  */
3484 int
3485 nfsvno_advlock(struct vnode *vp, int ftype, u_int64_t first,
3486     u_int64_t end, struct thread *td)
3487 {
3488         int error = 0;
3489         struct flock fl;
3490         u_int64_t tlen;
3491
3492         if (nfsrv_dolocallocks == 0)
3493                 goto out;
3494         ASSERT_VOP_UNLOCKED(vp, "nfsvno_advlock: vp locked");
3495
3496         fl.l_whence = SEEK_SET;
3497         fl.l_type = ftype;
3498         fl.l_start = (off_t)first;
3499         if (end == NFS64BITSSET) {
3500                 fl.l_len = 0;
3501         } else {
3502                 tlen = end - first;
3503                 fl.l_len = (off_t)tlen;
3504         }
3505         /*
3506          * For FreeBSD8, the l_pid and l_sysid must be set to the same
3507          * values for all calls, so that all locks will be held by the
3508          * nfsd server. (The nfsd server handles conflicts between the
3509          * various clients.)
3510          * Since an NFSv4 lockowner is a ClientID plus an array of up to 1024
3511          * bytes, so it can't be put in l_sysid.
3512          */
3513         if (nfsv4_sysid == 0)
3514                 nfsv4_sysid = nlm_acquire_next_sysid();
3515         fl.l_pid = (pid_t)0;
3516         fl.l_sysid = (int)nfsv4_sysid;
3517
3518         if (ftype == F_UNLCK)
3519                 error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_UNLCK, &fl,
3520                     (F_POSIX | F_REMOTE));
3521         else
3522                 error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_SETLK, &fl,
3523                     (F_POSIX | F_REMOTE));
3524
3525 out:
3526         NFSEXITCODE(error);
3527         return (error);
3528 }
3529
3530 /*
3531  * Check the nfsv4 root exports.
3532  */
3533 int
3534 nfsvno_v4rootexport(struct nfsrv_descript *nd)
3535 {
3536         struct ucred *credanon;
3537         int error = 0, numsecflavor, secflavors[MAXSECFLAVORS], i;
3538         uint64_t exflags;
3539
3540         error = vfs_stdcheckexp(&nfsv4root_mnt, nd->nd_nam, &exflags,
3541             &credanon, &numsecflavor, secflavors);
3542         if (error) {
3543                 error = NFSERR_PROGUNAVAIL;
3544                 goto out;
3545         }
3546         if (credanon != NULL)
3547                 crfree(credanon);
3548         for (i = 0; i < numsecflavor; i++) {
3549                 if (secflavors[i] == AUTH_SYS)
3550                         nd->nd_flag |= ND_EXAUTHSYS;
3551                 else if (secflavors[i] == RPCSEC_GSS_KRB5)
3552                         nd->nd_flag |= ND_EXGSS;
3553                 else if (secflavors[i] == RPCSEC_GSS_KRB5I)
3554                         nd->nd_flag |= ND_EXGSSINTEGRITY;
3555                 else if (secflavors[i] == RPCSEC_GSS_KRB5P)
3556                         nd->nd_flag |= ND_EXGSSPRIVACY;
3557         }
3558
3559         /* And set ND_EXxx flags for TLS. */
3560         if ((exflags & MNT_EXTLS) != 0) {
3561                 nd->nd_flag |= ND_EXTLS;
3562                 if ((exflags & MNT_EXTLSCERT) != 0)
3563                         nd->nd_flag |= ND_EXTLSCERT;
3564                 if ((exflags & MNT_EXTLSCERTUSER) != 0)
3565                         nd->nd_flag |= ND_EXTLSCERTUSER;
3566         }
3567
3568 out:
3569         NFSEXITCODE(error);
3570         return (error);
3571 }
3572
3573 /*
3574  * Nfs server pseudo system call for the nfsd's
3575  */
3576 /*
3577  * MPSAFE
3578  */
3579 static int
3580 nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap)
3581 {
3582         struct file *fp;
3583         struct nfsd_addsock_args sockarg;
3584         struct nfsd_nfsd_args nfsdarg;
3585         struct nfsd_nfsd_oargs onfsdarg;
3586         struct nfsd_pnfsd_args pnfsdarg;
3587         struct vnode *vp, *nvp, *curdvp;
3588         struct pnfsdsfile *pf;
3589         struct nfsdevice *ds, *fds;
3590         cap_rights_t rights;
3591         int buflen, error, ret;
3592         char *buf, *cp, *cp2, *cp3;
3593         char fname[PNFS_FILENAME_LEN + 1];
3594
3595         if (uap->flag & NFSSVC_NFSDADDSOCK) {
3596                 error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg));
3597                 if (error)
3598                         goto out;
3599                 /*
3600                  * Since we don't know what rights might be required,
3601                  * pretend that we need them all. It is better to be too
3602                  * careful than too reckless.
3603                  */
3604                 error = fget(td, sockarg.sock,
3605                     cap_rights_init(&rights, CAP_SOCK_SERVER), &fp);
3606                 if (error != 0)
3607                         goto out;
3608                 if (fp->f_type != DTYPE_SOCKET) {
3609                         fdrop(fp, td);
3610                         error = EPERM;
3611                         goto out;
3612                 }
3613                 error = nfsrvd_addsock(fp);
3614                 fdrop(fp, td);
3615         } else if (uap->flag & NFSSVC_NFSDNFSD) {
3616                 if (uap->argp == NULL) {
3617                         error = EINVAL;
3618                         goto out;
3619                 }
3620                 if ((uap->flag & NFSSVC_NEWSTRUCT) == 0) {
3621                         error = copyin(uap->argp, &onfsdarg, sizeof(onfsdarg));
3622                         if (error == 0) {
3623                                 nfsdarg.principal = onfsdarg.principal;
3624                                 nfsdarg.minthreads = onfsdarg.minthreads;
3625                                 nfsdarg.maxthreads = onfsdarg.maxthreads;
3626                                 nfsdarg.version = 1;
3627                                 nfsdarg.addr = NULL;
3628                                 nfsdarg.addrlen = 0;
3629                                 nfsdarg.dnshost = NULL;
3630                                 nfsdarg.dnshostlen = 0;
3631                                 nfsdarg.dspath = NULL;
3632                                 nfsdarg.dspathlen = 0;
3633                                 nfsdarg.mdspath = NULL;
3634                                 nfsdarg.mdspathlen = 0;
3635                                 nfsdarg.mirrorcnt = 1;
3636                         }
3637                 } else
3638                         error = copyin(uap->argp, &nfsdarg, sizeof(nfsdarg));
3639                 if (error)
3640                         goto out;
3641                 if (nfsdarg.addrlen > 0 && nfsdarg.addrlen < 10000 &&
3642                     nfsdarg.dnshostlen > 0 && nfsdarg.dnshostlen < 10000 &&
3643                     nfsdarg.dspathlen > 0 && nfsdarg.dspathlen < 10000 &&
3644                     nfsdarg.mdspathlen > 0 && nfsdarg.mdspathlen < 10000 &&
3645                     nfsdarg.mirrorcnt >= 1 &&
3646                     nfsdarg.mirrorcnt <= NFSDEV_MAXMIRRORS &&
3647                     nfsdarg.addr != NULL && nfsdarg.dnshost != NULL &&
3648                     nfsdarg.dspath != NULL && nfsdarg.mdspath != NULL) {
3649                         NFSD_DEBUG(1, "addrlen=%d dspathlen=%d dnslen=%d"
3650                             " mdspathlen=%d mirrorcnt=%d\n", nfsdarg.addrlen,
3651                             nfsdarg.dspathlen, nfsdarg.dnshostlen,
3652                             nfsdarg.mdspathlen, nfsdarg.mirrorcnt);
3653                         cp = malloc(nfsdarg.addrlen + 1, M_TEMP, M_WAITOK);
3654                         error = copyin(nfsdarg.addr, cp, nfsdarg.addrlen);
3655                         if (error != 0) {
3656                                 free(cp, M_TEMP);
3657                                 goto out;
3658                         }
3659                         cp[nfsdarg.addrlen] = '\0';     /* Ensure nul term. */
3660                         nfsdarg.addr = cp;
3661                         cp = malloc(nfsdarg.dnshostlen + 1, M_TEMP, M_WAITOK);
3662                         error = copyin(nfsdarg.dnshost, cp, nfsdarg.dnshostlen);
3663                         if (error != 0) {
3664                                 free(nfsdarg.addr, M_TEMP);
3665                                 free(cp, M_TEMP);
3666                                 goto out;
3667                         }
3668                         cp[nfsdarg.dnshostlen] = '\0';  /* Ensure nul term. */
3669                         nfsdarg.dnshost = cp;
3670                         cp = malloc(nfsdarg.dspathlen + 1, M_TEMP, M_WAITOK);
3671                         error = copyin(nfsdarg.dspath, cp, nfsdarg.dspathlen);
3672                         if (error != 0) {
3673                                 free(nfsdarg.addr, M_TEMP);
3674                                 free(nfsdarg.dnshost, M_TEMP);
3675                                 free(cp, M_TEMP);
3676                                 goto out;
3677                         }
3678                         cp[nfsdarg.dspathlen] = '\0';   /* Ensure nul term. */
3679                         nfsdarg.dspath = cp;
3680                         cp = malloc(nfsdarg.mdspathlen + 1, M_TEMP, M_WAITOK);
3681                         error = copyin(nfsdarg.mdspath, cp, nfsdarg.mdspathlen);
3682                         if (error != 0) {
3683                                 free(nfsdarg.addr, M_TEMP);
3684                                 free(nfsdarg.dnshost, M_TEMP);
3685                                 free(nfsdarg.dspath, M_TEMP);
3686                                 free(cp, M_TEMP);
3687                                 goto out;
3688                         }
3689                         cp[nfsdarg.mdspathlen] = '\0';  /* Ensure nul term. */
3690                         nfsdarg.mdspath = cp;
3691                 } else {
3692                         nfsdarg.addr = NULL;
3693                         nfsdarg.addrlen = 0;
3694                         nfsdarg.dnshost = NULL;
3695                         nfsdarg.dnshostlen = 0;
3696                         nfsdarg.dspath = NULL;
3697                         nfsdarg.dspathlen = 0;
3698                         nfsdarg.mdspath = NULL;
3699                         nfsdarg.mdspathlen = 0;
3700                         nfsdarg.mirrorcnt = 1;
3701                 }
3702                 error = nfsrvd_nfsd(td, &nfsdarg);
3703                 free(nfsdarg.addr, M_TEMP);
3704                 free(nfsdarg.dnshost, M_TEMP);
3705                 free(nfsdarg.dspath, M_TEMP);
3706                 free(nfsdarg.mdspath, M_TEMP);
3707         } else if (uap->flag & NFSSVC_PNFSDS) {
3708                 error = copyin(uap->argp, &pnfsdarg, sizeof(pnfsdarg));
3709                 if (error == 0 && (pnfsdarg.op == PNFSDOP_DELDSSERVER ||
3710                     pnfsdarg.op == PNFSDOP_FORCEDELDS)) {
3711                         cp = malloc(PATH_MAX + 1, M_TEMP, M_WAITOK);
3712                         error = copyinstr(pnfsdarg.dspath, cp, PATH_MAX + 1,
3713                             NULL);
3714                         if (error == 0)
3715                                 error = nfsrv_deldsserver(pnfsdarg.op, cp, td);
3716                         free(cp, M_TEMP);
3717                 } else if (error == 0 && pnfsdarg.op == PNFSDOP_COPYMR) {
3718                         cp = malloc(PATH_MAX + 1, M_TEMP, M_WAITOK);
3719                         buflen = sizeof(*pf) * NFSDEV_MAXMIRRORS;
3720                         buf = malloc(buflen, M_TEMP, M_WAITOK);
3721                         error = copyinstr(pnfsdarg.mdspath, cp, PATH_MAX + 1,
3722                             NULL);
3723                         NFSD_DEBUG(4, "pnfsdcopymr cp mdspath=%d\n", error);
3724                         if (error == 0 && pnfsdarg.dspath != NULL) {
3725                                 cp2 = malloc(PATH_MAX + 1, M_TEMP, M_WAITOK);
3726                                 error = copyinstr(pnfsdarg.dspath, cp2,
3727                                     PATH_MAX + 1, NULL);
3728                                 NFSD_DEBUG(4, "pnfsdcopymr cp dspath=%d\n",
3729                                     error);
3730                         } else
3731                                 cp2 = NULL;
3732                         if (error == 0 && pnfsdarg.curdspath != NULL) {
3733                                 cp3 = malloc(PATH_MAX + 1, M_TEMP, M_WAITOK);
3734                                 error = copyinstr(pnfsdarg.curdspath, cp3,
3735                                     PATH_MAX + 1, NULL);
3736                                 NFSD_DEBUG(4, "pnfsdcopymr cp curdspath=%d\n",
3737                                     error);
3738                         } else
3739                                 cp3 = NULL;
3740                         curdvp = NULL;
3741                         fds = NULL;
3742                         if (error == 0)
3743                                 error = nfsrv_mdscopymr(cp, cp2, cp3, buf,
3744                                     &buflen, fname, td, &vp, &nvp, &pf, &ds,
3745                                     &fds);
3746                         NFSD_DEBUG(4, "nfsrv_mdscopymr=%d\n", error);
3747                         if (error == 0) {
3748                                 if (pf->dsf_dir >= nfsrv_dsdirsize) {
3749                                         printf("copymr: dsdir out of range\n");
3750                                         pf->dsf_dir = 0;
3751                                 }
3752                                 NFSD_DEBUG(4, "copymr: buflen=%d\n", buflen);
3753                                 error = nfsrv_copymr(vp, nvp,
3754                                     ds->nfsdev_dsdir[pf->dsf_dir], ds, pf,
3755                                     (struct pnfsdsfile *)buf,
3756                                     buflen / sizeof(*pf), td->td_ucred, td);
3757                                 vput(vp);
3758                                 vput(nvp);
3759                                 if (fds != NULL && error == 0) {
3760                                         curdvp = fds->nfsdev_dsdir[pf->dsf_dir];
3761                                         ret = vn_lock(curdvp, LK_EXCLUSIVE);
3762                                         if (ret == 0) {
3763                                                 nfsrv_dsremove(curdvp, fname,
3764                                                     td->td_ucred, td);
3765                                                 NFSVOPUNLOCK(curdvp);
3766                                         }
3767                                 }
3768                                 NFSD_DEBUG(4, "nfsrv_copymr=%d\n", error);
3769                         }
3770                         free(cp, M_TEMP);
3771                         free(cp2, M_TEMP);
3772                         free(cp3, M_TEMP);
3773                         free(buf, M_TEMP);
3774                 }
3775         } else {
3776                 error = nfssvc_srvcall(td, uap, td->td_ucred);
3777         }
3778
3779 out:
3780         NFSEXITCODE(error);
3781         return (error);
3782 }
3783
3784 static int
3785 nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred)
3786 {
3787         struct nfsex_args export;
3788         struct nfsex_oldargs oexp;
3789         struct file *fp = NULL;
3790         int stablefd, i, len;
3791         struct nfsd_clid adminrevoke;
3792         struct nfsd_dumplist dumplist;
3793         struct nfsd_dumpclients *dumpclients;
3794         struct nfsd_dumplocklist dumplocklist;
3795         struct nfsd_dumplocks *dumplocks;
3796         struct nameidata nd;
3797         vnode_t vp;
3798         int error = EINVAL, igotlock;
3799         struct proc *procp;
3800         gid_t *grps;
3801         static int suspend_nfsd = 0;
3802
3803         if (uap->flag & NFSSVC_PUBLICFH) {
3804                 NFSBZERO((caddr_t)&nfs_pubfh.nfsrvfh_data,
3805                     sizeof (fhandle_t));
3806                 error = copyin(uap->argp,
3807                     &nfs_pubfh.nfsrvfh_data, sizeof (fhandle_t));
3808                 if (!error)
3809                         nfs_pubfhset = 1;
3810         } else if ((uap->flag & (NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT)) ==
3811             (NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT)) {
3812                 error = copyin(uap->argp,(caddr_t)&export,
3813                     sizeof (struct nfsex_args));
3814                 if (!error) {
3815                         grps = NULL;
3816                         if (export.export.ex_ngroups > NGROUPS_MAX ||
3817                             export.export.ex_ngroups < 0)
3818                                 error = EINVAL;
3819                         else if (export.export.ex_ngroups > 0) {
3820                                 grps = malloc(export.export.ex_ngroups *
3821                                     sizeof(gid_t), M_TEMP, M_WAITOK);
3822                                 error = copyin(export.export.ex_groups, grps,
3823                                     export.export.ex_ngroups * sizeof(gid_t));
3824                                 export.export.ex_groups = grps;
3825                         } else
3826                                 export.export.ex_groups = NULL;
3827                         if (!error)
3828                                 error = nfsrv_v4rootexport(&export, cred, p);
3829                         free(grps, M_TEMP);
3830                 }
3831         } else if ((uap->flag & (NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT)) ==
3832             NFSSVC_V4ROOTEXPORT) {
3833                 error = copyin(uap->argp,(caddr_t)&oexp,
3834                     sizeof (struct nfsex_oldargs));
3835                 if (!error) {
3836                         memset(&export.export, 0, sizeof(export.export));
3837                         export.export.ex_flags = (uint64_t)oexp.export.ex_flags;
3838                         export.export.ex_root = oexp.export.ex_root;
3839                         export.export.ex_uid = oexp.export.ex_anon.cr_uid;
3840                         export.export.ex_ngroups =
3841                             oexp.export.ex_anon.cr_ngroups;
3842                         export.export.ex_groups = NULL;
3843                         if (export.export.ex_ngroups > XU_NGROUPS ||
3844                             export.export.ex_ngroups < 0)
3845                                 error = EINVAL;
3846                         else if (export.export.ex_ngroups > 0) {
3847                                 export.export.ex_groups = malloc(
3848                                     export.export.ex_ngroups * sizeof(gid_t),
3849                                     M_TEMP, M_WAITOK);
3850                                 for (i = 0; i < export.export.ex_ngroups; i++)
3851                                         export.export.ex_groups[i] =
3852                                             oexp.export.ex_anon.cr_groups[i];
3853                         }
3854                         export.export.ex_addr = oexp.export.ex_addr;
3855                         export.export.ex_addrlen = oexp.export.ex_addrlen;
3856                         export.export.ex_mask = oexp.export.ex_mask;
3857                         export.export.ex_masklen = oexp.export.ex_masklen;
3858                         export.export.ex_indexfile = oexp.export.ex_indexfile;
3859                         export.export.ex_numsecflavors =
3860                             oexp.export.ex_numsecflavors;
3861                         if (export.export.ex_numsecflavors >= MAXSECFLAVORS ||
3862                             export.export.ex_numsecflavors < 0)
3863                                 error = EINVAL;
3864                         else {
3865                                 for (i = 0; i < export.export.ex_numsecflavors;
3866                                     i++)
3867                                         export.export.ex_secflavors[i] =
3868                                             oexp.export.ex_secflavors[i];
3869                         }
3870                         export.fspec = oexp.fspec;
3871                         if (error == 0)
3872                                 error = nfsrv_v4rootexport(&export, cred, p);
3873                         free(export.export.ex_groups, M_TEMP);
3874                 }
3875         } else if (uap->flag & NFSSVC_NOPUBLICFH) {
3876                 nfs_pubfhset = 0;
3877                 error = 0;
3878         } else if (uap->flag & NFSSVC_STABLERESTART) {
3879                 error = copyin(uap->argp, (caddr_t)&stablefd,
3880                     sizeof (int));
3881                 if (!error)
3882                         error = fp_getfvp(p, stablefd, &fp, &vp);
3883                 if (!error && (NFSFPFLAG(fp) & (FREAD | FWRITE)) != (FREAD | FWRITE))
3884                         error = EBADF;
3885                 if (!error && newnfs_numnfsd != 0)
3886                         error = EPERM;
3887                 if (!error) {
3888                         nfsrv_stablefirst.nsf_fp = fp;
3889                         nfsrv_setupstable(p);
3890                 }
3891         } else if (uap->flag & NFSSVC_ADMINREVOKE) {
3892                 error = copyin(uap->argp, (caddr_t)&adminrevoke,
3893                     sizeof (struct nfsd_clid));
3894                 if (!error)
3895                         error = nfsrv_adminrevoke(&adminrevoke, p);
3896         } else if (uap->flag & NFSSVC_DUMPCLIENTS) {
3897                 error = copyin(uap->argp, (caddr_t)&dumplist,
3898                     sizeof (struct nfsd_dumplist));
3899                 if (!error && (dumplist.ndl_size < 1 ||
3900                         dumplist.ndl_size > NFSRV_MAXDUMPLIST))
3901                         error = EPERM;
3902                 if (!error) {
3903                     len = sizeof (struct nfsd_dumpclients) * dumplist.ndl_size;
3904                     dumpclients = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
3905                     nfsrv_dumpclients(dumpclients, dumplist.ndl_size);
3906                     error = copyout(dumpclients, dumplist.ndl_list, len);
3907                     free(dumpclients, M_TEMP);
3908                 }
3909         } else if (uap->flag & NFSSVC_DUMPLOCKS) {
3910                 error = copyin(uap->argp, (caddr_t)&dumplocklist,
3911                     sizeof (struct nfsd_dumplocklist));
3912                 if (!error && (dumplocklist.ndllck_size < 1 ||
3913                         dumplocklist.ndllck_size > NFSRV_MAXDUMPLIST))
3914                         error = EPERM;
3915                 if (!error)
3916                         error = nfsrv_lookupfilename(&nd,
3917                                 dumplocklist.ndllck_fname, p);
3918                 if (!error) {
3919                         len = sizeof (struct nfsd_dumplocks) *
3920                                 dumplocklist.ndllck_size;
3921                         dumplocks = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
3922                         nfsrv_dumplocks(nd.ni_vp, dumplocks,
3923                             dumplocklist.ndllck_size, p);
3924                         vput(nd.ni_vp);
3925                         error = copyout(dumplocks, dumplocklist.ndllck_list,
3926                             len);
3927                         free(dumplocks, M_TEMP);
3928                 }
3929         } else if (uap->flag & NFSSVC_BACKUPSTABLE) {
3930                 procp = p->td_proc;
3931                 PROC_LOCK(procp);
3932                 nfsd_master_pid = procp->p_pid;
3933                 bcopy(procp->p_comm, nfsd_master_comm, MAXCOMLEN + 1);
3934                 nfsd_master_start = procp->p_stats->p_start;
3935                 nfsd_master_proc = procp;
3936                 PROC_UNLOCK(procp);
3937         } else if ((uap->flag & NFSSVC_SUSPENDNFSD) != 0) {
3938                 NFSLOCKV4ROOTMUTEX();
3939                 if (suspend_nfsd == 0) {
3940                         /* Lock out all nfsd threads */
3941                         do {
3942                                 igotlock = nfsv4_lock(&nfsd_suspend_lock, 1,
3943                                     NULL, NFSV4ROOTLOCKMUTEXPTR, NULL);
3944                         } while (igotlock == 0 && suspend_nfsd == 0);
3945                         suspend_nfsd = 1;
3946                 }
3947                 NFSUNLOCKV4ROOTMUTEX();
3948                 error = 0;
3949         } else if ((uap->flag & NFSSVC_RESUMENFSD) != 0) {
3950                 NFSLOCKV4ROOTMUTEX();
3951                 if (suspend_nfsd != 0) {
3952                         nfsv4_unlock(&nfsd_suspend_lock, 0);
3953                         suspend_nfsd = 0;
3954                 }
3955                 NFSUNLOCKV4ROOTMUTEX();
3956                 error = 0;
3957         }
3958
3959         NFSEXITCODE(error);
3960         return (error);
3961 }
3962
3963 /*
3964  * Check exports.
3965  * Returns 0 if ok, 1 otherwise.
3966  */
3967 int
3968 nfsvno_testexp(struct nfsrv_descript *nd, struct nfsexstuff *exp)
3969 {
3970         int i;
3971
3972         /*
3973          * This seems odd, but allow the case where the security flavor
3974          * list is empty. This happens when NFSv4 is traversing non-exported
3975          * file systems. Exported file systems should always have a non-empty
3976          * security flavor list.
3977          */
3978         if (exp->nes_numsecflavor == 0)
3979                 return (0);
3980
3981         for (i = 0; i < exp->nes_numsecflavor; i++) {
3982                 /*
3983                  * The tests for privacy and integrity must be first,
3984                  * since ND_GSS is set for everything but AUTH_SYS.
3985                  */
3986                 if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5P &&
3987                     (nd->nd_flag & ND_GSSPRIVACY))
3988                         return (0);
3989                 if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5I &&
3990                     (nd->nd_flag & ND_GSSINTEGRITY))
3991                         return (0);
3992                 if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5 &&
3993                     (nd->nd_flag & ND_GSS))
3994                         return (0);
3995                 if (exp->nes_secflavors[i] == AUTH_SYS &&
3996                     (nd->nd_flag & ND_GSS) == 0)
3997                         return (0);
3998         }
3999         return (1);
4000 }
4001
4002 /*
4003  * Calculate a hash value for the fid in a file handle.
4004  */
4005 uint32_t
4006 nfsrv_hashfh(fhandle_t *fhp)
4007 {
4008         uint32_t hashval;
4009
4010         hashval = hash32_buf(&fhp->fh_fid, sizeof(struct fid), 0);
4011         return (hashval);
4012 }
4013
4014 /*
4015  * Calculate a hash value for the sessionid.
4016  */
4017 uint32_t
4018 nfsrv_hashsessionid(uint8_t *sessionid)
4019 {
4020         uint32_t hashval;
4021
4022         hashval = hash32_buf(sessionid, NFSX_V4SESSIONID, 0);
4023         return (hashval);
4024 }
4025
4026 /*
4027  * Signal the userland master nfsd to backup the stable restart file.
4028  */
4029 void
4030 nfsrv_backupstable(void)
4031 {
4032         struct proc *procp;
4033
4034         if (nfsd_master_proc != NULL) {
4035                 procp = pfind(nfsd_master_pid);
4036                 /* Try to make sure it is the correct process. */
4037                 if (procp == nfsd_master_proc &&
4038                     procp->p_stats->p_start.tv_sec ==
4039                     nfsd_master_start.tv_sec &&
4040                     procp->p_stats->p_start.tv_usec ==
4041                     nfsd_master_start.tv_usec &&
4042                     strcmp(procp->p_comm, nfsd_master_comm) == 0)
4043                         kern_psignal(procp, SIGUSR2);
4044                 else
4045                         nfsd_master_proc = NULL;
4046
4047                 if (procp != NULL)
4048                         PROC_UNLOCK(procp);
4049         }
4050 }
4051
4052 /*
4053  * Create a DS data file for nfsrv_pnfscreate(). Called for each mirror.
4054  * The arguments are in a structure, so that they can be passed through
4055  * taskqueue for a kernel process to execute this function.
4056  */
4057 struct nfsrvdscreate {
4058         int                     done;
4059         int                     inprog;
4060         struct task             tsk;
4061         struct ucred            *tcred;
4062         struct vnode            *dvp;
4063         NFSPROC_T               *p;
4064         struct pnfsdsfile       *pf;
4065         int                     err;
4066         fhandle_t               fh;
4067         struct vattr            va;
4068         struct vattr            createva;
4069 };
4070
4071 int
4072 nfsrv_dscreate(struct vnode *dvp, struct vattr *vap, struct vattr *nvap,
4073     fhandle_t *fhp, struct pnfsdsfile *pf, struct pnfsdsattr *dsa,
4074     char *fnamep, struct ucred *tcred, NFSPROC_T *p, struct vnode **nvpp)
4075 {
4076         struct vnode *nvp;
4077         struct nameidata named;
4078         struct vattr va;
4079         char *bufp;
4080         u_long *hashp;
4081         struct nfsnode *np;
4082         struct nfsmount *nmp;
4083         int error;
4084
4085         NFSNAMEICNDSET(&named.ni_cnd, tcred, CREATE,
4086             LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
4087         nfsvno_setpathbuf(&named, &bufp, &hashp);
4088         named.ni_cnd.cn_lkflags = LK_EXCLUSIVE;
4089         named.ni_cnd.cn_thread = p;
4090         named.ni_cnd.cn_nameptr = bufp;
4091         if (fnamep != NULL) {
4092                 strlcpy(bufp, fnamep, PNFS_FILENAME_LEN + 1);
4093                 named.ni_cnd.cn_namelen = strlen(bufp);
4094         } else
4095                 named.ni_cnd.cn_namelen = nfsrv_putfhname(fhp, bufp);
4096         NFSD_DEBUG(4, "nfsrv_dscreate: dvp=%p fname=%s\n", dvp, bufp);
4097
4098         /* Create the date file in the DS mount. */
4099         error = NFSVOPLOCK(dvp, LK_EXCLUSIVE);
4100         if (error == 0) {
4101                 error = VOP_CREATE(dvp, &nvp, &named.ni_cnd, vap);
4102                 NFSVOPUNLOCK(dvp);
4103                 if (error == 0) {
4104                         /* Set the ownership of the file. */
4105                         error = VOP_SETATTR(nvp, nvap, tcred);
4106                         NFSD_DEBUG(4, "nfsrv_dscreate:"
4107                             " setattr-uid=%d\n", error);
4108                         if (error != 0)
4109                                 vput(nvp);
4110                 }
4111                 if (error != 0)
4112                         printf("pNFS: pnfscreate failed=%d\n", error);
4113         } else
4114                 printf("pNFS: pnfscreate vnlock=%d\n", error);
4115         if (error == 0) {
4116                 np = VTONFS(nvp);
4117                 nmp = VFSTONFS(nvp->v_mount);
4118                 if (strcmp(nvp->v_mount->mnt_vfc->vfc_name, "nfs")
4119                     != 0 || nmp->nm_nam->sa_len > sizeof(
4120                     struct sockaddr_in6) ||
4121                     np->n_fhp->nfh_len != NFSX_MYFH) {
4122                         printf("Bad DS file: fstype=%s salen=%d"
4123                             " fhlen=%d\n",
4124                             nvp->v_mount->mnt_vfc->vfc_name,
4125                             nmp->nm_nam->sa_len, np->n_fhp->nfh_len);
4126                         error = ENOENT;
4127                 }
4128
4129                 /* Set extattrs for the DS on the MDS file. */
4130                 if (error == 0) {
4131                         if (dsa != NULL) {
4132                                 error = VOP_GETATTR(nvp, &va, tcred);
4133                                 if (error == 0) {
4134                                         dsa->dsa_filerev = va.va_filerev;
4135                                         dsa->dsa_size = va.va_size;
4136                                         dsa->dsa_atime = va.va_atime;
4137                                         dsa->dsa_mtime = va.va_mtime;
4138                                         dsa->dsa_bytes = va.va_bytes;
4139                                 }
4140                         }
4141                         if (error == 0) {
4142                                 NFSBCOPY(np->n_fhp->nfh_fh, &pf->dsf_fh,
4143                                     NFSX_MYFH);
4144                                 NFSBCOPY(nmp->nm_nam, &pf->dsf_sin,
4145                                     nmp->nm_nam->sa_len);
4146                                 NFSBCOPY(named.ni_cnd.cn_nameptr,
4147                                     pf->dsf_filename,
4148                                     sizeof(pf->dsf_filename));
4149                         }
4150                 } else
4151                         printf("pNFS: pnfscreate can't get DS"
4152                             " attr=%d\n", error);
4153                 if (nvpp != NULL && error == 0)
4154                         *nvpp = nvp;
4155                 else
4156                         vput(nvp);
4157         }
4158         nfsvno_relpathbuf(&named);
4159         return (error);
4160 }
4161
4162 /*
4163  * Start up the thread that will execute nfsrv_dscreate().
4164  */
4165 static void
4166 start_dscreate(void *arg, int pending)
4167 {
4168         struct nfsrvdscreate *dsc;
4169
4170         dsc = (struct nfsrvdscreate *)arg;
4171         dsc->err = nfsrv_dscreate(dsc->dvp, &dsc->createva, &dsc->va, &dsc->fh,
4172             dsc->pf, NULL, NULL, dsc->tcred, dsc->p, NULL);
4173         dsc->done = 1;
4174         NFSD_DEBUG(4, "start_dscreate: err=%d\n", dsc->err);
4175 }
4176
4177 /*
4178  * Create a pNFS data file on the Data Server(s).
4179  */
4180 static void
4181 nfsrv_pnfscreate(struct vnode *vp, struct vattr *vap, struct ucred *cred,
4182     NFSPROC_T *p)
4183 {
4184         struct nfsrvdscreate *dsc, *tdsc = NULL;
4185         struct nfsdevice *ds, *tds, *fds;
4186         struct mount *mp;
4187         struct pnfsdsfile *pf, *tpf;
4188         struct pnfsdsattr dsattr;
4189         struct vattr va;
4190         struct vnode *dvp[NFSDEV_MAXMIRRORS];
4191         struct nfsmount *nmp;
4192         fhandle_t fh;
4193         uid_t vauid;
4194         gid_t vagid;
4195         u_short vamode;
4196         struct ucred *tcred;
4197         int dsdir[NFSDEV_MAXMIRRORS], error, i, mirrorcnt, ret;
4198         int failpos, timo;
4199
4200         /* Get a DS server directory in a round-robin order. */
4201         mirrorcnt = 1;
4202         mp = vp->v_mount;
4203         ds = fds = NULL;
4204         NFSDDSLOCK();
4205         /*
4206          * Search for the first entry that handles this MDS fs, but use the
4207          * first entry for all MDS fs's otherwise.
4208          */
4209         TAILQ_FOREACH(tds, &nfsrv_devidhead, nfsdev_list) {
4210                 if (tds->nfsdev_nmp != NULL) {
4211                         if (tds->nfsdev_mdsisset == 0 && ds == NULL)
4212                                 ds = tds;
4213                         else if (tds->nfsdev_mdsisset != 0 && fsidcmp(
4214                             &mp->mnt_stat.f_fsid, &tds->nfsdev_mdsfsid) == 0) {
4215                                 ds = fds = tds;
4216                                 break;
4217                         }
4218                 }
4219         }
4220         if (ds == NULL) {
4221                 NFSDDSUNLOCK();
4222                 NFSD_DEBUG(4, "nfsrv_pnfscreate: no srv\n");
4223                 return;
4224         }
4225         i = dsdir[0] = ds->nfsdev_nextdir;
4226         ds->nfsdev_nextdir = (ds->nfsdev_nextdir + 1) % nfsrv_dsdirsize;
4227         dvp[0] = ds->nfsdev_dsdir[i];
4228         tds = TAILQ_NEXT(ds, nfsdev_list);
4229         if (nfsrv_maxpnfsmirror > 1 && tds != NULL) {
4230                 TAILQ_FOREACH_FROM(tds, &nfsrv_devidhead, nfsdev_list) {
4231                         if (tds->nfsdev_nmp != NULL &&
4232                             ((tds->nfsdev_mdsisset == 0 && fds == NULL) ||
4233                              (tds->nfsdev_mdsisset != 0 && fds != NULL &&
4234                               fsidcmp(&mp->mnt_stat.f_fsid,
4235                               &tds->nfsdev_mdsfsid) == 0))) {
4236                                 dsdir[mirrorcnt] = i;
4237                                 dvp[mirrorcnt] = tds->nfsdev_dsdir[i];
4238                                 mirrorcnt++;
4239                                 if (mirrorcnt >= nfsrv_maxpnfsmirror)
4240                                         break;
4241                         }
4242                 }
4243         }
4244         /* Put at end of list to implement round-robin usage. */
4245         TAILQ_REMOVE(&nfsrv_devidhead, ds, nfsdev_list);
4246         TAILQ_INSERT_TAIL(&nfsrv_devidhead, ds, nfsdev_list);
4247         NFSDDSUNLOCK();
4248         dsc = NULL;
4249         if (mirrorcnt > 1)
4250                 tdsc = dsc = malloc(sizeof(*dsc) * (mirrorcnt - 1), M_TEMP,
4251                     M_WAITOK | M_ZERO);
4252         tpf = pf = malloc(sizeof(*pf) * nfsrv_maxpnfsmirror, M_TEMP, M_WAITOK |
4253             M_ZERO);
4254
4255         error = nfsvno_getfh(vp, &fh, p);
4256         if (error == 0)
4257                 error = VOP_GETATTR(vp, &va, cred);
4258         if (error == 0) {
4259                 /* Set the attributes for "vp" to Setattr the DS vp. */
4260                 vauid = va.va_uid;
4261                 vagid = va.va_gid;
4262                 vamode = va.va_mode;
4263                 VATTR_NULL(&va);
4264                 va.va_uid = vauid;
4265                 va.va_gid = vagid;
4266                 va.va_mode = vamode;
4267                 va.va_size = 0;
4268         } else
4269                 printf("pNFS: pnfscreate getfh+attr=%d\n", error);
4270
4271         NFSD_DEBUG(4, "nfsrv_pnfscreate: cruid=%d crgid=%d\n", cred->cr_uid,
4272             cred->cr_gid);
4273         /* Make data file name based on FH. */
4274         tcred = newnfs_getcred();
4275
4276         /*
4277          * Create the file on each DS mirror, using kernel process(es) for the
4278          * additional mirrors.
4279          */
4280         failpos = -1;
4281         for (i = 0; i < mirrorcnt - 1 && error == 0; i++, tpf++, tdsc++) {
4282                 tpf->dsf_dir = dsdir[i];
4283                 tdsc->tcred = tcred;
4284                 tdsc->p = p;
4285                 tdsc->pf = tpf;
4286                 tdsc->createva = *vap;
4287                 NFSBCOPY(&fh, &tdsc->fh, sizeof(fh));
4288                 tdsc->va = va;
4289                 tdsc->dvp = dvp[i];
4290                 tdsc->done = 0;
4291                 tdsc->inprog = 0;
4292                 tdsc->err = 0;
4293                 ret = EIO;
4294                 if (nfs_pnfsiothreads != 0) {
4295                         ret = nfs_pnfsio(start_dscreate, tdsc);
4296                         NFSD_DEBUG(4, "nfsrv_pnfscreate: nfs_pnfsio=%d\n", ret);
4297                 }
4298                 if (ret != 0) {
4299                         ret = nfsrv_dscreate(dvp[i], vap, &va, &fh, tpf, NULL,
4300                             NULL, tcred, p, NULL);
4301                         if (ret != 0) {
4302                                 KASSERT(error == 0, ("nfsrv_dscreate err=%d",
4303                                     error));
4304                                 if (failpos == -1 && nfsds_failerr(ret))
4305                                         failpos = i;
4306                                 else
4307                                         error = ret;
4308                         }
4309                 }
4310         }
4311         if (error == 0) {
4312                 tpf->dsf_dir = dsdir[mirrorcnt - 1];
4313                 error = nfsrv_dscreate(dvp[mirrorcnt - 1], vap, &va, &fh, tpf,
4314                     &dsattr, NULL, tcred, p, NULL);
4315                 if (failpos == -1 && mirrorcnt > 1 && nfsds_failerr(error)) {
4316                         failpos = mirrorcnt - 1;
4317                         error = 0;
4318                 }
4319         }
4320         timo = hz / 50;         /* Wait for 20msec. */
4321         if (timo < 1)
4322                 timo = 1;
4323         /* Wait for kernel task(s) to complete. */
4324         for (tdsc = dsc, i = 0; i < mirrorcnt - 1; i++, tdsc++) {
4325                 while (tdsc->inprog != 0 && tdsc->done == 0)
4326                         tsleep(&tdsc->tsk, PVFS, "srvdcr", timo);
4327                 if (tdsc->err != 0) {
4328                         if (failpos == -1 && nfsds_failerr(tdsc->err))
4329                                 failpos = i;
4330                         else if (error == 0)
4331                                 error = tdsc->err;
4332                 }
4333         }
4334
4335         /*
4336          * If failpos has been set, that mirror has failed, so it needs
4337          * to be disabled.
4338          */
4339         if (failpos >= 0) {
4340                 nmp = VFSTONFS(dvp[failpos]->v_mount);
4341                 NFSLOCKMNT(nmp);
4342                 if ((nmp->nm_privflag & (NFSMNTP_FORCEDISM |
4343                      NFSMNTP_CANCELRPCS)) == 0) {
4344                         nmp->nm_privflag |= NFSMNTP_CANCELRPCS;
4345                         NFSUNLOCKMNT(nmp);
4346                         ds = nfsrv_deldsnmp(PNFSDOP_DELDSSERVER, nmp, p);
4347                         NFSD_DEBUG(4, "dscreatfail fail=%d ds=%p\n", failpos,
4348                             ds);
4349                         if (ds != NULL)
4350                                 nfsrv_killrpcs(nmp);
4351                         NFSLOCKMNT(nmp);
4352                         nmp->nm_privflag &= ~NFSMNTP_CANCELRPCS;
4353                         wakeup(nmp);
4354                 }
4355                 NFSUNLOCKMNT(nmp);
4356         }
4357
4358         NFSFREECRED(tcred);
4359         if (error == 0) {
4360                 ASSERT_VOP_ELOCKED(vp, "nfsrv_pnfscreate vp");
4361
4362                 NFSD_DEBUG(4, "nfsrv_pnfscreate: mirrorcnt=%d maxmirror=%d\n",
4363                     mirrorcnt, nfsrv_maxpnfsmirror);
4364                 /*
4365                  * For all mirrors that couldn't be created, fill in the
4366                  * *pf structure, but with an IP address == 0.0.0.0.
4367                  */
4368                 tpf = pf + mirrorcnt;
4369                 for (i = mirrorcnt; i < nfsrv_maxpnfsmirror; i++, tpf++) {
4370                         *tpf = *pf;
4371                         tpf->dsf_sin.sin_family = AF_INET;
4372                         tpf->dsf_sin.sin_len = sizeof(struct sockaddr_in);
4373                         tpf->dsf_sin.sin_addr.s_addr = 0;
4374                         tpf->dsf_sin.sin_port = 0;
4375                 }
4376
4377                 error = vn_extattr_set(vp, IO_NODELOCKED,
4378                     EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile",
4379                     sizeof(*pf) * nfsrv_maxpnfsmirror, (char *)pf, p);
4380                 if (error == 0)
4381                         error = vn_extattr_set(vp, IO_NODELOCKED,
4382                             EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsattr",
4383                             sizeof(dsattr), (char *)&dsattr, p);
4384                 if (error != 0)
4385                         printf("pNFS: pnfscreate setextattr=%d\n",
4386                             error);
4387         } else
4388                 printf("pNFS: pnfscreate=%d\n", error);
4389         free(pf, M_TEMP);
4390         free(dsc, M_TEMP);
4391 }
4392
4393 /*
4394  * Get the information needed to remove the pNFS Data Server file from the
4395  * Metadata file.  Upon success, ddvp is set non-NULL to the locked
4396  * DS directory vnode.  The caller must unlock *ddvp when done with it.
4397  */
4398 static void
4399 nfsrv_pnfsremovesetup(struct vnode *vp, NFSPROC_T *p, struct vnode **dvpp,
4400     int *mirrorcntp, char *fname, fhandle_t *fhp)
4401 {
4402         struct vattr va;
4403         struct ucred *tcred;
4404         char *buf;
4405         int buflen, error;
4406
4407         dvpp[0] = NULL;
4408         /* If not an exported regular file or not a pNFS server, just return. */
4409         if (vp->v_type != VREG || (vp->v_mount->mnt_flag & MNT_EXPORTED) == 0 ||
4410             nfsrv_devidcnt == 0)
4411                 return;
4412
4413         /* Check to see if this is the last hard link. */
4414         tcred = newnfs_getcred();
4415         error = VOP_GETATTR(vp, &va, tcred);
4416         NFSFREECRED(tcred);
4417         if (error != 0) {
4418                 printf("pNFS: nfsrv_pnfsremovesetup getattr=%d\n", error);
4419                 return;
4420         }
4421         if (va.va_nlink > 1)
4422                 return;
4423
4424         error = nfsvno_getfh(vp, fhp, p);
4425         if (error != 0) {
4426                 printf("pNFS: nfsrv_pnfsremovesetup getfh=%d\n", error);
4427                 return;
4428         }
4429
4430         buflen = 1024;
4431         buf = malloc(buflen, M_TEMP, M_WAITOK);
4432         /* Get the directory vnode for the DS mount and the file handle. */
4433         error = nfsrv_dsgetsockmnt(vp, 0, buf, &buflen, mirrorcntp, p, dvpp,
4434             NULL, NULL, fname, NULL, NULL, NULL, NULL, NULL);
4435         free(buf, M_TEMP);
4436         if (error != 0)
4437                 printf("pNFS: nfsrv_pnfsremovesetup getsockmnt=%d\n", error);
4438 }
4439
4440 /*
4441  * Remove a DS data file for nfsrv_pnfsremove(). Called for each mirror.
4442  * The arguments are in a structure, so that they can be passed through
4443  * taskqueue for a kernel process to execute this function.
4444  */
4445 struct nfsrvdsremove {
4446         int                     done;
4447         int                     inprog;
4448         struct task             tsk;
4449         struct ucred            *tcred;
4450         struct vnode            *dvp;
4451         NFSPROC_T               *p;
4452         int                     err;
4453         char                    fname[PNFS_FILENAME_LEN + 1];
4454 };
4455
4456 static int
4457 nfsrv_dsremove(struct vnode *dvp, char *fname, struct ucred *tcred,
4458     NFSPROC_T *p)
4459 {
4460         struct nameidata named;
4461         struct vnode *nvp;
4462         char *bufp;
4463         u_long *hashp;
4464         int error;
4465
4466         error = NFSVOPLOCK(dvp, LK_EXCLUSIVE);
4467         if (error != 0)
4468                 return (error);
4469         named.ni_cnd.cn_nameiop = DELETE;
4470         named.ni_cnd.cn_lkflags = LK_EXCLUSIVE | LK_RETRY;
4471         named.ni_cnd.cn_cred = tcred;
4472         named.ni_cnd.cn_thread = p;
4473         named.ni_cnd.cn_flags = ISLASTCN | LOCKPARENT | LOCKLEAF | SAVENAME;
4474         nfsvno_setpathbuf(&named, &bufp, &hashp);
4475         named.ni_cnd.cn_nameptr = bufp;
4476         named.ni_cnd.cn_namelen = strlen(fname);
4477         strlcpy(bufp, fname, NAME_MAX);
4478         NFSD_DEBUG(4, "nfsrv_pnfsremove: filename=%s\n", bufp);
4479         error = VOP_LOOKUP(dvp, &nvp, &named.ni_cnd);
4480         NFSD_DEBUG(4, "nfsrv_pnfsremove: aft LOOKUP=%d\n", error);
4481         if (error == 0) {
4482                 error = VOP_REMOVE(dvp, nvp, &named.ni_cnd);
4483                 vput(nvp);
4484         }
4485         NFSVOPUNLOCK(dvp);
4486         nfsvno_relpathbuf(&named);
4487         if (error != 0)
4488                 printf("pNFS: nfsrv_pnfsremove failed=%d\n", error);
4489         return (error);
4490 }
4491
4492 /*
4493  * Start up the thread that will execute nfsrv_dsremove().
4494  */
4495 static void
4496 start_dsremove(void *arg, int pending)
4497 {
4498         struct nfsrvdsremove *dsrm;
4499
4500         dsrm = (struct nfsrvdsremove *)arg;
4501         dsrm->err = nfsrv_dsremove(dsrm->dvp, dsrm->fname, dsrm->tcred,
4502             dsrm->p);
4503         dsrm->done = 1;
4504         NFSD_DEBUG(4, "start_dsremove: err=%d\n", dsrm->err);
4505 }
4506
4507 /*
4508  * Remove a pNFS data file from a Data Server.
4509  * nfsrv_pnfsremovesetup() must have been called before the MDS file was
4510  * removed to set up the dvp and fill in the FH.
4511  */
4512 static void
4513 nfsrv_pnfsremove(struct vnode **dvp, int mirrorcnt, char *fname, fhandle_t *fhp,
4514     NFSPROC_T *p)
4515 {
4516         struct ucred *tcred;
4517         struct nfsrvdsremove *dsrm, *tdsrm;
4518         struct nfsdevice *ds;
4519         struct nfsmount *nmp;
4520         int failpos, i, ret, timo;
4521
4522         tcred = newnfs_getcred();
4523         dsrm = NULL;
4524         if (mirrorcnt > 1)
4525                 dsrm = malloc(sizeof(*dsrm) * mirrorcnt - 1, M_TEMP, M_WAITOK);
4526         /*
4527          * Remove the file on each DS mirror, using kernel process(es) for the
4528          * additional mirrors.
4529          */
4530         failpos = -1;
4531         for (tdsrm = dsrm, i = 0; i < mirrorcnt - 1; i++, tdsrm++) {
4532                 tdsrm->tcred = tcred;
4533                 tdsrm->p = p;
4534                 tdsrm->dvp = dvp[i];
4535                 strlcpy(tdsrm->fname, fname, PNFS_FILENAME_LEN + 1);
4536                 tdsrm->inprog = 0;
4537                 tdsrm->done = 0;
4538                 tdsrm->err = 0;
4539                 ret = EIO;
4540                 if (nfs_pnfsiothreads != 0) {
4541                         ret = nfs_pnfsio(start_dsremove, tdsrm);
4542                         NFSD_DEBUG(4, "nfsrv_pnfsremove: nfs_pnfsio=%d\n", ret);
4543                 }
4544                 if (ret != 0) {
4545                         ret = nfsrv_dsremove(dvp[i], fname, tcred, p);
4546                         if (failpos == -1 && nfsds_failerr(ret))
4547                                 failpos = i;
4548                 }
4549         }
4550         ret = nfsrv_dsremove(dvp[mirrorcnt - 1], fname, tcred, p);
4551         if (failpos == -1 && mirrorcnt > 1 && nfsds_failerr(ret))
4552                 failpos = mirrorcnt - 1;
4553         timo = hz / 50;         /* Wait for 20msec. */
4554         if (timo < 1)
4555                 timo = 1;
4556         /* Wait for kernel task(s) to complete. */
4557         for (tdsrm = dsrm, i = 0; i < mirrorcnt - 1; i++, tdsrm++) {
4558                 while (tdsrm->inprog != 0 && tdsrm->done == 0)
4559                         tsleep(&tdsrm->tsk, PVFS, "srvdsrm", timo);
4560                 if (failpos == -1 && nfsds_failerr(tdsrm->err))
4561                         failpos = i;
4562         }
4563
4564         /*
4565          * If failpos has been set, that mirror has failed, so it needs
4566          * to be disabled.
4567          */
4568         if (failpos >= 0) {
4569                 nmp = VFSTONFS(dvp[failpos]->v_mount);
4570                 NFSLOCKMNT(nmp);
4571                 if ((nmp->nm_privflag & (NFSMNTP_FORCEDISM |
4572                      NFSMNTP_CANCELRPCS)) == 0) {
4573                         nmp->nm_privflag |= NFSMNTP_CANCELRPCS;
4574                         NFSUNLOCKMNT(nmp);
4575                         ds = nfsrv_deldsnmp(PNFSDOP_DELDSSERVER, nmp, p);
4576                         NFSD_DEBUG(4, "dsremovefail fail=%d ds=%p\n", failpos,
4577                             ds);
4578                         if (ds != NULL)
4579                                 nfsrv_killrpcs(nmp);
4580                         NFSLOCKMNT(nmp);
4581                         nmp->nm_privflag &= ~NFSMNTP_CANCELRPCS;
4582                         wakeup(nmp);
4583                 }
4584                 NFSUNLOCKMNT(nmp);
4585         }
4586
4587         /* Get rid all layouts for the file. */
4588         nfsrv_freefilelayouts(fhp);
4589
4590         NFSFREECRED(tcred);
4591         free(dsrm, M_TEMP);
4592 }
4593
4594 /*
4595  * Generate a file name based on the file handle and put it in *bufp.
4596  * Return the number of bytes generated.
4597  */
4598 static int
4599 nfsrv_putfhname(fhandle_t *fhp, char *bufp)
4600 {
4601         int i;
4602         uint8_t *cp;
4603         const uint8_t *hexdigits = "0123456789abcdef";
4604
4605         cp = (uint8_t *)fhp;
4606         for (i = 0; i < sizeof(*fhp); i++) {
4607                 bufp[2 * i] = hexdigits[(*cp >> 4) & 0xf];
4608                 bufp[2 * i + 1] = hexdigits[*cp++ & 0xf];
4609         }
4610         bufp[2 * i] = '\0';
4611         return (2 * i);
4612 }
4613
4614 /*
4615  * Update the Metadata file's attributes from the DS file when a Read/Write
4616  * layout is returned.
4617  * Basically just call nfsrv_proxyds() with procedure == NFSPROC_LAYOUTRETURN
4618  * so that it does a nfsrv_getattrdsrpc() and nfsrv_setextattr() on the DS file.
4619  */
4620 int
4621 nfsrv_updatemdsattr(struct vnode *vp, struct nfsvattr *nap, NFSPROC_T *p)
4622 {
4623         struct ucred *tcred;
4624         int error;
4625
4626         /* Do this as root so that it won't fail with EACCES. */
4627         tcred = newnfs_getcred();
4628         error = nfsrv_proxyds(vp, 0, 0, tcred, p, NFSPROC_LAYOUTRETURN,
4629             NULL, NULL, NULL, nap, NULL, NULL, 0, NULL);
4630         NFSFREECRED(tcred);
4631         return (error);
4632 }
4633
4634 /*
4635  * Set the NFSv4 ACL on the DS file to the same ACL as the MDS file.
4636  */
4637 static int
4638 nfsrv_dssetacl(struct vnode *vp, struct acl *aclp, struct ucred *cred,
4639     NFSPROC_T *p)
4640 {
4641         int error;
4642
4643         error = nfsrv_proxyds(vp, 0, 0, cred, p, NFSPROC_SETACL,
4644             NULL, NULL, NULL, NULL, aclp, NULL, 0, NULL);
4645         return (error);
4646 }
4647
4648 static int
4649 nfsrv_proxyds(struct vnode *vp, off_t off, int cnt, struct ucred *cred,
4650     struct thread *p, int ioproc, struct mbuf **mpp, char *cp,
4651     struct mbuf **mpp2, struct nfsvattr *nap, struct acl *aclp,
4652     off_t *offp, int content, bool *eofp)
4653 {
4654         struct nfsmount *nmp[NFSDEV_MAXMIRRORS], *failnmp;
4655         fhandle_t fh[NFSDEV_MAXMIRRORS];
4656         struct vnode *dvp[NFSDEV_MAXMIRRORS];
4657         struct nfsdevice *ds;
4658         struct pnfsdsattr dsattr;
4659         struct opnfsdsattr odsattr;
4660         char *buf;
4661         int buflen, error, failpos, i, mirrorcnt, origmircnt, trycnt;
4662
4663         NFSD_DEBUG(4, "in nfsrv_proxyds\n");
4664         /*
4665          * If not a regular file, not exported or not a pNFS server,
4666          * just return ENOENT.
4667          */
4668         if (vp->v_type != VREG || (vp->v_mount->mnt_flag & MNT_EXPORTED) == 0 ||
4669             nfsrv_devidcnt == 0)
4670                 return (ENOENT);
4671
4672         buflen = 1024;
4673         buf = malloc(buflen, M_TEMP, M_WAITOK);
4674         error = 0;
4675
4676         /*
4677          * For Getattr, get the Change attribute (va_filerev) and size (va_size)
4678          * from the MetaData file's extended attribute.
4679          */
4680         if (ioproc == NFSPROC_GETATTR) {
4681                 error = vn_extattr_get(vp, IO_NODELOCKED,
4682                     EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsattr", &buflen, buf,
4683                     p);
4684                 if (error == 0) {
4685                         if (buflen == sizeof(odsattr)) {
4686                                 NFSBCOPY(buf, &odsattr, buflen);
4687                                 nap->na_filerev = odsattr.dsa_filerev;
4688                                 nap->na_size = odsattr.dsa_size;
4689                                 nap->na_atime = odsattr.dsa_atime;
4690                                 nap->na_mtime = odsattr.dsa_mtime;
4691                                 /*
4692                                  * Fake na_bytes by rounding up na_size.
4693                                  * Since we don't know the block size, just
4694                                  * use BLKDEV_IOSIZE.
4695                                  */
4696                                 nap->na_bytes = (odsattr.dsa_size +
4697                                     BLKDEV_IOSIZE - 1) & ~(BLKDEV_IOSIZE - 1);
4698                         } else if (buflen == sizeof(dsattr)) {
4699                                 NFSBCOPY(buf, &dsattr, buflen);
4700                                 nap->na_filerev = dsattr.dsa_filerev;
4701                                 nap->na_size = dsattr.dsa_size;
4702                                 nap->na_atime = dsattr.dsa_atime;
4703                                 nap->na_mtime = dsattr.dsa_mtime;
4704                                 nap->na_bytes = dsattr.dsa_bytes;
4705                         } else
4706                                 error = ENXIO;
4707                 }
4708                 if (error == 0) {
4709                         /*
4710                          * If nfsrv_pnfsgetdsattr is 0 or nfsrv_checkdsattr()
4711                          * returns 0, just return now.  nfsrv_checkdsattr()
4712                          * returns 0 if there is no Read/Write layout
4713                          * plus either an Open/Write_access or Write
4714                          * delegation issued to a client for the file.
4715                          */
4716                         if (nfsrv_pnfsgetdsattr == 0 ||
4717                             nfsrv_checkdsattr(vp, p) == 0) {
4718                                 free(buf, M_TEMP);
4719                                 return (error);
4720                         }
4721                 }
4722
4723                 /*
4724                  * Clear ENOATTR so the code below will attempt to do a
4725                  * nfsrv_getattrdsrpc() to get the attributes and (re)create
4726                  * the extended attribute.
4727                  */
4728                 if (error == ENOATTR)
4729                         error = 0;
4730         }
4731
4732         origmircnt = -1;
4733         trycnt = 0;
4734 tryagain:
4735         if (error == 0) {
4736                 buflen = 1024;
4737                 if (ioproc == NFSPROC_READDS && NFSVOPISLOCKED(vp) ==
4738                     LK_EXCLUSIVE)
4739                         printf("nfsrv_proxyds: Readds vp exclusively locked\n");
4740                 error = nfsrv_dsgetsockmnt(vp, LK_SHARED, buf, &buflen,
4741                     &mirrorcnt, p, dvp, fh, NULL, NULL, NULL, NULL, NULL,
4742                     NULL, NULL);
4743                 if (error == 0) {
4744                         for (i = 0; i < mirrorcnt; i++)
4745                                 nmp[i] = VFSTONFS(dvp[i]->v_mount);
4746                 } else
4747                         printf("pNFS: proxy getextattr sockaddr=%d\n", error);
4748         } else
4749                 printf("pNFS: nfsrv_dsgetsockmnt=%d\n", error);
4750         if (error == 0) {
4751                 failpos = -1;
4752                 if (origmircnt == -1)
4753                         origmircnt = mirrorcnt;
4754                 /*
4755                  * If failpos is set to a mirror#, then that mirror has
4756                  * failed and will be disabled. For Read, Getattr and Seek, the
4757                  * function only tries one mirror, so if that mirror has
4758                  * failed, it will need to be retried. As such, increment
4759                  * tryitagain for these cases.
4760                  * For Write, Setattr and Setacl, the function tries all
4761                  * mirrors and will not return an error for the case where
4762                  * one mirror has failed. For these cases, the functioning
4763                  * mirror(s) will have been modified, so a retry isn't
4764                  * necessary. These functions will set failpos for the
4765                  * failed mirror#.
4766                  */
4767                 if (ioproc == NFSPROC_READDS) {
4768                         error = nfsrv_readdsrpc(fh, off, cnt, cred, p, nmp[0],
4769                             mpp, mpp2);
4770                         if (nfsds_failerr(error) && mirrorcnt > 1) {
4771                                 /*
4772                                  * Setting failpos will cause the mirror
4773                                  * to be disabled and then a retry of this
4774                                  * read is required.
4775                                  */
4776                                 failpos = 0;
4777                                 error = 0;
4778                                 trycnt++;
4779                         }
4780                 } else if (ioproc == NFSPROC_WRITEDS)
4781                         error = nfsrv_writedsrpc(fh, off, cnt, cred, p, vp,
4782                             &nmp[0], mirrorcnt, mpp, cp, &failpos);
4783                 else if (ioproc == NFSPROC_SETATTR)
4784                         error = nfsrv_setattrdsrpc(fh, cred, p, vp, &nmp[0],
4785                             mirrorcnt, nap, &failpos);
4786                 else if (ioproc == NFSPROC_SETACL)
4787                         error = nfsrv_setacldsrpc(fh, cred, p, vp, &nmp[0],
4788                             mirrorcnt, aclp, &failpos);
4789                 else if (ioproc == NFSPROC_SEEKDS) {
4790                         error = nfsrv_seekdsrpc(fh, offp, content, eofp, cred,
4791                             p, nmp[0]);
4792                         if (nfsds_failerr(error) && mirrorcnt > 1) {
4793                                 /*
4794                                  * Setting failpos will cause the mirror
4795                                  * to be disabled and then a retry of this
4796                                  * read is required.
4797                                  */
4798                                 failpos = 0;
4799                                 error = 0;
4800                                 trycnt++;
4801                         }
4802                 } else if (ioproc == NFSPROC_ALLOCATE)
4803                         error = nfsrv_allocatedsrpc(fh, off, *offp, cred, p, vp,
4804                             &nmp[0], mirrorcnt, &failpos);
4805                 else {
4806                         error = nfsrv_getattrdsrpc(&fh[mirrorcnt - 1], cred, p,
4807                             vp, nmp[mirrorcnt - 1], nap);
4808                         if (nfsds_failerr(error) && mirrorcnt > 1) {
4809                                 /*
4810                                  * Setting failpos will cause the mirror
4811                                  * to be disabled and then a retry of this
4812                                  * getattr is required.
4813                                  */
4814                                 failpos = mirrorcnt - 1;
4815                                 error = 0;
4816                                 trycnt++;
4817                         }
4818                 }
4819                 ds = NULL;
4820                 if (failpos >= 0) {
4821                         failnmp = nmp[failpos];
4822                         NFSLOCKMNT(failnmp);
4823                         if ((failnmp->nm_privflag & (NFSMNTP_FORCEDISM |
4824                              NFSMNTP_CANCELRPCS)) == 0) {
4825                                 failnmp->nm_privflag |= NFSMNTP_CANCELRPCS;
4826                                 NFSUNLOCKMNT(failnmp);
4827                                 ds = nfsrv_deldsnmp(PNFSDOP_DELDSSERVER,
4828                                     failnmp, p);
4829                                 NFSD_DEBUG(4, "dsldsnmp fail=%d ds=%p\n",
4830                                     failpos, ds);
4831                                 if (ds != NULL)
4832                                         nfsrv_killrpcs(failnmp);
4833                                 NFSLOCKMNT(failnmp);
4834                                 failnmp->nm_privflag &= ~NFSMNTP_CANCELRPCS;
4835                                 wakeup(failnmp);
4836                         }
4837                         NFSUNLOCKMNT(failnmp);
4838                 }
4839                 for (i = 0; i < mirrorcnt; i++)
4840                         NFSVOPUNLOCK(dvp[i]);
4841                 NFSD_DEBUG(4, "nfsrv_proxyds: aft RPC=%d trya=%d\n", error,
4842                     trycnt);
4843                 /* Try the Read/Getattr again if a mirror was deleted. */
4844                 if (ds != NULL && trycnt > 0 && trycnt < origmircnt)
4845                         goto tryagain;
4846         } else {
4847                 /* Return ENOENT for any Extended Attribute error. */
4848                 error = ENOENT;
4849         }
4850         free(buf, M_TEMP);
4851         NFSD_DEBUG(4, "nfsrv_proxyds: error=%d\n", error);
4852         return (error);
4853 }
4854
4855 /*
4856  * Get the DS mount point, fh and directory from the "pnfsd.dsfile" extended
4857  * attribute.
4858  * newnmpp - If it points to a non-NULL nmp, that is the destination and needs
4859  *           to be checked.  If it points to a NULL nmp, then it returns
4860  *           a suitable destination.
4861  * curnmp - If non-NULL, it is the source mount for the copy.
4862  */
4863 int
4864 nfsrv_dsgetsockmnt(struct vnode *vp, int lktype, char *buf, int *buflenp,
4865     int *mirrorcntp, NFSPROC_T *p, struct vnode **dvpp, fhandle_t *fhp,
4866     char *devid, char *fnamep, struct vnode **nvpp, struct nfsmount **newnmpp,
4867     struct nfsmount *curnmp, int *ippos, int *dsdirp)
4868 {
4869         struct vnode *dvp, *nvp = NULL, **tdvpp;
4870         struct mount *mp;
4871         struct nfsmount *nmp, *newnmp;
4872         struct sockaddr *sad;
4873         struct sockaddr_in *sin;
4874         struct nfsdevice *ds, *tds, *fndds;
4875         struct pnfsdsfile *pf;
4876         uint32_t dsdir;
4877         int error, fhiszero, fnd, gotone, i, mirrorcnt;
4878
4879         ASSERT_VOP_LOCKED(vp, "nfsrv_dsgetsockmnt vp");
4880         *mirrorcntp = 1;
4881         tdvpp = dvpp;
4882         if (nvpp != NULL)
4883                 *nvpp = NULL;
4884         if (dvpp != NULL)
4885                 *dvpp = NULL;
4886         if (ippos != NULL)
4887                 *ippos = -1;
4888         if (newnmpp != NULL)
4889                 newnmp = *newnmpp;
4890         else
4891                 newnmp = NULL;
4892         mp = vp->v_mount;
4893         error = vn_extattr_get(vp, IO_NODELOCKED, EXTATTR_NAMESPACE_SYSTEM,
4894             "pnfsd.dsfile", buflenp, buf, p);
4895         mirrorcnt = *buflenp / sizeof(*pf);
4896         if (error == 0 && (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS ||
4897             *buflenp != sizeof(*pf) * mirrorcnt))
4898                 error = ENOATTR;
4899
4900         pf = (struct pnfsdsfile *)buf;
4901         /* If curnmp != NULL, check for a match in the mirror list. */
4902         if (curnmp != NULL && error == 0) {
4903                 fnd = 0;
4904                 for (i = 0; i < mirrorcnt; i++, pf++) {
4905                         sad = (struct sockaddr *)&pf->dsf_sin;
4906                         if (nfsaddr2_match(sad, curnmp->nm_nam)) {
4907                                 if (ippos != NULL)
4908                                         *ippos = i;
4909                                 fnd = 1;
4910                                 break;
4911                         }
4912                 }
4913                 if (fnd == 0)
4914                         error = ENXIO;
4915         }
4916
4917         gotone = 0;
4918         pf = (struct pnfsdsfile *)buf;
4919         NFSD_DEBUG(4, "nfsrv_dsgetsockmnt: mirrorcnt=%d err=%d\n", mirrorcnt,
4920             error);
4921         for (i = 0; i < mirrorcnt && error == 0; i++, pf++) {
4922                 fhiszero = 0;
4923                 sad = (struct sockaddr *)&pf->dsf_sin;
4924                 sin = &pf->dsf_sin;
4925                 dsdir = pf->dsf_dir;
4926                 if (dsdir >= nfsrv_dsdirsize) {
4927                         printf("nfsrv_dsgetsockmnt: dsdir=%d\n", dsdir);
4928                         error = ENOATTR;
4929                 } else if (nvpp != NULL && newnmp != NULL &&
4930                     nfsaddr2_match(sad, newnmp->nm_nam))
4931                         error = EEXIST;
4932                 if (error == 0) {
4933                         if (ippos != NULL && curnmp == NULL &&
4934                             sad->sa_family == AF_INET &&
4935                             sin->sin_addr.s_addr == 0)
4936                                 *ippos = i;
4937                         if (NFSBCMP(&zerofh, &pf->dsf_fh, sizeof(zerofh)) == 0)
4938                                 fhiszero = 1;
4939                         /* Use the socket address to find the mount point. */
4940                         fndds = NULL;
4941                         NFSDDSLOCK();
4942                         /* Find a match for the IP address. */
4943                         TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4944                                 if (ds->nfsdev_nmp != NULL) {
4945                                         dvp = ds->nfsdev_dvp;
4946                                         nmp = VFSTONFS(dvp->v_mount);
4947                                         if (nmp != ds->nfsdev_nmp)
4948                                                 printf("different2 nmp %p %p\n",
4949                                                     nmp, ds->nfsdev_nmp);
4950                                         if (nfsaddr2_match(sad, nmp->nm_nam)) {
4951                                                 fndds = ds;
4952                                                 break;
4953                                         }
4954                                 }
4955                         }
4956                         if (fndds != NULL && newnmpp != NULL &&
4957                             newnmp == NULL) {
4958                                 /* Search for a place to make a mirror copy. */
4959                                 TAILQ_FOREACH(tds, &nfsrv_devidhead,
4960                                     nfsdev_list) {
4961                                         if (tds->nfsdev_nmp != NULL &&
4962                                             fndds != tds &&
4963                                             ((tds->nfsdev_mdsisset == 0 &&
4964                                               fndds->nfsdev_mdsisset == 0) ||
4965                                              (tds->nfsdev_mdsisset != 0 &&
4966                                               fndds->nfsdev_mdsisset != 0 &&
4967                                               fsidcmp(&tds->nfsdev_mdsfsid,
4968                                               &mp->mnt_stat.f_fsid) == 0))) {
4969                                                 *newnmpp = tds->nfsdev_nmp;
4970                                                 break;
4971                                         }
4972                                 }
4973                                 if (tds != NULL) {
4974                                         /*
4975                                          * Move this entry to the end of the
4976                                          * list, so it won't be selected as
4977                                          * easily the next time.
4978                                          */
4979                                         TAILQ_REMOVE(&nfsrv_devidhead, tds,
4980                                             nfsdev_list);
4981                                         TAILQ_INSERT_TAIL(&nfsrv_devidhead, tds,
4982                                             nfsdev_list);
4983                                 }
4984                         }
4985                         NFSDDSUNLOCK();
4986                         if (fndds != NULL) {
4987                                 dvp = fndds->nfsdev_dsdir[dsdir];
4988                                 if (lktype != 0 || fhiszero != 0 ||
4989                                     (nvpp != NULL && *nvpp == NULL)) {
4990                                         if (fhiszero != 0)
4991                                                 error = vn_lock(dvp,
4992                                                     LK_EXCLUSIVE);
4993                                         else if (lktype != 0)
4994                                                 error = vn_lock(dvp, lktype);
4995                                         else
4996                                                 error = vn_lock(dvp, LK_SHARED);
4997                                         /*
4998                                          * If the file handle is all 0's, try to
4999                                          * do a Lookup against the DS to acquire
5000                                          * it.
5001                                          * If dvpp == NULL or the Lookup fails,
5002                                          * unlock dvp after the call.
5003                                          */
5004                                         if (error == 0 && (fhiszero != 0 ||
5005                                             (nvpp != NULL && *nvpp == NULL))) {
5006                                                 error = nfsrv_pnfslookupds(vp,
5007                                                     dvp, pf, &nvp, p);
5008                                                 if (error == 0) {
5009                                                         if (fhiszero != 0)
5010                                                                 nfsrv_pnfssetfh(
5011                                                                     vp, pf,
5012                                                                     devid,
5013                                                                     fnamep,
5014                                                                     nvp, p);
5015                                                         if (nvpp != NULL &&
5016                                                             *nvpp == NULL) {
5017                                                                 *nvpp = nvp;
5018                                                                 *dsdirp = dsdir;
5019                                                         } else
5020                                                                 vput(nvp);
5021                                                 }
5022                                                 if (error != 0 || lktype == 0)
5023                                                         NFSVOPUNLOCK(dvp);
5024                                         }
5025                                 }
5026                                 if (error == 0) {
5027                                         gotone++;
5028                                         NFSD_DEBUG(4, "gotone=%d\n", gotone);
5029                                         if (devid != NULL) {
5030                                                 NFSBCOPY(fndds->nfsdev_deviceid,
5031                                                     devid, NFSX_V4DEVICEID);
5032                                                 devid += NFSX_V4DEVICEID;
5033                                         }
5034                                         if (dvpp != NULL)
5035                                                 *tdvpp++ = dvp;
5036                                         if (fhp != NULL)
5037                                                 NFSBCOPY(&pf->dsf_fh, fhp++,
5038                                                     NFSX_MYFH);
5039                                         if (fnamep != NULL && gotone == 1)
5040                                                 strlcpy(fnamep,
5041                                                     pf->dsf_filename,
5042                                                     sizeof(pf->dsf_filename));
5043                                 } else
5044                                         NFSD_DEBUG(4, "nfsrv_dsgetsockmnt "
5045                                             "err=%d\n", error);
5046                         }
5047                 }
5048         }
5049         if (error == 0 && gotone == 0)
5050                 error = ENOENT;
5051
5052         NFSD_DEBUG(4, "eo nfsrv_dsgetsockmnt: gotone=%d err=%d\n", gotone,
5053             error);
5054         if (error == 0)
5055                 *mirrorcntp = gotone;
5056         else {
5057                 if (gotone > 0 && dvpp != NULL) {
5058                         /*
5059                          * If the error didn't occur on the first one and
5060                          * dvpp != NULL, the one(s) prior to the failure will
5061                          * have locked dvp's that need to be unlocked.
5062                          */
5063                         for (i = 0; i < gotone; i++) {
5064                                 NFSVOPUNLOCK(*dvpp);
5065                                 *dvpp++ = NULL;
5066                         }
5067                 }
5068                 /*
5069                  * If it found the vnode to be copied from before a failure,
5070                  * it needs to be vput()'d.
5071                  */
5072                 if (nvpp != NULL && *nvpp != NULL) {
5073                         vput(*nvpp);
5074                         *nvpp = NULL;
5075                 }
5076         }
5077         return (error);
5078 }
5079
5080 /*
5081  * Set the extended attribute for the Change attribute.
5082  */
5083 static int
5084 nfsrv_setextattr(struct vnode *vp, struct nfsvattr *nap, NFSPROC_T *p)
5085 {
5086         struct pnfsdsattr dsattr;
5087         int error;
5088
5089         ASSERT_VOP_ELOCKED(vp, "nfsrv_setextattr vp");
5090         dsattr.dsa_filerev = nap->na_filerev;
5091         dsattr.dsa_size = nap->na_size;
5092         dsattr.dsa_atime = nap->na_atime;
5093         dsattr.dsa_mtime = nap->na_mtime;
5094         dsattr.dsa_bytes = nap->na_bytes;
5095         error = vn_extattr_set(vp, IO_NODELOCKED, EXTATTR_NAMESPACE_SYSTEM,
5096             "pnfsd.dsattr", sizeof(dsattr), (char *)&dsattr, p);
5097         if (error != 0)
5098                 printf("pNFS: setextattr=%d\n", error);
5099         return (error);
5100 }
5101
5102 static int
5103 nfsrv_readdsrpc(fhandle_t *fhp, off_t off, int len, struct ucred *cred,
5104     NFSPROC_T *p, struct nfsmount *nmp, struct mbuf **mpp, struct mbuf **mpendp)
5105 {
5106         uint32_t *tl;
5107         struct nfsrv_descript *nd;
5108         nfsv4stateid_t st;
5109         struct mbuf *m, *m2;
5110         int error = 0, retlen, tlen, trimlen;
5111
5112         NFSD_DEBUG(4, "in nfsrv_readdsrpc\n");
5113         nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO);
5114         *mpp = NULL;
5115         /*
5116          * Use a stateid where other is an alternating 01010 pattern and
5117          * seqid is 0xffffffff.  This value is not defined as special by
5118          * the RFC and is used by the FreeBSD NFS server to indicate an
5119          * MDS->DS proxy operation.
5120          */
5121         st.other[0] = 0x55555555;
5122         st.other[1] = 0x55555555;
5123         st.other[2] = 0x55555555;
5124         st.seqid = 0xffffffff;
5125         nfscl_reqstart(nd, NFSPROC_READDS, nmp, (u_int8_t *)fhp, sizeof(*fhp),
5126             NULL, NULL, 0, 0);
5127         nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID);
5128         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
5129         txdr_hyper(off, tl);
5130         *(tl + 2) = txdr_unsigned(len);
5131         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5132             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5133         if (error != 0) {
5134                 free(nd, M_TEMP);
5135                 return (error);
5136         }
5137         if (nd->nd_repstat == 0) {
5138                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
5139                 NFSM_STRSIZ(retlen, len);
5140                 if (retlen > 0) {
5141                         /* Trim off the pre-data XDR from the mbuf chain. */
5142                         m = nd->nd_mrep;
5143                         while (m != NULL && m != nd->nd_md) {
5144                                 if (m->m_next == nd->nd_md) {
5145                                         m->m_next = NULL;
5146                                         m_freem(nd->nd_mrep);
5147                                         nd->nd_mrep = m = nd->nd_md;
5148                                 } else
5149                                         m = m->m_next;
5150                         }
5151                         if (m == NULL) {
5152                                 printf("nfsrv_readdsrpc: busted mbuf list\n");
5153                                 error = ENOENT;
5154                                 goto nfsmout;
5155                         }
5156
5157                         /*
5158                          * Now, adjust first mbuf so that any XDR before the
5159                          * read data is skipped over.
5160                          */
5161                         trimlen = nd->nd_dpos - mtod(m, char *);
5162                         if (trimlen > 0) {
5163                                 m->m_len -= trimlen;
5164                                 NFSM_DATAP(m, trimlen);
5165                         }
5166
5167                         /*
5168                          * Truncate the mbuf chain at retlen bytes of data,
5169                          * plus XDR padding that brings the length up to a
5170                          * multiple of 4.
5171                          */
5172                         tlen = NFSM_RNDUP(retlen);
5173                         do {
5174                                 if (m->m_len >= tlen) {
5175                                         m->m_len = tlen;
5176                                         tlen = 0;
5177                                         m2 = m->m_next;
5178                                         m->m_next = NULL;
5179                                         m_freem(m2);
5180                                         break;
5181                                 }
5182                                 tlen -= m->m_len;
5183                                 m = m->m_next;
5184                         } while (m != NULL);
5185                         if (tlen > 0) {
5186                                 printf("nfsrv_readdsrpc: busted mbuf list\n");
5187                                 error = ENOENT;
5188                                 goto nfsmout;
5189                         }
5190                         *mpp = nd->nd_mrep;
5191                         *mpendp = m;
5192                         nd->nd_mrep = NULL;
5193                 }
5194         } else
5195                 error = nd->nd_repstat;
5196 nfsmout:
5197         /* If nd->nd_mrep is already NULL, this is a no-op. */
5198         m_freem(nd->nd_mrep);
5199         free(nd, M_TEMP);
5200         NFSD_DEBUG(4, "nfsrv_readdsrpc error=%d\n", error);
5201         return (error);
5202 }
5203
5204 /*
5205  * Do a write RPC on a DS data file, using this structure for the arguments,
5206  * so that this function can be executed by a separate kernel process.
5207  */
5208 struct nfsrvwritedsdorpc {
5209         int                     done;
5210         int                     inprog;
5211         struct task             tsk;
5212         fhandle_t               fh;
5213         off_t                   off;
5214         int                     len;
5215         struct nfsmount         *nmp;
5216         struct ucred            *cred;
5217         NFSPROC_T               *p;
5218         struct mbuf             *m;
5219         int                     err;
5220 };
5221
5222 static int
5223 nfsrv_writedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off, int len,
5224     struct nfsvattr *nap, struct mbuf *m, struct ucred *cred, NFSPROC_T *p)
5225 {
5226         uint32_t *tl;
5227         struct nfsrv_descript *nd;
5228         nfsattrbit_t attrbits;
5229         nfsv4stateid_t st;
5230         int commit, error, retlen;
5231
5232         nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO);
5233         nfscl_reqstart(nd, NFSPROC_WRITE, nmp, (u_int8_t *)fhp,
5234             sizeof(fhandle_t), NULL, NULL, 0, 0);
5235
5236         /*
5237          * Use a stateid where other is an alternating 01010 pattern and
5238          * seqid is 0xffffffff.  This value is not defined as special by
5239          * the RFC and is used by the FreeBSD NFS server to indicate an
5240          * MDS->DS proxy operation.
5241          */
5242         st.other[0] = 0x55555555;
5243         st.other[1] = 0x55555555;
5244         st.other[2] = 0x55555555;
5245         st.seqid = 0xffffffff;
5246         nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID);
5247         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
5248         txdr_hyper(off, tl);
5249         tl += 2;
5250         /*
5251          * Do all writes FileSync, since the server doesn't hold onto dirty
5252          * buffers.  Since clients should be accessing the DS servers directly
5253          * using the pNFS layouts, this just needs to work correctly as a
5254          * fallback.
5255          */
5256         *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
5257         *tl = txdr_unsigned(len);
5258         NFSD_DEBUG(4, "nfsrv_writedsdorpc: len=%d\n", len);
5259
5260         /* Put data in mbuf chain. */
5261         nd->nd_mb->m_next = m;
5262
5263         /* Set nd_mb and nd_bpos to end of data. */
5264         while (m->m_next != NULL)
5265                 m = m->m_next;
5266         nd->nd_mb = m;
5267         nfsm_set(nd, m->m_len);
5268         NFSD_DEBUG(4, "nfsrv_writedsdorpc: lastmb len=%d\n", m->m_len);
5269
5270         /* Do a Getattr for the attributes that change upon writing. */
5271         NFSZERO_ATTRBIT(&attrbits);
5272         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
5273         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5274         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESS);
5275         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
5276         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SPACEUSED);
5277         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
5278         *tl = txdr_unsigned(NFSV4OP_GETATTR);
5279         (void) nfsrv_putattrbit(nd, &attrbits);
5280         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
5281             cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5282         if (error != 0) {
5283                 free(nd, M_TEMP);
5284                 return (error);
5285         }
5286         NFSD_DEBUG(4, "nfsrv_writedsdorpc: aft writerpc=%d\n", nd->nd_repstat);
5287         /* Get rid of weak cache consistency data for now. */
5288         if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR)) ==
5289             (ND_NFSV4 | ND_V4WCCATTR)) {
5290                 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL,
5291                     NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
5292                 NFSD_DEBUG(4, "nfsrv_writedsdorpc: wcc attr=%d\n", error);
5293                 if (error != 0)
5294                         goto nfsmout;
5295                 /*
5296                  * Get rid of Op# and status for next op.
5297                  */
5298                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5299                 if (*++tl != 0)
5300                         nd->nd_flag |= ND_NOMOREDATA;
5301         }
5302         if (nd->nd_repstat == 0) {
5303                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
5304                 retlen = fxdr_unsigned(int, *tl++);
5305                 commit = fxdr_unsigned(int, *tl);
5306                 if (commit != NFSWRITE_FILESYNC)
5307                         error = NFSERR_IO;
5308                 NFSD_DEBUG(4, "nfsrv_writedsdorpc:retlen=%d commit=%d err=%d\n",
5309                     retlen, commit, error);
5310         } else
5311                 error = nd->nd_repstat;
5312         /* We have no use for the Write Verifier since we use FileSync. */
5313
5314         /*
5315          * Get the Change, Size, Access Time and Modify Time attributes and set
5316          * on the Metadata file, so its attributes will be what the file's
5317          * would be if it had been written.
5318          */
5319         if (error == 0) {
5320                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5321                 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL,
5322                     NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
5323         }
5324         NFSD_DEBUG(4, "nfsrv_writedsdorpc: aft loadattr=%d\n", error);
5325 nfsmout:
5326         m_freem(nd->nd_mrep);
5327         free(nd, M_TEMP);
5328         NFSD_DEBUG(4, "nfsrv_writedsdorpc error=%d\n", error);
5329         return (error);
5330 }
5331
5332 /*
5333  * Start up the thread that will execute nfsrv_writedsdorpc().
5334  */
5335 static void
5336 start_writedsdorpc(void *arg, int pending)
5337 {
5338         struct nfsrvwritedsdorpc *drpc;
5339
5340         drpc = (struct nfsrvwritedsdorpc *)arg;
5341         drpc->err = nfsrv_writedsdorpc(drpc->nmp, &drpc->fh, drpc->off,
5342             drpc->len, NULL, drpc->m, drpc->cred, drpc->p);
5343         drpc->done = 1;
5344         NFSD_DEBUG(4, "start_writedsdorpc: err=%d\n", drpc->err);
5345 }
5346
5347 static int
5348 nfsrv_writedsrpc(fhandle_t *fhp, off_t off, int len, struct ucred *cred,
5349     NFSPROC_T *p, struct vnode *vp, struct nfsmount **nmpp, int mirrorcnt,
5350     struct mbuf **mpp, char *cp, int *failposp)
5351 {
5352         struct nfsrvwritedsdorpc *drpc, *tdrpc = NULL;
5353         struct nfsvattr na;
5354         struct mbuf *m;
5355         int error, i, offs, ret, timo;
5356
5357         NFSD_DEBUG(4, "in nfsrv_writedsrpc\n");
5358         KASSERT(*mpp != NULL, ("nfsrv_writedsrpc: NULL mbuf chain"));
5359         drpc = NULL;
5360         if (mirrorcnt > 1)
5361                 tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP,
5362                     M_WAITOK);
5363
5364         /* Calculate offset in mbuf chain that data starts. */
5365         offs = cp - mtod(*mpp, char *);
5366         NFSD_DEBUG(4, "nfsrv_writedsrpc: mcopy offs=%d len=%d\n", offs, len);
5367
5368         /*
5369          * Do the write RPC for every DS, using a separate kernel process
5370          * for every DS except the last one.
5371          */
5372         error = 0;
5373         for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) {
5374                 tdrpc->done = 0;
5375                 NFSBCOPY(fhp, &tdrpc->fh, sizeof(*fhp));
5376                 tdrpc->off = off;
5377                 tdrpc->len = len;
5378                 tdrpc->nmp = *nmpp;
5379                 tdrpc->cred = cred;
5380                 tdrpc->p = p;
5381                 tdrpc->inprog = 0;
5382                 tdrpc->err = 0;
5383                 tdrpc->m = m_copym(*mpp, offs, NFSM_RNDUP(len), M_WAITOK);
5384                 ret = EIO;
5385                 if (nfs_pnfsiothreads != 0) {
5386                         ret = nfs_pnfsio(start_writedsdorpc, tdrpc);
5387                         NFSD_DEBUG(4, "nfsrv_writedsrpc: nfs_pnfsio=%d\n",
5388                             ret);
5389                 }
5390                 if (ret != 0) {
5391                         ret = nfsrv_writedsdorpc(*nmpp, fhp, off, len, NULL,
5392                             tdrpc->m, cred, p);
5393                         if (nfsds_failerr(ret) && *failposp == -1)
5394                                 *failposp = i;
5395                         else if (error == 0 && ret != 0)
5396                                 error = ret;
5397                 }
5398                 nmpp++;
5399                 fhp++;
5400         }
5401         m = m_copym(*mpp, offs, NFSM_RNDUP(len), M_WAITOK);
5402         ret = nfsrv_writedsdorpc(*nmpp, fhp, off, len, &na, m, cred, p);
5403         if (nfsds_failerr(ret) && *failposp == -1 && mirrorcnt > 1)
5404                 *failposp = mirrorcnt - 1;
5405         else if (error == 0 && ret != 0)
5406                 error = ret;
5407         if (error == 0)
5408                 error = nfsrv_setextattr(vp, &na, p);
5409         NFSD_DEBUG(4, "nfsrv_writedsrpc: aft setextat=%d\n", error);
5410         tdrpc = drpc;
5411         timo = hz / 50;         /* Wait for 20msec. */
5412         if (timo < 1)
5413                 timo = 1;
5414         for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) {
5415                 /* Wait for RPCs on separate threads to complete. */
5416                 while (tdrpc->inprog != 0 && tdrpc->done == 0)
5417                         tsleep(&tdrpc->tsk, PVFS, "srvwrds", timo);
5418                 if (nfsds_failerr(tdrpc->err) && *failposp == -1)
5419                         *failposp = i;
5420                 else if (error == 0 && tdrpc->err != 0)
5421                         error = tdrpc->err;
5422         }
5423         free(drpc, M_TEMP);
5424         return (error);
5425 }
5426
5427 /*
5428  * Do a allocate RPC on a DS data file, using this structure for the arguments,
5429  * so that this function can be executed by a separate kernel process.
5430  */
5431 struct nfsrvallocatedsdorpc {
5432         int                     done;
5433         int                     inprog;
5434         struct task             tsk;
5435         fhandle_t               fh;
5436         off_t                   off;
5437         off_t                   len;
5438         struct nfsmount         *nmp;
5439         struct ucred            *cred;
5440         NFSPROC_T               *p;
5441         int                     err;
5442 };
5443
5444 static int
5445 nfsrv_allocatedsdorpc(struct nfsmount *nmp, fhandle_t *fhp, off_t off,
5446     off_t len, struct nfsvattr *nap, struct ucred *cred, NFSPROC_T *p)
5447 {
5448         uint32_t *tl;
5449         struct nfsrv_descript *nd;
5450         nfsattrbit_t attrbits;
5451         nfsv4stateid_t st;
5452         int error;
5453
5454         nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO);
5455         nfscl_reqstart(nd, NFSPROC_ALLOCATE, nmp, (u_int8_t *)fhp,
5456             sizeof(fhandle_t), NULL, NULL, 0, 0);
5457
5458         /*
5459          * Use a stateid where other is an alternating 01010 pattern and
5460          * seqid is 0xffffffff.  This value is not defined as special by
5461          * the RFC and is used by the FreeBSD NFS server to indicate an
5462          * MDS->DS proxy operation.
5463          */
5464         st.other[0] = 0x55555555;
5465         st.other[1] = 0x55555555;
5466         st.other[2] = 0x55555555;
5467         st.seqid = 0xffffffff;
5468         nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID);
5469         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
5470         txdr_hyper(off, tl); tl += 2;
5471         txdr_hyper(len, tl); tl += 2;
5472         NFSD_DEBUG(4, "nfsrv_allocatedsdorpc: len=%jd\n", (intmax_t)len);
5473
5474         *tl = txdr_unsigned(NFSV4OP_GETATTR);
5475         NFSGETATTR_ATTRBIT(&attrbits);
5476         nfsrv_putattrbit(nd, &attrbits);
5477         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
5478             cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5479         if (error != 0) {
5480                 free(nd, M_TEMP);
5481                 return (error);
5482         }
5483         NFSD_DEBUG(4, "nfsrv_allocatedsdorpc: aft allocaterpc=%d\n",
5484             nd->nd_repstat);
5485         if (nd->nd_repstat == 0) {
5486                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5487                 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL,
5488                     NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
5489         } else
5490                 error = nd->nd_repstat;
5491         NFSD_DEBUG(4, "nfsrv_allocatedsdorpc: aft loadattr=%d\n", error);
5492 nfsmout:
5493         m_freem(nd->nd_mrep);
5494         free(nd, M_TEMP);
5495         NFSD_DEBUG(4, "nfsrv_allocatedsdorpc error=%d\n", error);
5496         return (error);
5497 }
5498
5499 /*
5500  * Start up the thread that will execute nfsrv_allocatedsdorpc().
5501  */
5502 static void
5503 start_allocatedsdorpc(void *arg, int pending)
5504 {
5505         struct nfsrvallocatedsdorpc *drpc;
5506
5507         drpc = (struct nfsrvallocatedsdorpc *)arg;
5508         drpc->err = nfsrv_allocatedsdorpc(drpc->nmp, &drpc->fh, drpc->off,
5509             drpc->len, NULL, drpc->cred, drpc->p);
5510         drpc->done = 1;
5511         NFSD_DEBUG(4, "start_allocatedsdorpc: err=%d\n", drpc->err);
5512 }
5513
5514 static int
5515 nfsrv_allocatedsrpc(fhandle_t *fhp, off_t off, off_t len, struct ucred *cred,
5516     NFSPROC_T *p, struct vnode *vp, struct nfsmount **nmpp, int mirrorcnt,
5517     int *failposp)
5518 {
5519         struct nfsrvallocatedsdorpc *drpc, *tdrpc = NULL;
5520         struct nfsvattr na;
5521         int error, i, ret, timo;
5522
5523         NFSD_DEBUG(4, "in nfsrv_allocatedsrpc\n");
5524         drpc = NULL;
5525         if (mirrorcnt > 1)
5526                 tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP,
5527                     M_WAITOK);
5528
5529         /*
5530          * Do the allocate RPC for every DS, using a separate kernel process
5531          * for every DS except the last one.
5532          */
5533         error = 0;
5534         for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) {
5535                 tdrpc->done = 0;
5536                 NFSBCOPY(fhp, &tdrpc->fh, sizeof(*fhp));
5537                 tdrpc->off = off;
5538                 tdrpc->len = len;
5539                 tdrpc->nmp = *nmpp;
5540                 tdrpc->cred = cred;
5541                 tdrpc->p = p;
5542                 tdrpc->inprog = 0;
5543                 tdrpc->err = 0;
5544                 ret = EIO;
5545                 if (nfs_pnfsiothreads != 0) {
5546                         ret = nfs_pnfsio(start_allocatedsdorpc, tdrpc);
5547                         NFSD_DEBUG(4, "nfsrv_allocatedsrpc: nfs_pnfsio=%d\n",
5548                             ret);
5549                 }
5550                 if (ret != 0) {
5551                         ret = nfsrv_allocatedsdorpc(*nmpp, fhp, off, len, NULL,
5552                             cred, p);
5553                         if (nfsds_failerr(ret) && *failposp == -1)
5554                                 *failposp = i;
5555                         else if (error == 0 && ret != 0)
5556                                 error = ret;
5557                 }
5558                 nmpp++;
5559                 fhp++;
5560         }
5561         ret = nfsrv_allocatedsdorpc(*nmpp, fhp, off, len, &na, cred, p);
5562         if (nfsds_failerr(ret) && *failposp == -1 && mirrorcnt > 1)
5563                 *failposp = mirrorcnt - 1;
5564         else if (error == 0 && ret != 0)
5565                 error = ret;
5566         if (error == 0)
5567                 error = nfsrv_setextattr(vp, &na, p);
5568         NFSD_DEBUG(4, "nfsrv_allocatedsrpc: aft setextat=%d\n", error);
5569         tdrpc = drpc;
5570         timo = hz / 50;         /* Wait for 20msec. */
5571         if (timo < 1)
5572                 timo = 1;
5573         for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) {
5574                 /* Wait for RPCs on separate threads to complete. */
5575                 while (tdrpc->inprog != 0 && tdrpc->done == 0)
5576                         tsleep(&tdrpc->tsk, PVFS, "srvalds", timo);
5577                 if (nfsds_failerr(tdrpc->err) && *failposp == -1)
5578                         *failposp = i;
5579                 else if (error == 0 && tdrpc->err != 0)
5580                         error = tdrpc->err;
5581         }
5582         free(drpc, M_TEMP);
5583         return (error);
5584 }
5585
5586 static int
5587 nfsrv_setattrdsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
5588     struct vnode *vp, struct nfsmount *nmp, struct nfsvattr *nap,
5589     struct nfsvattr *dsnap)
5590 {
5591         uint32_t *tl;
5592         struct nfsrv_descript *nd;
5593         nfsv4stateid_t st;
5594         nfsattrbit_t attrbits;
5595         int error;
5596
5597         NFSD_DEBUG(4, "in nfsrv_setattrdsdorpc\n");
5598         nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO);
5599         /*
5600          * Use a stateid where other is an alternating 01010 pattern and
5601          * seqid is 0xffffffff.  This value is not defined as special by
5602          * the RFC and is used by the FreeBSD NFS server to indicate an
5603          * MDS->DS proxy operation.
5604          */
5605         st.other[0] = 0x55555555;
5606         st.other[1] = 0x55555555;
5607         st.other[2] = 0x55555555;
5608         st.seqid = 0xffffffff;
5609         nfscl_reqstart(nd, NFSPROC_SETATTR, nmp, (u_int8_t *)fhp, sizeof(*fhp),
5610             NULL, NULL, 0, 0);
5611         nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID);
5612         nfscl_fillsattr(nd, &nap->na_vattr, vp, NFSSATTR_FULL, 0);
5613
5614         /* Do a Getattr for the attributes that change due to writing. */
5615         NFSZERO_ATTRBIT(&attrbits);
5616         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
5617         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5618         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESS);
5619         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
5620         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SPACEUSED);
5621         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
5622         *tl = txdr_unsigned(NFSV4OP_GETATTR);
5623         (void) nfsrv_putattrbit(nd, &attrbits);
5624         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5625             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5626         if (error != 0) {
5627                 free(nd, M_TEMP);
5628                 return (error);
5629         }
5630         NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: aft setattrrpc=%d\n",
5631             nd->nd_repstat);
5632         /* Get rid of weak cache consistency data for now. */
5633         if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR)) ==
5634             (ND_NFSV4 | ND_V4WCCATTR)) {
5635                 error = nfsv4_loadattr(nd, NULL, dsnap, NULL, NULL, 0, NULL,
5636                     NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
5637                 NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: wcc attr=%d\n", error);
5638                 if (error != 0)
5639                         goto nfsmout;
5640                 /*
5641                  * Get rid of Op# and status for next op.
5642                  */
5643                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5644                 if (*++tl != 0)
5645                         nd->nd_flag |= ND_NOMOREDATA;
5646         }
5647         error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
5648         if (error != 0)
5649                 goto nfsmout;
5650         if (nd->nd_repstat != 0)
5651                 error = nd->nd_repstat;
5652         /*
5653          * Get the Change, Size, Access Time and Modify Time attributes and set
5654          * on the Metadata file, so its attributes will be what the file's
5655          * would be if it had been written.
5656          */
5657         if (error == 0) {
5658                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5659                 error = nfsv4_loadattr(nd, NULL, dsnap, NULL, NULL, 0, NULL,
5660                     NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
5661         }
5662         NFSD_DEBUG(4, "nfsrv_setattrdsdorpc: aft setattr loadattr=%d\n", error);
5663 nfsmout:
5664         m_freem(nd->nd_mrep);
5665         free(nd, M_TEMP);
5666         NFSD_DEBUG(4, "nfsrv_setattrdsdorpc error=%d\n", error);
5667         return (error);
5668 }
5669
5670 struct nfsrvsetattrdsdorpc {
5671         int                     done;
5672         int                     inprog;
5673         struct task             tsk;
5674         fhandle_t               fh;
5675         struct nfsmount         *nmp;
5676         struct vnode            *vp;
5677         struct ucred            *cred;
5678         NFSPROC_T               *p;
5679         struct nfsvattr         na;
5680         struct nfsvattr         dsna;
5681         int                     err;
5682 };
5683
5684 /*
5685  * Start up the thread that will execute nfsrv_setattrdsdorpc().
5686  */
5687 static void
5688 start_setattrdsdorpc(void *arg, int pending)
5689 {
5690         struct nfsrvsetattrdsdorpc *drpc;
5691
5692         drpc = (struct nfsrvsetattrdsdorpc *)arg;
5693         drpc->err = nfsrv_setattrdsdorpc(&drpc->fh, drpc->cred, drpc->p,
5694             drpc->vp, drpc->nmp, &drpc->na, &drpc->dsna);
5695         drpc->done = 1;
5696 }
5697
5698 static int
5699 nfsrv_setattrdsrpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
5700     struct vnode *vp, struct nfsmount **nmpp, int mirrorcnt,
5701     struct nfsvattr *nap, int *failposp)
5702 {
5703         struct nfsrvsetattrdsdorpc *drpc, *tdrpc = NULL;
5704         struct nfsvattr na;
5705         int error, i, ret, timo;
5706
5707         NFSD_DEBUG(4, "in nfsrv_setattrdsrpc\n");
5708         drpc = NULL;
5709         if (mirrorcnt > 1)
5710                 tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP,
5711                     M_WAITOK);
5712
5713         /*
5714          * Do the setattr RPC for every DS, using a separate kernel process
5715          * for every DS except the last one.
5716          */
5717         error = 0;
5718         for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) {
5719                 tdrpc->done = 0;
5720                 tdrpc->inprog = 0;
5721                 NFSBCOPY(fhp, &tdrpc->fh, sizeof(*fhp));
5722                 tdrpc->nmp = *nmpp;
5723                 tdrpc->vp = vp;
5724                 tdrpc->cred = cred;
5725                 tdrpc->p = p;
5726                 tdrpc->na = *nap;
5727                 tdrpc->err = 0;
5728                 ret = EIO;
5729                 if (nfs_pnfsiothreads != 0) {
5730                         ret = nfs_pnfsio(start_setattrdsdorpc, tdrpc);
5731                         NFSD_DEBUG(4, "nfsrv_setattrdsrpc: nfs_pnfsio=%d\n",
5732                             ret);
5733                 }
5734                 if (ret != 0) {
5735                         ret = nfsrv_setattrdsdorpc(fhp, cred, p, vp, *nmpp, nap,
5736                             &na);
5737                         if (nfsds_failerr(ret) && *failposp == -1)
5738                                 *failposp = i;
5739                         else if (error == 0 && ret != 0)
5740                                 error = ret;
5741                 }
5742                 nmpp++;
5743                 fhp++;
5744         }
5745         ret = nfsrv_setattrdsdorpc(fhp, cred, p, vp, *nmpp, nap, &na);
5746         if (nfsds_failerr(ret) && *failposp == -1 && mirrorcnt > 1)
5747                 *failposp = mirrorcnt - 1;
5748         else if (error == 0 && ret != 0)
5749                 error = ret;
5750         if (error == 0)
5751                 error = nfsrv_setextattr(vp, &na, p);
5752         NFSD_DEBUG(4, "nfsrv_setattrdsrpc: aft setextat=%d\n", error);
5753         tdrpc = drpc;
5754         timo = hz / 50;         /* Wait for 20msec. */
5755         if (timo < 1)
5756                 timo = 1;
5757         for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) {
5758                 /* Wait for RPCs on separate threads to complete. */
5759                 while (tdrpc->inprog != 0 && tdrpc->done == 0)
5760                         tsleep(&tdrpc->tsk, PVFS, "srvsads", timo);
5761                 if (nfsds_failerr(tdrpc->err) && *failposp == -1)
5762                         *failposp = i;
5763                 else if (error == 0 && tdrpc->err != 0)
5764                         error = tdrpc->err;
5765         }
5766         free(drpc, M_TEMP);
5767         return (error);
5768 }
5769
5770 /*
5771  * Do a Setattr of an NFSv4 ACL on the DS file.
5772  */
5773 static int
5774 nfsrv_setacldsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
5775     struct vnode *vp, struct nfsmount *nmp, struct acl *aclp)
5776 {
5777         struct nfsrv_descript *nd;
5778         nfsv4stateid_t st;
5779         nfsattrbit_t attrbits;
5780         int error;
5781
5782         NFSD_DEBUG(4, "in nfsrv_setacldsdorpc\n");
5783         nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO);
5784         /*
5785          * Use a stateid where other is an alternating 01010 pattern and
5786          * seqid is 0xffffffff.  This value is not defined as special by
5787          * the RFC and is used by the FreeBSD NFS server to indicate an
5788          * MDS->DS proxy operation.
5789          */
5790         st.other[0] = 0x55555555;
5791         st.other[1] = 0x55555555;
5792         st.other[2] = 0x55555555;
5793         st.seqid = 0xffffffff;
5794         nfscl_reqstart(nd, NFSPROC_SETACL, nmp, (u_int8_t *)fhp, sizeof(*fhp),
5795             NULL, NULL, 0, 0);
5796         nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID);
5797         NFSZERO_ATTRBIT(&attrbits);
5798         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
5799         /*
5800          * The "vp" argument to nfsv4_fillattr() is only used for vnode_type(),
5801          * so passing in the metadata "vp" will be ok, since it is of
5802          * the same type (VREG).
5803          */
5804         nfsv4_fillattr(nd, NULL, vp, aclp, NULL, NULL, 0, &attrbits, NULL,
5805             NULL, 0, 0, 0, 0, 0, NULL);
5806         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5807             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5808         if (error != 0) {
5809                 free(nd, M_TEMP);
5810                 return (error);
5811         }
5812         NFSD_DEBUG(4, "nfsrv_setacldsdorpc: aft setaclrpc=%d\n",
5813             nd->nd_repstat);
5814         error = nd->nd_repstat;
5815         m_freem(nd->nd_mrep);
5816         free(nd, M_TEMP);
5817         return (error);
5818 }
5819
5820 struct nfsrvsetacldsdorpc {
5821         int                     done;
5822         int                     inprog;
5823         struct task             tsk;
5824         fhandle_t               fh;
5825         struct nfsmount         *nmp;
5826         struct vnode            *vp;
5827         struct ucred            *cred;
5828         NFSPROC_T               *p;
5829         struct acl              *aclp;
5830         int                     err;
5831 };
5832
5833 /*
5834  * Start up the thread that will execute nfsrv_setacldsdorpc().
5835  */
5836 static void
5837 start_setacldsdorpc(void *arg, int pending)
5838 {
5839         struct nfsrvsetacldsdorpc *drpc;
5840
5841         drpc = (struct nfsrvsetacldsdorpc *)arg;
5842         drpc->err = nfsrv_setacldsdorpc(&drpc->fh, drpc->cred, drpc->p,
5843             drpc->vp, drpc->nmp, drpc->aclp);
5844         drpc->done = 1;
5845 }
5846
5847 static int
5848 nfsrv_setacldsrpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
5849     struct vnode *vp, struct nfsmount **nmpp, int mirrorcnt, struct acl *aclp,
5850     int *failposp)
5851 {
5852         struct nfsrvsetacldsdorpc *drpc, *tdrpc = NULL;
5853         int error, i, ret, timo;
5854
5855         NFSD_DEBUG(4, "in nfsrv_setacldsrpc\n");
5856         drpc = NULL;
5857         if (mirrorcnt > 1)
5858                 tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP,
5859                     M_WAITOK);
5860
5861         /*
5862          * Do the setattr RPC for every DS, using a separate kernel process
5863          * for every DS except the last one.
5864          */
5865         error = 0;
5866         for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) {
5867                 tdrpc->done = 0;
5868                 tdrpc->inprog = 0;
5869                 NFSBCOPY(fhp, &tdrpc->fh, sizeof(*fhp));
5870                 tdrpc->nmp = *nmpp;
5871                 tdrpc->vp = vp;
5872                 tdrpc->cred = cred;
5873                 tdrpc->p = p;
5874                 tdrpc->aclp = aclp;
5875                 tdrpc->err = 0;
5876                 ret = EIO;
5877                 if (nfs_pnfsiothreads != 0) {
5878                         ret = nfs_pnfsio(start_setacldsdorpc, tdrpc);
5879                         NFSD_DEBUG(4, "nfsrv_setacldsrpc: nfs_pnfsio=%d\n",
5880                             ret);
5881                 }
5882                 if (ret != 0) {
5883                         ret = nfsrv_setacldsdorpc(fhp, cred, p, vp, *nmpp,
5884                             aclp);
5885                         if (nfsds_failerr(ret) && *failposp == -1)
5886                                 *failposp = i;
5887                         else if (error == 0 && ret != 0)
5888                                 error = ret;
5889                 }
5890                 nmpp++;
5891                 fhp++;
5892         }
5893         ret = nfsrv_setacldsdorpc(fhp, cred, p, vp, *nmpp, aclp);
5894         if (nfsds_failerr(ret) && *failposp == -1 && mirrorcnt > 1)
5895                 *failposp = mirrorcnt - 1;
5896         else if (error == 0 && ret != 0)
5897                 error = ret;
5898         NFSD_DEBUG(4, "nfsrv_setacldsrpc: aft setextat=%d\n", error);
5899         tdrpc = drpc;
5900         timo = hz / 50;         /* Wait for 20msec. */
5901         if (timo < 1)
5902                 timo = 1;
5903         for (i = 0; i < mirrorcnt - 1; i++, tdrpc++) {
5904                 /* Wait for RPCs on separate threads to complete. */
5905                 while (tdrpc->inprog != 0 && tdrpc->done == 0)
5906                         tsleep(&tdrpc->tsk, PVFS, "srvacds", timo);
5907                 if (nfsds_failerr(tdrpc->err) && *failposp == -1)
5908                         *failposp = i;
5909                 else if (error == 0 && tdrpc->err != 0)
5910                         error = tdrpc->err;
5911         }
5912         free(drpc, M_TEMP);
5913         return (error);
5914 }
5915
5916 /*
5917  * Getattr call to the DS for the attributes that change due to writing.
5918  */
5919 static int
5920 nfsrv_getattrdsrpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
5921     struct vnode *vp, struct nfsmount *nmp, struct nfsvattr *nap)
5922 {
5923         struct nfsrv_descript *nd;
5924         int error;
5925         nfsattrbit_t attrbits;
5926
5927         NFSD_DEBUG(4, "in nfsrv_getattrdsrpc\n");
5928         nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO);
5929         nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, (u_int8_t *)fhp,
5930             sizeof(fhandle_t), NULL, NULL, 0, 0);
5931         NFSZERO_ATTRBIT(&attrbits);
5932         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
5933         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5934         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESS);
5935         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
5936         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SPACEUSED);
5937         (void) nfsrv_putattrbit(nd, &attrbits);
5938         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5939             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5940         if (error != 0) {
5941                 free(nd, M_TEMP);
5942                 return (error);
5943         }
5944         NFSD_DEBUG(4, "nfsrv_getattrdsrpc: aft getattrrpc=%d\n",
5945             nd->nd_repstat);
5946         if (nd->nd_repstat == 0) {
5947                 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
5948                     NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL,
5949                     NULL, NULL);
5950                 /*
5951                  * We can only save the updated values in the extended
5952                  * attribute if the vp is exclusively locked.
5953                  * This should happen when any of the following operations
5954                  * occur on the vnode:
5955                  *    Close, Delegreturn, LayoutCommit, LayoutReturn
5956                  * As such, the updated extended attribute should get saved
5957                  * before nfsrv_checkdsattr() returns 0 and allows the cached
5958                  * attributes to be returned without calling this function.
5959                  */
5960                 if (error == 0 && VOP_ISLOCKED(vp) == LK_EXCLUSIVE) {
5961                         error = nfsrv_setextattr(vp, nap, p);
5962                         NFSD_DEBUG(4, "nfsrv_getattrdsrpc: aft setextat=%d\n",
5963                             error);
5964                 }
5965         } else
5966                 error = nd->nd_repstat;
5967         m_freem(nd->nd_mrep);
5968         free(nd, M_TEMP);
5969         NFSD_DEBUG(4, "nfsrv_getattrdsrpc error=%d\n", error);
5970         return (error);
5971 }
5972
5973 /*
5974  * Seek call to a DS.
5975  */
5976 static int
5977 nfsrv_seekdsrpc(fhandle_t *fhp, off_t *offp, int content, bool *eofp,
5978     struct ucred *cred, NFSPROC_T *p, struct nfsmount *nmp)
5979 {
5980         uint32_t *tl;
5981         struct nfsrv_descript *nd;
5982         nfsv4stateid_t st;
5983         int error;
5984
5985         NFSD_DEBUG(4, "in nfsrv_seekdsrpc\n");
5986         /*
5987          * Use a stateid where other is an alternating 01010 pattern and
5988          * seqid is 0xffffffff.  This value is not defined as special by
5989          * the RFC and is used by the FreeBSD NFS server to indicate an
5990          * MDS->DS proxy operation.
5991          */
5992         st.other[0] = 0x55555555;
5993         st.other[1] = 0x55555555;
5994         st.other[2] = 0x55555555;
5995         st.seqid = 0xffffffff;
5996         nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK | M_ZERO);
5997         nfscl_reqstart(nd, NFSPROC_SEEKDS, nmp, (u_int8_t *)fhp,
5998             sizeof(fhandle_t), NULL, NULL, 0, 0);
5999         nfsm_stateidtom(nd, &st, NFSSTATEID_PUTSTATEID);
6000         NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6001         txdr_hyper(*offp, tl); tl += 2;
6002         *tl = txdr_unsigned(content);
6003         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
6004             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
6005         if (error != 0) {
6006                 free(nd, M_TEMP);
6007                 return (error);
6008         }
6009         NFSD_DEBUG(4, "nfsrv_seekdsrpc: aft seekrpc=%d\n", nd->nd_repstat);
6010         if (nd->nd_repstat == 0) {
6011                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
6012                 if (*tl++ == newnfs_true)
6013                         *eofp = true;
6014                 else
6015                         *eofp = false;
6016                 *offp = fxdr_hyper(tl);
6017         } else
6018                 error = nd->nd_repstat;
6019 nfsmout:
6020         m_freem(nd->nd_mrep);
6021         free(nd, M_TEMP);
6022         NFSD_DEBUG(4, "nfsrv_seekdsrpc error=%d\n", error);
6023         return (error);
6024 }
6025
6026 /*
6027  * Get the device id and file handle for a DS file.
6028  */
6029 int
6030 nfsrv_dsgetdevandfh(struct vnode *vp, NFSPROC_T *p, int *mirrorcntp,
6031     fhandle_t *fhp, char *devid)
6032 {
6033         int buflen, error;
6034         char *buf;
6035
6036         buflen = 1024;
6037         buf = malloc(buflen, M_TEMP, M_WAITOK);
6038         error = nfsrv_dsgetsockmnt(vp, 0, buf, &buflen, mirrorcntp, p, NULL,
6039             fhp, devid, NULL, NULL, NULL, NULL, NULL, NULL);
6040         free(buf, M_TEMP);
6041         return (error);
6042 }
6043
6044 /*
6045  * Do a Lookup against the DS for the filename.
6046  */
6047 static int
6048 nfsrv_pnfslookupds(struct vnode *vp, struct vnode *dvp, struct pnfsdsfile *pf,
6049     struct vnode **nvpp, NFSPROC_T *p)
6050 {
6051         struct nameidata named;
6052         struct ucred *tcred;
6053         char *bufp;
6054         u_long *hashp;
6055         struct vnode *nvp;
6056         int error;
6057
6058         tcred = newnfs_getcred();
6059         named.ni_cnd.cn_nameiop = LOOKUP;
6060         named.ni_cnd.cn_lkflags = LK_SHARED | LK_RETRY;
6061         named.ni_cnd.cn_cred = tcred;
6062         named.ni_cnd.cn_thread = p;
6063         named.ni_cnd.cn_flags = ISLASTCN | LOCKPARENT | LOCKLEAF | SAVENAME;
6064         nfsvno_setpathbuf(&named, &bufp, &hashp);
6065         named.ni_cnd.cn_nameptr = bufp;
6066         named.ni_cnd.cn_namelen = strlen(pf->dsf_filename);
6067         strlcpy(bufp, pf->dsf_filename, NAME_MAX);
6068         NFSD_DEBUG(4, "nfsrv_pnfslookupds: filename=%s\n", bufp);
6069         error = VOP_LOOKUP(dvp, &nvp, &named.ni_cnd);
6070         NFSD_DEBUG(4, "nfsrv_pnfslookupds: aft LOOKUP=%d\n", error);
6071         NFSFREECRED(tcred);
6072         nfsvno_relpathbuf(&named);
6073         if (error == 0)
6074                 *nvpp = nvp;
6075         NFSD_DEBUG(4, "eo nfsrv_pnfslookupds=%d\n", error);
6076         return (error);
6077 }
6078
6079 /*
6080  * Set the file handle to the correct one.
6081  */
6082 static void
6083 nfsrv_pnfssetfh(struct vnode *vp, struct pnfsdsfile *pf, char *devid,
6084     char *fnamep, struct vnode *nvp, NFSPROC_T *p)
6085 {
6086         struct nfsnode *np;
6087         int ret = 0;
6088
6089         np = VTONFS(nvp);
6090         NFSBCOPY(np->n_fhp->nfh_fh, &pf->dsf_fh, NFSX_MYFH);
6091         /*
6092          * We can only do a vn_set_extattr() if the vnode is exclusively
6093          * locked and vn_start_write() has been done.  If devid != NULL or
6094          * fnamep != NULL or the vnode is shared locked, vn_start_write()
6095          * may not have been done.
6096          * If not done now, it will be done on a future call.
6097          */
6098         if (devid == NULL && fnamep == NULL && NFSVOPISLOCKED(vp) ==
6099             LK_EXCLUSIVE)
6100                 ret = vn_extattr_set(vp, IO_NODELOCKED,
6101                     EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile", sizeof(*pf),
6102                     (char *)pf, p);
6103         NFSD_DEBUG(4, "eo nfsrv_pnfssetfh=%d\n", ret);
6104 }
6105
6106 /*
6107  * Cause RPCs waiting on "nmp" to fail.  This is called for a DS mount point
6108  * when the DS has failed.
6109  */
6110 void
6111 nfsrv_killrpcs(struct nfsmount *nmp)
6112 {
6113
6114         /*
6115          * Call newnfs_nmcancelreqs() to cause
6116          * any RPCs in progress on the mount point to
6117          * fail.
6118          * This will cause any process waiting for an
6119          * RPC to complete while holding a vnode lock
6120          * on the mounted-on vnode (such as "df" or
6121          * a non-forced "umount") to fail.
6122          * This will unlock the mounted-on vnode so
6123          * a forced dismount can succeed.
6124          * The NFSMNTP_CANCELRPCS flag should be set when this function is
6125          * called.
6126          */
6127         newnfs_nmcancelreqs(nmp);
6128 }
6129
6130 /*
6131  * Sum up the statfs info for each of the DSs, so that the client will
6132  * receive the total for all DSs.
6133  */
6134 static int
6135 nfsrv_pnfsstatfs(struct statfs *sf, struct mount *mp)
6136 {
6137         struct statfs *tsf;
6138         struct nfsdevice *ds;
6139         struct vnode **dvpp, **tdvpp, *dvp;
6140         uint64_t tot;
6141         int cnt, error = 0, i;
6142
6143         if (nfsrv_devidcnt <= 0)
6144                 return (ENXIO);
6145         dvpp = mallocarray(nfsrv_devidcnt, sizeof(*dvpp), M_TEMP, M_WAITOK);
6146         tsf = malloc(sizeof(*tsf), M_TEMP, M_WAITOK);
6147
6148         /* Get an array of the dvps for the DSs. */
6149         tdvpp = dvpp;
6150         i = 0;
6151         NFSDDSLOCK();
6152         /* First, search for matches for same file system. */
6153         TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
6154                 if (ds->nfsdev_nmp != NULL && ds->nfsdev_mdsisset != 0 &&
6155                     fsidcmp(&ds->nfsdev_mdsfsid, &mp->mnt_stat.f_fsid) == 0) {
6156                         if (++i > nfsrv_devidcnt)
6157                                 break;
6158                         *tdvpp++ = ds->nfsdev_dvp;
6159                 }
6160         }
6161         /*
6162          * If no matches for same file system, total all servers not assigned
6163          * to a file system.
6164          */
6165         if (i == 0) {
6166                 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
6167                         if (ds->nfsdev_nmp != NULL &&
6168                             ds->nfsdev_mdsisset == 0) {
6169                                 if (++i > nfsrv_devidcnt)
6170                                         break;
6171                                 *tdvpp++ = ds->nfsdev_dvp;
6172                         }
6173                 }
6174         }
6175         NFSDDSUNLOCK();
6176         cnt = i;
6177
6178         /* Do a VFS_STATFS() for each of the DSs and sum them up. */
6179         tdvpp = dvpp;
6180         for (i = 0; i < cnt && error == 0; i++) {
6181                 dvp = *tdvpp++;
6182                 error = VFS_STATFS(dvp->v_mount, tsf);
6183                 if (error == 0) {
6184                         if (sf->f_bsize == 0) {
6185                                 if (tsf->f_bsize > 0)
6186                                         sf->f_bsize = tsf->f_bsize;
6187                                 else
6188                                         sf->f_bsize = 8192;
6189                         }
6190                         if (tsf->f_blocks > 0) {
6191                                 if (sf->f_bsize != tsf->f_bsize) {
6192                                         tot = tsf->f_blocks * tsf->f_bsize;
6193                                         sf->f_blocks += (tot / sf->f_bsize);
6194                                 } else
6195                                         sf->f_blocks += tsf->f_blocks;
6196                         }
6197                         if (tsf->f_bfree > 0) {
6198                                 if (sf->f_bsize != tsf->f_bsize) {
6199                                         tot = tsf->f_bfree * tsf->f_bsize;
6200                                         sf->f_bfree += (tot / sf->f_bsize);
6201                                 } else
6202                                         sf->f_bfree += tsf->f_bfree;
6203                         }
6204                         if (tsf->f_bavail > 0) {
6205                                 if (sf->f_bsize != tsf->f_bsize) {
6206                                         tot = tsf->f_bavail * tsf->f_bsize;
6207                                         sf->f_bavail += (tot / sf->f_bsize);
6208                                 } else
6209                                         sf->f_bavail += tsf->f_bavail;
6210                         }
6211                 }
6212         }
6213         free(tsf, M_TEMP);
6214         free(dvpp, M_TEMP);
6215         return (error);
6216 }
6217
6218 /*
6219  * Set an NFSv4 acl.
6220  */
6221 int
6222 nfsrv_setacl(struct vnode *vp, NFSACL_T *aclp, struct ucred *cred, NFSPROC_T *p)
6223 {
6224         int error;
6225
6226         if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
6227                 error = NFSERR_ATTRNOTSUPP;
6228                 goto out;
6229         }
6230         /*
6231          * With NFSv4 ACLs, chmod(2) may need to add additional entries.
6232          * Make sure it has enough room for that - splitting every entry
6233          * into two and appending "canonical six" entries at the end.
6234          * Cribbed out of kern/vfs_acl.c - Rick M.
6235          */
6236         if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) {
6237                 error = NFSERR_ATTRNOTSUPP;
6238                 goto out;
6239         }
6240         error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p);
6241         if (error == 0) {
6242                 error = nfsrv_dssetacl(vp, aclp, cred, p);
6243                 if (error == ENOENT)
6244                         error = 0;
6245         }
6246
6247 out:
6248         NFSEXITCODE(error);
6249         return (error);
6250 }
6251
6252 /*
6253  * Seek vnode op call (actually it is a VOP_IOCTL()).
6254  * This function is called with the vnode locked, but unlocks and vrele()s
6255  * the vp before returning.
6256  */
6257 int
6258 nfsvno_seek(struct nfsrv_descript *nd, struct vnode *vp, u_long cmd,
6259     off_t *offp, int content, bool *eofp, struct ucred *cred, NFSPROC_T *p)
6260 {
6261         struct nfsvattr at;
6262         int error, ret;
6263
6264         ASSERT_VOP_LOCKED(vp, "nfsvno_seek vp");
6265         /*
6266          * Attempt to seek on a DS file. A return of ENOENT implies
6267          * there is no DS file to seek on.
6268          */
6269         error = nfsrv_proxyds(vp, 0, 0, cred, p, NFSPROC_SEEKDS, NULL,
6270             NULL, NULL, NULL, NULL, offp, content, eofp);
6271         if (error != ENOENT) {
6272                 vput(vp);
6273                 return (error);
6274         }
6275
6276         /*
6277          * Do the VOP_IOCTL() call.  For the case where *offp == file_size,
6278          * VOP_IOCTL() will return ENXIO.  However, the correct reply for
6279          * NFSv4.2 is *eofp == true and error == 0 for this case.
6280          */
6281         NFSVOPUNLOCK(vp);
6282         error = VOP_IOCTL(vp, cmd, offp, 0, cred, p);
6283         *eofp = false;
6284         if (error == ENXIO || (error == 0 && cmd == FIOSEEKHOLE)) {
6285                 /* Handle the cases where we might be at EOF. */
6286                 ret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
6287                 if (ret == 0 && *offp == at.na_size) {
6288                         *eofp = true;
6289                         error = 0;
6290                 }
6291                 if (ret != 0 && error == 0)
6292                         error = ret;
6293         }
6294         vrele(vp);
6295         NFSEXITCODE(error);
6296         return (error);
6297 }
6298
6299 /*
6300  * Allocate vnode op call.
6301  */
6302 int
6303 nfsvno_allocate(struct vnode *vp, off_t off, off_t len, struct ucred *cred,
6304     NFSPROC_T *p)
6305 {
6306         int error, trycnt;
6307
6308         ASSERT_VOP_ELOCKED(vp, "nfsvno_allocate vp");
6309         /*
6310          * Attempt to allocate on a DS file. A return of ENOENT implies
6311          * there is no DS file to allocate on.
6312          */
6313         error = nfsrv_proxyds(vp, off, 0, cred, p, NFSPROC_ALLOCATE, NULL,
6314             NULL, NULL, NULL, NULL, &len, 0, NULL);
6315         if (error != ENOENT)
6316                 return (error);
6317         error = 0;
6318
6319         /*
6320          * Do the actual VOP_ALLOCATE(), looping a reasonable number of
6321          * times to achieve completion.
6322          */
6323         trycnt = 0;
6324         while (error == 0 && len > 0 && trycnt++ < 20)
6325                 error = VOP_ALLOCATE(vp, &off, &len);
6326         if (error == 0 && len > 0)
6327                 error = NFSERR_IO;
6328         NFSEXITCODE(error);
6329         return (error);
6330 }
6331
6332 /*
6333  * Get Extended Atribute vnode op into an mbuf list.
6334  */
6335 int
6336 nfsvno_getxattr(struct vnode *vp, char *name, uint32_t maxresp,
6337     struct ucred *cred, uint64_t flag, int maxextsiz, struct thread *p,
6338     struct mbuf **mpp, struct mbuf **mpendp, int *lenp)
6339 {
6340         struct iovec *iv;
6341         struct uio io, *uiop = &io;
6342         struct mbuf *m, *m2;
6343         int alen, error, len, tlen;
6344         size_t siz;
6345
6346         /* First, find out the size of the extended attribute. */
6347         error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6348             &siz, cred, p);
6349         if (error != 0)
6350                 return (NFSERR_NOXATTR);
6351         if (siz > maxresp - NFS_MAXXDR)
6352                 return (NFSERR_XATTR2BIG);
6353         len = siz;
6354         tlen = NFSM_RNDUP(len);
6355         if (tlen > 0) {
6356                 /*
6357                  * If cnt > MCLBYTES and the reply will not be saved, use
6358                  * ext_pgs mbufs for TLS.
6359                  * For NFSv4.0, we do not know for sure if the reply will
6360                  * be saved, so do not use ext_pgs mbufs for NFSv4.0.
6361                  * Always use ext_pgs mbufs if ND_EXTPG is set.
6362                  */
6363                 if ((flag & ND_EXTPG) != 0 || (tlen > MCLBYTES &&
6364                     (flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS &&
6365                     (flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4))
6366                         uiop->uio_iovcnt = nfsrv_createiovec_extpgs(tlen,
6367                             maxextsiz, &m, &m2, &iv);
6368                 else
6369                         uiop->uio_iovcnt = nfsrv_createiovec(tlen, &m, &m2,
6370                             &iv);
6371                 uiop->uio_iov = iv;
6372         } else {
6373                 uiop->uio_iovcnt = 0;
6374                 uiop->uio_iov = iv = NULL;
6375                 m = m2 = NULL;
6376         }
6377         uiop->uio_offset = 0;
6378         uiop->uio_resid = tlen;
6379         uiop->uio_rw = UIO_READ;
6380         uiop->uio_segflg = UIO_SYSSPACE;
6381         uiop->uio_td = p;
6382 #ifdef MAC
6383         error = mac_vnode_check_getextattr(cred, vp, EXTATTR_NAMESPACE_USER,
6384             name);
6385         if (error != 0)
6386                 goto out;
6387 #endif
6388
6389         if (tlen > 0)
6390                 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, uiop,
6391                     NULL, cred, p);
6392         if (error != 0)
6393                 goto out;
6394         if (uiop->uio_resid > 0) {
6395                 alen = tlen;
6396                 len = tlen - uiop->uio_resid;
6397                 tlen = NFSM_RNDUP(len);
6398                 if (alen != tlen)
6399                         printf("nfsvno_getxattr: weird size read\n");
6400                 if (tlen == 0) {
6401                         m_freem(m);
6402                         m = m2 = NULL;
6403                 } else if (alen != tlen || tlen != len)
6404                         m2 = nfsrv_adj(m, alen - tlen, tlen - len);
6405         }
6406         *lenp = len;
6407         *mpp = m;
6408         *mpendp = m2;
6409
6410 out:
6411         if (error != 0) {
6412                 if (m != NULL)
6413                         m_freem(m);
6414                 *lenp = 0;
6415         }
6416         free(iv, M_TEMP);
6417         NFSEXITCODE(error);
6418         return (error);
6419 }
6420
6421 /*
6422  * Set Extended attribute vnode op from an mbuf list.
6423  */
6424 int
6425 nfsvno_setxattr(struct vnode *vp, char *name, int len, struct mbuf *m,
6426     char *cp, struct ucred *cred, struct thread *p)
6427 {
6428         struct iovec *iv;
6429         struct uio uio, *uiop = &uio;
6430         int cnt, error;
6431
6432         error = 0;
6433 #ifdef MAC
6434         error = mac_vnode_check_setextattr(cred, vp, EXTATTR_NAMESPACE_USER,
6435             name);
6436 #endif
6437         if (error != 0)
6438                 goto out;
6439
6440         uiop->uio_rw = UIO_WRITE;
6441         uiop->uio_segflg = UIO_SYSSPACE;
6442         uiop->uio_td = p;
6443         uiop->uio_offset = 0;
6444         uiop->uio_resid = len;
6445         if (len > 0) {
6446                 error = nfsrv_createiovecw(len, m, cp, &iv, &cnt);
6447                 uiop->uio_iov = iv;
6448                 uiop->uio_iovcnt = cnt;
6449         } else {
6450                 uiop->uio_iov = iv = NULL;
6451                 uiop->uio_iovcnt = 0;
6452         }
6453         if (error == 0) {
6454                 error = VOP_SETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, uiop,
6455                     cred, p);
6456                 free(iv, M_TEMP);
6457         }
6458
6459 out:
6460         NFSEXITCODE(error);
6461         return (error);
6462 }
6463
6464 /*
6465  * Remove Extended attribute vnode op.
6466  */
6467 int
6468 nfsvno_rmxattr(struct nfsrv_descript *nd, struct vnode *vp, char *name,
6469     struct ucred *cred, struct thread *p)
6470 {
6471         int error;
6472
6473         /*
6474          * Get rid of any delegations.  I am not sure why this is required,
6475          * but RFC-8276 says so.
6476          */
6477         error = nfsrv_checkremove(vp, 0, nd, nd->nd_clientid, p);
6478         if (error != 0)
6479                 goto out;
6480 #ifdef MAC
6481         error = mac_vnode_check_deleteextattr(cred, vp, EXTATTR_NAMESPACE_USER,
6482             name);
6483         if (error != 0)
6484                 goto out;
6485 #endif
6486
6487         error = VOP_DELETEEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, cred, p);
6488         if (error == EOPNOTSUPP)
6489                 error = VOP_SETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6490                     cred, p);
6491 out:
6492         NFSEXITCODE(error);
6493         return (error);
6494 }
6495
6496 /*
6497  * List Extended Atribute vnode op into an mbuf list.
6498  */
6499 int
6500 nfsvno_listxattr(struct vnode *vp, uint64_t cookie, struct ucred *cred,
6501     struct thread *p, u_char **bufp, uint32_t *lenp, bool *eofp)
6502 {
6503         struct iovec iv;
6504         struct uio io;
6505         int error;
6506         size_t siz;
6507
6508         *bufp = NULL;
6509         /* First, find out the size of the extended attribute. */
6510         error = VOP_LISTEXTATTR(vp, EXTATTR_NAMESPACE_USER, NULL, &siz, cred,
6511             p);
6512         if (error != 0)
6513                 return (NFSERR_NOXATTR);
6514         if (siz <= cookie) {
6515                 *lenp = 0;
6516                 *eofp = true;
6517                 goto out;
6518         }
6519         if (siz > cookie + *lenp) {
6520                 siz = cookie + *lenp;
6521                 *eofp = false;
6522         } else
6523                 *eofp = true;
6524         /* Just choose a sanity limit of 10Mbytes for malloc(M_TEMP). */
6525         if (siz > 10 * 1024 * 1024) {
6526                 error = NFSERR_XATTR2BIG;
6527                 goto out;
6528         }
6529         *bufp = malloc(siz, M_TEMP, M_WAITOK);
6530         iv.iov_base = *bufp;
6531         iv.iov_len = siz;
6532         io.uio_iovcnt = 1;
6533         io.uio_iov = &iv;
6534         io.uio_offset = 0;
6535         io.uio_resid = siz;
6536         io.uio_rw = UIO_READ;
6537         io.uio_segflg = UIO_SYSSPACE;
6538         io.uio_td = p;
6539 #ifdef MAC
6540         error = mac_vnode_check_listextattr(cred, vp, EXTATTR_NAMESPACE_USER);
6541         if (error != 0)
6542                 goto out;
6543 #endif
6544
6545         error = VOP_LISTEXTATTR(vp, EXTATTR_NAMESPACE_USER, &io, NULL, cred,
6546             p);
6547         if (error != 0)
6548                 goto out;
6549         if (io.uio_resid > 0)
6550                 siz -= io.uio_resid;
6551         *lenp = siz;
6552
6553 out:
6554         if (error != 0) {
6555                 free(*bufp, M_TEMP);
6556                 *bufp = NULL;
6557         }
6558         NFSEXITCODE(error);
6559         return (error);
6560 }
6561
6562 /*
6563  * Trim trailing data off the mbuf list being built.
6564  */
6565 void
6566 nfsm_trimtrailing(struct nfsrv_descript *nd, struct mbuf *mb, char *bpos,
6567     int bextpg, int bextpgsiz)
6568 {
6569         vm_page_t pg;
6570         int fullpgsiz, i;
6571
6572         if (mb->m_next != NULL) {
6573                 m_freem(mb->m_next);
6574                 mb->m_next = NULL;
6575         }
6576         if ((mb->m_flags & M_EXTPG) != 0) {
6577                 /* First, get rid of any pages after this position. */
6578                 for (i = mb->m_epg_npgs - 1; i > bextpg; i--) {
6579                         pg = PHYS_TO_VM_PAGE(mb->m_epg_pa[i]);
6580                         vm_page_unwire_noq(pg);
6581                         vm_page_free(pg);
6582                 }
6583                 mb->m_epg_npgs = bextpg + 1;
6584                 if (bextpg == 0)
6585                         fullpgsiz = PAGE_SIZE - mb->m_epg_1st_off;
6586                 else
6587                         fullpgsiz = PAGE_SIZE;
6588                 mb->m_epg_last_len = fullpgsiz - bextpgsiz;
6589                 mb->m_len = m_epg_pagelen(mb, 0, mb->m_epg_1st_off);
6590                 for (i = 1; i < mb->m_epg_npgs; i++)
6591                         mb->m_len += m_epg_pagelen(mb, i, 0);
6592                 nd->nd_bextpgsiz = bextpgsiz;
6593                 nd->nd_bextpg = bextpg;
6594         } else
6595                 mb->m_len = bpos - mtod(mb, char *);
6596         nd->nd_mb = mb;
6597         nd->nd_bpos = bpos;
6598 }
6599
6600 extern int (*nfsd_call_nfsd)(struct thread *, struct nfssvc_args *);
6601
6602 /*
6603  * Called once to initialize data structures...
6604  */
6605 static int
6606 nfsd_modevent(module_t mod, int type, void *data)
6607 {
6608         int error = 0, i;
6609         static int loaded = 0;
6610
6611         switch (type) {
6612         case MOD_LOAD:
6613                 if (loaded)
6614                         goto out;
6615                 newnfs_portinit();
6616                 for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
6617                         mtx_init(&nfsrchash_table[i].mtx, "nfsrtc", NULL,
6618                             MTX_DEF);
6619                         mtx_init(&nfsrcahash_table[i].mtx, "nfsrtca", NULL,
6620                             MTX_DEF);
6621                 }
6622                 mtx_init(&nfsrc_udpmtx, "nfsuc", NULL, MTX_DEF);
6623                 mtx_init(&nfs_v4root_mutex, "nfs4rt", NULL, MTX_DEF);
6624                 mtx_init(&nfsv4root_mnt.mnt_mtx, "nfs4mnt", NULL, MTX_DEF);
6625                 mtx_init(&nfsrv_dontlistlock_mtx, "nfs4dnl", NULL, MTX_DEF);
6626                 mtx_init(&nfsrv_recalllock_mtx, "nfs4rec", NULL, MTX_DEF);
6627                 lockinit(&nfsv4root_mnt.mnt_explock, PVFS, "explock", 0, 0);
6628                 nfsrvd_initcache();
6629                 nfsd_init();
6630                 NFSD_LOCK();
6631                 nfsrvd_init(0);
6632                 NFSD_UNLOCK();
6633                 nfsd_mntinit();
6634 #ifdef VV_DISABLEDELEG
6635                 vn_deleg_ops.vndeleg_recall = nfsd_recalldelegation;
6636                 vn_deleg_ops.vndeleg_disable = nfsd_disabledelegation;
6637 #endif
6638                 nfsd_call_servertimer = nfsrv_servertimer;
6639                 nfsd_call_nfsd = nfssvc_nfsd;
6640                 loaded = 1;
6641                 break;
6642
6643         case MOD_UNLOAD:
6644                 if (newnfs_numnfsd != 0) {
6645                         error = EBUSY;
6646                         break;
6647                 }
6648
6649 #ifdef VV_DISABLEDELEG
6650                 vn_deleg_ops.vndeleg_recall = NULL;
6651                 vn_deleg_ops.vndeleg_disable = NULL;
6652 #endif
6653                 nfsd_call_servertimer = NULL;
6654                 nfsd_call_nfsd = NULL;
6655
6656                 /* Clean out all NFSv4 state. */
6657                 nfsrv_throwawayallstate(curthread);
6658
6659                 /* Clean the NFS server reply cache */
6660                 nfsrvd_cleancache();
6661
6662                 /* Free up the krpc server pool. */
6663                 if (nfsrvd_pool != NULL)
6664                         svcpool_destroy(nfsrvd_pool);
6665
6666                 /* and get rid of the locks */
6667                 for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
6668                         mtx_destroy(&nfsrchash_table[i].mtx);
6669                         mtx_destroy(&nfsrcahash_table[i].mtx);
6670                 }
6671                 mtx_destroy(&nfsrc_udpmtx);
6672                 mtx_destroy(&nfs_v4root_mutex);
6673                 mtx_destroy(&nfsv4root_mnt.mnt_mtx);
6674                 mtx_destroy(&nfsrv_dontlistlock_mtx);
6675                 mtx_destroy(&nfsrv_recalllock_mtx);
6676                 for (i = 0; i < nfsrv_sessionhashsize; i++)
6677                         mtx_destroy(&nfssessionhash[i].mtx);
6678                 if (nfslayouthash != NULL) {
6679                         for (i = 0; i < nfsrv_layouthashsize; i++)
6680                                 mtx_destroy(&nfslayouthash[i].mtx);
6681                         free(nfslayouthash, M_NFSDSESSION);
6682                 }
6683                 lockdestroy(&nfsv4root_mnt.mnt_explock);
6684                 free(nfsclienthash, M_NFSDCLIENT);
6685                 free(nfslockhash, M_NFSDLOCKFILE);
6686                 free(nfssessionhash, M_NFSDSESSION);
6687                 loaded = 0;
6688                 break;
6689         default:
6690                 error = EOPNOTSUPP;
6691                 break;
6692         }
6693
6694 out:
6695         NFSEXITCODE(error);
6696         return (error);
6697 }
6698 static moduledata_t nfsd_mod = {
6699         "nfsd",
6700         nfsd_modevent,
6701         NULL,
6702 };
6703 DECLARE_MODULE(nfsd, nfsd_mod, SI_SUB_VFS, SI_ORDER_ANY);
6704
6705 /* So that loader and kldload(2) can find us, wherever we are.. */
6706 MODULE_VERSION(nfsd, 1);
6707 MODULE_DEPEND(nfsd, nfscommon, 1, 1, 1);
6708 MODULE_DEPEND(nfsd, nfslockd, 1, 1, 1);
6709 MODULE_DEPEND(nfsd, krpc, 1, 1, 1);
6710 MODULE_DEPEND(nfsd, nfssvc, 1, 1, 1);