xref: /freebsd/sys/fs/p9fs/p9fs_vfsops.c (revision daa2c99c89f224200911aa6c8cdee07bc354947a)
1e97ad33aSDoug Rabson /*-
2e97ad33aSDoug Rabson  * Copyright (c) 2017-2020 Juniper Networks, Inc.
3e97ad33aSDoug Rabson  * All rights reserved.
4e97ad33aSDoug Rabson  *
5e97ad33aSDoug Rabson  * Redistribution and use in source and binary forms, with or without
6e97ad33aSDoug Rabson  * modification, are permitted provided that the following conditions
7e97ad33aSDoug Rabson  * are met:
8e97ad33aSDoug Rabson  * 1. Redistributions of source code must retain the above copyright
9e97ad33aSDoug Rabson  *    notice, this list of conditions and the following disclaimer.
10e97ad33aSDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
11e97ad33aSDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
12e97ad33aSDoug Rabson  *    documentation and/or other materials provided with the distribution.
13e97ad33aSDoug Rabson  *
14e97ad33aSDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15e97ad33aSDoug Rabson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16e97ad33aSDoug Rabson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17e97ad33aSDoug Rabson  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18e97ad33aSDoug Rabson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19e97ad33aSDoug Rabson  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20e97ad33aSDoug Rabson  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21e97ad33aSDoug Rabson  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22e97ad33aSDoug Rabson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23e97ad33aSDoug Rabson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24e97ad33aSDoug Rabson  *
25e97ad33aSDoug Rabson  */
26e97ad33aSDoug Rabson 
27e97ad33aSDoug Rabson /*
28e97ad33aSDoug Rabson  * This file consists of all the VFS interactions of VFS ops which include
29e97ad33aSDoug Rabson  * mount, unmount, initilaize etc. for p9fs.
30e97ad33aSDoug Rabson  */
31e97ad33aSDoug Rabson 
32e97ad33aSDoug Rabson #include <sys/cdefs.h>
33e97ad33aSDoug Rabson #include <sys/systm.h>
34e97ad33aSDoug Rabson #include <sys/fnv_hash.h>
35e97ad33aSDoug Rabson #include <sys/mount.h>
36e97ad33aSDoug Rabson #include <sys/sysctl.h>
37e97ad33aSDoug Rabson #include <sys/vnode.h>
38*daa2c99cSVal Packett #include <sys/buf.h>
39e97ad33aSDoug Rabson #include <vm/uma.h>
40e97ad33aSDoug Rabson 
41e97ad33aSDoug Rabson #include <fs/p9fs/p9fs_proto.h>
42e97ad33aSDoug Rabson #include <fs/p9fs/p9_client.h>
43e97ad33aSDoug Rabson #include <fs/p9fs/p9_debug.h>
44e97ad33aSDoug Rabson #include <fs/p9fs/p9fs.h>
45e97ad33aSDoug Rabson 
46e97ad33aSDoug Rabson SYSCTL_NODE(_vfs, OID_AUTO, p9fs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
47e97ad33aSDoug Rabson     "Plan 9 filesystem");
48e97ad33aSDoug Rabson 
49e97ad33aSDoug Rabson /* This count is static now. Can be made tunable later */
50e97ad33aSDoug Rabson #define P9FS_FLUSH_RETRIES 10
51e97ad33aSDoug Rabson 
52e97ad33aSDoug Rabson static MALLOC_DEFINE(M_P9MNT, "p9fs_mount", "Mount structures for p9fs");
53e97ad33aSDoug Rabson static uma_zone_t p9fs_node_zone;
54e97ad33aSDoug Rabson uma_zone_t p9fs_io_buffer_zone;
55e97ad33aSDoug Rabson uma_zone_t p9fs_getattr_zone;
56e97ad33aSDoug Rabson uma_zone_t p9fs_setattr_zone;
57*daa2c99cSVal Packett uma_zone_t p9fs_pbuf_zone;
58e97ad33aSDoug Rabson extern struct vop_vector p9fs_vnops;
59e97ad33aSDoug Rabson 
60e97ad33aSDoug Rabson /* option parsing */
61e97ad33aSDoug Rabson static const char *p9fs_opts[] = {
62e97ad33aSDoug Rabson         "from", "trans", "access", NULL
63e97ad33aSDoug Rabson };
64e97ad33aSDoug Rabson 
65e97ad33aSDoug Rabson /* Dispose p9fs node, freeing it to the UMA zone */
66e97ad33aSDoug Rabson void
p9fs_dispose_node(struct p9fs_node ** npp)67e97ad33aSDoug Rabson p9fs_dispose_node(struct p9fs_node **npp)
68e97ad33aSDoug Rabson {
69e97ad33aSDoug Rabson 	struct p9fs_node *node;
70e97ad33aSDoug Rabson 	struct vnode *vp;
71e97ad33aSDoug Rabson 
72e97ad33aSDoug Rabson 	node = *npp;
73e97ad33aSDoug Rabson 
74e97ad33aSDoug Rabson 	if (node == NULL)
75e97ad33aSDoug Rabson 		return;
76e97ad33aSDoug Rabson 
77e97ad33aSDoug Rabson 	if (node->parent && node->parent != node) {
78e97ad33aSDoug Rabson 		vrele(P9FS_NTOV(node->parent));
79e97ad33aSDoug Rabson 	}
80e97ad33aSDoug Rabson 
81e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: node: %p\n", __func__, *npp);
82e97ad33aSDoug Rabson 
83e97ad33aSDoug Rabson 	vp = P9FS_NTOV(node);
84e97ad33aSDoug Rabson 	vp->v_data = NULL;
85e97ad33aSDoug Rabson 
86e97ad33aSDoug Rabson 	/* Free our associated memory */
87e97ad33aSDoug Rabson 	if (!(vp->v_vflag & VV_ROOT)) {
88e97ad33aSDoug Rabson 		free(node->inode.i_name, M_TEMP);
89e97ad33aSDoug Rabson 		uma_zfree(p9fs_node_zone, node);
90e97ad33aSDoug Rabson 	}
91e97ad33aSDoug Rabson 
92e97ad33aSDoug Rabson 	*npp = NULL;
93e97ad33aSDoug Rabson }
94e97ad33aSDoug Rabson 
95e97ad33aSDoug Rabson /* Initialize memory allocation */
96e97ad33aSDoug Rabson static int
p9fs_init(struct vfsconf * vfsp)97e97ad33aSDoug Rabson p9fs_init(struct vfsconf *vfsp)
98e97ad33aSDoug Rabson {
99e97ad33aSDoug Rabson 
100e97ad33aSDoug Rabson 	p9fs_node_zone = uma_zcreate("p9fs node zone",
101e97ad33aSDoug Rabson 	    sizeof(struct p9fs_node), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
102e97ad33aSDoug Rabson 
103e97ad33aSDoug Rabson 	/* Create the getattr_dotl zone */
104e97ad33aSDoug Rabson 	p9fs_getattr_zone = uma_zcreate("p9fs getattr zone",
105e97ad33aSDoug Rabson 	    sizeof(struct p9_stat_dotl), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
106e97ad33aSDoug Rabson 
107e97ad33aSDoug Rabson 	/* Create the setattr_dotl zone */
108e97ad33aSDoug Rabson 	p9fs_setattr_zone = uma_zcreate("p9fs setattr zone",
109e97ad33aSDoug Rabson 	    sizeof(struct p9_iattr_dotl), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
110e97ad33aSDoug Rabson 
111*daa2c99cSVal Packett 	/* Create the putpages zone */
112*daa2c99cSVal Packett 	p9fs_pbuf_zone = pbuf_zsecond_create("p9fs pbuf zone", nswbuf / 2);
113*daa2c99cSVal Packett 
114e97ad33aSDoug Rabson 	/*
115e97ad33aSDoug Rabson 	 * Create the io_buffer zone pool to keep things simpler in case of
116e97ad33aSDoug Rabson 	 * multiple threads. Each thread works with its own so there is no
117e97ad33aSDoug Rabson 	 * contention.
118e97ad33aSDoug Rabson 	 */
119e97ad33aSDoug Rabson 	p9fs_io_buffer_zone = uma_zcreate("p9fs io_buffer zone",
120e97ad33aSDoug Rabson 	    P9FS_MTU, NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
121e97ad33aSDoug Rabson 
122e97ad33aSDoug Rabson 	return (0);
123e97ad33aSDoug Rabson }
124e97ad33aSDoug Rabson 
125e97ad33aSDoug Rabson /* Destroy all the allocated memory */
126e97ad33aSDoug Rabson static int
p9fs_uninit(struct vfsconf * vfsp)127e97ad33aSDoug Rabson p9fs_uninit(struct vfsconf *vfsp)
128e97ad33aSDoug Rabson {
129e97ad33aSDoug Rabson 
130e97ad33aSDoug Rabson 	uma_zdestroy(p9fs_node_zone);
131e97ad33aSDoug Rabson 	uma_zdestroy(p9fs_io_buffer_zone);
132e97ad33aSDoug Rabson 	uma_zdestroy(p9fs_getattr_zone);
133e97ad33aSDoug Rabson 	uma_zdestroy(p9fs_setattr_zone);
134*daa2c99cSVal Packett 	uma_zdestroy(p9fs_pbuf_zone);
135e97ad33aSDoug Rabson 
136e97ad33aSDoug Rabson 	return (0);
137e97ad33aSDoug Rabson }
138e97ad33aSDoug Rabson 
139e97ad33aSDoug Rabson /* Function to umount p9fs */
140e97ad33aSDoug Rabson static int
p9fs_unmount(struct mount * mp,int mntflags)141e97ad33aSDoug Rabson p9fs_unmount(struct mount *mp, int mntflags)
142e97ad33aSDoug Rabson {
143e97ad33aSDoug Rabson 	struct p9fs_mount *vmp;
144e97ad33aSDoug Rabson 	struct p9fs_session *vses;
145e97ad33aSDoug Rabson 	int error, flags, i;
146e97ad33aSDoug Rabson 
147e97ad33aSDoug Rabson 	error = 0;
148e97ad33aSDoug Rabson 	flags = 0;
149e97ad33aSDoug Rabson 	vmp = VFSTOP9(mp);
150e97ad33aSDoug Rabson 	if (vmp == NULL)
151e97ad33aSDoug Rabson 		return (0);
152e97ad33aSDoug Rabson 
153e97ad33aSDoug Rabson 	vses = &vmp->p9fs_session;
154e97ad33aSDoug Rabson 	if (mntflags & MNT_FORCE)
155e97ad33aSDoug Rabson 		flags |= FORCECLOSE;
156e97ad33aSDoug Rabson 
157e97ad33aSDoug Rabson 	p9fs_prepare_to_close(mp);
158e97ad33aSDoug Rabson 	for (i = 0; i < P9FS_FLUSH_RETRIES; i++) {
159e97ad33aSDoug Rabson 
160e97ad33aSDoug Rabson 		/* Flush everything on this mount point.*/
161e97ad33aSDoug Rabson 		error = vflush(mp, 1, flags, curthread);
162e97ad33aSDoug Rabson 
163e97ad33aSDoug Rabson 		if (error == 0 || (mntflags & MNT_FORCE) == 0)
164e97ad33aSDoug Rabson 			break;
165e97ad33aSDoug Rabson 		/* Sleep until interrupted or 1 tick expires. */
166e97ad33aSDoug Rabson 		error = tsleep(&error, PSOCK, "p9unmnt", 1);
167e97ad33aSDoug Rabson 		if (error == EINTR)
168e97ad33aSDoug Rabson 			break;
169e97ad33aSDoug Rabson 		error = EBUSY;
170e97ad33aSDoug Rabson 	}
171e97ad33aSDoug Rabson 
172e97ad33aSDoug Rabson 	if (error != 0)
173e97ad33aSDoug Rabson 		goto out;
174e97ad33aSDoug Rabson 	p9fs_close_session(mp);
175e97ad33aSDoug Rabson 	/* Cleanup the mount structure. */
176e97ad33aSDoug Rabson 	free(vmp, M_P9MNT);
177e97ad33aSDoug Rabson 	mp->mnt_data = NULL;
178e97ad33aSDoug Rabson 	return (error);
179e97ad33aSDoug Rabson out:
180e97ad33aSDoug Rabson 	/* Restore the flag in case of error */
181e97ad33aSDoug Rabson 	vses->clnt->trans_status = P9FS_CONNECT;
182e97ad33aSDoug Rabson 	return (error);
183e97ad33aSDoug Rabson }
184e97ad33aSDoug Rabson 
185e97ad33aSDoug Rabson /*
186e97ad33aSDoug Rabson  * Compare qid stored in p9fs node
187e97ad33aSDoug Rabson  * Return 1 if does not match otherwise return 0
188e97ad33aSDoug Rabson  */
189e97ad33aSDoug Rabson int
p9fs_node_cmp(struct vnode * vp,void * arg)190e97ad33aSDoug Rabson p9fs_node_cmp(struct vnode *vp, void *arg)
191e97ad33aSDoug Rabson {
192e97ad33aSDoug Rabson 	struct p9fs_node *np;
193e97ad33aSDoug Rabson 	struct p9_qid *qid;
194e97ad33aSDoug Rabson 
195e97ad33aSDoug Rabson 	np = vp->v_data;
196e97ad33aSDoug Rabson 	qid = (struct p9_qid *)arg;
197e97ad33aSDoug Rabson 
198e97ad33aSDoug Rabson 	if (np == NULL)
199e97ad33aSDoug Rabson 		return (1);
200e97ad33aSDoug Rabson 
201e97ad33aSDoug Rabson 	if (np->vqid.qid_path == qid->path) {
202e97ad33aSDoug Rabson 		if (vp->v_vflag & VV_ROOT)
203e97ad33aSDoug Rabson 			return (0);
204e97ad33aSDoug Rabson 		else if (np->vqid.qid_mode == qid->type &&
205e97ad33aSDoug Rabson 			    np->vqid.qid_version == qid->version)
206e97ad33aSDoug Rabson 			return (0);
207e97ad33aSDoug Rabson 	}
208e97ad33aSDoug Rabson 
209e97ad33aSDoug Rabson 	return (1);
210e97ad33aSDoug Rabson }
211e97ad33aSDoug Rabson 
212e97ad33aSDoug Rabson /*
213e97ad33aSDoug Rabson  * Cleanup p9fs node
214e97ad33aSDoug Rabson  *  - Destroy the FID LIST locks
215e97ad33aSDoug Rabson  *  - Dispose all node knowledge
216e97ad33aSDoug Rabson  */
217e97ad33aSDoug Rabson void
p9fs_destroy_node(struct p9fs_node ** npp)218e97ad33aSDoug Rabson p9fs_destroy_node(struct p9fs_node **npp)
219e97ad33aSDoug Rabson {
220e97ad33aSDoug Rabson 	struct p9fs_node *np;
221e97ad33aSDoug Rabson 
222e97ad33aSDoug Rabson 	np = *npp;
223e97ad33aSDoug Rabson 
224e97ad33aSDoug Rabson 	if (np == NULL)
225e97ad33aSDoug Rabson 		return;
226e97ad33aSDoug Rabson 
227e97ad33aSDoug Rabson 	/* Destroy the FID LIST locks */
228e97ad33aSDoug Rabson 	P9FS_VFID_LOCK_DESTROY(np);
229e97ad33aSDoug Rabson 	P9FS_VOFID_LOCK_DESTROY(np);
230e97ad33aSDoug Rabson 
231e97ad33aSDoug Rabson 	/* Dispose all node knowledge.*/
232e97ad33aSDoug Rabson 	p9fs_dispose_node(&np);
233e97ad33aSDoug Rabson }
234e97ad33aSDoug Rabson 
235e97ad33aSDoug Rabson /*
236e97ad33aSDoug Rabson  * Common code used across p9fs to return vnode for the file represented
237e97ad33aSDoug Rabson  * by the fid.
238e97ad33aSDoug Rabson  * Lookup for the vnode in hash_list. This lookup is based on the qid path
239e97ad33aSDoug Rabson  * which is unique to a file. p9fs_node_cmp is called in this lookup process.
240e97ad33aSDoug Rabson  * I. If the vnode we are looking for is found in the hash list
241e97ad33aSDoug Rabson  *    1. Check if the vnode is a valid vnode by reloading its stats
242e97ad33aSDoug Rabson  *       a. if the reloading of the vnode stats returns error then remove the
243e97ad33aSDoug Rabson  *          vnode from hash list and return
244e97ad33aSDoug Rabson  *       b. If reloading of vnode stats returns without any error then, clunk the
245e97ad33aSDoug Rabson  *          new fid which was created for the vnode as we know that the vnode
246e97ad33aSDoug Rabson  *          already has a fid associated with it and return the vnode.
247e97ad33aSDoug Rabson  *          This is to avoid fid leaks
248e97ad33aSDoug Rabson  * II. If vnode is not found in the hash list then, create new vnode, p9fs
249e97ad33aSDoug Rabson  *     node and return the vnode
250e97ad33aSDoug Rabson  */
251e97ad33aSDoug Rabson int
p9fs_vget_common(struct mount * mp,struct p9fs_node * np,int flags,struct p9fs_node * parent,struct p9_fid * fid,struct vnode ** vpp,char * name)252e97ad33aSDoug Rabson p9fs_vget_common(struct mount *mp, struct p9fs_node *np, int flags,
253e97ad33aSDoug Rabson     struct p9fs_node *parent, struct p9_fid *fid, struct vnode **vpp,
254e97ad33aSDoug Rabson     char *name)
255e97ad33aSDoug Rabson {
256e97ad33aSDoug Rabson 	struct p9fs_mount *vmp;
257e97ad33aSDoug Rabson 	struct p9fs_session *vses;
258e97ad33aSDoug Rabson 	struct vnode *vp;
259e97ad33aSDoug Rabson 	struct p9fs_node *node;
260e97ad33aSDoug Rabson 	struct thread *td;
261e97ad33aSDoug Rabson 	uint32_t hash;
262e97ad33aSDoug Rabson 	int error, error_reload = 0;
263e97ad33aSDoug Rabson 	struct p9fs_inode *inode;
264e97ad33aSDoug Rabson 
265e97ad33aSDoug Rabson 	td = curthread;
266e97ad33aSDoug Rabson 	vmp = VFSTOP9(mp);
267e97ad33aSDoug Rabson 	vses = &vmp->p9fs_session;
268e97ad33aSDoug Rabson 
269e97ad33aSDoug Rabson 	/* Look for vp in the hash_list */
270e97ad33aSDoug Rabson 	hash = fnv_32_buf(&fid->qid.path, sizeof(uint64_t), FNV1_32_INIT);
271e97ad33aSDoug Rabson 	error = vfs_hash_get(mp, hash, flags, td, &vp, p9fs_node_cmp,
272e97ad33aSDoug Rabson 	    &fid->qid);
273e97ad33aSDoug Rabson 	if (error != 0)
274e97ad33aSDoug Rabson 		return (error);
275e97ad33aSDoug Rabson 	else if (vp != NULL) {
276e97ad33aSDoug Rabson 		if (vp->v_vflag & VV_ROOT) {
277e97ad33aSDoug Rabson 			if (np == NULL)
278e97ad33aSDoug Rabson 				p9_client_clunk(fid);
279e97ad33aSDoug Rabson 			*vpp = vp;
280e97ad33aSDoug Rabson 			return (0);
281e97ad33aSDoug Rabson 		}
282e97ad33aSDoug Rabson 		error = p9fs_reload_stats_dotl(vp, curthread->td_ucred);
283e97ad33aSDoug Rabson 		if (error != 0) {
284e97ad33aSDoug Rabson 			node = vp->v_data;
285e97ad33aSDoug Rabson 			/* Remove stale vnode from hash list */
286e97ad33aSDoug Rabson 			vfs_hash_remove(vp);
287e97ad33aSDoug Rabson 			node->flags |= P9FS_NODE_DELETED;
288e97ad33aSDoug Rabson 
289e97ad33aSDoug Rabson 			vput(vp);
290e97ad33aSDoug Rabson 			*vpp = NULLVP;
291e97ad33aSDoug Rabson 			vp = NULL;
292e97ad33aSDoug Rabson 		} else {
293e97ad33aSDoug Rabson 			*vpp = vp;
294e97ad33aSDoug Rabson 			/* Clunk the new fid if not root */
295e97ad33aSDoug Rabson 			p9_client_clunk(fid);
296e97ad33aSDoug Rabson 			return (0);
297e97ad33aSDoug Rabson 		}
298e97ad33aSDoug Rabson 	}
299e97ad33aSDoug Rabson 
300e97ad33aSDoug Rabson 	/*
301e97ad33aSDoug Rabson 	 * We must promote to an exclusive lock for vnode creation.  This
302e97ad33aSDoug Rabson 	 * can happen if lookup is passed LOCKSHARED.
303e97ad33aSDoug Rabson 	 */
304e97ad33aSDoug Rabson 	if ((flags & LK_TYPE_MASK) == LK_SHARED) {
305e97ad33aSDoug Rabson 		flags &= ~LK_TYPE_MASK;
306e97ad33aSDoug Rabson 		flags |= LK_EXCLUSIVE;
307e97ad33aSDoug Rabson 	}
308e97ad33aSDoug Rabson 
309e97ad33aSDoug Rabson 	/* Allocate a new vnode. */
310e97ad33aSDoug Rabson 	if ((error = getnewvnode("p9fs", mp, &p9fs_vnops, &vp)) != 0) {
311e97ad33aSDoug Rabson 		*vpp = NULLVP;
312e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: getnewvnode failed: %d\n", __func__, error);
313e97ad33aSDoug Rabson 		return (error);
314e97ad33aSDoug Rabson 	}
315e97ad33aSDoug Rabson 
316e97ad33aSDoug Rabson 	/* If we dont have it, create one. */
317e97ad33aSDoug Rabson 	if (np == NULL) {
318e97ad33aSDoug Rabson 		np =  uma_zalloc(p9fs_node_zone, M_WAITOK | M_ZERO);
319e97ad33aSDoug Rabson 		/* Initialize the VFID list */
320e97ad33aSDoug Rabson 		P9FS_VFID_LOCK_INIT(np);
321e97ad33aSDoug Rabson 		STAILQ_INIT(&np->vfid_list);
322e97ad33aSDoug Rabson 		p9fs_fid_add(np, fid, VFID);
323e97ad33aSDoug Rabson 
324e97ad33aSDoug Rabson 		/* Initialize the VOFID list */
325e97ad33aSDoug Rabson 		P9FS_VOFID_LOCK_INIT(np);
326e97ad33aSDoug Rabson 		STAILQ_INIT(&np->vofid_list);
327e97ad33aSDoug Rabson 
328e97ad33aSDoug Rabson 		vref(P9FS_NTOV(parent));
329e97ad33aSDoug Rabson 		np->parent = parent;
330e97ad33aSDoug Rabson 		np->p9fs_ses = vses; /* Map the current session */
331e97ad33aSDoug Rabson 		inode = &np->inode;
332e97ad33aSDoug Rabson 		/*Fill the name of the file in inode */
333e97ad33aSDoug Rabson 		inode->i_name = malloc(strlen(name)+1, M_TEMP, M_NOWAIT | M_ZERO);
334e97ad33aSDoug Rabson 		strlcpy(inode->i_name, name, strlen(name)+1);
335e97ad33aSDoug Rabson 	} else {
336e97ad33aSDoug Rabson 		vp->v_type = VDIR; /* root vp is a directory */
337e97ad33aSDoug Rabson 		vp->v_vflag |= VV_ROOT;
338e97ad33aSDoug Rabson 		vref(vp); /* Increment a reference on root vnode during mount */
339e97ad33aSDoug Rabson 	}
340e97ad33aSDoug Rabson 
341e97ad33aSDoug Rabson 	vp->v_data = np;
342e97ad33aSDoug Rabson 	np->v_node = vp;
343e97ad33aSDoug Rabson 	inode = &np->inode;
344e97ad33aSDoug Rabson 	inode->i_qid_path = fid->qid.path;
345e97ad33aSDoug Rabson 	P9FS_SET_LINKS(inode);
346e97ad33aSDoug Rabson 
347e97ad33aSDoug Rabson 	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
348e97ad33aSDoug Rabson 	error = insmntque(vp, mp);
349e97ad33aSDoug Rabson 	if (error != 0) {
350e97ad33aSDoug Rabson 		/*
351e97ad33aSDoug Rabson 		 * vput(vp) is already called from insmntque_stddtr().
352e97ad33aSDoug Rabson 		 * Just goto 'out' to dispose the node.
353e97ad33aSDoug Rabson 		 */
354e97ad33aSDoug Rabson 		goto out;
355e97ad33aSDoug Rabson 	}
356e97ad33aSDoug Rabson 
357e97ad33aSDoug Rabson 	/* Init the vnode with the disk info*/
358e97ad33aSDoug Rabson 	error = p9fs_reload_stats_dotl(vp, curthread->td_ucred);
359e97ad33aSDoug Rabson 	if (error != 0) {
360e97ad33aSDoug Rabson 		error_reload = 1;
361e97ad33aSDoug Rabson 		goto out;
362e97ad33aSDoug Rabson 	}
363e97ad33aSDoug Rabson 
364e97ad33aSDoug Rabson 	error = vfs_hash_insert(vp, hash, flags, td, vpp,
365e97ad33aSDoug Rabson 	    p9fs_node_cmp, &fid->qid);
366e97ad33aSDoug Rabson 	if (error != 0) {
367e97ad33aSDoug Rabson 		goto out;
368e97ad33aSDoug Rabson 	}
369e97ad33aSDoug Rabson 
370e97ad33aSDoug Rabson 	if (*vpp == NULL) {
371e97ad33aSDoug Rabson 		P9FS_LOCK(vses);
372e97ad33aSDoug Rabson 		STAILQ_INSERT_TAIL(&vses->virt_node_list, np, p9fs_node_next);
373e97ad33aSDoug Rabson 		np->flags |= P9FS_NODE_IN_SESSION;
374e97ad33aSDoug Rabson 		P9FS_UNLOCK(vses);
375e97ad33aSDoug Rabson 
376e97ad33aSDoug Rabson 		*vpp = vp;
377e97ad33aSDoug Rabson 	} else {
378e97ad33aSDoug Rabson 		/*
379e97ad33aSDoug Rabson 		 * Returning matching vp found in hashlist.
380e97ad33aSDoug Rabson 		 * So cleanup the np allocated above in this context.
381e97ad33aSDoug Rabson 		 */
382e97ad33aSDoug Rabson 		if (!IS_ROOT(np)) {
383e97ad33aSDoug Rabson 			p9fs_destroy_node(&np);
384e97ad33aSDoug Rabson 		}
385e97ad33aSDoug Rabson 	}
386e97ad33aSDoug Rabson 
387e97ad33aSDoug Rabson 	return (0);
388e97ad33aSDoug Rabson out:
389e97ad33aSDoug Rabson 	/* Something went wrong, dispose the node */
390e97ad33aSDoug Rabson 	if (!IS_ROOT(np)) {
391e97ad33aSDoug Rabson 		p9fs_destroy_node(&np);
392e97ad33aSDoug Rabson 	}
393e97ad33aSDoug Rabson 
394e97ad33aSDoug Rabson 	if (error_reload) {
395e97ad33aSDoug Rabson 		vput(vp);
396e97ad33aSDoug Rabson 	}
397e97ad33aSDoug Rabson 
398e97ad33aSDoug Rabson 	*vpp = NULLVP;
399e97ad33aSDoug Rabson 	return (error);
400e97ad33aSDoug Rabson }
401e97ad33aSDoug Rabson 
402e97ad33aSDoug Rabson /* Main mount function for 9pfs */
403e97ad33aSDoug Rabson static int
p9_mount(struct mount * mp)404e97ad33aSDoug Rabson p9_mount(struct mount *mp)
405e97ad33aSDoug Rabson {
406e97ad33aSDoug Rabson 	struct p9_fid *fid;
407e97ad33aSDoug Rabson 	struct p9fs_mount *vmp;
408e97ad33aSDoug Rabson 	struct p9fs_session *vses;
409e97ad33aSDoug Rabson 	struct p9fs_node *p9fs_root;
410e97ad33aSDoug Rabson 	int error;
411e97ad33aSDoug Rabson 	char *from;
412e97ad33aSDoug Rabson 	int len;
413e97ad33aSDoug Rabson 
414e97ad33aSDoug Rabson 	/* Verify the validity of mount options */
415e97ad33aSDoug Rabson 	if (vfs_filteropt(mp->mnt_optnew, p9fs_opts))
416e97ad33aSDoug Rabson 		return (EINVAL);
417e97ad33aSDoug Rabson 
418e97ad33aSDoug Rabson 	/* Extract NULL terminated mount tag from mount options */
419e97ad33aSDoug Rabson 	error = vfs_getopt(mp->mnt_optnew, "from", (void **)&from, &len);
420e97ad33aSDoug Rabson 	if (error != 0 || from[len - 1] != '\0')
421e97ad33aSDoug Rabson 		return (EINVAL);
422e97ad33aSDoug Rabson 
423e97ad33aSDoug Rabson 	/* Allocate and initialize the private mount structure. */
424e97ad33aSDoug Rabson 	vmp = malloc(sizeof (struct p9fs_mount), M_P9MNT, M_WAITOK | M_ZERO);
425e97ad33aSDoug Rabson 	mp->mnt_data = vmp;
426e97ad33aSDoug Rabson 	vmp->p9fs_mountp = mp;
427e97ad33aSDoug Rabson 	vmp->mount_tag = from;
428e97ad33aSDoug Rabson 	vmp->mount_tag_len = len;
429e97ad33aSDoug Rabson 	vses = &vmp->p9fs_session;
430e97ad33aSDoug Rabson 	vses->p9fs_mount = mp;
431e97ad33aSDoug Rabson 	p9fs_root = &vses->rnp;
432e97ad33aSDoug Rabson 	/* Hardware iosize from the Qemu */
433e97ad33aSDoug Rabson 	mp->mnt_iosize_max = PAGE_SIZE;
434e97ad33aSDoug Rabson 	/*
435e97ad33aSDoug Rabson 	 * Init the session for the p9fs root. This creates a new root fid and
436e97ad33aSDoug Rabson 	 * attaches the client and server.
437e97ad33aSDoug Rabson 	 */
438e97ad33aSDoug Rabson 	fid = p9fs_init_session(mp, &error);
439e97ad33aSDoug Rabson 	if (fid == NULL) {
440e97ad33aSDoug Rabson 		goto out;
441e97ad33aSDoug Rabson 	}
442e97ad33aSDoug Rabson 
443e97ad33aSDoug Rabson 	P9FS_VFID_LOCK_INIT(p9fs_root);
444e97ad33aSDoug Rabson 	STAILQ_INIT(&p9fs_root->vfid_list);
445e97ad33aSDoug Rabson 	p9fs_fid_add(p9fs_root, fid, VFID);
446e97ad33aSDoug Rabson 	P9FS_VOFID_LOCK_INIT(p9fs_root);
447e97ad33aSDoug Rabson 	STAILQ_INIT(&p9fs_root->vofid_list);
448e97ad33aSDoug Rabson 	p9fs_root->parent = p9fs_root;
449e97ad33aSDoug Rabson 	p9fs_root->flags |= P9FS_ROOT;
450e97ad33aSDoug Rabson 	p9fs_root->p9fs_ses = vses;
451e97ad33aSDoug Rabson 	vfs_getnewfsid(mp);
452e97ad33aSDoug Rabson 	strlcpy(mp->mnt_stat.f_mntfromname, from,
453e97ad33aSDoug Rabson 	    sizeof(mp->mnt_stat.f_mntfromname));
454e97ad33aSDoug Rabson 	MNT_ILOCK(mp);
455e97ad33aSDoug Rabson 	mp->mnt_flag |= MNT_LOCAL;
456e97ad33aSDoug Rabson 	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
457e97ad33aSDoug Rabson 	MNT_IUNLOCK(mp);
458e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: Mount successful\n", __func__);
459e97ad33aSDoug Rabson 	/* Mount structures created. */
460e97ad33aSDoug Rabson 
461e97ad33aSDoug Rabson 	return (0);
462e97ad33aSDoug Rabson out:
463e97ad33aSDoug Rabson 	P9_DEBUG(ERROR, "%s: Mount Failed \n", __func__);
464e97ad33aSDoug Rabson 	if (vmp != NULL) {
465e97ad33aSDoug Rabson 		free(vmp, M_P9MNT);
466e97ad33aSDoug Rabson 		mp->mnt_data = NULL;
467e97ad33aSDoug Rabson 	}
468e97ad33aSDoug Rabson 	return (error);
469e97ad33aSDoug Rabson }
470e97ad33aSDoug Rabson 
471e97ad33aSDoug Rabson /* Mount entry point */
472e97ad33aSDoug Rabson static int
p9fs_mount(struct mount * mp)473e97ad33aSDoug Rabson p9fs_mount(struct mount *mp)
474e97ad33aSDoug Rabson {
475e97ad33aSDoug Rabson 	int error;
476e97ad33aSDoug Rabson 
477e97ad33aSDoug Rabson 	/*
478e97ad33aSDoug Rabson 	 * Minimal support for MNT_UPDATE - allow changing from
479e97ad33aSDoug Rabson 	 * readonly.
480e97ad33aSDoug Rabson 	 */
481e97ad33aSDoug Rabson 	if (mp->mnt_flag & MNT_UPDATE) {
482e97ad33aSDoug Rabson 		if ((mp->mnt_flag & MNT_RDONLY) && !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) {
483e97ad33aSDoug Rabson 			mp->mnt_flag &= ~MNT_RDONLY;
484e97ad33aSDoug Rabson 		}
485e97ad33aSDoug Rabson 		return (0);
486e97ad33aSDoug Rabson 	}
487e97ad33aSDoug Rabson 
488e97ad33aSDoug Rabson 	error = p9_mount(mp);
489e97ad33aSDoug Rabson 	if (error != 0)
490e97ad33aSDoug Rabson 		(void) p9fs_unmount(mp, MNT_FORCE);
491e97ad33aSDoug Rabson 
492e97ad33aSDoug Rabson 	return (error);
493e97ad33aSDoug Rabson }
494e97ad33aSDoug Rabson 
495e97ad33aSDoug Rabson /*
496e97ad33aSDoug Rabson  * Retrieve the root vnode of this mount. After filesystem is mounted, the root
497e97ad33aSDoug Rabson  * vnode is created for the first time. Subsequent calls to p9fs root will
498e97ad33aSDoug Rabson  * return the same vnode created during mount.
499e97ad33aSDoug Rabson  */
500e97ad33aSDoug Rabson static int
p9fs_root(struct mount * mp,int lkflags,struct vnode ** vpp)501e97ad33aSDoug Rabson p9fs_root(struct mount *mp, int lkflags, struct vnode **vpp)
502e97ad33aSDoug Rabson {
503e97ad33aSDoug Rabson 	struct p9fs_mount *vmp;
504e97ad33aSDoug Rabson 	struct p9fs_node *np;
505e97ad33aSDoug Rabson 	struct p9_client *clnt;
506e97ad33aSDoug Rabson 	struct p9_fid *vfid;
507e97ad33aSDoug Rabson 	int error;
508e97ad33aSDoug Rabson 
509e97ad33aSDoug Rabson 	vmp = VFSTOP9(mp);
510e97ad33aSDoug Rabson 	np = &vmp->p9fs_session.rnp;
511e97ad33aSDoug Rabson 	clnt = vmp->p9fs_session.clnt;
512e97ad33aSDoug Rabson 	error = 0;
513e97ad33aSDoug Rabson 
514e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: node=%p name=%s\n",__func__, np, np->inode.i_name);
515e97ad33aSDoug Rabson 
516e97ad33aSDoug Rabson 	vfid = p9fs_get_fid(clnt, np, curthread->td_ucred, VFID, -1, &error);
517e97ad33aSDoug Rabson 
518e97ad33aSDoug Rabson 	if (error != 0) {
519e97ad33aSDoug Rabson 		/* for root use the nobody user's fid as vfid.
520e97ad33aSDoug Rabson 		 * This is used while unmounting as root when non-root
521e97ad33aSDoug Rabson 		 * user has mounted p9fs
522e97ad33aSDoug Rabson 		 */
523e97ad33aSDoug Rabson 		if (vfid == NULL && clnt->trans_status == P9FS_BEGIN_DISCONNECT)
524e97ad33aSDoug Rabson 			vfid = vmp->p9fs_session.mnt_fid;
525e97ad33aSDoug Rabson 		else {
526e97ad33aSDoug Rabson 			*vpp = NULLVP;
527e97ad33aSDoug Rabson 			return (error);
528e97ad33aSDoug Rabson 		}
529e97ad33aSDoug Rabson 	}
530e97ad33aSDoug Rabson 
531e97ad33aSDoug Rabson 	error = p9fs_vget_common(mp, np, lkflags, np, vfid, vpp, NULL);
532e97ad33aSDoug Rabson 	if (error != 0) {
533e97ad33aSDoug Rabson 		*vpp = NULLVP;
534e97ad33aSDoug Rabson 		return (error);
535e97ad33aSDoug Rabson 	}
536e97ad33aSDoug Rabson 	np->v_node = *vpp;
537e97ad33aSDoug Rabson 	return (error);
538e97ad33aSDoug Rabson }
539e97ad33aSDoug Rabson 
540e97ad33aSDoug Rabson /* Retrieve the file system statistics */
541e97ad33aSDoug Rabson static int
p9fs_statfs(struct mount * mp __unused,struct statfs * buf)542e97ad33aSDoug Rabson p9fs_statfs(struct mount *mp __unused, struct statfs *buf)
543e97ad33aSDoug Rabson {
544e97ad33aSDoug Rabson 	struct p9fs_mount *vmp;
545e97ad33aSDoug Rabson 	struct p9fs_node *np;
546e97ad33aSDoug Rabson 	struct p9_client *clnt;
547e97ad33aSDoug Rabson 	struct p9_fid *vfid;
548e97ad33aSDoug Rabson 	struct p9_statfs statfs;
549e97ad33aSDoug Rabson 	int res, error;
550e97ad33aSDoug Rabson 
551e97ad33aSDoug Rabson 	vmp = VFSTOP9(mp);
552e97ad33aSDoug Rabson 	np = &vmp->p9fs_session.rnp;
553e97ad33aSDoug Rabson 	clnt = vmp->p9fs_session.clnt;
554e97ad33aSDoug Rabson 	error = 0;
555e97ad33aSDoug Rabson 
556e97ad33aSDoug Rabson 	vfid = p9fs_get_fid(clnt, np, curthread->td_ucred, VFID, -1, &error);
557e97ad33aSDoug Rabson 	if (error != 0) {
558e97ad33aSDoug Rabson 		return (error);
559e97ad33aSDoug Rabson 	}
560e97ad33aSDoug Rabson 
561e97ad33aSDoug Rabson 	res = p9_client_statfs(vfid, &statfs);
562e97ad33aSDoug Rabson 
563e97ad33aSDoug Rabson 	if (res == 0) {
564e97ad33aSDoug Rabson 		buf->f_type = statfs.type;
565e97ad33aSDoug Rabson 		/*
566e97ad33aSDoug Rabson 		 * We have a limit of 4k irrespective of what the
567e97ad33aSDoug Rabson 		 * Qemu server can do.
568e97ad33aSDoug Rabson 		 */
569e97ad33aSDoug Rabson 		if (statfs.bsize > PAGE_SIZE)
570e97ad33aSDoug Rabson 			buf->f_bsize = PAGE_SIZE;
571e97ad33aSDoug Rabson 		else
572e97ad33aSDoug Rabson 			buf->f_bsize = statfs.bsize;
573e97ad33aSDoug Rabson 
574e97ad33aSDoug Rabson 		buf->f_iosize = buf->f_bsize;
575e97ad33aSDoug Rabson 		buf->f_blocks = statfs.blocks;
576e97ad33aSDoug Rabson 		buf->f_bfree = statfs.bfree;
577e97ad33aSDoug Rabson 		buf->f_bavail = statfs.bavail;
578e97ad33aSDoug Rabson 		buf->f_files = statfs.files;
579e97ad33aSDoug Rabson 		buf->f_ffree = statfs.ffree;
580e97ad33aSDoug Rabson 	}
581e97ad33aSDoug Rabson 	else {
582e97ad33aSDoug Rabson 		/* Atleast set these if stat fail */
583e97ad33aSDoug Rabson 		buf->f_bsize = PAGE_SIZE;
584e97ad33aSDoug Rabson 		buf->f_iosize = buf->f_bsize;   /* XXX */
585e97ad33aSDoug Rabson 	}
586e97ad33aSDoug Rabson 
587e97ad33aSDoug Rabson 	return (0);
588e97ad33aSDoug Rabson }
589e97ad33aSDoug Rabson 
590e97ad33aSDoug Rabson static int
p9fs_fhtovp(struct mount * mp,struct fid * fhp,int flags,struct vnode ** vpp)591e97ad33aSDoug Rabson p9fs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
592e97ad33aSDoug Rabson {
593e97ad33aSDoug Rabson 
594e97ad33aSDoug Rabson 	return (EINVAL);
595e97ad33aSDoug Rabson }
596e97ad33aSDoug Rabson 
597e97ad33aSDoug Rabson struct vfsops p9fs_vfsops = {
598e97ad33aSDoug Rabson 	.vfs_init  =	p9fs_init,
599e97ad33aSDoug Rabson 	.vfs_uninit =	p9fs_uninit,
600e97ad33aSDoug Rabson 	.vfs_mount =	p9fs_mount,
601e97ad33aSDoug Rabson 	.vfs_unmount =	p9fs_unmount,
602e97ad33aSDoug Rabson 	.vfs_root =	p9fs_root,
603e97ad33aSDoug Rabson 	.vfs_statfs =	p9fs_statfs,
604e97ad33aSDoug Rabson 	.vfs_fhtovp =	p9fs_fhtovp,
605e97ad33aSDoug Rabson };
606e97ad33aSDoug Rabson 
607e97ad33aSDoug Rabson VFS_SET(p9fs_vfsops, p9fs, VFCF_JAIL);
608e97ad33aSDoug Rabson MODULE_VERSION(p9fs, 1);
609