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