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