xref: /dflybsd-src/sys/vfs/dirfs/dirfs_subr.c (revision fc36a10bce8c5678d103e0498db849506d9dac68)
1509bc517SAntonio Huete Jimenez /*
2509bc517SAntonio Huete Jimenez  * Copyright (c) 2013 The DragonFly Project.  All rights reserved.
3509bc517SAntonio Huete Jimenez  *
4509bc517SAntonio Huete Jimenez  * This code is derived from software contributed to The DragonFly Project
5509bc517SAntonio Huete Jimenez  * by Antonio Huete Jimenez <tuxillo@quantumachine.net>
6509bc517SAntonio Huete Jimenez  * by Matthew Dillon <dillon@dragonflybsd.org>
7509bc517SAntonio Huete Jimenez  *
8509bc517SAntonio Huete Jimenez  * Redistribution and use in source and binary forms, with or without
9509bc517SAntonio Huete Jimenez  * modification, are permitted provided that the following conditions
10509bc517SAntonio Huete Jimenez  * are met:
11509bc517SAntonio Huete Jimenez  *
12509bc517SAntonio Huete Jimenez  * 1. Redistributions of source code must retain the above copyright
13509bc517SAntonio Huete Jimenez  *    notice, this list of conditions and the following disclaimer.
14509bc517SAntonio Huete Jimenez  * 2. Redistributions in binary form must reproduce the above copyright
15509bc517SAntonio Huete Jimenez  *    notice, this list of conditions and the following disclaimer in
16509bc517SAntonio Huete Jimenez  *    the documentation and/or other materials provided with the
17509bc517SAntonio Huete Jimenez  *    distribution.
18509bc517SAntonio Huete Jimenez  * 3. Neither the name of The DragonFly Project nor the names of its
19509bc517SAntonio Huete Jimenez  *    contributors may be used to endorse or promote products derived
20509bc517SAntonio Huete Jimenez  *    from this software without specific, prior written permission.
21509bc517SAntonio Huete Jimenez  *
22509bc517SAntonio Huete Jimenez  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23509bc517SAntonio Huete Jimenez  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24509bc517SAntonio Huete Jimenez  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25509bc517SAntonio Huete Jimenez  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26509bc517SAntonio Huete Jimenez  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27509bc517SAntonio Huete Jimenez  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28509bc517SAntonio Huete Jimenez  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29509bc517SAntonio Huete Jimenez  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30509bc517SAntonio Huete Jimenez  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31509bc517SAntonio Huete Jimenez  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32509bc517SAntonio Huete Jimenez  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33509bc517SAntonio Huete Jimenez  * SUCH DAMAGE.
34509bc517SAntonio Huete Jimenez  *
35509bc517SAntonio Huete Jimenez  */
36509bc517SAntonio Huete Jimenez 
37509bc517SAntonio Huete Jimenez #include <errno.h>
38509bc517SAntonio Huete Jimenez #include <fcntl.h>
39509bc517SAntonio Huete Jimenez #include <unistd.h>
40509bc517SAntonio Huete Jimenez 
41509bc517SAntonio Huete Jimenez #include <sys/mount.h>
42509bc517SAntonio Huete Jimenez #include <sys/queue.h>
43509bc517SAntonio Huete Jimenez #include <sys/spinlock2.h>
44509bc517SAntonio Huete Jimenez #include <sys/stat.h>
45509bc517SAntonio Huete Jimenez #include <sys/systm.h>
46509bc517SAntonio Huete Jimenez #include <sys/types.h>
47509bc517SAntonio Huete Jimenez #include <sys/vfscache.h>
48509bc517SAntonio Huete Jimenez #include <sys/vnode.h>
49509bc517SAntonio Huete Jimenez 
50509bc517SAntonio Huete Jimenez #include "dirfs.h"
51509bc517SAntonio Huete Jimenez 
52509bc517SAntonio Huete Jimenez /*
53509bc517SAntonio Huete Jimenez  * Allocate and setup all is needed for the dirfs node to hold the filename.
54509bc517SAntonio Huete Jimenez  * Note: dn_name is NULL terminated.
55509bc517SAntonio Huete Jimenez  */
56509bc517SAntonio Huete Jimenez void
dirfs_node_setname(dirfs_node_t dnp,const char * name,int len)57509bc517SAntonio Huete Jimenez dirfs_node_setname(dirfs_node_t dnp, const char *name, int len)
58509bc517SAntonio Huete Jimenez {
5926ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
60509bc517SAntonio Huete Jimenez 
61509bc517SAntonio Huete Jimenez 	if (dnp->dn_name)
62509bc517SAntonio Huete Jimenez 		kfree(dnp->dn_name, M_DIRFS_MISC);
63509bc517SAntonio Huete Jimenez 	dnp->dn_name = kmalloc(len + 1, M_DIRFS_MISC, M_WAITOK | M_ZERO);
64509bc517SAntonio Huete Jimenez 	bcopy(name, dnp->dn_name, len);
65509bc517SAntonio Huete Jimenez 	dnp->dn_name[len] = 0;
66509bc517SAntonio Huete Jimenez 	dnp->dn_namelen = len;
67509bc517SAntonio Huete Jimenez }
68509bc517SAntonio Huete Jimenez 
69509bc517SAntonio Huete Jimenez /*
70509bc517SAntonio Huete Jimenez  * Allocate enough space to hold a dirfs node structure.
71509bc517SAntonio Huete Jimenez  * Note: Node name and length isn't handled here.
72509bc517SAntonio Huete Jimenez  */
73509bc517SAntonio Huete Jimenez dirfs_node_t
dirfs_node_alloc(struct mount * mp)74509bc517SAntonio Huete Jimenez dirfs_node_alloc(struct mount *mp)
75509bc517SAntonio Huete Jimenez {
76509bc517SAntonio Huete Jimenez         dirfs_node_t dnp;
77509bc517SAntonio Huete Jimenez 
7826ec059cSAntonio Huete Jimenez         dbg(5, "called\n");
79509bc517SAntonio Huete Jimenez 
80509bc517SAntonio Huete Jimenez         dnp = kmalloc(sizeof(*dnp), M_DIRFS_NODE, M_WAITOK | M_ZERO);
81509bc517SAntonio Huete Jimenez         lockinit(&dnp->dn_lock, "dfsnode", 0, LK_CANRECURSE);
82509bc517SAntonio Huete Jimenez 
83509bc517SAntonio Huete Jimenez 	dnp->dn_fd = DIRFS_NOFD;
84509bc517SAntonio Huete Jimenez 
85509bc517SAntonio Huete Jimenez         return dnp;
86509bc517SAntonio Huete Jimenez }
87509bc517SAntonio Huete Jimenez 
88509bc517SAntonio Huete Jimenez /*
89509bc517SAntonio Huete Jimenez  * Drops a reference to the node and. Node is freed when in the last reference.
90509bc517SAntonio Huete Jimenez  */
91509bc517SAntonio Huete Jimenez void
dirfs_node_drop(dirfs_mount_t dmp,dirfs_node_t dnp)92509bc517SAntonio Huete Jimenez dirfs_node_drop(dirfs_mount_t dmp, dirfs_node_t dnp)
93509bc517SAntonio Huete Jimenez {
9426ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
9526ec059cSAntonio Huete Jimenez 
96509bc517SAntonio Huete Jimenez 	if (dirfs_node_unref(dnp))
97509bc517SAntonio Huete Jimenez 		dirfs_node_free(dmp, dnp);
98509bc517SAntonio Huete Jimenez }
99509bc517SAntonio Huete Jimenez 
100509bc517SAntonio Huete Jimenez /*
101509bc517SAntonio Huete Jimenez  * Removes the association with its parent. Before freeing up its resources
102509bc517SAntonio Huete Jimenez  * the node will be removed from the per-mount passive fd cache and its fd
103509bc517SAntonio Huete Jimenez  * will be closed, either normally or forced.
104509bc517SAntonio Huete Jimenez  */
105509bc517SAntonio Huete Jimenez int
dirfs_node_free(dirfs_mount_t dmp,dirfs_node_t dnp)106509bc517SAntonio Huete Jimenez dirfs_node_free(dirfs_mount_t dmp, dirfs_node_t dnp)
107509bc517SAntonio Huete Jimenez {
108509bc517SAntonio Huete Jimenez 	struct vnode *vp;
109509bc517SAntonio Huete Jimenez 
11026ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
111509bc517SAntonio Huete Jimenez 
112509bc517SAntonio Huete Jimenez 	KKASSERT(dnp != NULL);
113509bc517SAntonio Huete Jimenez 	debug_node2(dnp);
114509bc517SAntonio Huete Jimenez 
115509bc517SAntonio Huete Jimenez 	KKASSERT(dirfs_node_refcnt(dnp) == 0);
116509bc517SAntonio Huete Jimenez 
117509bc517SAntonio Huete Jimenez 	vp = NODE_TO_VP(dnp);
118509bc517SAntonio Huete Jimenez 	/*
119509bc517SAntonio Huete Jimenez 	 * Remove the inode from the passive fds list
120509bc517SAntonio Huete Jimenez 	 * as we are tearing down the node.
121509bc517SAntonio Huete Jimenez 	 * Root inode will be removed on VOP_UNMOUNT()
122509bc517SAntonio Huete Jimenez 	 */
123509bc517SAntonio Huete Jimenez 	if (dnp->dn_parent) {	/* NULL when children reaped parents */
124509bc517SAntonio Huete Jimenez 		dirfs_node_drop(dmp, dnp->dn_parent);
125509bc517SAntonio Huete Jimenez 		dnp->dn_parent = NULL;
126509bc517SAntonio Huete Jimenez 	}
127509bc517SAntonio Huete Jimenez 	dirfs_node_setpassive(dmp, dnp, 0);
128509bc517SAntonio Huete Jimenez 	if (dnp->dn_name) {
129509bc517SAntonio Huete Jimenez 		kfree(dnp->dn_name, M_DIRFS_MISC);
130509bc517SAntonio Huete Jimenez 		dnp->dn_name = NULL;
131509bc517SAntonio Huete Jimenez 	}
132509bc517SAntonio Huete Jimenez 
133509bc517SAntonio Huete Jimenez 	/*
134509bc517SAntonio Huete Jimenez 	 * The file descriptor should have been closed already by the
135509bc517SAntonio Huete Jimenez 	 * previous call to dirfs_set-passive. If not, force a sync and
136509bc517SAntonio Huete Jimenez 	 * close it.
137509bc517SAntonio Huete Jimenez 	 */
138509bc517SAntonio Huete Jimenez 	if (dnp->dn_fd != DIRFS_NOFD) {
139509bc517SAntonio Huete Jimenez 		if (dnp->dn_vnode)
140509bc517SAntonio Huete Jimenez 			VOP_FSYNC(vp, MNT_WAIT, 0);
141509bc517SAntonio Huete Jimenez 		close(dnp->dn_fd);
142509bc517SAntonio Huete Jimenez 		dnp->dn_fd = DIRFS_NOFD;
143509bc517SAntonio Huete Jimenez 	}
144509bc517SAntonio Huete Jimenez 
145509bc517SAntonio Huete Jimenez 	lockuninit(&dnp->dn_lock);
146509bc517SAntonio Huete Jimenez 	kfree(dnp, M_DIRFS_NODE);
147509bc517SAntonio Huete Jimenez 	dnp = NULL;
148509bc517SAntonio Huete Jimenez 
149509bc517SAntonio Huete Jimenez 	return 0;
150509bc517SAntonio Huete Jimenez }
151509bc517SAntonio Huete Jimenez 
152509bc517SAntonio Huete Jimenez /*
153509bc517SAntonio Huete Jimenez  * Do all the operations needed to get a resulting inode <--> host file
154509bc517SAntonio Huete Jimenez  * association. This or may not include opening the file, which should be
155509bc517SAntonio Huete Jimenez  * only needed when creating it.
156509bc517SAntonio Huete Jimenez  *
157509bc517SAntonio Huete Jimenez  * In the case vap is not NULL and openflags are specified, open the file.
158509bc517SAntonio Huete Jimenez  */
159509bc517SAntonio Huete Jimenez int
dirfs_alloc_file(dirfs_mount_t dmp,dirfs_node_t * dnpp,dirfs_node_t pdnp,struct namecache * ncp,struct vnode ** vpp,struct vattr * vap,int openflags)160509bc517SAntonio Huete Jimenez dirfs_alloc_file(dirfs_mount_t dmp, dirfs_node_t *dnpp, dirfs_node_t pdnp,
161509bc517SAntonio Huete Jimenez     struct namecache *ncp, struct vnode **vpp, struct vattr *vap,
162509bc517SAntonio Huete Jimenez     int openflags)
163509bc517SAntonio Huete Jimenez {
164509bc517SAntonio Huete Jimenez 	dirfs_node_t dnp;
165509bc517SAntonio Huete Jimenez 	dirfs_node_t pathnp;
166509bc517SAntonio Huete Jimenez 	struct vnode *vp;
167509bc517SAntonio Huete Jimenez 	struct mount *mp;
168509bc517SAntonio Huete Jimenez 	char *tmp;
169509bc517SAntonio Huete Jimenez 	char *pathfree;
170509bc517SAntonio Huete Jimenez 	int error;
171509bc517SAntonio Huete Jimenez 
17226ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
173509bc517SAntonio Huete Jimenez 
174509bc517SAntonio Huete Jimenez 	error = 0;
175509bc517SAntonio Huete Jimenez 	vp = NULL;
176509bc517SAntonio Huete Jimenez 	mp = DIRFS_TO_VFS(dmp);
177509bc517SAntonio Huete Jimenez 
178509bc517SAntonio Huete Jimenez 	/* Sanity check */
179509bc517SAntonio Huete Jimenez 	if (pdnp == NULL)
180509bc517SAntonio Huete Jimenez 		return EINVAL;
181509bc517SAntonio Huete Jimenez 
182509bc517SAntonio Huete Jimenez 	dnp = dirfs_node_alloc(mp);
183509bc517SAntonio Huete Jimenez 	KKASSERT(dnp != NULL);
184509bc517SAntonio Huete Jimenez 
185509bc517SAntonio Huete Jimenez 	dirfs_node_lock(dnp);
186509bc517SAntonio Huete Jimenez 	dirfs_node_setname(dnp, ncp->nc_name, ncp->nc_nlen);
187509bc517SAntonio Huete Jimenez 	dnp->dn_parent = pdnp;
188509bc517SAntonio Huete Jimenez 	dirfs_node_ref(pdnp);   /* Children ref */
189509bc517SAntonio Huete Jimenez 	dirfs_node_unlock(dnp);
190509bc517SAntonio Huete Jimenez 
191509bc517SAntonio Huete Jimenez 	pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
192509bc517SAntonio Huete Jimenez 
193509bc517SAntonio Huete Jimenez 	if (openflags && vap != NULL) {
194509bc517SAntonio Huete Jimenez 		dnp->dn_fd = openat(pathnp->dn_fd, tmp,
195509bc517SAntonio Huete Jimenez 				    openflags, vap->va_mode);
196509bc517SAntonio Huete Jimenez 		if (dnp->dn_fd == -1) {
197509bc517SAntonio Huete Jimenez 			dirfs_dropfd(dmp, pathnp, pathfree);
198509bc517SAntonio Huete Jimenez 			return errno;
199509bc517SAntonio Huete Jimenez 		}
200509bc517SAntonio Huete Jimenez 	}
201509bc517SAntonio Huete Jimenez 
202509bc517SAntonio Huete Jimenez 	error = dirfs_node_stat(pathnp->dn_fd, tmp, dnp);
203509bc517SAntonio Huete Jimenez 	if (error) {		/* XXX Handle errors */
204509bc517SAntonio Huete Jimenez 		error = errno;
205509bc517SAntonio Huete Jimenez 		if (vp)
206509bc517SAntonio Huete Jimenez 			dirfs_free_vp(dmp, dnp);
207509bc517SAntonio Huete Jimenez 		dirfs_node_free(dmp, dnp);
208509bc517SAntonio Huete Jimenez 		dirfs_dropfd(dmp, pathnp, pathfree);
209509bc517SAntonio Huete Jimenez 		return error;
210509bc517SAntonio Huete Jimenez 	}
211509bc517SAntonio Huete Jimenez 
212509bc517SAntonio Huete Jimenez 	dirfs_alloc_vp(mp, &vp, LK_CANRECURSE, dnp);
213509bc517SAntonio Huete Jimenez 	*vpp = vp;
214509bc517SAntonio Huete Jimenez 	*dnpp = dnp;
215509bc517SAntonio Huete Jimenez 
21626ec059cSAntonio Huete Jimenez 	dbg(9, "tmp=%s dnp=%p allocated\n", tmp, dnp);
217509bc517SAntonio Huete Jimenez 	dirfs_dropfd(dmp, pathnp, pathfree);
218509bc517SAntonio Huete Jimenez 
219f15dabdbSAntonio Huete Jimenez 	/* We want VOP_INACTIVE() to be called on last ref */
220f15dabdbSAntonio Huete Jimenez 	atomic_set_int(&vp->v_refcnt, VREF_FINALIZE);
221f15dabdbSAntonio Huete Jimenez 
222509bc517SAntonio Huete Jimenez 	return error;
223509bc517SAntonio Huete Jimenez }
224509bc517SAntonio Huete Jimenez 
225509bc517SAntonio Huete Jimenez /*
226509bc517SAntonio Huete Jimenez  * Requires an already dirfs_node_t that has been already lstat(2)
227509bc517SAntonio Huete Jimenez  * for the type comparison
228509bc517SAntonio Huete Jimenez  */
229509bc517SAntonio Huete Jimenez void
dirfs_alloc_vp(struct mount * mp,struct vnode ** vpp,int lkflags,dirfs_node_t dnp)230509bc517SAntonio Huete Jimenez dirfs_alloc_vp(struct mount *mp, struct vnode **vpp, int lkflags,
231509bc517SAntonio Huete Jimenez 	       dirfs_node_t dnp)
232509bc517SAntonio Huete Jimenez {
233509bc517SAntonio Huete Jimenez 	struct vnode *vp;
234509bc517SAntonio Huete Jimenez 	dirfs_mount_t dmp = VFS_TO_DIRFS(mp);
235509bc517SAntonio Huete Jimenez 
23626ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
237509bc517SAntonio Huete Jimenez 
238509bc517SAntonio Huete Jimenez 	/*
239509bc517SAntonio Huete Jimenez 	 * Handle vnode reclaim/alloc races
240509bc517SAntonio Huete Jimenez 	 */
241509bc517SAntonio Huete Jimenez 	for (;;) {
242509bc517SAntonio Huete Jimenez 		vp = dnp->dn_vnode;
243509bc517SAntonio Huete Jimenez 		if (vp) {
244509bc517SAntonio Huete Jimenez 			if (vget(vp, LK_EXCLUSIVE) == 0)
245509bc517SAntonio Huete Jimenez 				break;	/* success */
246509bc517SAntonio Huete Jimenez 			/* vget raced a reclaim, retry */
247509bc517SAntonio Huete Jimenez 		} else {
248509bc517SAntonio Huete Jimenez 			getnewvnode(VT_UNUSED10, mp, &vp, 0, lkflags);
249509bc517SAntonio Huete Jimenez 			if (dnp->dn_vnode == NULL) {
250509bc517SAntonio Huete Jimenez 				dnp->dn_vnode = vp;
251509bc517SAntonio Huete Jimenez 				vp->v_data = dnp;
252509bc517SAntonio Huete Jimenez 				vp->v_type = dnp->dn_type;
253509bc517SAntonio Huete Jimenez 				if (dmp->dm_root == dnp)
254509bc517SAntonio Huete Jimenez 					vsetflags(vp, VROOT);
255509bc517SAntonio Huete Jimenez 				dirfs_node_ref(dnp);	/* ref for dnp<->vp */
256509bc517SAntonio Huete Jimenez 
257509bc517SAntonio Huete Jimenez 				/* Type-specific initialization. */
258509bc517SAntonio Huete Jimenez 				switch (dnp->dn_type) {
259509bc517SAntonio Huete Jimenez 				case VBLK:
260509bc517SAntonio Huete Jimenez 				case VCHR:
261509bc517SAntonio Huete Jimenez 				case VSOCK:
262509bc517SAntonio Huete Jimenez 					break;
263509bc517SAntonio Huete Jimenez 				case VREG:
264509bc517SAntonio Huete Jimenez 					vinitvmio(vp, dnp->dn_size, BMASK, -1);
265509bc517SAntonio Huete Jimenez 					break;
266509bc517SAntonio Huete Jimenez 				case VLNK:
267509bc517SAntonio Huete Jimenez 					break;
268509bc517SAntonio Huete Jimenez 				case VFIFO:
269509bc517SAntonio Huete Jimenez 			//              vp->v_ops = &mp->mnt_vn_fifo_ops;
270509bc517SAntonio Huete Jimenez 					break;
271509bc517SAntonio Huete Jimenez 				case VDIR:
272509bc517SAntonio Huete Jimenez 					break;
273509bc517SAntonio Huete Jimenez 				default:
274509bc517SAntonio Huete Jimenez 					panic("dirfs_alloc_vp: dnp=%p vp=%p "
275509bc517SAntonio Huete Jimenez 					      "type=%d",
276509bc517SAntonio Huete Jimenez 					      dnp, vp, dnp->dn_type);
277509bc517SAntonio Huete Jimenez 					/* NOT REACHED */
278509bc517SAntonio Huete Jimenez 					break;
279509bc517SAntonio Huete Jimenez 				}
280*fc36a10bSMatthew Dillon 				/* downgrade VX lock to VN lock */
281*fc36a10bSMatthew Dillon 				vx_downgrade(vp);
282509bc517SAntonio Huete Jimenez 				break;	/* success */
283509bc517SAntonio Huete Jimenez 			}
284509bc517SAntonio Huete Jimenez 			vp->v_type = VBAD;
285509bc517SAntonio Huete Jimenez 			vx_put(vp);
286509bc517SAntonio Huete Jimenez 			/* multiple dirfs_alloc_vp calls raced, retry */
287509bc517SAntonio Huete Jimenez 		}
288509bc517SAntonio Huete Jimenez 	}
289509bc517SAntonio Huete Jimenez 	KKASSERT(vp != NULL);
290509bc517SAntonio Huete Jimenez 	*vpp = vp;
29126ec059cSAntonio Huete Jimenez 	dbg(9, "dnp=%p vp=%p type=%d\n", dnp, vp, vp->v_type);
292509bc517SAntonio Huete Jimenez }
293509bc517SAntonio Huete Jimenez 
294509bc517SAntonio Huete Jimenez /*
295509bc517SAntonio Huete Jimenez  * Do not call locked!
296509bc517SAntonio Huete Jimenez  */
297509bc517SAntonio Huete Jimenez void
dirfs_free_vp(dirfs_mount_t dmp,dirfs_node_t dnp)298509bc517SAntonio Huete Jimenez dirfs_free_vp(dirfs_mount_t dmp, dirfs_node_t dnp)
299509bc517SAntonio Huete Jimenez {
300509bc517SAntonio Huete Jimenez 	struct vnode *vp = NODE_TO_VP(dnp);
301509bc517SAntonio Huete Jimenez 
30226ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
30326ec059cSAntonio Huete Jimenez 
304509bc517SAntonio Huete Jimenez 	dnp->dn_vnode = NULL;
305509bc517SAntonio Huete Jimenez 	vp->v_data = NULL;
306509bc517SAntonio Huete Jimenez 	dirfs_node_drop(dmp, dnp);
307509bc517SAntonio Huete Jimenez }
308509bc517SAntonio Huete Jimenez 
309509bc517SAntonio Huete Jimenez int
dirfs_nodetype(struct stat * st)310509bc517SAntonio Huete Jimenez dirfs_nodetype(struct stat *st)
311509bc517SAntonio Huete Jimenez {
312509bc517SAntonio Huete Jimenez 	int ret;
313509bc517SAntonio Huete Jimenez 	mode_t mode = st->st_mode;
314509bc517SAntonio Huete Jimenez 
315509bc517SAntonio Huete Jimenez 	if (S_ISDIR(mode))
316509bc517SAntonio Huete Jimenez 		ret = VDIR;
317509bc517SAntonio Huete Jimenez 	else if (S_ISBLK(mode))
318509bc517SAntonio Huete Jimenez 		ret = VBLK;
319509bc517SAntonio Huete Jimenez 	else if (S_ISCHR(mode))
320509bc517SAntonio Huete Jimenez 		ret = VCHR;
321509bc517SAntonio Huete Jimenez 	else if (S_ISFIFO(mode))
322509bc517SAntonio Huete Jimenez 		ret = VFIFO;
323509bc517SAntonio Huete Jimenez 	else if (S_ISSOCK(mode))
324509bc517SAntonio Huete Jimenez 		ret = VSOCK;
325509bc517SAntonio Huete Jimenez 	else if (S_ISLNK(mode))
326509bc517SAntonio Huete Jimenez 		ret = VLNK;
327509bc517SAntonio Huete Jimenez 	else if (S_ISREG(mode))
328509bc517SAntonio Huete Jimenez 		ret = VREG;
329509bc517SAntonio Huete Jimenez 	else
330509bc517SAntonio Huete Jimenez 		ret = VBAD;
331509bc517SAntonio Huete Jimenez 
332509bc517SAntonio Huete Jimenez 	return ret;
333509bc517SAntonio Huete Jimenez }
334509bc517SAntonio Huete Jimenez 
335509bc517SAntonio Huete Jimenez int
dirfs_node_stat(int fd,const char * path,dirfs_node_t dnp)336509bc517SAntonio Huete Jimenez dirfs_node_stat(int fd, const char *path, dirfs_node_t dnp)
337509bc517SAntonio Huete Jimenez {
338509bc517SAntonio Huete Jimenez 	struct stat st;
339509bc517SAntonio Huete Jimenez 	int error;
340509bc517SAntonio Huete Jimenez 
34126ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
342509bc517SAntonio Huete Jimenez 	if (fd == DIRFS_NOFD)
343509bc517SAntonio Huete Jimenez 		error = lstat(path, &st);
344509bc517SAntonio Huete Jimenez 	else
345509bc517SAntonio Huete Jimenez 		error = fstatat(fd, path, &st, AT_SYMLINK_NOFOLLOW);
346509bc517SAntonio Huete Jimenez 
347509bc517SAntonio Huete Jimenez 	if (error)
348509bc517SAntonio Huete Jimenez 		return errno;
349509bc517SAntonio Huete Jimenez 
350509bc517SAntonio Huete Jimenez 	/* Populate our dirfs node struct with stat data */
351509bc517SAntonio Huete Jimenez 	dnp->dn_uid = st.st_uid;
352509bc517SAntonio Huete Jimenez 	dnp->dn_gid = st.st_gid;
353509bc517SAntonio Huete Jimenez 	dnp->dn_mode = st.st_mode;
354509bc517SAntonio Huete Jimenez 	dnp->dn_flags = st.st_flags;
355509bc517SAntonio Huete Jimenez 	dnp->dn_links = st.st_nlink;
356509bc517SAntonio Huete Jimenez 	dnp->dn_atime = st.st_atime;
357509bc517SAntonio Huete Jimenez 	dnp->dn_atimensec = (st.st_atime * 1000000000L);
358509bc517SAntonio Huete Jimenez 	dnp->dn_mtime = st.st_mtime;
359509bc517SAntonio Huete Jimenez 	dnp->dn_mtimensec = (st.st_mtime * 1000000000L);
360509bc517SAntonio Huete Jimenez 	dnp->dn_ctime = st.st_ctime;
361509bc517SAntonio Huete Jimenez 	dnp->dn_ctimensec = (st.st_ctime * 1000000000L);
362509bc517SAntonio Huete Jimenez 	dnp->dn_gen = st.st_gen;
363509bc517SAntonio Huete Jimenez 	dnp->dn_ino = st.st_ino;
364509bc517SAntonio Huete Jimenez 	dnp->dn_st_dev = st.st_dev;
365509bc517SAntonio Huete Jimenez 	dnp->dn_size = st.st_size;
366509bc517SAntonio Huete Jimenez 	dnp->dn_type = dirfs_nodetype(&st);
367509bc517SAntonio Huete Jimenez 
368509bc517SAntonio Huete Jimenez 	return 0;
369509bc517SAntonio Huete Jimenez }
370509bc517SAntonio Huete Jimenez 
371509bc517SAntonio Huete Jimenez char *
dirfs_node_absolute_path(dirfs_mount_t dmp,dirfs_node_t cur,char ** pathfreep)372509bc517SAntonio Huete Jimenez dirfs_node_absolute_path(dirfs_mount_t dmp, dirfs_node_t cur, char **pathfreep)
373509bc517SAntonio Huete Jimenez {
374509bc517SAntonio Huete Jimenez 	return(dirfs_node_absolute_path_plus(dmp, cur, NULL, pathfreep));
375509bc517SAntonio Huete Jimenez }
376509bc517SAntonio Huete Jimenez 
377509bc517SAntonio Huete Jimenez char *
dirfs_node_absolute_path_plus(dirfs_mount_t dmp,dirfs_node_t cur,char * last,char ** pathfreep)378509bc517SAntonio Huete Jimenez dirfs_node_absolute_path_plus(dirfs_mount_t dmp, dirfs_node_t cur,
379509bc517SAntonio Huete Jimenez 			      char *last, char **pathfreep)
380509bc517SAntonio Huete Jimenez {
381509bc517SAntonio Huete Jimenez 	size_t len;
382509bc517SAntonio Huete Jimenez 	dirfs_node_t dnp1;
383509bc517SAntonio Huete Jimenez 	char *buf;
384509bc517SAntonio Huete Jimenez 	int count;
385509bc517SAntonio Huete Jimenez 
38626ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
387509bc517SAntonio Huete Jimenez 
388509bc517SAntonio Huete Jimenez 	KKASSERT(dmp->dm_root);	/* Sanity check */
389509bc517SAntonio Huete Jimenez 	*pathfreep = NULL;
390509bc517SAntonio Huete Jimenez 	if (cur == NULL)
391509bc517SAntonio Huete Jimenez 		return NULL;
392509bc517SAntonio Huete Jimenez 	buf = kmalloc(MAXPATHLEN + 1, M_DIRFS_MISC, M_WAITOK);
393509bc517SAntonio Huete Jimenez 
394509bc517SAntonio Huete Jimenez 	/*
395509bc517SAntonio Huete Jimenez 	 * Passed-in trailing element.
396509bc517SAntonio Huete Jimenez 	 */
397509bc517SAntonio Huete Jimenez 	count = 0;
398509bc517SAntonio Huete Jimenez 	buf[MAXPATHLEN] = 0;
399509bc517SAntonio Huete Jimenez 	if (last) {
400509bc517SAntonio Huete Jimenez 		len = strlen(last);
401509bc517SAntonio Huete Jimenez 		count += len;
402509bc517SAntonio Huete Jimenez 		if (count <= MAXPATHLEN)
403509bc517SAntonio Huete Jimenez 			bcopy(last, &buf[MAXPATHLEN - count], len);
404509bc517SAntonio Huete Jimenez 		++count;
405509bc517SAntonio Huete Jimenez 		if (count <= MAXPATHLEN)
406509bc517SAntonio Huete Jimenez 			buf[MAXPATHLEN - count] = '/';
407509bc517SAntonio Huete Jimenez 	}
408509bc517SAntonio Huete Jimenez 
409509bc517SAntonio Huete Jimenez 	/*
410509bc517SAntonio Huete Jimenez 	 * Iterate through the parents until we hit the root.
411509bc517SAntonio Huete Jimenez 	 */
412509bc517SAntonio Huete Jimenez 	dnp1 = cur;
413509bc517SAntonio Huete Jimenez 	while (dirfs_node_isroot(dnp1) == 0) {
414509bc517SAntonio Huete Jimenez 		count += dnp1->dn_namelen;
415509bc517SAntonio Huete Jimenez 		if (count <= MAXPATHLEN) {
416509bc517SAntonio Huete Jimenez 			bcopy(dnp1->dn_name, &buf[MAXPATHLEN - count],
417509bc517SAntonio Huete Jimenez 			      dnp1->dn_namelen);
418509bc517SAntonio Huete Jimenez 		}
419509bc517SAntonio Huete Jimenez 		++count;
420509bc517SAntonio Huete Jimenez 		if (count <= MAXPATHLEN)
421509bc517SAntonio Huete Jimenez 			buf[MAXPATHLEN - count] = '/';
422509bc517SAntonio Huete Jimenez 		dnp1 = dnp1->dn_parent;
423509bc517SAntonio Huete Jimenez 		if (dnp1 == NULL)
424509bc517SAntonio Huete Jimenez 			break;
425509bc517SAntonio Huete Jimenez 	}
426509bc517SAntonio Huete Jimenez 
427509bc517SAntonio Huete Jimenez 	/*
428509bc517SAntonio Huete Jimenez 	 * Prefix with the root mount path.  If the element was unlinked
429509bc517SAntonio Huete Jimenez 	 * dnp1 will be NULL and there is no path.
430509bc517SAntonio Huete Jimenez 	 */
431509bc517SAntonio Huete Jimenez 	len = strlen(dmp->dm_path);
432509bc517SAntonio Huete Jimenez 	count += len;
433509bc517SAntonio Huete Jimenez 	if (dnp1 && count <= MAXPATHLEN) {
434509bc517SAntonio Huete Jimenez 		bcopy(dmp->dm_path, &buf[MAXPATHLEN - count], len);
435509bc517SAntonio Huete Jimenez 		*pathfreep = buf;
43626ec059cSAntonio Huete Jimenez 		dbg(9, "absolute_path %s\n", &buf[MAXPATHLEN - count]);
437509bc517SAntonio Huete Jimenez 		return (&buf[MAXPATHLEN - count]);
438509bc517SAntonio Huete Jimenez 	} else {
439509bc517SAntonio Huete Jimenez 		kfree(buf, M_DIRFS_MISC);
440509bc517SAntonio Huete Jimenez 		*pathfreep = NULL;
441509bc517SAntonio Huete Jimenez 		return (NULL);
442509bc517SAntonio Huete Jimenez 	}
443509bc517SAntonio Huete Jimenez }
444509bc517SAntonio Huete Jimenez 
445509bc517SAntonio Huete Jimenez /*
446509bc517SAntonio Huete Jimenez  * Return a dirfs_node with a valid descriptor plus an allocated
447509bc517SAntonio Huete Jimenez  * relative path which can be used in openat(), fstatat(), etc calls
448509bc517SAntonio Huete Jimenez  * to locate the requested inode.
449509bc517SAntonio Huete Jimenez  */
450509bc517SAntonio Huete Jimenez dirfs_node_t
dirfs_findfd(dirfs_mount_t dmp,dirfs_node_t cur,char ** pathto,char ** pathfreep)451509bc517SAntonio Huete Jimenez dirfs_findfd(dirfs_mount_t dmp, dirfs_node_t cur,
452509bc517SAntonio Huete Jimenez 	     char **pathto, char **pathfreep)
453509bc517SAntonio Huete Jimenez {
454509bc517SAntonio Huete Jimenez 	dirfs_node_t dnp1;
455509bc517SAntonio Huete Jimenez 	int count;
456509bc517SAntonio Huete Jimenez 	char *buf;
457509bc517SAntonio Huete Jimenez 
45826ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
459509bc517SAntonio Huete Jimenez 
460509bc517SAntonio Huete Jimenez 	*pathfreep = NULL;
461509bc517SAntonio Huete Jimenez 	*pathto = NULL;
462509bc517SAntonio Huete Jimenez 
463509bc517SAntonio Huete Jimenez 	if (cur == NULL)
464509bc517SAntonio Huete Jimenez 		return NULL;
465509bc517SAntonio Huete Jimenez 
466509bc517SAntonio Huete Jimenez 	buf = kmalloc(MAXPATHLEN + 1, M_DIRFS_MISC, M_WAITOK | M_ZERO);
467509bc517SAntonio Huete Jimenez 	count = 0;
468509bc517SAntonio Huete Jimenez 
469509bc517SAntonio Huete Jimenez 	dnp1 = cur;
470509bc517SAntonio Huete Jimenez 	while (dnp1 == cur || dnp1->dn_fd == DIRFS_NOFD) {
471509bc517SAntonio Huete Jimenez 		count += dnp1->dn_namelen;
472509bc517SAntonio Huete Jimenez 		if (count <= MAXPATHLEN) {
473509bc517SAntonio Huete Jimenez 			bcopy(dnp1->dn_name, &buf[MAXPATHLEN - count],
474509bc517SAntonio Huete Jimenez 			      dnp1->dn_namelen);
475509bc517SAntonio Huete Jimenez 		}
476509bc517SAntonio Huete Jimenez 		++count;
477509bc517SAntonio Huete Jimenez 		if (count <= MAXPATHLEN)
478509bc517SAntonio Huete Jimenez 			buf[MAXPATHLEN - count] = '/';
479509bc517SAntonio Huete Jimenez 		dnp1 = dnp1->dn_parent;
480509bc517SAntonio Huete Jimenez 		KKASSERT(dnp1 != NULL);
481509bc517SAntonio Huete Jimenez 	}
482509bc517SAntonio Huete Jimenez 
483509bc517SAntonio Huete Jimenez 	if (dnp1 && count <= MAXPATHLEN) {
484509bc517SAntonio Huete Jimenez 		*pathfreep = buf;
485509bc517SAntonio Huete Jimenez 		*pathto = &buf[MAXPATHLEN - count + 1];	/* skip '/' prefix */
486509bc517SAntonio Huete Jimenez 		dirfs_node_ref(dnp1);
48726ec059cSAntonio Huete Jimenez 		dbg(9, "fd=%d dnp1=%p dnp1->dn_name=%d &buf[off]=%s\n",
488509bc517SAntonio Huete Jimenez 		    dnp1->dn_fd, dnp1, dnp1->dn_name, *pathto);
489509bc517SAntonio Huete Jimenez 	} else {
49026ec059cSAntonio Huete Jimenez 		dbg(9, "failed too long\n");
491509bc517SAntonio Huete Jimenez 		kfree(buf, M_DIRFS_MISC);
492509bc517SAntonio Huete Jimenez 		*pathfreep = NULL;
493509bc517SAntonio Huete Jimenez 		*pathto = NULL;
494509bc517SAntonio Huete Jimenez 		dnp1 = NULL;
495509bc517SAntonio Huete Jimenez 	}
496509bc517SAntonio Huete Jimenez 	return (dnp1);
497509bc517SAntonio Huete Jimenez }
498509bc517SAntonio Huete Jimenez 
499509bc517SAntonio Huete Jimenez void
dirfs_dropfd(dirfs_mount_t dmp,dirfs_node_t dnp1,char * pathfree)500509bc517SAntonio Huete Jimenez dirfs_dropfd(dirfs_mount_t dmp, dirfs_node_t dnp1, char *pathfree)
501509bc517SAntonio Huete Jimenez {
502509bc517SAntonio Huete Jimenez 	if (pathfree)
503509bc517SAntonio Huete Jimenez 		kfree(pathfree, M_DIRFS_MISC);
504509bc517SAntonio Huete Jimenez 	if (dnp1)
505509bc517SAntonio Huete Jimenez 		dirfs_node_drop(dmp, dnp1);
506509bc517SAntonio Huete Jimenez }
507509bc517SAntonio Huete Jimenez 
508509bc517SAntonio Huete Jimenez int
dirfs_node_getperms(dirfs_node_t dnp,int * flags)50983837cefSAntonio Huete Jimenez dirfs_node_getperms(dirfs_node_t dnp, int *flags)
510509bc517SAntonio Huete Jimenez {
51183837cefSAntonio Huete Jimenez 	dirfs_mount_t dmp;
51283837cefSAntonio Huete Jimenez 	struct vnode *vp = dnp->dn_vnode;
51383837cefSAntonio Huete Jimenez 	int isowner;
51483837cefSAntonio Huete Jimenez 	int isgroup;
515509bc517SAntonio Huete Jimenez 
51683837cefSAntonio Huete Jimenez 	/*
51783837cefSAntonio Huete Jimenez 	 * There must be an active vnode anyways since that
51883837cefSAntonio Huete Jimenez 	 * would indicate the dirfs node has valid data for
51983837cefSAntonio Huete Jimenez 	 * for dnp->dn_mode (via lstat syscall).
52083837cefSAntonio Huete Jimenez 	 */
52183837cefSAntonio Huete Jimenez 	KKASSERT(vp);
52283837cefSAntonio Huete Jimenez 	dmp = VFS_TO_DIRFS(vp->v_mount);
523509bc517SAntonio Huete Jimenez 
52483837cefSAntonio Huete Jimenez 	isowner = (dmp->dm_uid == dnp->dn_uid);
52583837cefSAntonio Huete Jimenez 	isgroup = (dmp->dm_gid == dnp->dn_gid);
526509bc517SAntonio Huete Jimenez 
52783837cefSAntonio Huete Jimenez 	if (isowner) {
52883837cefSAntonio Huete Jimenez 		if (dnp->dn_mode & S_IRUSR)
52983837cefSAntonio Huete Jimenez 			*flags |= DIRFS_NODE_RD;
53083837cefSAntonio Huete Jimenez 		if (dnp->dn_mode & S_IWUSR)
53183837cefSAntonio Huete Jimenez 			*flags |= DIRFS_NODE_WR;
53283837cefSAntonio Huete Jimenez 		if (dnp->dn_mode & S_IXUSR)
53383837cefSAntonio Huete Jimenez 			*flags |= DIRFS_NODE_EXE;
53483837cefSAntonio Huete Jimenez 	} else if (isgroup) {
53583837cefSAntonio Huete Jimenez 		if (dnp->dn_mode & S_IRGRP)
53683837cefSAntonio Huete Jimenez 			*flags |= DIRFS_NODE_RD;
53783837cefSAntonio Huete Jimenez 		if (dnp->dn_mode & S_IWGRP)
53883837cefSAntonio Huete Jimenez 			*flags |= DIRFS_NODE_WR;
53983837cefSAntonio Huete Jimenez 		if (dnp->dn_mode & S_IXGRP)
54083837cefSAntonio Huete Jimenez 			*flags |= DIRFS_NODE_EXE;
54183837cefSAntonio Huete Jimenez 	} else {
54283837cefSAntonio Huete Jimenez 		if (dnp->dn_mode & S_IROTH)
54383837cefSAntonio Huete Jimenez 			*flags |= DIRFS_NODE_RD;
54483837cefSAntonio Huete Jimenez 		if (dnp->dn_mode & S_IWOTH)
54583837cefSAntonio Huete Jimenez 			*flags |= DIRFS_NODE_WR;
54683837cefSAntonio Huete Jimenez 		if (dnp->dn_mode & S_IXOTH)
54783837cefSAntonio Huete Jimenez 			*flags |= DIRFS_NODE_EXE;
548509bc517SAntonio Huete Jimenez 	}
549509bc517SAntonio Huete Jimenez 
550509bc517SAntonio Huete Jimenez 	return 0;
551509bc517SAntonio Huete Jimenez }
552509bc517SAntonio Huete Jimenez 
553509bc517SAntonio Huete Jimenez /*
554509bc517SAntonio Huete Jimenez  * This requires an allocated node and vnode, otherwise it'll panic
555509bc517SAntonio Huete Jimenez  */
556509bc517SAntonio Huete Jimenez int
dirfs_open_helper(dirfs_mount_t dmp,dirfs_node_t dnp,int parentfd,char * relpath)557509bc517SAntonio Huete Jimenez dirfs_open_helper(dirfs_mount_t dmp, dirfs_node_t dnp, int parentfd,
558509bc517SAntonio Huete Jimenez 		  char *relpath)
559509bc517SAntonio Huete Jimenez {
560509bc517SAntonio Huete Jimenez 	dirfs_node_t pathnp;
561509bc517SAntonio Huete Jimenez 	char *pathfree;
56283837cefSAntonio Huete Jimenez 	char *tmp;
56383837cefSAntonio Huete Jimenez 	int flags;
56483837cefSAntonio Huete Jimenez 	int perms;
56583837cefSAntonio Huete Jimenez 	int error;
566509bc517SAntonio Huete Jimenez 
56726ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
568509bc517SAntonio Huete Jimenez 
56983837cefSAntonio Huete Jimenez 	flags = error = perms = 0;
570509bc517SAntonio Huete Jimenez 	tmp = NULL;
571509bc517SAntonio Huete Jimenez 
572509bc517SAntonio Huete Jimenez 	KKASSERT(dnp);
573509bc517SAntonio Huete Jimenez 	KKASSERT(dnp->dn_vnode);
574509bc517SAntonio Huete Jimenez 
575509bc517SAntonio Huete Jimenez 	/*
576509bc517SAntonio Huete Jimenez 	 * XXX Besides VDIR and VREG there are other file
577509bc517SAntonio Huete Jimenez 	 * types, y'know?
578509bc517SAntonio Huete Jimenez 	 * Also, O_RDWR alone might not be the best mode to open
579509bc517SAntonio Huete Jimenez 	 * a file with, need to investigate which suits better.
580509bc517SAntonio Huete Jimenez 	 */
58183837cefSAntonio Huete Jimenez 	dirfs_node_getperms(dnp, &perms);
582509bc517SAntonio Huete Jimenez 
583509bc517SAntonio Huete Jimenez 	if (dnp->dn_type & VDIR) {
584509bc517SAntonio Huete Jimenez 		flags |= O_DIRECTORY;
585509bc517SAntonio Huete Jimenez 	} else {
58683837cefSAntonio Huete Jimenez 		if (perms & DIRFS_NODE_WR)
587509bc517SAntonio Huete Jimenez 			flags |= O_RDWR;
588509bc517SAntonio Huete Jimenez 		else
589509bc517SAntonio Huete Jimenez 			flags |= O_RDONLY;
590509bc517SAntonio Huete Jimenez 	}
591509bc517SAntonio Huete Jimenez 	if (relpath != NULL) {
592509bc517SAntonio Huete Jimenez 		tmp = relpath;
593509bc517SAntonio Huete Jimenez 		pathnp = NULL;
594509bc517SAntonio Huete Jimenez 		KKASSERT(parentfd != DIRFS_NOFD);
595509bc517SAntonio Huete Jimenez 	} else if (parentfd == DIRFS_NOFD) {
596509bc517SAntonio Huete Jimenez 		pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree);
597509bc517SAntonio Huete Jimenez 		parentfd = pathnp->dn_fd;
598509bc517SAntonio Huete Jimenez 	} else {
599509bc517SAntonio Huete Jimenez 		pathnp = NULL;
600509bc517SAntonio Huete Jimenez 	}
601509bc517SAntonio Huete Jimenez 
602509bc517SAntonio Huete Jimenez 	dnp->dn_fd = openat(parentfd, tmp, flags);
603509bc517SAntonio Huete Jimenez 	if (dnp->dn_fd == -1)
604509bc517SAntonio Huete Jimenez 		error = errno;
605509bc517SAntonio Huete Jimenez 
60626ec059cSAntonio Huete Jimenez 	dbg(9, "dnp=%p tmp2=%s parentfd=%d flags=%d error=%d "
60783837cefSAntonio Huete Jimenez 	    "flags=%08x w=%d x=%d\n", dnp, tmp, parentfd, flags, error,
60883837cefSAntonio Huete Jimenez 	    perms);
609509bc517SAntonio Huete Jimenez 
610509bc517SAntonio Huete Jimenez 	if (pathnp)
611509bc517SAntonio Huete Jimenez 		dirfs_dropfd(dmp, pathnp, pathfree);
612509bc517SAntonio Huete Jimenez 
613509bc517SAntonio Huete Jimenez 	return error;
614509bc517SAntonio Huete Jimenez }
615509bc517SAntonio Huete Jimenez 
616509bc517SAntonio Huete Jimenez int
dirfs_close_helper(dirfs_node_t dnp)617509bc517SAntonio Huete Jimenez dirfs_close_helper(dirfs_node_t dnp)
618509bc517SAntonio Huete Jimenez {
619509bc517SAntonio Huete Jimenez 	int error = 0;
620509bc517SAntonio Huete Jimenez 
62126ec059cSAntonio Huete Jimenez 	dbg(5, "called\n");
622509bc517SAntonio Huete Jimenez 
623509bc517SAntonio Huete Jimenez 
624509bc517SAntonio Huete Jimenez 	if (dnp->dn_fd != DIRFS_NOFD) {
62526ec059cSAntonio Huete Jimenez 		dbg(9, "closed fd on dnp=%p\n", dnp);
626509bc517SAntonio Huete Jimenez #if 0
627509bc517SAntonio Huete Jimenez 		/* buffer cache buffers may still be present */
628509bc517SAntonio Huete Jimenez 		error = close(dnp->dn_fd); /* XXX EINTR should be checked */
629509bc517SAntonio Huete Jimenez 		dnp->dn_fd = DIRFS_NOFD;
630509bc517SAntonio Huete Jimenez #endif
631509bc517SAntonio Huete Jimenez 	}
632509bc517SAntonio Huete Jimenez 
633509bc517SAntonio Huete Jimenez 	return error;
634509bc517SAntonio Huete Jimenez }
635509bc517SAntonio Huete Jimenez 
636509bc517SAntonio Huete Jimenez int
dirfs_node_refcnt(dirfs_node_t dnp)637509bc517SAntonio Huete Jimenez dirfs_node_refcnt(dirfs_node_t dnp)
638509bc517SAntonio Huete Jimenez {
639509bc517SAntonio Huete Jimenez 	return dnp->dn_refcnt;
640509bc517SAntonio Huete Jimenez }
641509bc517SAntonio Huete Jimenez 
642509bc517SAntonio Huete Jimenez int
dirfs_node_chtimes(dirfs_node_t dnp)643509bc517SAntonio Huete Jimenez dirfs_node_chtimes(dirfs_node_t dnp)
644509bc517SAntonio Huete Jimenez {
645509bc517SAntonio Huete Jimenez 	struct vnode *vp;
646509bc517SAntonio Huete Jimenez 	dirfs_mount_t dmp;
647509bc517SAntonio Huete Jimenez 	int error = 0;
648509bc517SAntonio Huete Jimenez 	char *tmp;
649509bc517SAntonio Huete Jimenez 	char *pathfree;
650509bc517SAntonio Huete Jimenez 
651509bc517SAntonio Huete Jimenez 	vp = NODE_TO_VP(dnp);
652509bc517SAntonio Huete Jimenez 	dmp = VFS_TO_DIRFS(vp->v_mount);
653509bc517SAntonio Huete Jimenez 
654509bc517SAntonio Huete Jimenez 	KKASSERT(vn_islocked(vp));
655509bc517SAntonio Huete Jimenez 
656509bc517SAntonio Huete Jimenez 	if (dnp->dn_flags & (IMMUTABLE | APPEND))
657509bc517SAntonio Huete Jimenez 		return EPERM;
658509bc517SAntonio Huete Jimenez 
659509bc517SAntonio Huete Jimenez 	tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
660509bc517SAntonio Huete Jimenez 	KKASSERT(tmp);
661509bc517SAntonio Huete Jimenez 	if((lutimes(tmp, NULL)) == -1)
662509bc517SAntonio Huete Jimenez 		error = errno;
663509bc517SAntonio Huete Jimenez 
664509bc517SAntonio Huete Jimenez 	dirfs_node_stat(DIRFS_NOFD, tmp, dnp);
665509bc517SAntonio Huete Jimenez 	dirfs_dropfd(dmp, NULL, pathfree);
666509bc517SAntonio Huete Jimenez 
667509bc517SAntonio Huete Jimenez 	KKASSERT(vn_islocked(vp));
668509bc517SAntonio Huete Jimenez 
669509bc517SAntonio Huete Jimenez 
670509bc517SAntonio Huete Jimenez 	return error;
671509bc517SAntonio Huete Jimenez }
672509bc517SAntonio Huete Jimenez 
673509bc517SAntonio Huete Jimenez int
dirfs_node_chflags(dirfs_node_t dnp,u_long vaflags,struct ucred * cred)674513a5bc4Szrj dirfs_node_chflags(dirfs_node_t dnp, u_long vaflags, struct ucred *cred)
675509bc517SAntonio Huete Jimenez {
676509bc517SAntonio Huete Jimenez 	struct vnode *vp;
677509bc517SAntonio Huete Jimenez 	dirfs_mount_t dmp;
678509bc517SAntonio Huete Jimenez 	int error = 0;
679509bc517SAntonio Huete Jimenez 	int flags;
680509bc517SAntonio Huete Jimenez 	char *tmp;
681509bc517SAntonio Huete Jimenez 	char *pathfree;
682509bc517SAntonio Huete Jimenez 
683509bc517SAntonio Huete Jimenez 	vp = NODE_TO_VP(dnp);
684509bc517SAntonio Huete Jimenez 	dmp = VFS_TO_DIRFS(vp->v_mount);
685509bc517SAntonio Huete Jimenez 
686509bc517SAntonio Huete Jimenez 	KKASSERT(vn_islocked(vp));
687509bc517SAntonio Huete Jimenez 
688509bc517SAntonio Huete Jimenez 	flags = dnp->dn_flags;
689509bc517SAntonio Huete Jimenez 
690509bc517SAntonio Huete Jimenez 	error = vop_helper_setattr_flags(&flags, vaflags, dnp->dn_uid, cred);
691509bc517SAntonio Huete Jimenez 	/*
692509bc517SAntonio Huete Jimenez 	 * When running vkernels with non-root it is not possible to set
693509bc517SAntonio Huete Jimenez 	 * certain flags on host files, such as SF* flags. chflags(2) call
694509bc517SAntonio Huete Jimenez 	 * will spit an error in that case.
695509bc517SAntonio Huete Jimenez 	 */
696509bc517SAntonio Huete Jimenez 	if (error == 0) {
697509bc517SAntonio Huete Jimenez 		tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
698509bc517SAntonio Huete Jimenez 		KKASSERT(tmp);
699509bc517SAntonio Huete Jimenez 		if((lchflags(tmp, flags)) == -1)
700509bc517SAntonio Huete Jimenez 			error = errno;
701509bc517SAntonio Huete Jimenez 		dirfs_node_stat(DIRFS_NOFD, tmp, dnp);
702509bc517SAntonio Huete Jimenez 		dirfs_dropfd(dmp, NULL, pathfree);
703509bc517SAntonio Huete Jimenez 	}
704509bc517SAntonio Huete Jimenez 
705509bc517SAntonio Huete Jimenez 	KKASSERT(vn_islocked(vp));
706509bc517SAntonio Huete Jimenez 
707509bc517SAntonio Huete Jimenez 	return error;
708509bc517SAntonio Huete Jimenez }
709509bc517SAntonio Huete Jimenez 
710509bc517SAntonio Huete Jimenez int
dirfs_node_chmod(dirfs_mount_t dmp,dirfs_node_t dnp,mode_t mode)711509bc517SAntonio Huete Jimenez dirfs_node_chmod(dirfs_mount_t dmp, dirfs_node_t dnp, mode_t mode)
712509bc517SAntonio Huete Jimenez {
713509bc517SAntonio Huete Jimenez 	char *tmp;
714509bc517SAntonio Huete Jimenez 	char *pathfree;
715509bc517SAntonio Huete Jimenez 	int error = 0;
716509bc517SAntonio Huete Jimenez 
717509bc517SAntonio Huete Jimenez 	tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
718509bc517SAntonio Huete Jimenez 	KKASSERT(tmp);
719509bc517SAntonio Huete Jimenez 	if (lchmod(tmp, mode) < 0)
720509bc517SAntonio Huete Jimenez 		error = errno;
721509bc517SAntonio Huete Jimenez 	dirfs_node_stat(DIRFS_NOFD, tmp, dnp);
722509bc517SAntonio Huete Jimenez 	dirfs_dropfd(dmp, NULL, pathfree);
723509bc517SAntonio Huete Jimenez 
724509bc517SAntonio Huete Jimenez 	return error;
725509bc517SAntonio Huete Jimenez }
726509bc517SAntonio Huete Jimenez 
727509bc517SAntonio Huete Jimenez int
dirfs_node_chown(dirfs_mount_t dmp,dirfs_node_t dnp,uid_t uid,uid_t gid,mode_t mode)728509bc517SAntonio Huete Jimenez dirfs_node_chown(dirfs_mount_t dmp, dirfs_node_t dnp,
729509bc517SAntonio Huete Jimenez 		 uid_t uid, uid_t gid, mode_t mode)
730509bc517SAntonio Huete Jimenez {
731509bc517SAntonio Huete Jimenez 	char *tmp;
732509bc517SAntonio Huete Jimenez 	char *pathfree;
733509bc517SAntonio Huete Jimenez 	int error = 0;
734509bc517SAntonio Huete Jimenez 
735509bc517SAntonio Huete Jimenez 	tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
736509bc517SAntonio Huete Jimenez 	KKASSERT(tmp);
737509bc517SAntonio Huete Jimenez 	if (lchown(tmp, uid, gid) < 0)
738509bc517SAntonio Huete Jimenez 		error = errno;
739509bc517SAntonio Huete Jimenez 	if (mode != dnp->dn_mode)
740509bc517SAntonio Huete Jimenez 		lchmod(tmp, mode);
741509bc517SAntonio Huete Jimenez 	dirfs_node_stat(DIRFS_NOFD, tmp, dnp);
742509bc517SAntonio Huete Jimenez 	dirfs_dropfd(dmp, NULL, pathfree);
743509bc517SAntonio Huete Jimenez 
744509bc517SAntonio Huete Jimenez 	return error;
745509bc517SAntonio Huete Jimenez }
746509bc517SAntonio Huete Jimenez 
747509bc517SAntonio Huete Jimenez 
748509bc517SAntonio Huete Jimenez int
dirfs_node_chsize(dirfs_node_t dnp,off_t nsize)749509bc517SAntonio Huete Jimenez dirfs_node_chsize(dirfs_node_t dnp, off_t nsize)
750509bc517SAntonio Huete Jimenez {
751509bc517SAntonio Huete Jimenez 	dirfs_mount_t dmp;
752509bc517SAntonio Huete Jimenez 	struct vnode *vp;
753509bc517SAntonio Huete Jimenez 	int error = 0;
754509bc517SAntonio Huete Jimenez 	char *tmp;
755509bc517SAntonio Huete Jimenez 	char *pathfree;
756509bc517SAntonio Huete Jimenez 	off_t osize;
757509bc517SAntonio Huete Jimenez 	int biosize;
758509bc517SAntonio Huete Jimenez 
759509bc517SAntonio Huete Jimenez 	KKASSERT(dnp);
760509bc517SAntonio Huete Jimenez 
761509bc517SAntonio Huete Jimenez 	vp = NODE_TO_VP(dnp);
762509bc517SAntonio Huete Jimenez 	dmp = VFS_TO_DIRFS(vp->v_mount);
763509bc517SAntonio Huete Jimenez 	biosize = BSIZE;
764509bc517SAntonio Huete Jimenez 	osize = dnp->dn_size;
765509bc517SAntonio Huete Jimenez 
766509bc517SAntonio Huete Jimenez 	KKASSERT(vn_islocked(vp));
767509bc517SAntonio Huete Jimenez 
768509bc517SAntonio Huete Jimenez 	switch (vp->v_type) {
769509bc517SAntonio Huete Jimenez 	case VDIR:
770509bc517SAntonio Huete Jimenez 		return (EISDIR);
771509bc517SAntonio Huete Jimenez 	case VREG:
772509bc517SAntonio Huete Jimenez 		break;
773509bc517SAntonio Huete Jimenez 	default:
774509bc517SAntonio Huete Jimenez 		return (EOPNOTSUPP);
775509bc517SAntonio Huete Jimenez 
776509bc517SAntonio Huete Jimenez 	}
777509bc517SAntonio Huete Jimenez 
778509bc517SAntonio Huete Jimenez 	tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree);
779509bc517SAntonio Huete Jimenez 	if (nsize < osize) {
780509bc517SAntonio Huete Jimenez 		error = nvtruncbuf(vp, nsize, biosize, -1, 0);
781509bc517SAntonio Huete Jimenez 	} else {
782509bc517SAntonio Huete Jimenez 		error = nvextendbuf(vp, osize, nsize,
783509bc517SAntonio Huete Jimenez 				    biosize, biosize,
784509bc517SAntonio Huete Jimenez 				    -1, -1, 0);
785509bc517SAntonio Huete Jimenez 	}
786509bc517SAntonio Huete Jimenez 	if (error == 0 && truncate(tmp, nsize) < 0)
787509bc517SAntonio Huete Jimenez 		error = errno;
788509bc517SAntonio Huete Jimenez 	if (error == 0)
789509bc517SAntonio Huete Jimenez 		dnp->dn_size = nsize;
79026ec059cSAntonio Huete Jimenez 	dbg(9, "TRUNCATE %016jx %016jx\n", (intmax_t)nsize, dnp->dn_size);
791509bc517SAntonio Huete Jimenez 	/*dirfs_node_stat(DIRFS_NOFD, tmp, dnp); don't need to do this*/
792509bc517SAntonio Huete Jimenez 
793509bc517SAntonio Huete Jimenez 	dirfs_dropfd(dmp, NULL, pathfree);
794509bc517SAntonio Huete Jimenez 
795509bc517SAntonio Huete Jimenez 
796509bc517SAntonio Huete Jimenez 	KKASSERT(vn_islocked(vp));
797509bc517SAntonio Huete Jimenez 
798509bc517SAntonio Huete Jimenez 	return error;
799509bc517SAntonio Huete Jimenez }
800509bc517SAntonio Huete Jimenez 
801509bc517SAntonio Huete Jimenez void
dirfs_node_setpassive(dirfs_mount_t dmp,dirfs_node_t dnp,int state)802509bc517SAntonio Huete Jimenez dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state)
803509bc517SAntonio Huete Jimenez {
804509bc517SAntonio Huete Jimenez 	struct vnode *vp;
805509bc517SAntonio Huete Jimenez 
80626ec059cSAntonio Huete Jimenez 	dbg(5, "dnp=%p state=%d dnp->dn_fd=%d\n", dnp, state, dnp->dn_fd);
80726ec059cSAntonio Huete Jimenez 
808509bc517SAntonio Huete Jimenez 	if (state && (dnp->dn_state & DIRFS_PASVFD) == 0 &&
809509bc517SAntonio Huete Jimenez 	    dnp->dn_fd != DIRFS_NOFD) {
810509bc517SAntonio Huete Jimenez 		dirfs_node_ref(dnp);
811509bc517SAntonio Huete Jimenez 		dirfs_node_setflags(dnp, DIRFS_PASVFD);
812509bc517SAntonio Huete Jimenez 		TAILQ_INSERT_TAIL(&dmp->dm_fdlist, dnp, dn_fdentry);
813509bc517SAntonio Huete Jimenez 		++dirfs_fd_used;
814509bc517SAntonio Huete Jimenez 		++dmp->dm_fd_used;
815509bc517SAntonio Huete Jimenez 
816509bc517SAntonio Huete Jimenez 		/*
817509bc517SAntonio Huete Jimenez 		 * If we are over our limit remove nodes from the
818509bc517SAntonio Huete Jimenez 		 * passive fd cache.
819509bc517SAntonio Huete Jimenez 		 */
820509bc517SAntonio Huete Jimenez 		while (dmp->dm_fd_used > dirfs_fd_limit) {
821509bc517SAntonio Huete Jimenez 			dnp = TAILQ_FIRST(&dmp->dm_fdlist);
822509bc517SAntonio Huete Jimenez 			dirfs_node_setpassive(dmp, dnp, 0);
823509bc517SAntonio Huete Jimenez 		}
824509bc517SAntonio Huete Jimenez 	}
825509bc517SAntonio Huete Jimenez 	if (state == 0 && (dnp->dn_state & DIRFS_PASVFD)) {
826509bc517SAntonio Huete Jimenez 		dirfs_node_clrflags(dnp, DIRFS_PASVFD);
827509bc517SAntonio Huete Jimenez 		TAILQ_REMOVE(&dmp->dm_fdlist, dnp, dn_fdentry);
828509bc517SAntonio Huete Jimenez 		--dirfs_fd_used;
829509bc517SAntonio Huete Jimenez 		--dmp->dm_fd_used;
83026ec059cSAntonio Huete Jimenez 		dbg(5, "dnp=%p removed from fdlist. %d used refs=%d\n",
83126ec059cSAntonio Huete Jimenez 		    dnp, dirfs_fd_used, dirfs_node_refcnt(dnp));
832509bc517SAntonio Huete Jimenez 
833509bc517SAntonio Huete Jimenez 		/*
834509bc517SAntonio Huete Jimenez 		 * Attempt to close the descriptor.  We can only do this
835509bc517SAntonio Huete Jimenez 		 * if the related vnode is inactive and has exactly two
836509bc517SAntonio Huete Jimenez 		 * refs (representing the vp<->dnp and PASVFD).  Otherwise
837509bc517SAntonio Huete Jimenez 		 * someone might have ref'd the node in order to use the
838509bc517SAntonio Huete Jimenez 		 * dn_fd.
839509bc517SAntonio Huete Jimenez 		 *
840509bc517SAntonio Huete Jimenez 		 * Also, if the vnode is in any way dirty we leave the fd
841509bc517SAntonio Huete Jimenez 		 * open for the buffer cache code.  The syncer will eventually
842509bc517SAntonio Huete Jimenez 		 * come along and fsync the vnode, and the next inactive
843509bc517SAntonio Huete Jimenez 		 * transition will deal with the descriptor.
844509bc517SAntonio Huete Jimenez 		 *
845509bc517SAntonio Huete Jimenez 		 * The descriptor for the root node is NEVER closed by
846509bc517SAntonio Huete Jimenez 		 * this function.
847509bc517SAntonio Huete Jimenez 		 */
848509bc517SAntonio Huete Jimenez 		vp = dnp->dn_vnode;
849509bc517SAntonio Huete Jimenez 		if (dirfs_node_refcnt(dnp) == 2 && vp &&
850509bc517SAntonio Huete Jimenez 		    dnp->dn_fd != DIRFS_NOFD &&
851509bc517SAntonio Huete Jimenez 		    !dirfs_node_isroot(dnp) &&
852509bc517SAntonio Huete Jimenez 		    (vp->v_flag & (VINACTIVE|VOBJDIRTY)) == VINACTIVE &&
853509bc517SAntonio Huete Jimenez 		    RB_EMPTY(&vp->v_rbdirty_tree)) {
85426ec059cSAntonio Huete Jimenez 			dbg(9, "passive cache: closing %d\n", dnp->dn_fd);
855509bc517SAntonio Huete Jimenez 			close(dnp->dn_fd);
856509bc517SAntonio Huete Jimenez 			dnp->dn_fd = DIRFS_NOFD;
857509bc517SAntonio Huete Jimenez 		} else {
858509bc517SAntonio Huete Jimenez 			if (dirfs_node_refcnt(dnp) == 1 && dnp->dn_vnode == NULL &&
859509bc517SAntonio Huete Jimenez 			    dnp->dn_fd != DIRFS_NOFD &&
860509bc517SAntonio Huete Jimenez 			    dnp != dmp->dm_root) {
86126ec059cSAntonio Huete Jimenez 				dbg(9, "passive cache: closing %d\n", dnp->dn_fd);
862509bc517SAntonio Huete Jimenez 				close(dnp->dn_fd);
863509bc517SAntonio Huete Jimenez 				dnp->dn_fd = DIRFS_NOFD;
864509bc517SAntonio Huete Jimenez 			}
865509bc517SAntonio Huete Jimenez 		}
866509bc517SAntonio Huete Jimenez 		dirfs_node_drop(dmp, dnp);
867509bc517SAntonio Huete Jimenez 	}
868509bc517SAntonio Huete Jimenez }
869509bc517SAntonio Huete Jimenez 
870509bc517SAntonio Huete Jimenez char *
dirfs_flag2str(dirfs_node_t dnp)871509bc517SAntonio Huete Jimenez dirfs_flag2str(dirfs_node_t dnp)
872509bc517SAntonio Huete Jimenez {
873509bc517SAntonio Huete Jimenez 	const char *txtflg[] = { DIRFS_TXTFLG };
874509bc517SAntonio Huete Jimenez 	static char str[512] = {0};
875509bc517SAntonio Huete Jimenez 
876509bc517SAntonio Huete Jimenez 	if (dnp->dn_state & DIRFS_PASVFD)
877509bc517SAntonio Huete Jimenez 		ksprintf(str, "%s ", txtflg[0]);
878509bc517SAntonio Huete Jimenez 
879509bc517SAntonio Huete Jimenez 	return str;
880509bc517SAntonio Huete Jimenez }
881509bc517SAntonio Huete Jimenez 
882509bc517SAntonio Huete Jimenez void
debug(int level,const char * fmt,...)883509bc517SAntonio Huete Jimenez debug(int level, const char *fmt, ...)
884509bc517SAntonio Huete Jimenez {
885509bc517SAntonio Huete Jimenez 	__va_list ap;
886509bc517SAntonio Huete Jimenez 
887509bc517SAntonio Huete Jimenez 	if (debuglvl >= level) {
888509bc517SAntonio Huete Jimenez 		__va_start(ap, fmt);
889509bc517SAntonio Huete Jimenez 		kvprintf(fmt, ap);
890509bc517SAntonio Huete Jimenez 		__va_end(ap);
891509bc517SAntonio Huete Jimenez 	}
892509bc517SAntonio Huete Jimenez }
893