dirfs - Change debug levels
[dragonfly.git] / sys / vfs / dirfs / dirfs_vnops.c
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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(9, "vfsync error=%d\n", error);
344         }
345         vop_stdclose(ap);
346
347         KTR_LOG(dirfs_close, dnp, dnp->dn_fd, vp->v_opencount,
348             vp->v_writecount, error);
349
350         return 0;
351 }
352
353 int
354 dirfs_access(struct vop_access_args *ap)
355 {
356         struct vnode *vp = ap->a_vp;
357         int error;
358         dirfs_node_t dnp;
359
360         dbg(3, "called\n");
361
362         dnp = VP_TO_NODE(vp);
363
364         switch (vp->v_type) {
365         case VDIR:
366                 /* FALLTHROUGH */
367         case VLNK:
368                 /* FALLTHROUGH */
369         case VREG:
370                 if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
371                         error = EROFS;
372                         goto out;
373                 }
374                 break;
375         case VBLK:
376                 /* FALLTHROUGH */
377         case VCHR:
378                 /* FALLTHROUGH */
379         case VSOCK:
380                 /* FALLTHROUGH */
381         case VFIFO:
382                 break;
383
384         default:
385                 error = EINVAL;
386                 goto out;
387         }
388
389         error = vop_helper_access(ap, dnp->dn_uid,
390             dnp->dn_gid, dnp->dn_mode, 0);
391
392 out:
393         KTR_LOG(dirfs_access, dnp, error);
394
395         return error;
396 }
397
398 int
399 dirfs_getattr(struct vop_getattr_args *ap)
400 {
401         dirfs_mount_t dmp;
402         dirfs_node_t dnp;
403         dirfs_node_t pathnp;
404         struct vnode *vp;
405         struct vattr *vap;
406         char *tmp;
407         char *pathfree;
408         int error;
409
410         dbg(3, "called\n");
411
412         vp = ap->a_vp;
413         vap = ap->a_vap;
414         dnp = VP_TO_NODE(vp);
415         dmp = VFS_TO_DIRFS(vp->v_mount);
416
417         KKASSERT(dnp);  /* This must not happen */
418
419         if (!dirfs_node_isroot(dnp)) {
420                 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
421
422                 KKASSERT(pathnp->dn_fd != DIRFS_NOFD);
423
424                 error = dirfs_node_stat(pathnp->dn_fd, tmp, dnp);
425                 dirfs_dropfd(dmp, pathnp, pathfree);
426         } else {
427                 error = dirfs_node_stat(DIRFS_NOFD, dmp->dm_path, dnp);
428         }
429
430         if (error == 0) {
431                 dirfs_node_lock(dnp);
432                 vap->va_nlink = dnp->dn_links;
433                 vap->va_type = dnp->dn_type;
434                 vap->va_mode = dnp->dn_mode;
435                 vap->va_uid = dnp->dn_uid;
436                 vap->va_gid = dnp->dn_gid;
437                 vap->va_fileid = dnp->dn_ino;
438                 vap->va_size = dnp->dn_size;
439                 vap->va_blocksize = dnp->dn_blocksize;
440                 vap->va_atime.tv_sec = dnp->dn_atime;
441                 vap->va_atime.tv_nsec = dnp->dn_atimensec;
442                 vap->va_mtime.tv_sec = dnp->dn_mtime;
443                 vap->va_mtime.tv_nsec = dnp->dn_mtimensec;
444                 vap->va_ctime.tv_sec = dnp->dn_ctime;
445                 vap->va_ctime.tv_nsec = dnp->dn_ctimensec;
446                 vap->va_bytes = dnp->dn_size;
447                 vap->va_gen = dnp->dn_gen;
448                 vap->va_flags = dnp->dn_flags;
449                 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
450                 dirfs_node_unlock(dnp);
451         }
452
453         KTR_LOG(dirfs_getattr, dnp, error);
454
455         return 0;
456 }
457
458 int
459 dirfs_setattr(struct vop_setattr_args *ap)
460 {
461         dirfs_mount_t dmp;
462         dirfs_node_t dnp;
463         struct vnode *vp;
464         struct vattr *vap;
465         struct ucred *cred;
466         int error;
467 #ifdef KTR
468         const char *msg[6] = {
469                 "invalid",
470                 "chflags",
471                 "chsize",
472                 "chown",
473                 "chmod",
474                 "chtimes"
475         };
476 #endif
477         int msgno;
478
479         dbg(3, "called\n");
480
481         error = msgno = 0;
482         vp = ap->a_vp;
483         vap = ap->a_vap;
484         cred = ap->a_cred;
485         dnp = VP_TO_NODE(vp);
486         dmp = VFS_TO_DIRFS(vp->v_mount);
487
488         dirfs_mount_gettoken(dmp);
489
490         /*
491          * Check for unsettable attributes.
492          */
493         if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
494             (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
495             (vap->va_blocksize != VNOVAL) || (vap->va_rmajor != VNOVAL) ||
496             ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
497                 msgno = 0;
498                 error = EINVAL;
499                 goto out;
500         }
501
502         /*
503          * Change file flags
504          */
505         if (error == 0 && (vap->va_flags != VNOVAL)) {
506                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
507                         error = EROFS;
508                 else
509                         error = dirfs_node_chflags(dnp, vap->va_flags, cred);
510                 msgno = 1;
511                 goto out;
512         }
513
514         /*
515          * Extend or truncate a file
516          */
517         if (error == 0 && (vap->va_size != VNOVAL)) {
518                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
519                         error = EROFS;
520                 else
521                         error = dirfs_node_chsize(dnp, vap->va_size);
522                 dbg(9, "dnp size=%jd vap size=%jd\n", dnp->dn_size, vap->va_size);
523                 msgno = 2;
524                 goto out;
525         }
526
527         /*
528          * Change file owner or group
529          */
530         if (error == 0 && (vap->va_uid != (uid_t)VNOVAL ||
531                 vap->va_gid != (gid_t)VNOVAL)) {
532                 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
533                         error = EROFS;
534                 } else {
535                         mode_t cur_mode = dnp->dn_mode;
536                         uid_t cur_uid = dnp->dn_uid;
537                         gid_t cur_gid = dnp->dn_gid;
538
539                         error = vop_helper_chown(ap->a_vp, vap->va_uid,
540                                                  vap->va_gid, ap->a_cred,
541                                                  &cur_uid, &cur_gid, &cur_mode);
542                         if (error == 0 &&
543                             (cur_mode != dnp->dn_mode ||
544                              cur_uid != dnp->dn_uid ||
545                              cur_gid != dnp->dn_gid)) {
546                                 error = dirfs_node_chown(dmp, dnp, cur_uid,
547                                                          cur_gid, cur_mode);
548                         }
549                 }
550                 msgno = 3;
551                 goto out;
552         }
553
554         /*
555          * Change file mode
556          */
557         if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) {
558                 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
559                         error = EROFS;
560                 } else {
561                         mode_t cur_mode = dnp->dn_mode;
562                         uid_t cur_uid = dnp->dn_uid;
563                         gid_t cur_gid = dnp->dn_gid;
564
565                         error = vop_helper_chmod(ap->a_vp, vap->va_mode,
566                                                  ap->a_cred,
567                                                  cur_uid, cur_gid, &cur_mode);
568                         if (error == 0 && cur_mode != dnp->dn_mode) {
569                                 error = dirfs_node_chmod(dmp, dnp, cur_mode);
570                         }
571                 }
572                 msgno = 4;
573                 goto out;
574         }
575
576         /*
577          * Change file times
578          */
579         if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
580                 vap->va_atime.tv_nsec != VNOVAL) ||
581                 (vap->va_mtime.tv_sec != VNOVAL &&
582                 vap->va_mtime.tv_nsec != VNOVAL) )) {
583                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
584                         error = EROFS;
585                 else
586                         error = dirfs_node_chtimes(dnp);
587                 msgno = 5;
588                 goto out;
589
590         }
591 out:
592         dirfs_mount_reltoken(dmp);
593
594         KTR_LOG(dirfs_setattr, dnp, msg[msgno], error);
595
596         return error;
597 }
598
599 static int
600 dirfs_fsync(struct vop_fsync_args *ap)
601 {
602         dirfs_node_t dnp = VP_TO_NODE(ap->a_vp);
603         int error = 0;
604
605         dbg(3, "called\n");
606
607         vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL);
608
609         if (dnp->dn_fd != DIRFS_NOFD) {
610                 if (fsync(dnp->dn_fd) == -1)
611                         error = fsync(dnp->dn_fd);
612         }
613
614         KTR_LOG(dirfs_fsync, dnp, error);
615
616         return 0;
617 }
618
619 static int
620 dirfs_read(struct vop_read_args *ap)
621 {
622         struct buf *bp;
623         struct vnode *vp = ap->a_vp;
624         struct uio *uio = ap->a_uio;
625         dirfs_node_t dnp;
626         off_t base_offset;
627         size_t offset;
628         size_t len;
629         int error;
630
631         dbg(3, "called\n");
632
633         error = 0;
634         if (uio->uio_resid == 0) {
635                 dbg(9, "zero len uio->uio_resid\n");
636                 return error;
637         }
638
639         dnp = VP_TO_NODE(vp);
640
641         if (uio->uio_offset < 0)
642                 return (EINVAL);
643         if (vp->v_type != VREG)
644                 return (EINVAL);
645
646         while (uio->uio_resid > 0 && uio->uio_offset < dnp->dn_size) {
647                 /*
648                  * Use buffer cache I/O (via dirfs_strategy)
649                  */
650                 offset = (size_t)uio->uio_offset & BMASK;
651                 base_offset = (off_t)uio->uio_offset - offset;
652                 bp = getcacheblk(vp, base_offset, BSIZE, 0);
653                 if (bp == NULL) {
654                         lwkt_gettoken(&vp->v_mount->mnt_token);
655                         error = bread(vp, base_offset, BSIZE, &bp);
656                         if (error) {
657                                 brelse(bp);
658                                 lwkt_reltoken(&vp->v_mount->mnt_token);
659                                 dbg(9, "dirfs_read bread error %d\n", error);
660                                 break;
661                         }
662                         lwkt_reltoken(&vp->v_mount->mnt_token);
663                 }
664
665                 /*
666                  * Figure out how many bytes we can actually copy this loop.
667                  */
668                 len = BSIZE - offset;
669                 if (len > uio->uio_resid)
670                         len = uio->uio_resid;
671                 if (len > dnp->dn_size - uio->uio_offset)
672                         len = (size_t)(dnp->dn_size - uio->uio_offset);
673
674                 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
675                 bqrelse(bp);
676                 if (error) {
677                         dbg(9, "dirfs_read uiomove error %d\n", error);
678                         break;
679                 }
680         }
681
682         KTR_LOG(dirfs_read, dnp, dnp->dn_size, error);
683
684         return(error);
685 }
686
687 static int
688 dirfs_write (struct vop_write_args *ap)
689 {
690         dirfs_node_t dnp;
691         dirfs_mount_t dmp;
692         struct buf *bp;
693         struct vnode *vp = ap->a_vp;
694         struct uio *uio = ap->a_uio;
695         struct thread *td = uio->uio_td;
696         int error;
697         off_t osize;
698         off_t nsize;
699         off_t base_offset;
700         size_t offset;
701         size_t len;
702         struct rlimit limit;
703
704         dbg(3, "called\n");
705
706         error = 0;
707         if (uio->uio_resid == 0) {
708                 dbg(9, "zero-length uio->uio_resid\n");
709                 return error;
710         }
711
712         dnp = VP_TO_NODE(vp);
713         dmp = VFS_TO_DIRFS(vp->v_mount);
714
715         if (vp->v_type != VREG)
716                 return (EINVAL);
717
718         if (vp->v_type == VREG && td != NULL) {
719                 error = kern_getrlimit(RLIMIT_FSIZE, &limit);
720                 if (error != 0) {
721                         dbg(9, "rlimit failure\n");
722                         return error;
723                 }
724                 if (uio->uio_offset + uio->uio_resid > limit.rlim_cur) {
725                         dbg(9, "file too big\n");
726                         ksignal(td->td_proc, SIGXFSZ);
727                         return (EFBIG);
728                 }
729         }
730
731         if (ap->a_ioflag & IO_APPEND)
732                 uio->uio_offset = dnp->dn_size;
733
734         /*
735          * buffer cache operations may be deferred, make sure
736          * the file is correctly sized right now.
737          */
738         osize = dnp->dn_size;
739         nsize = uio->uio_offset + uio->uio_resid;
740         if (nsize > osize && uio->uio_resid) {
741                 KKASSERT(dnp->dn_fd >= 0);
742                 dnp->dn_size = nsize;
743                 ftruncate(dnp->dn_fd, nsize);
744                 nvextendbuf(vp, osize, nsize,
745                             BSIZE, BSIZE, -1, -1, 0);
746         } /* else nsize = osize; NOT USED */
747
748         while (uio->uio_resid > 0) {
749                 /*
750                  * Use buffer cache I/O (via dirfs_strategy)
751                  */
752                 offset = (size_t)uio->uio_offset & BMASK;
753                 base_offset = (off_t)uio->uio_offset - offset;
754                 len = BSIZE - offset;
755
756                 if (len > uio->uio_resid)
757                         len = uio->uio_resid;
758
759                 error = bread(vp, base_offset, BSIZE, &bp);
760                 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
761                 if (error) {
762                         brelse(bp);
763                         dbg(9, "WRITE uiomove failed\n");
764                         break;
765                 }
766
767                 dbg(9, "WRITE dn_size=%jd uio_offset=%jd uio_resid=%jd base_offset=%jd\n",
768                     dnp->dn_size, uio->uio_offset, uio->uio_resid, base_offset);
769
770                 if (ap->a_ioflag & IO_SYNC)
771                         bwrite(bp);
772                 else
773                         bdwrite(bp);
774         }
775
776         KTR_LOG(dirfs_write, dnp, base_offset, uio->uio_resid,
777             dnp->dn_size, error);
778
779         return error;
780 }
781
782 static int
783 dirfs_advlock (struct vop_advlock_args *ap)
784 {
785         struct vnode *vp = ap->a_vp;
786         dirfs_node_t dnp = VP_TO_NODE(vp);
787
788         dbg(3, "called\n");
789
790         return (lf_advlock(ap, &dnp->dn_advlock, dnp->dn_size));
791 }
792
793 static int
794 dirfs_strategy(struct vop_strategy_args *ap)
795 {
796         dirfs_node_t dnp;
797         dirfs_mount_t dmp;
798         struct bio *bio = ap->a_bio;
799         struct buf *bp = bio->bio_buf;
800         struct vnode *vp = ap->a_vp;
801         int error;
802         size_t iosize;
803         char *tmp;
804         char *pathfree;
805
806         dbg(3, "called\n");
807
808         dnp = VP_TO_NODE(vp);
809         dmp = VFS_TO_DIRFS(vp->v_mount);
810
811         error = 0;
812
813         if (vp->v_type != VREG)  {
814                 dbg(9, "not VREG\n");
815                 bp->b_resid = bp->b_bcount;
816                 bp->b_flags |= B_ERROR | B_INVAL;
817                 bp->b_error = EINVAL;
818                 biodone(bio);
819                 return(0);
820         }
821
822         if (dnp->dn_fd == DIRFS_NOFD) {
823                 print_backtrace(-1);
824                 panic("Meh, no fd to write to. dnp=%p\n", dnp);
825         }
826
827         if (bio->bio_offset + bp->b_bcount > dnp->dn_size)
828                 iosize = dnp->dn_size - bio->bio_offset;
829         else
830                 iosize = bp->b_bcount;
831         KKASSERT((ssize_t)iosize >= 0);
832
833         switch (bp->b_cmd) {
834         case BUF_CMD_WRITE:
835                 error = pwrite(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset);
836                 break;
837         case BUF_CMD_READ:
838                 error = pread(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset);
839                 break;
840         default:
841                 bp->b_error = error = EINVAL;
842                 bp->b_flags |= B_ERROR;
843                 break;
844         }
845
846         if (error >= 0 && error < bp->b_bcount)
847                 bzero(bp->b_data + error, bp->b_bcount - error);
848
849         if (error < 0 && errno != EINTR) {
850                 dbg(9, "error=%d dnp=%p dnp->dn_fd=%d "
851                     "bio->bio_offset=%ld bcount=%d resid=%d iosize=%zd\n",
852                     errno, dnp, dnp->dn_fd, bio->bio_offset, bp->b_bcount,
853                     bp->b_resid, iosize);
854                 bp->b_error = errno;
855                 bp->b_resid = bp->b_bcount;
856                 bp->b_flags |= B_ERROR;
857         } else {
858                 tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
859                 dirfs_node_stat(DIRFS_NOFD, tmp, dnp);
860                 dirfs_dropfd(dmp, NULL, pathfree);
861         }
862
863         KTR_LOG(dirfs_strategy, dnp, dnp->dn_size, iosize, bp->b_cmd,
864             bp->b_error, bp->b_resid, bio->bio_offset, error);
865
866         biodone(bio);
867
868         return 0;
869 }
870
871 static int
872 dirfs_bmap(struct vop_bmap_args *ap)
873 {
874         dbg(3, "called\n");
875
876         if (ap->a_doffsetp != NULL)
877                 *ap->a_doffsetp = ap->a_loffset;
878         if (ap->a_runp != NULL)
879                 *ap->a_runp = 0;
880         if (ap->a_runb != NULL)
881                 *ap->a_runb = 0;
882
883         return 0;
884 }
885
886 static int
887 dirfs_nremove(struct vop_nremove_args *ap)
888 {
889         dirfs_node_t dnp, pdnp;
890         dirfs_node_t pathnp;
891         dirfs_mount_t dmp;
892         struct vnode *dvp;
893         struct nchandle *nch;
894         struct namecache *ncp;
895         struct mount *mp;
896         struct vnode *vp;
897         int error;
898         char *tmp;
899         char *pathfree;
900
901         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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(9, "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(9, "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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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(9, "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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
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         dbg(3, "called\n");
1451
1452         return EOPNOTSUPP;
1453 }
1454
1455 static int
1456 dirfs_kqfilter (struct vop_kqfilter_args *ap)
1457 {
1458         dbg(3, "called\n");
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 };