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