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