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