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