xref: /dragonfly/sys/vfs/dirfs/dirfs_vnops.c (revision 267c04fd)
1 /*
2  * Copyright (c) 2013 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Antonio Huete Jimenez <tuxillo@quantumachine.net>
6  * by Matthew Dillon <dillon@dragonflybsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  * 3. Neither the name of The DragonFly Project nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific, prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  */
36 
37 /*
38  * See below a small table with the vnode operation and syscall correspondence
39  * where it applies:
40  *
41  * VNODE OP		SCALL	SCALL_AT  FD	PATH	COMMENTS
42  * dirfs_ncreate	Y	Y	  Y	Y	open(2), openat(2)
43  * dirfs_nresolve	-	-	  -	Y	no syscall needed
44  * dirfs_nlookupdot	-	-	  -	-	-
45  * dirfs_nmknod		Y	Y	  Y	Y	mknod(2), mknodat(2)
46  * dirfs_open		Y	Y	  Y	Y	open(2), openat(2)
47  * dirfs_close		Y	Y	  Y	Y	close(2)
48  * dirfs_access		-	-	  -	-	data from stat(2)
49  * dirfs_getattr	Y	Y	  Y	Y	lstat(2), fstatat(2)
50  * dirfs_setattr	-	-	  -	-	-
51  * dirfs_read		Y	-	  Y	-	read(2).
52  * dirfs_write		Y	-	  Y	-	write(2).
53  * dirfs_fsync		Y	-	  Y	-	fsync(2)
54  * dirfs_mountctl	-	-	  -	-	-
55  * dirfs_nremove	Y	-	  -	Y	unlink(2)
56  * dirfs_nlink		-	-	  -	-	-
57  * dirfs_nrename	Y	Y	  Y	Y	rename(2), renameat(2)
58  * dirfs_nmkdir		Y	Y	  Y	Y	mkdir(2), mkdirat(2)
59  * dirfs_nrmdir		Y	-	  -	Y	rmdir(2)
60  * dirfs_nsymlink	Y	Y	  Y	Y	symlink(2), symlinkat(2)
61  * dirfs_readdir	Y	-	  Y	-	getdirentries(2)
62  * dirfs_readlink	Y	Y	  Y	Y	readlinkat(2)
63  * dirfs_inactive	-	-	  -	-	-
64  * dirfs_reclaim	-	-	  -	-	-
65  * dirfs_print		-	-	  -	-	-
66  * dirfs_pathconf	-	-	  -	-	-
67  * dirfs_bmap		-	-	  -	-	-
68  * dirfs_strategy	Y	-	  Y	-	pwrite(2), pread(2)
69  * dirfs_advlock	-	-	  -	-	-
70  * dirfs_kqfilter	-	-	  -	-	-
71  */
72 
73 #include <stdio.h>
74 #include <errno.h>
75 #include <strings.h>
76 #include <unistd.h>
77 
78 #include <sys/vfsops.h>
79 #include <sys/vnode.h>
80 #include <sys/stat.h>
81 #include <sys/namecache.h>
82 #include <sys/queue.h>
83 #include <sys/systm.h>
84 #include <sys/dirent.h>
85 #include <sys/mount.h>
86 #include <sys/signalvar.h>
87 #include <sys/resource.h>
88 #include <sys/buf2.h>
89 #include <sys/kern_syscall.h>
90 #include <sys/ktr.h>
91 
92 #include "dirfs.h"
93 
94 /*
95  * Kernel tracing facilities
96  */
97 KTR_INFO_MASTER_EXTERN(dirfs);
98 
99 KTR_INFO(KTR_DIRFS, dirfs, unsupported, 0,
100     "DIRFS(func=%s)",
101     const char *func);
102 
103 KTR_INFO(KTR_DIRFS, dirfs, nresolve, 0,
104     "DIRFS(dnp=%p ncp_name=%s parent=%p pfd=%d error=%d)",
105     dirfs_node_t dnp, char *name, dirfs_node_t pdnp, int pfd, int error);
106 
107 KTR_INFO(KTR_DIRFS, dirfs, ncreate, 1,
108     "DIRFS(dnp=%p ncp_name=%s parent=%p pfd=%d error=%d)",
109     dirfs_node_t dnp, char *name, dirfs_node_t pdnp, int pfd, int error);
110 
111 KTR_INFO(KTR_DIRFS, dirfs, open, 2,
112     "DIRFS(dnp=%p dn_name=%s nfd=%d)",
113     dirfs_node_t dnp, char *name, int fd);
114 
115 KTR_INFO(KTR_DIRFS, dirfs, close, 3,
116     "DIRFS(dnp=%p fd=%d opencount=%d writecount=%d vfsync error=%d)",
117     dirfs_node_t dnp, int fd, int oc, int wc, int error);
118 
119 KTR_INFO(KTR_DIRFS, dirfs, readdir, 4,
120     "DIRFS(dnp=%p fd=%d startoff=%jd uio_offset=%jd)",
121     dirfs_node_t dnp, int fd, off_t startoff, off_t uoff);
122 
123 KTR_INFO(KTR_DIRFS, dirfs, access, 5,
124     "DIRFS(dnp=%p error=%d)",
125     dirfs_node_t dnp, int error);
126 
127 KTR_INFO(KTR_DIRFS, dirfs, getattr, 6,
128     "DIRFS(dnp=%p error=%d)",
129     dirfs_node_t dnp, int error);
130 
131 KTR_INFO(KTR_DIRFS, dirfs, setattr, 7,
132     "DIRFS(dnp=%p action=%s error=%d)",
133     dirfs_node_t dnp, const char *action, int error);
134 
135 KTR_INFO(KTR_DIRFS, dirfs, fsync, 8,
136     "DIRFS(dnp=%p error=%d)",
137     dirfs_node_t dnp, int error);
138 
139 KTR_INFO(KTR_DIRFS, dirfs, read, 9,
140     "DIRFS(dnp=%p size=%jd error=%d)",
141     dirfs_node_t dnp, size_t size, int error);
142 
143 KTR_INFO(KTR_DIRFS, dirfs, write, 10,
144     "DIRFS(dnp=%p size=%jd boff=%jd uio_resid=%jd error=%d)",
145     dirfs_node_t dnp, off_t boff, size_t resid, size_t size, int error);
146 
147 KTR_INFO(KTR_DIRFS, dirfs, strategy, 11,
148     "DIRFS(dnp=%p dnp_size=%jd iosize=%jd b_cmd=%d b_error=%d "
149     "b_resid=%d bio_off=%jd error=%d)",
150     dirfs_node_t dnp, size_t size, size_t iosize, int cmd, int berror,
151     int bresid, off_t biooff, int error);
152 
153 KTR_INFO(KTR_DIRFS, dirfs, nremove, 12,
154     "DIRFS(dnp=%p pdnp=%p error=%d)",
155     dirfs_node_t dnp, dirfs_node_t pdnp, int error);
156 
157 KTR_INFO(KTR_DIRFS, dirfs, nmkdir, 13,
158     "DIRFS(pdnp=%p dnp=%p nc_name=%p error=%d)",
159     dirfs_node_t dnp, dirfs_node_t pdnp, char *n, int error);
160 
161 KTR_INFO(KTR_DIRFS, dirfs, nrmdir, 13,
162     "DIRFS(pdnp=%p dnp=%p error=%d)",
163     dirfs_node_t dnp, dirfs_node_t pdnp, int error);
164 
165 KTR_INFO(KTR_DIRFS, dirfs, nsymlink, 14,
166     "DIRFS(dnp=%p target=%s symlink=%s error=%d)",
167     dirfs_node_t dnp, char *tgt, char *lnk, int error);
168 
169 /* Needed prototypes */
170 int dirfs_access(struct vop_access_args *);
171 int dirfs_getattr(struct vop_getattr_args *);
172 int dirfs_setattr(struct vop_setattr_args *);
173 int dirfs_reclaim(struct vop_reclaim_args *);
174 
175 static int
176 dirfs_nresolve(struct vop_nresolve_args *ap)
177 {
178 	dirfs_node_t pdnp, dnp, d1, d2;
179 	dirfs_mount_t dmp;
180 	struct namecache *ncp;
181 	struct nchandle *nch;
182 	struct vnode *dvp;
183 	struct vnode *vp;
184 	struct mount *mp;
185 	int error;
186 
187 	debug_called();
188 
189 	error = 0;
190 	nch = ap->a_nch;
191 	ncp = nch->ncp;
192 	mp = nch->mount;
193 	dvp = ap->a_dvp;
194 	vp = NULL;
195 	dnp = d1 = d2 = NULL;
196 	pdnp = VP_TO_NODE(dvp);
197 	dmp = VFS_TO_DIRFS(mp);
198 
199 	dirfs_node_lock(pdnp);
200 	TAILQ_FOREACH_MUTABLE(d1, &dmp->dm_fdlist, dn_fdentry, d2) {
201 		if (d1->dn_parent == pdnp &&
202 		    (strcmp(d1->dn_name, ncp->nc_name) == 0)) {
203 			dnp = d1;
204 			dirfs_node_ref(dnp);
205 			passive_fd_list_hits++;
206 			break;
207 		}
208 	}
209 	dirfs_node_unlock(pdnp);
210 
211 	if (dnp) {
212 		dirfs_alloc_vp(mp, &vp, LK_CANRECURSE, dnp);
213 		dirfs_node_drop(dmp, dnp);
214 	} else {
215 		passive_fd_list_miss++;
216 		error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, &vp, NULL, 0);
217 	}
218 
219 	if (vp) {
220 		if ((vp->v_refcnt & VREF_FINALIZE) == 0)
221 			atomic_set_int(&vp->v_refcnt, VREF_FINALIZE);
222 
223 		if (error && error == ENOENT) {
224 			cache_setvp(nch, NULL);
225 		} else {
226 			vn_unlock(vp);
227 			cache_setvp(nch, vp);
228 			vrele(vp);
229 		}
230 	}
231 
232 	KTR_LOG(dirfs_nresolve, dnp, ncp->nc_name, pdnp, pdnp->dn_fd, error);
233 
234 	return error;
235 }
236 
237 static int
238 dirfs_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
239 {
240 	debug_called();
241 
242 	KTR_LOG(dirfs_unsupported, __func__);
243 
244 	return EOPNOTSUPP;
245 }
246 
247 static int
248 dirfs_ncreate(struct vop_ncreate_args *ap)
249 {
250 	dirfs_node_t pdnp;
251 	dirfs_node_t dnp;
252 	dirfs_mount_t dmp;
253 	struct namecache *ncp;
254 	struct vnode *dvp;
255 	struct vnode **vpp;
256 	struct vattr *vap;
257 	int perms = 0;
258 	int error;
259 
260 	debug_called();
261 
262 	error = 0;
263 	dnp = NULL;
264 	dvp = ap->a_dvp;
265 	pdnp = VP_TO_NODE(dvp);
266 	dmp = VFS_TO_DIRFS(dvp->v_mount);
267 	vap = ap->a_vap;
268 	ncp = ap->a_nch->ncp;
269 	vpp = ap->a_vpp;
270 
271 	dirfs_mount_gettoken(dmp);
272 
273 	dirfs_node_getperms(pdnp, &perms);
274 	if ((perms & DIRFS_NODE_WR) == 0)
275 		error = EPERM;
276 
277 	error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp, vap,
278 	    (O_CREAT | O_RDWR));
279 
280 	if (error == 0) {
281 		cache_setunresolved(ap->a_nch);
282 		cache_setvp(ap->a_nch, *vpp);
283 	}
284 
285 	dirfs_mount_reltoken(dmp);
286 
287 	KTR_LOG(dirfs_ncreate, dnp, ncp->nc_name, pdnp, pdnp->dn_fd, error);
288 
289 	return error;
290 }
291 
292 static int
293 dirfs_nmknod(struct vop_nmknod_args *v)
294 {
295 	debug_called();
296 
297 	return EOPNOTSUPP;
298 }
299 
300 static int
301 dirfs_open(struct vop_open_args *ap)
302 {
303 	dirfs_node_t dnp;
304 	dirfs_mount_t dmp;
305 	struct vnode *vp;
306 	int error;
307 
308 	debug_called();
309 
310 	vp = ap->a_vp;
311 	dnp = VP_TO_NODE(vp);
312 	dmp = VFS_TO_DIRFS(vp->v_mount);
313 	error = 0;
314 
315 	/*
316 	 * Root inode has been allocated and opened in VFS_ROOT() so
317 	 * no reason to attempt to open it again.
318 	 */
319 	if (dmp->dm_root != dnp && dnp->dn_fd == DIRFS_NOFD) {
320 		error = dirfs_open_helper(dmp, dnp, DIRFS_NOFD, NULL);
321 		if (error)
322 			return error;
323 	}
324 
325 	KTR_LOG(dirfs_open, dnp, dnp->dn_name, dnp->dn_fd);
326 
327 	return vop_stdopen(ap);
328 }
329 
330 static int
331 dirfs_close(struct vop_close_args *ap)
332 {
333 	struct vnode *vp;
334 	dirfs_node_t dnp;
335 	int error;
336 
337 	debug_called();
338 
339 	error = 0;
340 	vp = ap->a_vp;
341 	dnp = VP_TO_NODE(vp);
342 
343 	if (vp->v_type == VREG) {
344 		error = vfsync(vp, 0, 1, NULL, NULL);
345 		if (error)
346 			dbg(5, "vfsync error=%d\n", error);
347 	}
348 	vop_stdclose(ap);
349 
350 	KTR_LOG(dirfs_close, dnp, dnp->dn_fd, vp->v_opencount,
351 	    vp->v_writecount, error);
352 
353 	return 0;
354 }
355 
356 int
357 dirfs_access(struct vop_access_args *ap)
358 {
359 	struct vnode *vp = ap->a_vp;
360 	int error;
361 	dirfs_node_t dnp;
362 
363 	debug_called();
364 
365 	dnp = VP_TO_NODE(vp);
366 
367 	switch (vp->v_type) {
368 	case VDIR:
369 		/* FALLTHROUGH */
370 	case VLNK:
371 		/* FALLTHROUGH */
372 	case VREG:
373 		if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
374 			error = EROFS;
375 			goto out;
376 		}
377 		break;
378 	case VBLK:
379 		/* FALLTHROUGH */
380 	case VCHR:
381 		/* FALLTHROUGH */
382 	case VSOCK:
383 		/* FALLTHROUGH */
384 	case VFIFO:
385 		break;
386 
387 	default:
388 		error = EINVAL;
389 		goto out;
390 	}
391 
392 	error = vop_helper_access(ap, dnp->dn_uid,
393 	    dnp->dn_gid, dnp->dn_mode, 0);
394 
395 out:
396 	KTR_LOG(dirfs_access, dnp, error);
397 
398 	return error;
399 }
400 
401 int
402 dirfs_getattr(struct vop_getattr_args *ap)
403 {
404 	dirfs_mount_t dmp;
405 	dirfs_node_t dnp;
406 	dirfs_node_t pathnp;
407 	struct vnode *vp;
408 	struct vattr *vap;
409 	char *tmp;
410 	char *pathfree;
411 	int error;
412 
413 	debug_called();
414 
415 	vp = ap->a_vp;
416 	vap = ap->a_vap;
417 	dnp = VP_TO_NODE(vp);
418 	dmp = VFS_TO_DIRFS(vp->v_mount);
419 
420 	KKASSERT(dnp);	/* This must not happen */
421 
422 	if (!dirfs_node_isroot(dnp)) {
423 		pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
424 
425 		KKASSERT(pathnp->dn_fd != DIRFS_NOFD);
426 
427 		error = dirfs_node_stat(pathnp->dn_fd, tmp, dnp);
428 		dirfs_dropfd(dmp, pathnp, pathfree);
429 	} else {
430 		error = dirfs_node_stat(DIRFS_NOFD, dmp->dm_path, dnp);
431 	}
432 
433 	if (error == 0) {
434 		dirfs_node_lock(dnp);
435 		vap->va_nlink = dnp->dn_links;
436 		vap->va_type = dnp->dn_type;
437 		vap->va_mode = dnp->dn_mode;
438 		vap->va_uid = dnp->dn_uid;
439 		vap->va_gid = dnp->dn_gid;
440 		vap->va_fileid = dnp->dn_ino;
441 		vap->va_size = dnp->dn_size;
442 		vap->va_blocksize = dnp->dn_blocksize;
443 		vap->va_atime.tv_sec = dnp->dn_atime;
444 		vap->va_atime.tv_nsec = dnp->dn_atimensec;
445 		vap->va_mtime.tv_sec = dnp->dn_mtime;
446 		vap->va_mtime.tv_nsec = dnp->dn_mtimensec;
447 		vap->va_ctime.tv_sec = dnp->dn_ctime;
448 		vap->va_ctime.tv_nsec = dnp->dn_ctimensec;
449 		vap->va_bytes = dnp->dn_size;
450 		vap->va_gen = dnp->dn_gen;
451 		vap->va_flags = dnp->dn_flags;
452 		vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
453 		dirfs_node_unlock(dnp);
454 	}
455 
456 	KTR_LOG(dirfs_getattr, dnp, error);
457 
458 	return 0;
459 }
460 
461 int
462 dirfs_setattr(struct vop_setattr_args *ap)
463 {
464 	dirfs_mount_t dmp;
465 	dirfs_node_t dnp;
466 	struct vnode *vp;
467 	struct vattr *vap;
468 	struct ucred *cred;
469 	int error;
470 #ifdef KTR
471 	const char *msg[6] = {
472 		"invalid",
473 		"chflags",
474 		"chsize",
475 		"chown",
476 		"chmod",
477 		"chtimes"
478 	};
479 #endif
480 	int msgno;
481 
482 	debug_called();
483 
484 	error = msgno = 0;
485 	vp = ap->a_vp;
486 	vap = ap->a_vap;
487 	cred = ap->a_cred;
488 	dnp = VP_TO_NODE(vp);
489 	dmp = VFS_TO_DIRFS(vp->v_mount);
490 
491 	dirfs_mount_gettoken(dmp);
492 
493 	/*
494 	 * Check for unsettable attributes.
495 	 */
496 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
497 	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
498 	    (vap->va_blocksize != VNOVAL) || (vap->va_rmajor != VNOVAL) ||
499 	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
500 		msgno = 0;
501 		error = EINVAL;
502 		goto out;
503 	}
504 
505 	/*
506 	 * Change file flags
507 	 */
508 	if (error == 0 && (vap->va_flags != VNOVAL)) {
509 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
510 			error = EROFS;
511 		else
512 			error = dirfs_node_chflags(dnp, vap->va_flags, cred);
513 		msgno = 1;
514 		goto out;
515 	}
516 
517 	/*
518 	 * Extend or truncate a file
519 	 */
520 	if (error == 0 && (vap->va_size != VNOVAL)) {
521 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
522 			error = EROFS;
523 		else
524 			error = dirfs_node_chsize(dnp, vap->va_size);
525 		dbg(2, "dnp size=%jd vap size=%jd\n", dnp->dn_size, vap->va_size);
526 		msgno = 2;
527 		goto out;
528 	}
529 
530 	/*
531 	 * Change file owner or group
532 	 */
533 	if (error == 0 && (vap->va_uid != (uid_t)VNOVAL ||
534 		vap->va_gid != (gid_t)VNOVAL)) {
535 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
536 			error = EROFS;
537 		} else {
538 			mode_t cur_mode = dnp->dn_mode;
539 			uid_t cur_uid = dnp->dn_uid;
540 			gid_t cur_gid = dnp->dn_gid;
541 
542 			error = vop_helper_chown(ap->a_vp, vap->va_uid,
543 						 vap->va_gid, ap->a_cred,
544 						 &cur_uid, &cur_gid, &cur_mode);
545 			if (error == 0 &&
546 			    (cur_mode != dnp->dn_mode ||
547 			     cur_uid != dnp->dn_uid ||
548 			     cur_gid != dnp->dn_gid)) {
549 				error = dirfs_node_chown(dmp, dnp, cur_uid,
550 							 cur_gid, cur_mode);
551 			}
552 		}
553 		msgno = 3;
554 		goto out;
555 	}
556 
557 	/*
558 	 * Change file mode
559 	 */
560 	if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) {
561 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
562 			error = EROFS;
563 		} else {
564 			mode_t cur_mode = dnp->dn_mode;
565 			uid_t cur_uid = dnp->dn_uid;
566 			gid_t cur_gid = dnp->dn_gid;
567 
568 			error = vop_helper_chmod(ap->a_vp, vap->va_mode,
569 						 ap->a_cred,
570 						 cur_uid, cur_gid, &cur_mode);
571 			if (error == 0 && cur_mode != dnp->dn_mode) {
572 				error = dirfs_node_chmod(dmp, dnp, cur_mode);
573 			}
574 		}
575 		msgno = 4;
576 		goto out;
577 	}
578 
579 	/*
580 	 * Change file times
581 	 */
582 	if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
583 		vap->va_atime.tv_nsec != VNOVAL) ||
584 		(vap->va_mtime.tv_sec != VNOVAL &&
585 		vap->va_mtime.tv_nsec != VNOVAL) )) {
586 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
587 			error = EROFS;
588 		else
589 			error = dirfs_node_chtimes(dnp);
590 		msgno = 5;
591 		goto out;
592 
593 	}
594 out:
595 	dirfs_mount_reltoken(dmp);
596 
597 	KTR_LOG(dirfs_setattr, dnp, msg[msgno], error);
598 
599 	return error;
600 }
601 
602 static int
603 dirfs_fsync(struct vop_fsync_args *ap)
604 {
605 	dirfs_node_t dnp = VP_TO_NODE(ap->a_vp);
606 	int error = 0;
607 
608 	debug_called();
609 
610 	vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL);
611 
612 	if (dnp->dn_fd != DIRFS_NOFD) {
613 		if (fsync(dnp->dn_fd) == -1)
614 			error = fsync(dnp->dn_fd);
615 	}
616 
617 	KTR_LOG(dirfs_fsync, dnp, error);
618 
619 	return 0;
620 }
621 
622 static int
623 dirfs_read(struct vop_read_args *ap)
624 {
625 	struct buf *bp;
626 	struct vnode *vp = ap->a_vp;
627 	struct uio *uio = ap->a_uio;
628 	dirfs_node_t dnp;
629 	off_t base_offset;
630 	size_t offset;
631 	size_t len;
632 	int error;
633 
634 	debug_called();
635 
636 	error = 0;
637 	if (uio->uio_resid == 0) {
638 		dbg(5, "zero len uio->uio_resid\n");
639 		return error;
640 	}
641 
642 	dnp = VP_TO_NODE(vp);
643 
644 	if (uio->uio_offset < 0)
645 		return (EINVAL);
646 	if (vp->v_type != VREG)
647 		return (EINVAL);
648 
649 	while (uio->uio_resid > 0 && uio->uio_offset < dnp->dn_size) {
650 		/*
651 		 * Use buffer cache I/O (via dirfs_strategy)
652 		 */
653 		offset = (size_t)uio->uio_offset & BMASK;
654 		base_offset = (off_t)uio->uio_offset - offset;
655 		bp = getcacheblk(vp, base_offset, BSIZE, 0);
656 		if (bp == NULL) {
657 			lwkt_gettoken(&vp->v_mount->mnt_token);
658 			error = bread(vp, base_offset, BSIZE, &bp);
659 			if (error) {
660 				brelse(bp);
661 				lwkt_reltoken(&vp->v_mount->mnt_token);
662 				dbg(5, "dirfs_read bread error %d\n", error);
663 				break;
664 			}
665 			lwkt_reltoken(&vp->v_mount->mnt_token);
666 		}
667 
668 		/*
669 		 * Figure out how many bytes we can actually copy this loop.
670 		 */
671 		len = BSIZE - offset;
672 		if (len > uio->uio_resid)
673 			len = uio->uio_resid;
674 		if (len > dnp->dn_size - uio->uio_offset)
675 			len = (size_t)(dnp->dn_size - uio->uio_offset);
676 
677 		error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
678 		bqrelse(bp);
679 		if (error) {
680 			dbg(5, "dirfs_read uiomove error %d\n", error);
681 			break;
682 		}
683 	}
684 
685 	KTR_LOG(dirfs_read, dnp, dnp->dn_size, error);
686 
687 	return(error);
688 }
689 
690 static int
691 dirfs_write (struct vop_write_args *ap)
692 {
693 	dirfs_node_t dnp;
694 	dirfs_mount_t dmp;
695 	struct buf *bp;
696 	struct vnode *vp = ap->a_vp;
697 	struct uio *uio = ap->a_uio;
698 	struct thread *td = uio->uio_td;
699 	int error;
700 	off_t osize;
701 	off_t nsize;
702 	off_t base_offset;
703 	size_t offset;
704 	size_t len;
705 	struct rlimit limit;
706 
707 	debug_called();
708 
709 	error = 0;
710 	if (uio->uio_resid == 0) {
711 		dbg(5, "zero-length uio->uio_resid\n");
712 		return error;
713 	}
714 
715 	dnp = VP_TO_NODE(vp);
716 	dmp = VFS_TO_DIRFS(vp->v_mount);
717 
718 	if (vp->v_type != VREG)
719 		return (EINVAL);
720 
721 	if (vp->v_type == VREG && td != NULL) {
722 		error = kern_getrlimit(RLIMIT_FSIZE, &limit);
723 		if (error != 0) {
724 			dbg(5, "rlimit failure\n");
725 			return error;
726 		}
727 		if (uio->uio_offset + uio->uio_resid > limit.rlim_cur) {
728 			dbg(5, "file too big\n");
729 			ksignal(td->td_proc, SIGXFSZ);
730 			return (EFBIG);
731 		}
732 	}
733 
734 	if (ap->a_ioflag & IO_APPEND)
735 		uio->uio_offset = dnp->dn_size;
736 
737 	/*
738 	 * buffer cache operations may be deferred, make sure
739 	 * the file is correctly sized right now.
740 	 */
741 	osize = dnp->dn_size;
742 	nsize = uio->uio_offset + uio->uio_resid;
743 	if (nsize > osize && uio->uio_resid) {
744 		KKASSERT(dnp->dn_fd >= 0);
745 		dnp->dn_size = nsize;
746 		ftruncate(dnp->dn_fd, nsize);
747 		nvextendbuf(vp, osize, nsize,
748 			    BSIZE, BSIZE, -1, -1, 0);
749 	} /* else nsize = osize; NOT USED */
750 
751 	while (uio->uio_resid > 0) {
752 		/*
753 		 * Use buffer cache I/O (via dirfs_strategy)
754 		 */
755 		offset = (size_t)uio->uio_offset & BMASK;
756 		base_offset = (off_t)uio->uio_offset - offset;
757 		len = BSIZE - offset;
758 
759 		if (len > uio->uio_resid)
760 			len = uio->uio_resid;
761 
762 		error = bread(vp, base_offset, BSIZE, &bp);
763 		error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
764 		if (error) {
765 			brelse(bp);
766 			dbg(2, "WRITE uiomove failed\n");
767 			break;
768 		}
769 
770 //		dbg(2, "WRITE dn_size=%jd uio_offset=%jd uio_resid=%jd base_offset=%jd\n",
771 //		    dnp->dn_size, uio->uio_offset, uio->uio_resid, base_offset);
772 
773 		if (ap->a_ioflag & IO_SYNC)
774 			bwrite(bp);
775 		else
776 			bdwrite(bp);
777 	}
778 
779 	KTR_LOG(dirfs_write, dnp, base_offset, uio->uio_resid,
780 	    dnp->dn_size, error);
781 
782 	return error;
783 }
784 
785 static int
786 dirfs_advlock (struct vop_advlock_args *ap)
787 {
788 	struct vnode *vp = ap->a_vp;
789 	dirfs_node_t dnp = VP_TO_NODE(vp);
790 
791 	debug_called();
792 
793 	return (lf_advlock(ap, &dnp->dn_advlock, dnp->dn_size));
794 }
795 
796 static int
797 dirfs_strategy(struct vop_strategy_args *ap)
798 {
799 	dirfs_node_t dnp;
800 	dirfs_mount_t dmp;
801 	struct bio *bio = ap->a_bio;
802 	struct buf *bp = bio->bio_buf;
803 	struct vnode *vp = ap->a_vp;
804 	int error;
805 	size_t iosize;
806 	char *tmp;
807 	char *pathfree;
808 
809 	debug_called();
810 
811 	dnp = VP_TO_NODE(vp);
812 	dmp = VFS_TO_DIRFS(vp->v_mount);
813 
814 	error = 0;
815 
816 	if (vp->v_type != VREG)  {
817 		dbg(5, "not VREG\n");
818 		bp->b_resid = bp->b_bcount;
819 		bp->b_flags |= B_ERROR | B_INVAL;
820 		bp->b_error = EINVAL;
821 		biodone(bio);
822 		return(0);
823 	}
824 
825 	if (dnp->dn_fd == DIRFS_NOFD) {
826 		print_backtrace(-1);
827 		panic("Meh, no fd to write to. dnp=%p\n", dnp);
828 	}
829 
830 	if (bio->bio_offset + bp->b_bcount > dnp->dn_size)
831 		iosize = dnp->dn_size - bio->bio_offset;
832 	else
833 		iosize = bp->b_bcount;
834 	KKASSERT((ssize_t)iosize >= 0);
835 
836 	switch (bp->b_cmd) {
837 	case BUF_CMD_WRITE:
838 		error = pwrite(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset);
839 		break;
840 	case BUF_CMD_READ:
841 		error = pread(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset);
842 		break;
843 	default:
844 		bp->b_error = error = EINVAL;
845 		bp->b_flags |= B_ERROR;
846 		break;
847 	}
848 
849 	if (error >= 0 && error < bp->b_bcount)
850 		bzero(bp->b_data + error, bp->b_bcount - error);
851 
852 	if (error < 0 && errno != EINTR) {
853 		dbg(5, "error=%d dnp=%p dnp->dn_fd=%d "
854 		    "bio->bio_offset=%ld bcount=%d resid=%d iosize=%zd\n",
855 		    errno, dnp, dnp->dn_fd, bio->bio_offset, bp->b_bcount,
856 		    bp->b_resid, iosize);
857 		bp->b_error = errno;
858 		bp->b_resid = bp->b_bcount;
859 		bp->b_flags |= B_ERROR;
860 	} else {
861 		tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
862 		dirfs_node_stat(DIRFS_NOFD, tmp, dnp);
863 		dirfs_dropfd(dmp, NULL, pathfree);
864 	}
865 
866 	KTR_LOG(dirfs_strategy, dnp, dnp->dn_size, iosize, bp->b_cmd,
867 	    bp->b_error, bp->b_resid, bio->bio_offset, error);
868 
869 	biodone(bio);
870 
871 	return 0;
872 }
873 
874 static int
875 dirfs_bmap(struct vop_bmap_args *ap)
876 {
877 	debug_called();
878 
879 	if (ap->a_doffsetp != NULL)
880 		*ap->a_doffsetp = ap->a_loffset;
881 	if (ap->a_runp != NULL)
882 		*ap->a_runp = 0;
883 	if (ap->a_runb != NULL)
884 		*ap->a_runb = 0;
885 
886 	return 0;
887 }
888 
889 static int
890 dirfs_nremove(struct vop_nremove_args *ap)
891 {
892 	dirfs_node_t dnp, pdnp;
893 	dirfs_node_t pathnp;
894 	dirfs_mount_t dmp;
895 	struct vnode *dvp;
896 	struct nchandle *nch;
897 	struct namecache *ncp;
898 	struct mount *mp;
899 	struct vnode *vp;
900 	int error;
901 	char *tmp;
902 	char *pathfree;
903 	debug_called();
904 
905 	error = 0;
906 	tmp = NULL;
907 	vp = NULL;
908 	dvp = ap->a_dvp;
909 	nch = ap->a_nch;
910 	ncp = nch->ncp;
911 
912 	mp = dvp->v_mount;
913 	dmp = VFS_TO_DIRFS(mp);
914 
915 	lwkt_gettoken(&mp->mnt_token);
916 	cache_vget(nch, ap->a_cred, LK_SHARED, &vp);
917 	vn_unlock(vp);
918 
919 	pdnp = VP_TO_NODE(dvp);
920 	dnp = VP_TO_NODE(vp);
921 
922 	if (vp->v_type == VDIR) {
923 		error = EISDIR;
924 	} else {
925 		pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
926 		dirfs_node_lock(pdnp);
927 		error = unlinkat(pathnp->dn_fd, tmp, 0);
928 		if (error == 0) {
929 			cache_unlink(nch);
930 			dirfs_node_setpassive(dmp, dnp, 0);
931 			if (dnp->dn_parent) {
932 				dirfs_node_drop(dmp, dnp->dn_parent);
933 				dnp->dn_parent = NULL;
934 			}
935 		} else {
936 			error = errno;
937 		}
938 		dirfs_node_unlock(pdnp);
939 		dirfs_dropfd(dmp, pathnp, pathfree);
940 	}
941 	vrele(vp);
942 	lwkt_reltoken(&mp->mnt_token);
943 
944 	KTR_LOG(dirfs_nremove, dnp, pdnp, error);
945 
946 	return error;
947 }
948 
949 static int
950 dirfs_nlink(struct vop_nlink_args *ap)
951 {
952 	debug_called();
953 
954 	KTR_LOG(dirfs_unsupported, __func__);
955 
956 	return EOPNOTSUPP;
957 }
958 
959 static int
960 dirfs_nrename(struct vop_nrename_args *ap)
961 {
962 	dirfs_node_t dnp, fdnp, tdnp;
963 	dirfs_mount_t dmp;
964 	struct namecache *fncp, *tncp;
965 	struct vnode *fdvp, *tdvp, *vp;
966 	struct mount *mp;
967 	char *fpath, *fpathfree;
968 	char *tpath, *tpathfree;
969 	int error;
970 
971 	debug_called();
972 
973 	error = 0;
974 	fdvp = ap->a_fdvp;
975 	tdvp = ap->a_tdvp;
976 	fncp = ap->a_fnch->ncp;
977 	tncp = ap->a_tnch->ncp;
978 	mp = fdvp->v_mount;
979 	dmp = VFS_TO_DIRFS(mp);
980 	fdnp = VP_TO_NODE(fdvp);
981 	tdnp = VP_TO_NODE(tdvp);
982 
983 	dbg(5, "fdnp=%p tdnp=%p from=%s to=%s\n", fdnp, tdnp, fncp->nc_name,
984 	    tncp->nc_name);
985 
986 	if (fdvp->v_mount != tdvp->v_mount)
987 		return(EXDEV);
988 	if (fdvp->v_mount != fncp->nc_vp->v_mount)
989 		return(EXDEV);
990 	if (fdvp->v_mount->mnt_flag & MNT_RDONLY)
991 		return (EROFS);
992 
993 	tpath = dirfs_node_absolute_path_plus(dmp, tdnp,
994 					      tncp->nc_name, &tpathfree);
995 	fpath = dirfs_node_absolute_path_plus(dmp, fdnp,
996 					      fncp->nc_name, &fpathfree);
997 	error = rename(fpath, tpath);
998 	if (error < 0)
999 		error = errno;
1000 	if (error == 0) {
1001 		vp = fncp->nc_vp;	/* file being renamed */
1002 		dnp = VP_TO_NODE(vp);
1003 		dirfs_node_setname(dnp, tncp->nc_name, tncp->nc_nlen);
1004 
1005 		/*
1006 		 * We have to mark the target file that was replaced by
1007 		 * the rename as having been unlinked.
1008 		 */
1009 		vp = tncp->nc_vp;
1010 		if (vp) {
1011 			dbg(5, "RENAME2\n");
1012 			dnp = VP_TO_NODE(vp);
1013 			cache_unlink(ap->a_tnch);
1014 			dirfs_node_setpassive(dmp, dnp, 0);
1015 			if (dnp->dn_parent) {
1016 				dirfs_node_drop(dmp, dnp->dn_parent);
1017 				dnp->dn_parent = NULL;
1018 			}
1019 
1020 			/*
1021 			 * nlinks on directories can be a bit weird.  Zero
1022 			 * it out.
1023 			 */
1024 			dnp->dn_links = 0;
1025 			cache_inval_vp(vp, CINV_DESTROY);
1026 		}
1027 		cache_rename(ap->a_fnch, ap->a_tnch);
1028 	}
1029 	dirfs_dropfd(dmp, NULL, fpathfree);
1030 	dirfs_dropfd(dmp, NULL, tpathfree);
1031 
1032 	return error;
1033 }
1034 
1035 static int
1036 dirfs_nmkdir(struct vop_nmkdir_args *ap)
1037 {
1038 	dirfs_mount_t dmp;
1039 	dirfs_node_t dnp, pdnp, dnp1;
1040 	struct namecache *ncp;
1041 	struct vattr *vap;
1042 	struct vnode *dvp;
1043 	struct vnode **vpp;
1044 	char *tmp, *pathfree;
1045 	char *path;
1046 	int pfd, error;
1047 	int extrapath;
1048 
1049 	debug_called();
1050 
1051 	extrapath = error = 0;
1052 	dvp = ap->a_dvp;
1053 	vpp = ap->a_vpp;
1054 	dmp = VFS_TO_DIRFS(dvp->v_mount);
1055 	pdnp = VP_TO_NODE(dvp);
1056 	ncp = ap->a_nch->ncp;
1057 	vap = ap->a_vap;
1058 	pathfree = tmp = path = NULL;
1059 	dnp = NULL;
1060 
1061 	dirfs_node_lock(pdnp);
1062 	if (pdnp->dn_fd != DIRFS_NOFD) {
1063 		pfd = pdnp->dn_fd;
1064 		path = ncp->nc_name;
1065 	} else {
1066 		dnp1 = dirfs_findfd(dmp, pdnp, &tmp, &pathfree);
1067 		pfd = dnp1->dn_fd;
1068 		/* XXX check there is room to copy the path */
1069 		path = kmalloc(MAXPATHLEN, M_DIRFS_MISC, M_ZERO | M_WAITOK);
1070 		ksnprintf(path, MAXPATHLEN, "%s/%s", tmp, ncp->nc_name);
1071 		extrapath = 1;
1072 		dirfs_dropfd(dmp, dnp1, pathfree);
1073 	}
1074 
1075 	error = mkdirat(pfd, path, vap->va_mode);
1076 	if (error) {
1077 		error = errno;
1078 	} else { /* Directory has been made */
1079 		error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp,
1080 		    vap, O_DIRECTORY);
1081 		if (error)
1082 			error = errno;
1083 		cache_setunresolved(ap->a_nch);
1084 		cache_setvp(ap->a_nch, *vpp);
1085 	}
1086 	dirfs_node_unlock(pdnp);
1087 
1088 	if (extrapath)
1089 		kfree(path, M_DIRFS_MISC);
1090 
1091 	KTR_LOG(dirfs_nmkdir, pdnp, dnp, ncp->nc_name, error);
1092 
1093 	return error;
1094 }
1095 
1096 static int
1097 dirfs_nrmdir(struct vop_nrmdir_args *ap)
1098 {
1099 	dirfs_node_t dnp, pdnp;
1100 	dirfs_mount_t dmp;
1101 	struct vnode *dvp;
1102 	struct nchandle *nch;
1103 	struct namecache *ncp;
1104 	struct mount *mp;
1105 	struct vnode *vp;
1106 	int error;
1107 	char *tmp;
1108 	char *pathfree;
1109 
1110 	debug_called();
1111 
1112 	error = 0;
1113 	tmp = NULL;
1114 	vp = NULL;
1115 	dvp = ap->a_dvp;
1116 	nch = ap->a_nch;
1117 	ncp = nch->ncp;
1118 
1119 	mp = dvp->v_mount;
1120 	dmp = VFS_TO_DIRFS(mp);
1121 
1122 	lwkt_gettoken(&mp->mnt_token);
1123 	cache_vget(nch, ap->a_cred, LK_SHARED, &vp);
1124 	vn_unlock(vp);
1125 
1126 	pdnp = VP_TO_NODE(dvp);
1127 	dnp = VP_TO_NODE(vp);
1128 
1129 	if (vp->v_type != VDIR) {
1130 		error = ENOTDIR;
1131 	} else {
1132 		tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
1133 		dirfs_node_lock(pdnp);
1134 		error = rmdir(tmp);
1135 		if (error == 0) {
1136 			cache_unlink(nch);
1137 			dirfs_node_setpassive(dmp, dnp, 0);
1138 			if (dnp->dn_parent) {
1139 				dirfs_node_drop(dmp, dnp->dn_parent);
1140 				dnp->dn_parent = NULL;
1141 			}
1142 
1143 			/*
1144 			 * nlinks on directories can be a bit weird.  Zero
1145 			 * it out.
1146 			 */
1147 			dnp->dn_links = 0;
1148 			cache_inval_vp(vp, CINV_DESTROY);
1149 		} else {
1150 			error = errno;
1151 		}
1152 		dirfs_node_unlock(pdnp);
1153 		dirfs_dropfd(dmp, NULL, pathfree);
1154 	}
1155 	vrele(vp);
1156 	lwkt_reltoken(&mp->mnt_token);
1157 
1158 	KTR_LOG(dirfs_nrmdir, dnp, pdnp, error);
1159 
1160 	return error;
1161 }
1162 
1163 static int
1164 dirfs_nsymlink(struct vop_nsymlink_args *ap)
1165 {
1166 	dirfs_mount_t dmp;
1167 	dirfs_node_t dnp, pdnp;
1168 	struct mount *mp;
1169 	struct namecache *ncp;
1170 	struct vattr *vap;
1171 	struct vnode *dvp;
1172 	struct vnode **vpp;
1173 	char *tmp, *pathfree;
1174 	char *path;
1175 	int error;
1176 
1177 	debug_called();
1178 
1179 	error = 0;
1180 	dvp = ap->a_dvp;
1181 	vpp = ap->a_vpp;
1182 	mp = dvp->v_mount;
1183 	dmp = VFS_TO_DIRFS(dvp->v_mount);
1184 	pdnp = VP_TO_NODE(dvp);
1185 	ncp = ap->a_nch->ncp;
1186 	vap = ap->a_vap;
1187 	pathfree = tmp = path = NULL;
1188 	dnp = NULL;
1189 
1190 	lwkt_gettoken(&mp->mnt_token);
1191 	vap->va_type = VLNK;
1192 
1193 	/* Find out the whole path of our new symbolic link */
1194 	tmp = dirfs_node_absolute_path(dmp, pdnp, &pathfree);
1195 	/* XXX check there is room to copy the path */
1196 	path = kmalloc(MAXPATHLEN, M_DIRFS_MISC, M_ZERO | M_WAITOK);
1197 	ksnprintf(path, MAXPATHLEN, "%s/%s", tmp, ncp->nc_name);
1198 	dirfs_dropfd(dmp, NULL, pathfree);
1199 
1200 	error = symlink(ap->a_target, path);
1201 	if (error) {
1202 		error = errno;
1203 	} else { /* Symlink has been made */
1204 		error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp,
1205 		    NULL, 0);
1206 		if (error)
1207 			error = errno;
1208 		cache_setunresolved(ap->a_nch);
1209 		cache_setvp(ap->a_nch, *vpp);
1210 	}
1211 	dbg(5, "path=%s a_target=%s\n", path, ap->a_target);
1212 
1213 	KTR_LOG(dirfs_nsymlink, dnp, ap->a_target, path, error);
1214 	kfree(path, M_DIRFS_MISC);
1215 	lwkt_reltoken(&mp->mnt_token);
1216 
1217 	return error;
1218 
1219 }
1220 
1221 static int
1222 dirfs_readdir(struct vop_readdir_args *ap)
1223 {
1224 
1225 	struct dirent *dp, *dpn;
1226 	off_t __unused **cookies = ap->a_cookies;
1227 	int *ncookies = ap->a_ncookies;
1228 	int bytes;
1229 	char *buf;
1230 	long base;
1231 	struct vnode *vp = ap->a_vp;
1232 	struct uio *uio;
1233 	dirfs_node_t dnp;
1234 	off_t startoff;
1235 	off_t cnt;
1236 	int error, r;
1237 	size_t bufsiz;
1238 	off_t curoff;
1239 
1240 	debug_called();
1241 
1242 	if (ncookies)
1243 		debug(1, "ncookies=%d\n", *ncookies);
1244 
1245 	dnp = VP_TO_NODE(vp);
1246 	uio = ap->a_uio;
1247 	startoff = uio->uio_offset;
1248 	cnt = 0;
1249 	error = 0;
1250 	base = 0;
1251 	bytes = 0;
1252 
1253 	if (vp->v_type != VDIR)
1254 		return ENOTDIR;
1255 	if (uio->uio_resid < 0)
1256 		return EINVAL;
1257 	if ((bufsiz = uio->uio_resid) > 4096)
1258 		bufsiz = 4096;
1259 	buf = kmalloc(bufsiz, M_DIRFS_MISC, M_WAITOK | M_ZERO);
1260 
1261 	/*
1262 	 * Generally speaking we have to be able to process ALL the
1263 	 * entries returned by getdirentries() in order for the seek
1264 	 * position to be correct.  For now try to size the buffer
1265 	 * to make this happen.  A smaller buffer always works.  For
1266 	 * now just use an appropriate size.
1267 	 */
1268 	dirfs_node_lock(dnp);
1269 	lseek(dnp->dn_fd, startoff, SEEK_SET);
1270 	bytes = getdirentries(dnp->dn_fd, buf, bufsiz, &base);
1271 	dbg(5, "seek %016jx %016jx %016jx\n",
1272 		(intmax_t)startoff, (intmax_t)base,
1273 		(intmax_t)lseek(dnp->dn_fd, 0, SEEK_CUR));
1274 	if (bytes < 0) {
1275 		if (errno == EINVAL)
1276 			panic("EINVAL on readdir\n");
1277 		error = errno;
1278 		curoff = startoff;
1279 		goto out;
1280 	} else if (bytes == 0) {
1281 		*ap->a_eofflag = 1;
1282 		curoff = startoff;
1283 		goto out;
1284 	}
1285 
1286 	for (dp = (struct dirent *)buf; bytes > 0 && uio->uio_resid > 0;
1287 	    bytes -= _DIRENT_DIRSIZ(dp), dp = dpn) {
1288 		r = vop_write_dirent(&error, uio, dp->d_ino, dp->d_type,
1289 		    dp->d_namlen, dp->d_name);
1290 		if (error || r)
1291 			break;
1292 		dpn = _DIRENT_NEXT(dp);
1293 		dp = dpn;
1294 		cnt++;
1295 	}
1296 	curoff = lseek(dnp->dn_fd, 0, SEEK_CUR);
1297 
1298 out:
1299 	kfree(buf, M_DIRFS_MISC);
1300 	uio->uio_offset = curoff;
1301 	dirfs_node_unlock(dnp);
1302 
1303 	KTR_LOG(dirfs_readdir, dnp, dnp->dn_fd, startoff, uio->uio_offset);
1304 
1305 	return error;
1306 }
1307 
1308 static int
1309 dirfs_readlink(struct vop_readlink_args *ap)
1310 {
1311 	dirfs_node_t dnp, pathnp;
1312 	dirfs_mount_t dmp;
1313 	struct vnode *vp;
1314 	struct mount *mp;
1315 	struct uio *uio;
1316 	char *tmp, *pathfree, *buf;
1317 	ssize_t nlen;
1318 	int error;
1319 
1320 	debug_called();
1321 
1322 	vp = ap->a_vp;
1323 
1324 	KKASSERT(vp->v_type == VLNK);
1325 
1326 	error = 0;
1327 	tmp = pathfree = NULL;
1328 	uio = ap->a_uio;
1329 	mp = vp->v_mount;
1330 	dmp = VFS_TO_DIRFS(mp);
1331 	dnp = VP_TO_NODE(vp);
1332 
1333 	lwkt_gettoken(&mp->mnt_token);
1334 
1335 	pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
1336 
1337 	buf = kmalloc(uio->uio_resid, M_DIRFS_MISC, M_WAITOK | M_ZERO);
1338 	nlen = readlinkat(pathnp->dn_fd, dnp->dn_name, buf, uio->uio_resid);
1339 	if (nlen == -1 ) {
1340 		error = errno;
1341 	} else {
1342 		error = uiomove(buf, nlen + 1, uio);
1343 		buf[nlen] = '\0';
1344 		if (error)
1345 			error = errno;
1346 	}
1347 	dirfs_dropfd(dmp, pathnp, pathfree);
1348 	kfree(buf, M_DIRFS_MISC);
1349 
1350 	lwkt_reltoken(&mp->mnt_token);
1351 
1352 	return error;
1353 }
1354 
1355 /*
1356  * Main tasks to be performed.
1357  * 1) When inode is NULL recycle the vnode
1358  * 2) When the inode has 0 links:
1359  *	- Check if in the TAILQ, if so remove.
1360  *	- Destroy the inode.
1361  *	- Recycle the vnode.
1362  * 3) If none of the above, add the node to the TAILQ
1363  *    when it has a valid fd and there is room on the
1364  *    queue.
1365  *
1366  */
1367 static int
1368 dirfs_inactive(struct vop_inactive_args *ap)
1369 {
1370 	struct vnode *vp;
1371 	dirfs_mount_t dmp;
1372 	dirfs_node_t dnp;
1373 
1374 	debug_called();
1375 
1376 	vp = ap->a_vp;
1377 	dmp = VFS_TO_DIRFS(vp->v_mount);
1378 	dnp = VP_TO_NODE(vp);
1379 
1380 	/* Degenerate case */
1381 	if (dnp == NULL) {
1382 		dbg(5, "dnp was NULL\n");
1383 		vrecycle(vp);
1384 		return 0;
1385 	}
1386 
1387 	dirfs_mount_gettoken(dmp);
1388 
1389 	/*
1390 	 * Deal with the case the inode has 0 links which means it was unlinked.
1391 	 */
1392 	if (dnp->dn_links == 0) {
1393 		vrecycle(vp);
1394 		dbg(5, "recycled a vnode of an unlinked dnp\n");
1395 
1396 		goto out;
1397 	}
1398 
1399 	/*
1400 	 * Try to retain the fd in our fd cache.
1401 	 */
1402 	dirfs_node_setpassive(dmp, dnp, 1);
1403 out:
1404 	dirfs_mount_reltoken(dmp);
1405 
1406 	return 0;
1407 
1408 }
1409 
1410 int
1411 dirfs_reclaim(struct vop_reclaim_args *ap)
1412 {
1413 	struct vnode *vp;
1414 	dirfs_node_t dnp;
1415 	dirfs_mount_t dmp;
1416 
1417 	debug_called();
1418 
1419 	vp = ap->a_vp;
1420 	dnp = VP_TO_NODE(vp);
1421 	dmp = VFS_TO_DIRFS(vp->v_mount);
1422 
1423 	dirfs_free_vp(dmp, dnp);
1424 	/* dnp is now invalid, may have been destroyed */
1425 
1426 	return 0;
1427 }
1428 
1429 static int
1430 dirfs_mountctl(struct vop_mountctl_args *ap)
1431 {
1432 	debug_called();
1433 
1434 	KTR_LOG(dirfs_unsupported, __func__);
1435 
1436 	return EOPNOTSUPP;
1437 }
1438 
1439 static int
1440 dirfs_print(struct vop_print_args *v)
1441 {
1442 	debug_called();
1443 
1444 	KTR_LOG(dirfs_unsupported, __func__);
1445 
1446 	return EOPNOTSUPP;
1447 }
1448 
1449 static int __unused
1450 dirfs_pathconf(struct vop_pathconf_args *v)
1451 {
1452 	debug_called();
1453 
1454 	return EOPNOTSUPP;
1455 }
1456 
1457 static int
1458 dirfs_kqfilter (struct vop_kqfilter_args *ap)
1459 {
1460 	debug_called();
1461 
1462 	KTR_LOG(dirfs_unsupported, __func__);
1463 
1464 	return EOPNOTSUPP;
1465 }
1466 
1467 struct vop_ops dirfs_vnode_vops = {
1468 	.vop_default =			vop_defaultop,
1469 	.vop_nwhiteout =		vop_compat_nwhiteout,
1470 	.vop_ncreate =			dirfs_ncreate,
1471 	.vop_nresolve =			dirfs_nresolve,
1472 	.vop_markatime =		vop_stdmarkatime,
1473 	.vop_nlookupdotdot =		dirfs_nlookupdotdot,
1474 	.vop_nmknod =			dirfs_nmknod,
1475 	.vop_open =			dirfs_open,
1476 	.vop_close =			dirfs_close,
1477 	.vop_access =			dirfs_access,
1478 	.vop_getattr =			dirfs_getattr,
1479 	.vop_setattr =			dirfs_setattr,
1480 	.vop_read =			dirfs_read,
1481 	.vop_write =			dirfs_write,
1482 	.vop_fsync =			dirfs_fsync,
1483 	.vop_mountctl =			dirfs_mountctl,
1484 	.vop_nremove =			dirfs_nremove,
1485 	.vop_nlink =			dirfs_nlink,
1486 	.vop_nrename =			dirfs_nrename,
1487 	.vop_nmkdir =			dirfs_nmkdir,
1488 	.vop_nrmdir =			dirfs_nrmdir,
1489 	.vop_nsymlink =			dirfs_nsymlink,
1490 	.vop_readdir =			dirfs_readdir,
1491 	.vop_readlink =			dirfs_readlink,
1492 	.vop_inactive =			dirfs_inactive,
1493 	.vop_reclaim =			dirfs_reclaim,
1494 	.vop_print =			dirfs_print,
1495 	.vop_pathconf =			vop_stdpathconf,
1496 	.vop_bmap =			dirfs_bmap,
1497 	.vop_strategy =			dirfs_strategy,
1498 	.vop_advlock =			dirfs_advlock,
1499 	.vop_kqfilter =			dirfs_kqfilter,
1500 	.vop_getpages =			vop_stdgetpages,
1501 	.vop_putpages =			vop_stdputpages
1502 };
1503