2 * Copyright (c) 2013 The DragonFly Project. All rights reserved.
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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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
38 * See below a small table with the vnode operation and syscall correspondence
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 - - - - -
78 #include <sys/vfsops.h>
79 #include <sys/vnode.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>
89 #include <sys/kern_syscall.h>
95 * Kernel tracing facilities
97 KTR_INFO_MASTER_EXTERN(dirfs);
99 KTR_INFO(KTR_DIRFS, dirfs, unsupported, 0,
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);
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);
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);
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);
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);
123 KTR_INFO(KTR_DIRFS, dirfs, access, 5,
124 "DIRFS(dnp=%p error=%d)",
125 dirfs_node_t dnp, int error);
127 KTR_INFO(KTR_DIRFS, dirfs, getattr, 6,
128 "DIRFS(dnp=%p error=%d)",
129 dirfs_node_t dnp, int error);
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);
135 KTR_INFO(KTR_DIRFS, dirfs, fsync, 8,
136 "DIRFS(dnp=%p error=%d)",
137 dirfs_node_t dnp, int error);
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);
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);
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);
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);
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);
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);
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);
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 *);
176 dirfs_nresolve(struct vop_nresolve_args *ap)
178 dirfs_node_t pdnp, dnp, d1, d2;
180 struct namecache *ncp;
181 struct nchandle *nch;
195 dnp = d1 = d2 = NULL;
196 pdnp = VP_TO_NODE(dvp);
197 dmp = VFS_TO_DIRFS(mp);
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)) {
205 passive_fd_list_hits++;
209 dirfs_node_unlock(pdnp);
212 dirfs_alloc_vp(mp, &vp, LK_CANRECURSE, dnp);
213 dirfs_node_drop(dmp, dnp);
215 passive_fd_list_miss++;
216 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, &vp, NULL, 0);
220 if (error && error == ENOENT) {
221 cache_setvp(nch, NULL);
224 cache_setvp(nch, vp);
229 KTR_LOG(dirfs_nresolve, dnp, ncp->nc_name, pdnp, pdnp->dn_fd, error);
235 dirfs_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
239 KTR_LOG(dirfs_unsupported, __func__);
245 dirfs_ncreate(struct vop_ncreate_args *ap)
250 struct namecache *ncp;
262 pdnp = VP_TO_NODE(dvp);
263 dmp = VFS_TO_DIRFS(dvp->v_mount);
265 ncp = ap->a_nch->ncp;
268 dirfs_mount_gettoken(dmp);
270 dirfs_node_getperms(pdnp, &perms);
271 if ((perms & DIRFS_NODE_WR) == 0)
274 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp, vap,
278 cache_setunresolved(ap->a_nch);
279 cache_setvp(ap->a_nch, *vpp);
282 dirfs_mount_reltoken(dmp);
284 KTR_LOG(dirfs_ncreate, dnp, ncp->nc_name, pdnp, pdnp->dn_fd, error);
290 dirfs_nmknod(struct vop_nmknod_args *v)
298 dirfs_open(struct vop_open_args *ap)
308 dnp = VP_TO_NODE(vp);
309 dmp = VFS_TO_DIRFS(vp->v_mount);
313 * Root inode has been allocated and opened in VFS_ROOT() so
314 * no reason to attempt to open it again.
316 if (dmp->dm_root != dnp && dnp->dn_fd == DIRFS_NOFD) {
317 error = dirfs_open_helper(dmp, dnp, DIRFS_NOFD, NULL);
322 KTR_LOG(dirfs_open, dnp, dnp->dn_name, dnp->dn_fd);
324 return vop_stdopen(ap);
328 dirfs_close(struct vop_close_args *ap)
338 dnp = VP_TO_NODE(vp);
340 if (vp->v_type == VREG) {
341 error = vfsync(vp, 0, 1, NULL, NULL);
343 dbg(5, "vfsync error=%d\n", error);
348 * XXX - Currently VOP_INACTIVE() is not being called unless there is
349 * vnode pressure so, by now, call inactive directly on last close.
351 vn_lock(vp, LK_UPGRADE | LK_RETRY);
352 if (vp->v_opencount == 0 && vp->v_writecount == 0)
355 KTR_LOG(dirfs_close, dnp, dnp->dn_fd, vp->v_opencount,
356 vp->v_writecount, error);
362 dirfs_access(struct vop_access_args *ap)
364 struct vnode *vp = ap->a_vp;
370 dnp = VP_TO_NODE(vp);
372 switch (vp->v_type) {
378 if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
397 error = vop_helper_access(ap, dnp->dn_uid,
398 dnp->dn_gid, dnp->dn_mode, 0);
401 KTR_LOG(dirfs_access, dnp, error);
407 dirfs_getattr(struct vop_getattr_args *ap)
422 dnp = VP_TO_NODE(vp);
423 dmp = VFS_TO_DIRFS(vp->v_mount);
425 KKASSERT(dnp); /* This must not happen */
427 if (!dirfs_node_isroot(dnp)) {
428 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
430 KKASSERT(pathnp->dn_fd != DIRFS_NOFD);
432 error = dirfs_node_stat(pathnp->dn_fd, tmp, dnp);
433 dirfs_dropfd(dmp, pathnp, pathfree);
435 error = dirfs_node_stat(DIRFS_NOFD, dmp->dm_path, dnp);
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);
461 KTR_LOG(dirfs_getattr, dnp, error);
467 dirfs_setattr(struct vop_setattr_args *ap)
476 const char *msg[6] = {
493 dnp = VP_TO_NODE(vp);
494 dmp = VFS_TO_DIRFS(vp->v_mount);
496 dirfs_mount_gettoken(dmp);
499 * Check for unsettable attributes.
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)) {
513 if (error == 0 && (vap->va_flags != VNOVAL)) {
514 if (vp->v_mount->mnt_flag & MNT_RDONLY)
517 error = dirfs_node_chflags(dnp, vap->va_flags, cred);
523 * Extend or truncate a file
525 if (error == 0 && (vap->va_size != VNOVAL)) {
526 if (vp->v_mount->mnt_flag & MNT_RDONLY)
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);
536 * Change file owner or group
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) {
543 mode_t cur_mode = dnp->dn_mode;
544 uid_t cur_uid = dnp->dn_uid;
545 gid_t cur_gid = dnp->dn_gid;
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);
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,
565 if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) {
566 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
569 mode_t cur_mode = dnp->dn_mode;
570 uid_t cur_uid = dnp->dn_uid;
571 gid_t cur_gid = dnp->dn_gid;
573 error = vop_helper_chmod(ap->a_vp, vap->va_mode,
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);
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)
594 error = dirfs_node_chtimes(dnp);
600 dirfs_mount_reltoken(dmp);
602 KTR_LOG(dirfs_setattr, dnp, msg[msgno], error);
608 dirfs_fsync(struct vop_fsync_args *ap)
610 dirfs_node_t dnp = VP_TO_NODE(ap->a_vp);
615 vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL);
617 if (dnp->dn_fd != DIRFS_NOFD) {
618 if (fsync(dnp->dn_fd) == -1)
619 error = fsync(dnp->dn_fd);
622 KTR_LOG(dirfs_fsync, dnp, error);
628 dirfs_read(struct vop_read_args *ap)
631 struct vnode *vp = ap->a_vp;
632 struct uio *uio = ap->a_uio;
642 if (uio->uio_resid == 0) {
643 dbg(5, "zero len uio->uio_resid\n");
647 dnp = VP_TO_NODE(vp);
649 if (uio->uio_offset < 0)
651 if (vp->v_type != VREG)
654 while (uio->uio_resid > 0 && uio->uio_offset < dnp->dn_size) {
656 * Use buffer cache I/O (via dirfs_strategy)
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);
662 lwkt_gettoken(&vp->v_mount->mnt_token);
663 error = bread(vp, base_offset, BSIZE, &bp);
666 lwkt_reltoken(&vp->v_mount->mnt_token);
667 dbg(5, "dirfs_read bread error %d\n", error);
670 lwkt_reltoken(&vp->v_mount->mnt_token);
674 * Figure out how many bytes we can actually copy this loop.
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);
682 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
685 dbg(5, "dirfs_read uiomove error %d\n", error);
690 KTR_LOG(dirfs_read, dnp, dnp->dn_size, error);
696 dirfs_write (struct vop_write_args *ap)
701 struct vnode *vp = ap->a_vp;
702 struct uio *uio = ap->a_uio;
703 struct thread *td = uio->uio_td;
715 if (uio->uio_resid == 0) {
716 dbg(5, "zero-length uio->uio_resid\n");
720 dnp = VP_TO_NODE(vp);
721 dmp = VFS_TO_DIRFS(vp->v_mount);
723 if (vp->v_type != VREG)
726 if (vp->v_type == VREG && td != NULL) {
727 error = kern_getrlimit(RLIMIT_FSIZE, &limit);
729 dbg(5, "rlimit failure\n");
732 if (uio->uio_offset + uio->uio_resid > limit.rlim_cur) {
733 dbg(5, "file too big\n");
734 ksignal(td->td_proc, SIGXFSZ);
739 if (ap->a_ioflag & IO_APPEND)
740 uio->uio_offset = dnp->dn_size;
743 * buffer cache operations may be deferred, make sure
744 * the file is correctly sized right now.
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 */
756 while (uio->uio_resid > 0) {
758 * Use buffer cache I/O (via dirfs_strategy)
760 offset = (size_t)uio->uio_offset & BMASK;
761 base_offset = (off_t)uio->uio_offset - offset;
762 len = BSIZE - offset;
764 if (len > uio->uio_resid)
765 len = uio->uio_resid;
767 error = bread(vp, base_offset, BSIZE, &bp);
768 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
771 dbg(2, "WRITE uiomove failed\n");
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);
778 if (ap->a_ioflag & IO_SYNC)
784 KTR_LOG(dirfs_write, dnp, base_offset, uio->uio_resid,
785 dnp->dn_size, error);
791 dirfs_advlock (struct vop_advlock_args *ap)
793 struct vnode *vp = ap->a_vp;
794 dirfs_node_t dnp = VP_TO_NODE(vp);
798 return (lf_advlock(ap, &dnp->dn_advlock, dnp->dn_size));
802 dirfs_strategy(struct vop_strategy_args *ap)
806 struct bio *bio = ap->a_bio;
807 struct buf *bp = bio->bio_buf;
808 struct vnode *vp = ap->a_vp;
816 dnp = VP_TO_NODE(vp);
817 dmp = VFS_TO_DIRFS(vp->v_mount);
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;
830 if (dnp->dn_fd == DIRFS_NOFD) {
832 panic("Meh, no fd to write to. dnp=%p\n", dnp);
835 if (bio->bio_offset + bp->b_bcount > dnp->dn_size)
836 iosize = dnp->dn_size - bio->bio_offset;
838 iosize = bp->b_bcount;
839 KKASSERT((ssize_t)iosize >= 0);
843 error = pwrite(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset);
846 error = pread(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset);
849 bp->b_error = error = EINVAL;
850 bp->b_flags |= B_ERROR;
854 if (error >= 0 && error < bp->b_bcount)
855 bzero(bp->b_data + error, bp->b_bcount - error);
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);
863 bp->b_resid = bp->b_bcount;
864 bp->b_flags |= B_ERROR;
866 tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
867 dirfs_node_stat(DIRFS_NOFD, tmp, dnp);
868 dirfs_dropfd(dmp, NULL, pathfree);
871 KTR_LOG(dirfs_strategy, dnp, dnp->dn_size, iosize, bp->b_cmd,
872 bp->b_error, bp->b_resid, bio->bio_offset, error);
880 dirfs_bmap(struct vop_bmap_args *ap)
884 if (ap->a_doffsetp != NULL)
885 *ap->a_doffsetp = ap->a_loffset;
886 if (ap->a_runp != NULL)
888 if (ap->a_runb != NULL)
895 dirfs_nremove(struct vop_nremove_args *ap)
897 dirfs_node_t dnp, pdnp;
901 struct nchandle *nch;
902 struct namecache *ncp;
918 dmp = VFS_TO_DIRFS(mp);
920 lwkt_gettoken(&mp->mnt_token);
921 cache_vget(nch, ap->a_cred, LK_SHARED, &vp);
924 pdnp = VP_TO_NODE(dvp);
925 dnp = VP_TO_NODE(vp);
927 if (vp->v_type == VDIR) {
930 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
931 dirfs_node_lock(pdnp);
932 error = unlinkat(pathnp->dn_fd, tmp, 0);
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;
943 dirfs_node_unlock(pdnp);
944 dirfs_dropfd(dmp, pathnp, pathfree);
947 lwkt_reltoken(&mp->mnt_token);
949 KTR_LOG(dirfs_nremove, dnp, pdnp, error);
955 dirfs_nlink(struct vop_nlink_args *ap)
959 KTR_LOG(dirfs_unsupported, __func__);
965 dirfs_nrename(struct vop_nrename_args *ap)
967 dirfs_node_t dnp, fdnp, tdnp;
969 struct namecache *fncp, *tncp;
970 struct vnode *fdvp, *tdvp, *vp;
972 char *fpath, *fpathfree;
973 char *tpath, *tpathfree;
981 fncp = ap->a_fnch->ncp;
982 tncp = ap->a_tnch->ncp;
984 dmp = VFS_TO_DIRFS(mp);
985 fdnp = VP_TO_NODE(fdvp);
986 tdnp = VP_TO_NODE(tdvp);
988 dbg(5, "fdnp=%p tdnp=%p from=%s to=%s\n", fdnp, tdnp, fncp->nc_name,
991 if (fdvp->v_mount != tdvp->v_mount)
993 if (fdvp->v_mount != fncp->nc_vp->v_mount)
995 if (fdvp->v_mount->mnt_flag & MNT_RDONLY)
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);
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);
1011 * We have to mark the target file that was replaced by
1012 * the rename as having been unlinked.
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;
1026 * nlinks on directories can be a bit weird. Zero
1030 cache_inval_vp(vp, CINV_DESTROY);
1032 cache_rename(ap->a_fnch, ap->a_tnch);
1034 dirfs_dropfd(dmp, NULL, fpathfree);
1035 dirfs_dropfd(dmp, NULL, tpathfree);
1041 dirfs_nmkdir(struct vop_nmkdir_args *ap)
1044 dirfs_node_t dnp, pdnp, dnp1;
1045 struct namecache *ncp;
1049 char *tmp, *pathfree;
1056 extrapath = error = 0;
1059 dmp = VFS_TO_DIRFS(dvp->v_mount);
1060 pdnp = VP_TO_NODE(dvp);
1061 ncp = ap->a_nch->ncp;
1063 pathfree = tmp = path = NULL;
1066 dirfs_node_lock(pdnp);
1067 if (pdnp->dn_fd != DIRFS_NOFD) {
1069 path = ncp->nc_name;
1071 dnp1 = dirfs_findfd(dmp, pdnp, &tmp, &pathfree);
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);
1077 dirfs_dropfd(dmp, dnp1, pathfree);
1080 error = mkdirat(pfd, path, vap->va_mode);
1083 } else { /* Directory has been made */
1084 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp,
1088 cache_setunresolved(ap->a_nch);
1089 cache_setvp(ap->a_nch, *vpp);
1091 dirfs_node_unlock(pdnp);
1094 kfree(path, M_DIRFS_MISC);
1096 KTR_LOG(dirfs_nmkdir, pdnp, dnp, ncp->nc_name, error);
1102 dirfs_nrmdir(struct vop_nrmdir_args *ap)
1104 dirfs_node_t dnp, pdnp;
1107 struct nchandle *nch;
1108 struct namecache *ncp;
1125 dmp = VFS_TO_DIRFS(mp);
1127 lwkt_gettoken(&mp->mnt_token);
1128 cache_vget(nch, ap->a_cred, LK_SHARED, &vp);
1131 pdnp = VP_TO_NODE(dvp);
1132 dnp = VP_TO_NODE(vp);
1134 if (vp->v_type != VDIR) {
1137 tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
1138 dirfs_node_lock(pdnp);
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;
1149 * nlinks on directories can be a bit weird. Zero
1153 cache_inval_vp(vp, CINV_DESTROY);
1157 dirfs_node_unlock(pdnp);
1158 dirfs_dropfd(dmp, NULL, pathfree);
1161 lwkt_reltoken(&mp->mnt_token);
1163 KTR_LOG(dirfs_nrmdir, dnp, pdnp, error);
1169 dirfs_nsymlink(struct vop_nsymlink_args *ap)
1172 dirfs_node_t dnp, pdnp;
1174 struct namecache *ncp;
1178 char *tmp, *pathfree;
1188 dmp = VFS_TO_DIRFS(dvp->v_mount);
1189 pdnp = VP_TO_NODE(dvp);
1190 ncp = ap->a_nch->ncp;
1192 pathfree = tmp = path = NULL;
1195 lwkt_gettoken(&mp->mnt_token);
1196 vap->va_type = VLNK;
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);
1205 error = symlink(ap->a_target, path);
1208 } else { /* Symlink has been made */
1209 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp,
1213 cache_setunresolved(ap->a_nch);
1214 cache_setvp(ap->a_nch, *vpp);
1216 dbg(5, "path=%s a_target=%s\n", path, ap->a_target);
1218 KTR_LOG(dirfs_nsymlink, dnp, ap->a_target, path, error);
1219 kfree(path, M_DIRFS_MISC);
1220 lwkt_reltoken(&mp->mnt_token);
1227 dirfs_readdir(struct vop_readdir_args *ap)
1230 struct dirent *dp, *dpn;
1231 off_t __unused **cookies = ap->a_cookies;
1232 int *ncookies = ap->a_ncookies;
1236 struct vnode *vp = ap->a_vp;
1248 debug(1, "ncookies=%d\n", *ncookies);
1250 dnp = VP_TO_NODE(vp);
1252 startoff = uio->uio_offset;
1258 if (vp->v_type != VDIR)
1260 if (uio->uio_resid < 0)
1262 if ((bufsiz = uio->uio_resid) > 4096)
1264 buf = kmalloc(bufsiz, M_DIRFS_MISC, M_WAITOK | M_ZERO);
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.
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));
1280 if (errno == EINVAL)
1281 panic("EINVAL on readdir\n");
1285 } else if (bytes == 0) {
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);
1297 dpn = _DIRENT_NEXT(dp);
1301 curoff = lseek(dnp->dn_fd, 0, SEEK_CUR);
1304 kfree(buf, M_DIRFS_MISC);
1305 uio->uio_offset = curoff;
1306 dirfs_node_unlock(dnp);
1308 KTR_LOG(dirfs_readdir, dnp, dnp->dn_fd, startoff, uio->uio_offset);
1314 dirfs_readlink(struct vop_readlink_args *ap)
1316 dirfs_node_t dnp, pathnp;
1321 char *tmp, *pathfree, *buf;
1329 KKASSERT(vp->v_type == VLNK);
1332 tmp = pathfree = NULL;
1335 dmp = VFS_TO_DIRFS(mp);
1336 dnp = VP_TO_NODE(vp);
1338 lwkt_gettoken(&mp->mnt_token);
1340 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
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);
1347 error = uiomove(buf, nlen + 1, uio);
1352 dirfs_dropfd(dmp, pathnp, pathfree);
1353 kfree(buf, M_DIRFS_MISC);
1355 lwkt_reltoken(&mp->mnt_token);
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
1373 dirfs_inactive(struct vop_inactive_args *ap)
1382 dmp = VFS_TO_DIRFS(vp->v_mount);
1383 dnp = VP_TO_NODE(vp);
1385 /* Degenerate case */
1387 dbg(5, "dnp was NULL\n");
1392 dirfs_mount_gettoken(dmp);
1395 * Deal with the case the inode has 0 links which means it was unlinked.
1397 if (dnp->dn_links == 0) {
1399 dbg(5, "recycled a vnode of an unlinked dnp\n");
1405 * Try to retain the fd in our fd cache.
1407 dirfs_node_setpassive(dmp, dnp, 1);
1409 dirfs_mount_reltoken(dmp);
1416 dirfs_reclaim(struct vop_reclaim_args *ap)
1425 dnp = VP_TO_NODE(vp);
1426 dmp = VFS_TO_DIRFS(vp->v_mount);
1428 dirfs_free_vp(dmp, dnp);
1429 /* dnp is now invalid, may have been destroyed */
1435 dirfs_mountctl(struct vop_mountctl_args *ap)
1439 KTR_LOG(dirfs_unsupported, __func__);
1445 dirfs_print(struct vop_print_args *v)
1449 KTR_LOG(dirfs_unsupported, __func__);
1455 dirfs_pathconf(struct vop_pathconf_args *v)
1463 dirfs_kqfilter (struct vop_kqfilter_args *ap)
1467 KTR_LOG(dirfs_unsupported, __func__);
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