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