xref: /freebsd-src/sys/fs/p9fs/p9fs_vnops.c (revision 1d99e8d9a37e1ba528628186df57b79fe74e196c)
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 /* This file contains VFS file ops for the 9P protocol.
28e97ad33aSDoug Rabson  * This makes the upper layer of the p9fs driver. These functions interact
29e97ad33aSDoug Rabson  * with the VFS layer and lower layer of p9fs driver which is 9Pnet. All
30e97ad33aSDoug Rabson  * the user file operations are handled here.
31e97ad33aSDoug Rabson  */
32e97ad33aSDoug Rabson #include <sys/cdefs.h>
33e97ad33aSDoug Rabson #include <sys/systm.h>
34e97ad33aSDoug Rabson #include <sys/bio.h>
35e97ad33aSDoug Rabson #include <sys/buf.h>
36e97ad33aSDoug Rabson #include <sys/dirent.h>
37e97ad33aSDoug Rabson #include <sys/fcntl.h>
38e97ad33aSDoug Rabson #include <sys/namei.h>
39e97ad33aSDoug Rabson #include <sys/priv.h>
40e97ad33aSDoug Rabson #include <sys/stat.h>
41e97ad33aSDoug Rabson #include <sys/vnode.h>
42daa2c99cSVal Packett #include <sys/rwlock.h>
43daa2c99cSVal Packett #include <sys/vmmeter.h>
44e97ad33aSDoug Rabson 
45e97ad33aSDoug Rabson #include <vm/vm.h>
46e97ad33aSDoug Rabson #include <vm/vm_extern.h>
47e97ad33aSDoug Rabson #include <vm/vm_object.h>
48daa2c99cSVal Packett #include <vm/vm_page.h>
49daa2c99cSVal Packett #include <vm/vm_pager.h>
50e97ad33aSDoug Rabson #include <vm/vnode_pager.h>
51e97ad33aSDoug Rabson 
52e97ad33aSDoug Rabson #include <fs/p9fs/p9_client.h>
53e97ad33aSDoug Rabson #include <fs/p9fs/p9_debug.h>
54e97ad33aSDoug Rabson #include <fs/p9fs/p9fs.h>
55e97ad33aSDoug Rabson #include <fs/p9fs/p9fs_proto.h>
56e97ad33aSDoug Rabson 
57e97ad33aSDoug Rabson /* File permissions. */
58e97ad33aSDoug Rabson #define IEXEC		0000100 /* Executable. */
59e97ad33aSDoug Rabson #define IWRITE		0000200 /* Writeable. */
60e97ad33aSDoug Rabson #define IREAD		0000400 /* Readable. */
61e97ad33aSDoug Rabson #define ISVTX		0001000 /* Sticky bit. */
62e97ad33aSDoug Rabson #define ISGID		0002000 /* Set-gid. */
63e97ad33aSDoug Rabson #define ISUID		0004000 /* Set-uid. */
64e97ad33aSDoug Rabson 
65e97ad33aSDoug Rabson static MALLOC_DEFINE(M_P9UIOV, "uio", "UIOV structures for strategy in p9fs");
66e97ad33aSDoug Rabson extern uma_zone_t p9fs_io_buffer_zone;
67e97ad33aSDoug Rabson extern uma_zone_t p9fs_getattr_zone;
68e97ad33aSDoug Rabson extern uma_zone_t p9fs_setattr_zone;
69daa2c99cSVal Packett extern uma_zone_t p9fs_pbuf_zone;
70e97ad33aSDoug Rabson /* For the root vnode's vnops. */
71e97ad33aSDoug Rabson struct vop_vector p9fs_vnops;
72e97ad33aSDoug Rabson 
73e97ad33aSDoug Rabson static uint32_t p9fs_unix2p9_mode(uint32_t mode);
74e97ad33aSDoug Rabson 
75e97ad33aSDoug Rabson static void
76e97ad33aSDoug Rabson p9fs_itimes(struct vnode *vp)
77e97ad33aSDoug Rabson {
78e97ad33aSDoug Rabson 	struct p9fs_node *node;
79e97ad33aSDoug Rabson 	struct timespec ts;
80e97ad33aSDoug Rabson 	struct p9fs_inode *inode;
81e97ad33aSDoug Rabson 
82e97ad33aSDoug Rabson 	node = P9FS_VTON(vp);
83e97ad33aSDoug Rabson 	inode = &node->inode;
84e97ad33aSDoug Rabson 
85e97ad33aSDoug Rabson 	vfs_timestamp(&ts);
86e97ad33aSDoug Rabson 	inode->i_mtime = ts.tv_sec;
87e97ad33aSDoug Rabson }
88e97ad33aSDoug Rabson 
89e97ad33aSDoug Rabson /*
90e97ad33aSDoug Rabson  * Cleanup the p9fs node, the in memory representation of a vnode for p9fs.
91e97ad33aSDoug Rabson  * The cleanup includes invalidating all cache entries for the vnode,
92e97ad33aSDoug Rabson  * destroying the vobject, removing vnode from hashlist, removing p9fs node
93e97ad33aSDoug Rabson  * from the list of session p9fs nodes, and disposing of the p9fs node.
94e97ad33aSDoug Rabson  * Basically it is doing a reverse of what a create/vget does.
95e97ad33aSDoug Rabson  */
96e97ad33aSDoug Rabson void
97e97ad33aSDoug Rabson p9fs_cleanup(struct p9fs_node *np)
98e97ad33aSDoug Rabson {
99e97ad33aSDoug Rabson 	struct vnode *vp;
100e97ad33aSDoug Rabson 	struct p9fs_session *vses;
101e97ad33aSDoug Rabson 
102e97ad33aSDoug Rabson 	if (np == NULL)
103e97ad33aSDoug Rabson 		return;
104e97ad33aSDoug Rabson 
105e97ad33aSDoug Rabson 	vp = P9FS_NTOV(np);
106e97ad33aSDoug Rabson 	vses = np->p9fs_ses;
107e97ad33aSDoug Rabson 
108e97ad33aSDoug Rabson 	/* Remove the vnode from hash list if vnode is not already deleted */
109e97ad33aSDoug Rabson 	if ((np->flags & P9FS_NODE_DELETED) == 0)
110e97ad33aSDoug Rabson 		vfs_hash_remove(vp);
111e97ad33aSDoug Rabson 
112e97ad33aSDoug Rabson 	P9FS_LOCK(vses);
113e97ad33aSDoug Rabson 	if ((np->flags & P9FS_NODE_IN_SESSION) != 0) {
114e97ad33aSDoug Rabson 		np->flags &= ~P9FS_NODE_IN_SESSION;
115e97ad33aSDoug Rabson 		STAILQ_REMOVE(&vses->virt_node_list, np, p9fs_node, p9fs_node_next);
116e97ad33aSDoug Rabson 	} else {
117e97ad33aSDoug Rabson 		P9FS_UNLOCK(vses);
118e97ad33aSDoug Rabson 		return;
119e97ad33aSDoug Rabson 	}
120e97ad33aSDoug Rabson 	P9FS_UNLOCK(vses);
121e97ad33aSDoug Rabson 
122e97ad33aSDoug Rabson 	/* Invalidate all entries to a particular vnode. */
123e97ad33aSDoug Rabson 	cache_purge(vp);
124e97ad33aSDoug Rabson 
125e97ad33aSDoug Rabson 	/* Destroy the vm object and flush associated pages. */
126e97ad33aSDoug Rabson 	vnode_destroy_vobject(vp);
127e97ad33aSDoug Rabson 
128e97ad33aSDoug Rabson 	/* Remove all the FID */
129e97ad33aSDoug Rabson 	p9fs_fid_remove_all(np, FALSE);
130e97ad33aSDoug Rabson 
131e97ad33aSDoug Rabson 	/* Dispose all node knowledge.*/
132e97ad33aSDoug Rabson 	p9fs_destroy_node(&np);
133e97ad33aSDoug Rabson }
134e97ad33aSDoug Rabson 
135e97ad33aSDoug Rabson /*
136e97ad33aSDoug Rabson  * Reclaim VOP is defined to be called for every vnode. This starts off
137e97ad33aSDoug Rabson  * the cleanup by clunking(remove the fid on the server) and calls
138e97ad33aSDoug Rabson  * p9fs_cleanup to free all the resources allocated for p9fs node.
139e97ad33aSDoug Rabson  */
140e97ad33aSDoug Rabson static int
141e97ad33aSDoug Rabson p9fs_reclaim(struct vop_reclaim_args *ap)
142e97ad33aSDoug Rabson {
143e97ad33aSDoug Rabson 	struct vnode *vp;
144e97ad33aSDoug Rabson 	struct p9fs_node *np;
145e97ad33aSDoug Rabson 
146e97ad33aSDoug Rabson 	vp = ap->a_vp;
147e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
148e97ad33aSDoug Rabson 
149e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp:%p node:%p\n", __func__, vp, np);
150e97ad33aSDoug Rabson 	p9fs_cleanup(np);
151e97ad33aSDoug Rabson 
152e97ad33aSDoug Rabson 	return (0);
153e97ad33aSDoug Rabson }
154e97ad33aSDoug Rabson 
155e97ad33aSDoug Rabson /*
156e97ad33aSDoug Rabson  * recycle vnodes which are no longer referenced i.e, their usecount is zero
157e97ad33aSDoug Rabson  */
158e97ad33aSDoug Rabson static int
159e97ad33aSDoug Rabson p9fs_inactive(struct vop_inactive_args *ap)
160e97ad33aSDoug Rabson {
161e97ad33aSDoug Rabson 	struct vnode *vp;
162e97ad33aSDoug Rabson 	struct p9fs_node *np;
163e97ad33aSDoug Rabson 
164e97ad33aSDoug Rabson 	vp = ap->a_vp;
165e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
166e97ad33aSDoug Rabson 
167e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp:%p node:%p file:%s\n", __func__, vp, np, np->inode.i_name);
168e97ad33aSDoug Rabson 	if (np->flags & P9FS_NODE_DELETED)
169e97ad33aSDoug Rabson 		vrecycle(vp);
170e97ad33aSDoug Rabson 
171e97ad33aSDoug Rabson 	return (0);
172e97ad33aSDoug Rabson }
173e97ad33aSDoug Rabson 
174e97ad33aSDoug Rabson struct p9fs_lookup_alloc_arg {
175e97ad33aSDoug Rabson 	struct componentname *cnp;
176e97ad33aSDoug Rabson 	struct p9fs_node *dnp;
177e97ad33aSDoug Rabson 	struct p9_fid *newfid;
178e97ad33aSDoug Rabson };
179e97ad33aSDoug Rabson 
180e97ad33aSDoug Rabson /* Callback for vn_get_ino */
181e97ad33aSDoug Rabson static int
182e97ad33aSDoug Rabson p9fs_lookup_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp)
183e97ad33aSDoug Rabson {
184e97ad33aSDoug Rabson 	struct p9fs_lookup_alloc_arg *p9aa = arg;
185e97ad33aSDoug Rabson 
186e97ad33aSDoug Rabson 	return (p9fs_vget_common(mp, NULL, p9aa->cnp->cn_lkflags, p9aa->dnp,
187e97ad33aSDoug Rabson 		p9aa->newfid, vpp, p9aa->cnp->cn_nameptr));
188e97ad33aSDoug Rabson }
189e97ad33aSDoug Rabson 
190e97ad33aSDoug Rabson /*
191e97ad33aSDoug Rabson  * p9fs_lookup is called for every component name that is being searched for.
192e97ad33aSDoug Rabson  *
193e97ad33aSDoug Rabson  * I. If component is found on the server, we look for the in-memory
194e97ad33aSDoug Rabson  *    repesentation(vnode) of this component in namecache.
195e97ad33aSDoug Rabson  *    A. If the node is found in the namecache, we check is the vnode is still
196e97ad33aSDoug Rabson  *	 valid.
197e97ad33aSDoug Rabson  *	 1. If it is still valid, return vnode.
198e97ad33aSDoug Rabson  *	 2. If it is not valid, we remove this vnode from the name cache and
199e97ad33aSDoug Rabson  *	    create a new vnode for the component and return that vnode.
200e97ad33aSDoug Rabson  *    B. If the vnode is not found in the namecache, we look for it in the
201e97ad33aSDoug Rabson  *       hash list.
202e97ad33aSDoug Rabson  *       1. If the vnode is in the hash list, we check if the vnode is still
203e97ad33aSDoug Rabson  *	    valid.
204e97ad33aSDoug Rabson  *	    a. If it is still valid, we add that vnode to the namecache for
205e97ad33aSDoug Rabson  *	       future lookups and return the vnode.
206e97ad33aSDoug Rabson  *	    b. If it is not valid, create a new vnode and p9fs node,
207e97ad33aSDoug Rabson  *	       initialize them and return the vnode.
208e97ad33aSDoug Rabson  *	 2. If the vnode is not found in the hash list, we create a new vnode
209e97ad33aSDoug Rabson  *	    and p9fs node, initialize them and return the vnode.
210e97ad33aSDoug Rabson  * II. If the component is not found on the server, an error code is returned.
211e97ad33aSDoug Rabson  *     A. For the creation case, we return EJUSTRETURN so VFS can handle it.
212e97ad33aSDoug Rabson  *     B. For all other cases, ENOENT is returned.
213e97ad33aSDoug Rabson  */
214e97ad33aSDoug Rabson static int
215e97ad33aSDoug Rabson p9fs_lookup(struct vop_lookup_args *ap)
216e97ad33aSDoug Rabson {
217e97ad33aSDoug Rabson 	struct vnode *dvp;
218e97ad33aSDoug Rabson 	struct vnode **vpp, *vp;
219e97ad33aSDoug Rabson 	struct componentname *cnp;
220e97ad33aSDoug Rabson 	struct p9fs_node *dnp; /*dir p9_node */
221e97ad33aSDoug Rabson 	struct p9fs_node *np;
222e97ad33aSDoug Rabson 	struct p9fs_session *vses;
223e97ad33aSDoug Rabson 	struct mount *mp; /* Get the mount point */
224e97ad33aSDoug Rabson 	struct p9_fid *dvfid, *newfid;
225e97ad33aSDoug Rabson 	int error;
226e97ad33aSDoug Rabson 	struct vattr vattr;
227e97ad33aSDoug Rabson 	int flags;
228e97ad33aSDoug Rabson 	char tmpchr;
229e97ad33aSDoug Rabson 
230e97ad33aSDoug Rabson 	dvp = ap->a_dvp;
231e97ad33aSDoug Rabson 	vpp = ap->a_vpp;
232e97ad33aSDoug Rabson 	cnp = ap->a_cnp;
233e97ad33aSDoug Rabson 	dnp = P9FS_VTON(dvp);
234e97ad33aSDoug Rabson 	error = 0;
235e97ad33aSDoug Rabson 	flags = cnp->cn_flags;
236e97ad33aSDoug Rabson 	*vpp = NULLVP;
237e97ad33aSDoug Rabson 
238e97ad33aSDoug Rabson 	if (dnp == NULL)
239e97ad33aSDoug Rabson 		return (ENOENT);
240e97ad33aSDoug Rabson 
24162bb18abSBakul Shah 	if (cnp->cn_nameptr[0] == '.' && cnp->cn_namelen == 1) {
24256e46225SDoug Rabson 		vref(dvp);
24356e46225SDoug Rabson 		*vpp = dvp;
24456e46225SDoug Rabson 		return (0);
24556e46225SDoug Rabson 	}
24656e46225SDoug Rabson 
247e97ad33aSDoug Rabson 	vses = dnp->p9fs_ses;
248e97ad33aSDoug Rabson 	mp = vses->p9fs_mount;
249e97ad33aSDoug Rabson 
250e97ad33aSDoug Rabson 	/* Do the cache part ourselves */
251e97ad33aSDoug Rabson 	if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) &&
252e97ad33aSDoug Rabson 	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
253e97ad33aSDoug Rabson 		return (EROFS);
254e97ad33aSDoug Rabson 
255e97ad33aSDoug Rabson 	if (dvp->v_type != VDIR)
256e97ad33aSDoug Rabson 		return (ENOTDIR);
257e97ad33aSDoug Rabson 
258e97ad33aSDoug Rabson 	error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, curthread);
259e97ad33aSDoug Rabson 	if (error)
260e97ad33aSDoug Rabson 		return (error);
261e97ad33aSDoug Rabson 
262e97ad33aSDoug Rabson 	/* Do the directory walk on host to check if file exist */
263e97ad33aSDoug Rabson 	dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error);
264e97ad33aSDoug Rabson 	if (error)
265e97ad33aSDoug Rabson 		return (error);
266e97ad33aSDoug Rabson 
267e97ad33aSDoug Rabson 	/*
268e97ad33aSDoug Rabson 	 * Save the character present at namelen in nameptr string and
269e97ad33aSDoug Rabson 	 * null terminate the character to get the search name for p9_dir_walk
270e97ad33aSDoug Rabson 	 * This is done to handle when lookup is for "a" and component
271e97ad33aSDoug Rabson 	 * name contains a/b/c
272e97ad33aSDoug Rabson 	 */
273e97ad33aSDoug Rabson 	tmpchr = cnp->cn_nameptr[cnp->cn_namelen];
274e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = '\0';
275e97ad33aSDoug Rabson 
276e97ad33aSDoug Rabson 	/*
277e97ad33aSDoug Rabson 	 * If the client_walk fails, it means the file looking for doesnt exist.
278e97ad33aSDoug Rabson 	 * Create the file is the flags are set or just return the error
279e97ad33aSDoug Rabson 	 */
280e97ad33aSDoug Rabson 	newfid = p9_client_walk(dvfid, 1, &cnp->cn_nameptr, 1, &error);
281e97ad33aSDoug Rabson 
282e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = tmpchr;
283e97ad33aSDoug Rabson 
284e97ad33aSDoug Rabson 	if (error != 0 || newfid == NULL) {
285e97ad33aSDoug Rabson 		/* Clunk the newfid if it is not NULL */
286e97ad33aSDoug Rabson 		if (newfid != NULL)
287e97ad33aSDoug Rabson 			p9_client_clunk(newfid);
288e97ad33aSDoug Rabson 
289e97ad33aSDoug Rabson 		if (error != ENOENT)
290e97ad33aSDoug Rabson 			return (error);
291e97ad33aSDoug Rabson 
292e97ad33aSDoug Rabson 		/* The requested file was not found. */
293e97ad33aSDoug Rabson 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
294e97ad33aSDoug Rabson 		    (flags & ISLASTCN)) {
295e97ad33aSDoug Rabson 
296e97ad33aSDoug Rabson 			if (mp->mnt_flag & MNT_RDONLY)
297e97ad33aSDoug Rabson 				return (EROFS);
298e97ad33aSDoug Rabson 
299e97ad33aSDoug Rabson 			error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
300e97ad33aSDoug Rabson 			    curthread);
301e97ad33aSDoug Rabson 			if (!error) {
302e97ad33aSDoug Rabson 				return (EJUSTRETURN);
303e97ad33aSDoug Rabson 			}
304e97ad33aSDoug Rabson 		}
305e97ad33aSDoug Rabson 		return (error);
306e97ad33aSDoug Rabson 	}
307e97ad33aSDoug Rabson 
308e97ad33aSDoug Rabson 	/* Look for the entry in the component cache*/
309e97ad33aSDoug Rabson 	error = cache_lookup(dvp, vpp, cnp, NULL, NULL);
310e97ad33aSDoug Rabson 	if (error > 0 && error != ENOENT) {
311e97ad33aSDoug Rabson 		P9_DEBUG(VOPS, "%s: Cache lookup error %d \n", __func__, error);
312e97ad33aSDoug Rabson 		goto out;
313e97ad33aSDoug Rabson 	}
314e97ad33aSDoug Rabson 
315e97ad33aSDoug Rabson 	if (error == -1) {
316e97ad33aSDoug Rabson 		vp = *vpp;
317e97ad33aSDoug Rabson 		/* Check if the entry in cache is stale or not */
318e97ad33aSDoug Rabson 		if ((p9fs_node_cmp(vp, &newfid->qid) == 0) &&
319e97ad33aSDoug Rabson 		    ((error = VOP_GETATTR(vp, &vattr, cnp->cn_cred)) == 0)) {
320e97ad33aSDoug Rabson 			goto out;
321e97ad33aSDoug Rabson 		}
322e97ad33aSDoug Rabson 		/*
323e97ad33aSDoug Rabson 		 * This case, we have an error coming from getattr,
324e97ad33aSDoug Rabson 		 * act accordingly.
325e97ad33aSDoug Rabson 		 */
326e97ad33aSDoug Rabson 		cache_purge(vp);
327e97ad33aSDoug Rabson 		if (dvp != vp)
328e97ad33aSDoug Rabson 			vput(vp);
329e97ad33aSDoug Rabson 		else
330e97ad33aSDoug Rabson 			vrele(vp);
331e97ad33aSDoug Rabson 
332e97ad33aSDoug Rabson 		*vpp = NULLVP;
333e97ad33aSDoug Rabson 	} else if (error == ENOENT) {
334e97ad33aSDoug Rabson 		if (VN_IS_DOOMED(dvp))
335e97ad33aSDoug Rabson 			goto out;
336e97ad33aSDoug Rabson 		if (VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0) {
337e97ad33aSDoug Rabson 			error = ENOENT;
338e97ad33aSDoug Rabson 			goto out;
339e97ad33aSDoug Rabson 		}
340e97ad33aSDoug Rabson 		cache_purge_negative(dvp);
341e97ad33aSDoug Rabson 	}
342e97ad33aSDoug Rabson 	/* Reset values */
343e97ad33aSDoug Rabson 	error = 0;
344e97ad33aSDoug Rabson 	vp = NULLVP;
345e97ad33aSDoug Rabson 
346e97ad33aSDoug Rabson 	tmpchr = cnp->cn_nameptr[cnp->cn_namelen];
347e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = '\0';
348e97ad33aSDoug Rabson 
349e97ad33aSDoug Rabson 	/*
350e97ad33aSDoug Rabson 	 * Looks like we have found an entry. Now take care of all other cases.
351e97ad33aSDoug Rabson 	 */
352e97ad33aSDoug Rabson 	if (flags & ISDOTDOT) {
353e97ad33aSDoug Rabson 		struct p9fs_lookup_alloc_arg p9aa;
354e97ad33aSDoug Rabson 		p9aa.cnp = cnp;
355e97ad33aSDoug Rabson 		p9aa.dnp = dnp;
356e97ad33aSDoug Rabson 		p9aa.newfid = newfid;
357e97ad33aSDoug Rabson 		error = vn_vget_ino_gen(dvp, p9fs_lookup_alloc, &p9aa, 0, &vp);
358e97ad33aSDoug Rabson 		if (error)
359e97ad33aSDoug Rabson 			goto out;
360e97ad33aSDoug Rabson 		*vpp = vp;
361e97ad33aSDoug Rabson 	} else {
362e97ad33aSDoug Rabson 		/*
363e97ad33aSDoug Rabson 		 * client_walk is equivalent to searching a component name in a
364e97ad33aSDoug Rabson 		 * directory(fid) here. If new fid is returned, we have found an
365e97ad33aSDoug Rabson 		 * entry for this component name so, go and create the rest of
366e97ad33aSDoug Rabson 		 * the vnode infra(vget_common) for the returned newfid.
367e97ad33aSDoug Rabson 		 */
368e97ad33aSDoug Rabson 		if ((cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
369e97ad33aSDoug Rabson 		    && (flags & ISLASTCN)) {
370e97ad33aSDoug Rabson 			error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
371e97ad33aSDoug Rabson 			    curthread);
372e97ad33aSDoug Rabson 			if (error)
373e97ad33aSDoug Rabson 				goto out;
374e97ad33aSDoug Rabson 
375e97ad33aSDoug Rabson 			error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags,
376e97ad33aSDoug Rabson 			    dnp, newfid, &vp, cnp->cn_nameptr);
377e97ad33aSDoug Rabson 			if (error)
378e97ad33aSDoug Rabson 				goto out;
379e97ad33aSDoug Rabson 
380e97ad33aSDoug Rabson 			*vpp = vp;
381e97ad33aSDoug Rabson 			np = P9FS_VTON(vp);
382e97ad33aSDoug Rabson 			if ((dnp->inode.i_mode & ISVTX) &&
383e97ad33aSDoug Rabson 			    cnp->cn_cred->cr_uid != 0 &&
384e97ad33aSDoug Rabson 			    cnp->cn_cred->cr_uid != dnp->inode.n_uid &&
385e97ad33aSDoug Rabson 			    cnp->cn_cred->cr_uid != np->inode.n_uid) {
386e97ad33aSDoug Rabson 				vput(*vpp);
387e97ad33aSDoug Rabson 				*vpp = NULL;
388e97ad33aSDoug Rabson 				cnp->cn_nameptr[cnp->cn_namelen] = tmpchr;
389e97ad33aSDoug Rabson 				return (EPERM);
390e97ad33aSDoug Rabson 			}
391e97ad33aSDoug Rabson 		} else {
392e97ad33aSDoug Rabson 			error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags,
393e97ad33aSDoug Rabson 			    dnp, newfid, &vp, cnp->cn_nameptr);
394e97ad33aSDoug Rabson 			if (error)
395e97ad33aSDoug Rabson 				goto out;
396e97ad33aSDoug Rabson 			*vpp = vp;
397e97ad33aSDoug Rabson 		}
398e97ad33aSDoug Rabson 	}
399e97ad33aSDoug Rabson 
400e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = tmpchr;
401e97ad33aSDoug Rabson 
402e97ad33aSDoug Rabson 	/* Store the result the cache if MAKEENTRY is specified in flags */
403e97ad33aSDoug Rabson 	if ((cnp->cn_flags & MAKEENTRY) != 0)
404e97ad33aSDoug Rabson 		cache_enter(dvp, *vpp, cnp);
405e97ad33aSDoug Rabson 	return (error);
406e97ad33aSDoug Rabson out:
407e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = tmpchr;
408e97ad33aSDoug Rabson 	p9_client_clunk(newfid);
409e97ad33aSDoug Rabson 	return (error);
410e97ad33aSDoug Rabson }
411e97ad33aSDoug Rabson 
412e97ad33aSDoug Rabson /*
413e97ad33aSDoug Rabson  * Common creation function for file/directory with respective flags. We first
414e97ad33aSDoug Rabson  * open the parent directory in order to create the file under it. For this,
415e97ad33aSDoug Rabson  * as 9P protocol suggests, we need to call client_walk to create the open fid.
416e97ad33aSDoug Rabson  * Once we have the open fid, the file_create function creates the direntry with
417e97ad33aSDoug Rabson  * the name and perm specified under the parent dir. If this succeeds (an entry
418e97ad33aSDoug Rabson  * is created for the new file on the server), we create our metadata for this
419e97ad33aSDoug Rabson  * file (vnode, p9fs node calling vget). Once we are done, we clunk the open
420e97ad33aSDoug Rabson  * fid of the parent directory.
421e97ad33aSDoug Rabson  */
422e97ad33aSDoug Rabson static int
423e97ad33aSDoug Rabson create_common(struct p9fs_node *dnp, struct componentname *cnp,
424e97ad33aSDoug Rabson     char *extension, uint32_t perm, uint8_t mode, struct vnode **vpp)
425e97ad33aSDoug Rabson {
426e97ad33aSDoug Rabson 	char tmpchr;
427e97ad33aSDoug Rabson 	struct p9_fid *dvfid, *ofid, *newfid;
428e97ad33aSDoug Rabson 	struct p9fs_session *vses;
429e97ad33aSDoug Rabson 	struct mount *mp;
430e97ad33aSDoug Rabson 	int error;
431e97ad33aSDoug Rabson 
432e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: name %s\n", __func__, cnp->cn_nameptr);
433e97ad33aSDoug Rabson 
434e97ad33aSDoug Rabson 	vses = dnp->p9fs_ses;
435e97ad33aSDoug Rabson 	mp = vses->p9fs_mount;
436e97ad33aSDoug Rabson 	newfid = NULL;
437e97ad33aSDoug Rabson 	error = 0;
438e97ad33aSDoug Rabson 
439e97ad33aSDoug Rabson 	dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error);
440e97ad33aSDoug Rabson 	if (error != 0)
441e97ad33aSDoug Rabson 		return (error);
442e97ad33aSDoug Rabson 
443e97ad33aSDoug Rabson 	/* Clone the directory fid to create the new file */
444e97ad33aSDoug Rabson 	ofid = p9_client_walk(dvfid, 0, NULL, 1, &error);
445e97ad33aSDoug Rabson 	if (error != 0)
446e97ad33aSDoug Rabson 		return (error);
447e97ad33aSDoug Rabson 
448e97ad33aSDoug Rabson 	/*
449e97ad33aSDoug Rabson 	 * Save the character present at namelen in nameptr string and
450e97ad33aSDoug Rabson 	 * null terminate the character to get the search name for p9_dir_walk
451e97ad33aSDoug Rabson 	 */
452e97ad33aSDoug Rabson 	tmpchr = cnp->cn_nameptr[cnp->cn_namelen];
453e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = '\0';
454e97ad33aSDoug Rabson 
455e97ad33aSDoug Rabson 	error = p9_client_file_create(ofid, cnp->cn_nameptr, perm, mode,
456e97ad33aSDoug Rabson 		    extension);
457e97ad33aSDoug Rabson 	if (error != 0) {
458e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p9_client_fcreate failed %d\n", __func__, error);
459e97ad33aSDoug Rabson 		goto out;
460e97ad33aSDoug Rabson 	}
461e97ad33aSDoug Rabson 
462e97ad33aSDoug Rabson 	/* If its not hardlink only then do the walk, else we are done. */
463e97ad33aSDoug Rabson 	if (!(perm & P9PROTO_DMLINK)) {
464e97ad33aSDoug Rabson 		/*
465e97ad33aSDoug Rabson 		 * Do the lookup part and add the vnode, p9fs node. Note that vpp
466e97ad33aSDoug Rabson 		 * is filled in here.
467e97ad33aSDoug Rabson 		 */
468e97ad33aSDoug Rabson 		newfid = p9_client_walk(dvfid, 1, &cnp->cn_nameptr, 1, &error);
469e97ad33aSDoug Rabson 		if (newfid != NULL) {
470e97ad33aSDoug Rabson 			error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags,
471e97ad33aSDoug Rabson 			    dnp, newfid, vpp, cnp->cn_nameptr);
472e97ad33aSDoug Rabson 			if (error != 0)
473e97ad33aSDoug Rabson 				goto out;
474e97ad33aSDoug Rabson 		} else {
475e97ad33aSDoug Rabson 			/* Not found return NOENTRY.*/
476e97ad33aSDoug Rabson 			goto out;
477e97ad33aSDoug Rabson 		}
478e97ad33aSDoug Rabson 
479e97ad33aSDoug Rabson 		if ((cnp->cn_flags & MAKEENTRY) != 0)
480e97ad33aSDoug Rabson 			cache_enter(P9FS_NTOV(dnp), *vpp, cnp);
481e97ad33aSDoug Rabson 	}
482e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: created file under vp %p node %p fid %ju\n",
483e97ad33aSDoug Rabson 	    __func__, *vpp, dnp, (uintmax_t)dvfid->fid);
484e97ad33aSDoug Rabson 	/* Clunk the open ofid. */
485e97ad33aSDoug Rabson 	if (ofid != NULL)
486e97ad33aSDoug Rabson 		(void)p9_client_clunk(ofid);
487e97ad33aSDoug Rabson 
488e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = tmpchr;
489e97ad33aSDoug Rabson 	return (0);
490e97ad33aSDoug Rabson out:
491e97ad33aSDoug Rabson 	if (ofid != NULL)
492e97ad33aSDoug Rabson 		(void)p9_client_clunk(ofid);
493e97ad33aSDoug Rabson 
494e97ad33aSDoug Rabson 	if (newfid != NULL)
495e97ad33aSDoug Rabson 		(void)p9_client_clunk(newfid);
496e97ad33aSDoug Rabson 
497e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = tmpchr;
498e97ad33aSDoug Rabson 	return (error);
499e97ad33aSDoug Rabson }
500e97ad33aSDoug Rabson 
501e97ad33aSDoug Rabson /*
502e97ad33aSDoug Rabson  * This is the main file creation VOP. Make the permissions of the new
503e97ad33aSDoug Rabson  * file and call the create_common common code to complete the create.
504e97ad33aSDoug Rabson  */
505e97ad33aSDoug Rabson static int
506e97ad33aSDoug Rabson p9fs_create(struct vop_create_args *ap)
507e97ad33aSDoug Rabson {
508e97ad33aSDoug Rabson 	struct vnode *dvp;
509e97ad33aSDoug Rabson 	struct vnode **vpp;
510e97ad33aSDoug Rabson 	struct componentname *cnp;
511e97ad33aSDoug Rabson 	uint32_t mode;
512e97ad33aSDoug Rabson 	struct p9fs_node *dnp;
513e97ad33aSDoug Rabson 	struct p9fs_inode *dinode;
514e97ad33aSDoug Rabson 	uint32_t perm;
515e97ad33aSDoug Rabson 	int ret;
516e97ad33aSDoug Rabson 
517e97ad33aSDoug Rabson 	dvp = ap->a_dvp;
518e97ad33aSDoug Rabson 	vpp = ap->a_vpp;
519e97ad33aSDoug Rabson 	cnp = ap->a_cnp;
520e97ad33aSDoug Rabson 	dnp = P9FS_VTON(dvp);
521e97ad33aSDoug Rabson 	dinode = &dnp->inode;
522e97ad33aSDoug Rabson 	mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
523e97ad33aSDoug Rabson 	perm = p9fs_unix2p9_mode(mode);
524e97ad33aSDoug Rabson 
525e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp);
526e97ad33aSDoug Rabson 
527e97ad33aSDoug Rabson 	ret = create_common(dnp, cnp, NULL, perm, P9PROTO_ORDWR, vpp);
528e97ad33aSDoug Rabson 	if (ret == 0) {
529e97ad33aSDoug Rabson 		P9FS_INCR_LINKS(dinode);
530e97ad33aSDoug Rabson 	}
531e97ad33aSDoug Rabson 
532e97ad33aSDoug Rabson 	return (ret);
533e97ad33aSDoug Rabson }
534e97ad33aSDoug Rabson 
535e97ad33aSDoug Rabson /*
536e97ad33aSDoug Rabson  * p9fs_mkdir is the main directory creation vop. Make the permissions of the new dir
537e97ad33aSDoug Rabson  * and call the create_common common code to complete the create.
538e97ad33aSDoug Rabson  */
539e97ad33aSDoug Rabson static int
540e97ad33aSDoug Rabson p9fs_mkdir(struct vop_mkdir_args *ap)
541e97ad33aSDoug Rabson {
542e97ad33aSDoug Rabson 	struct vnode *dvp;
543e97ad33aSDoug Rabson 	struct vnode **vpp;
544e97ad33aSDoug Rabson 	struct componentname *cnp;
545e97ad33aSDoug Rabson 	uint32_t mode;
546e97ad33aSDoug Rabson 	struct p9fs_node *dnp;
547e97ad33aSDoug Rabson 	struct p9fs_inode *dinode;
548e97ad33aSDoug Rabson 	uint32_t perm;
549e97ad33aSDoug Rabson 	int ret;
550e97ad33aSDoug Rabson 
551e97ad33aSDoug Rabson 	dvp = ap->a_dvp;
552e97ad33aSDoug Rabson 	vpp = ap->a_vpp;
553e97ad33aSDoug Rabson 	cnp = ap->a_cnp;
554e97ad33aSDoug Rabson 	dnp = P9FS_VTON(dvp);
555e97ad33aSDoug Rabson 	dinode = &dnp->inode;
556e97ad33aSDoug Rabson 	mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
557e97ad33aSDoug Rabson 	perm = p9fs_unix2p9_mode(mode | S_IFDIR);
558e97ad33aSDoug Rabson 
559e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp);
560e97ad33aSDoug Rabson 
561e97ad33aSDoug Rabson 	ret = create_common(dnp, cnp, NULL, perm, P9PROTO_ORDWR, vpp);
562e97ad33aSDoug Rabson 	if (ret == 0)
563e97ad33aSDoug Rabson 		P9FS_INCR_LINKS(dinode);
564e97ad33aSDoug Rabson 
565e97ad33aSDoug Rabson 	return (ret);
566e97ad33aSDoug Rabson }
567e97ad33aSDoug Rabson 
568e97ad33aSDoug Rabson /*
569e97ad33aSDoug Rabson  * p9fs_mknod is the main node creation vop. Make the permissions of the new node
570e97ad33aSDoug Rabson  * and call the create_common common code to complete the create.
571e97ad33aSDoug Rabson  */
572e97ad33aSDoug Rabson static int
573e97ad33aSDoug Rabson p9fs_mknod(struct vop_mknod_args *ap)
574e97ad33aSDoug Rabson {
575e97ad33aSDoug Rabson 	struct vnode *dvp;
576e97ad33aSDoug Rabson 	struct vnode **vpp;
577e97ad33aSDoug Rabson 	struct componentname *cnp;
578e97ad33aSDoug Rabson 	uint32_t mode;
579e97ad33aSDoug Rabson 	struct p9fs_node *dnp;
580e97ad33aSDoug Rabson 	struct p9fs_inode *dinode;
581e97ad33aSDoug Rabson 	uint32_t perm;
582e97ad33aSDoug Rabson 	int ret;
583e97ad33aSDoug Rabson 
584e97ad33aSDoug Rabson 	dvp = ap->a_dvp;
585e97ad33aSDoug Rabson 	vpp = ap->a_vpp;
586e97ad33aSDoug Rabson 	cnp = ap->a_cnp;
587e97ad33aSDoug Rabson 	dnp = P9FS_VTON(dvp);
588e97ad33aSDoug Rabson 	dinode = &dnp->inode;
589e97ad33aSDoug Rabson 	mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
590e97ad33aSDoug Rabson 	perm = p9fs_unix2p9_mode(mode);
591e97ad33aSDoug Rabson 
592e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp);
593e97ad33aSDoug Rabson 
594e97ad33aSDoug Rabson 	ret = create_common(dnp, cnp, NULL, perm, P9PROTO_OREAD, vpp);
595e97ad33aSDoug Rabson 	if (ret == 0) {
596e97ad33aSDoug Rabson 		P9FS_INCR_LINKS(dinode);
597e97ad33aSDoug Rabson 	}
598e97ad33aSDoug Rabson 
599e97ad33aSDoug Rabson 	return (ret);
600e97ad33aSDoug Rabson }
601e97ad33aSDoug Rabson 
602e97ad33aSDoug Rabson /* Convert open mode permissions to P9 */
603e97ad33aSDoug Rabson static int
604e97ad33aSDoug Rabson p9fs_uflags_mode(int uflags, int extended)
605e97ad33aSDoug Rabson {
606e97ad33aSDoug Rabson 	uint32_t ret;
607e97ad33aSDoug Rabson 
608e97ad33aSDoug Rabson 	/* Convert first to O flags.*/
609e97ad33aSDoug Rabson 	uflags = OFLAGS(uflags);
610e97ad33aSDoug Rabson 
611e97ad33aSDoug Rabson 	switch (uflags & 3) {
612e97ad33aSDoug Rabson 
613e97ad33aSDoug Rabson 	case O_RDONLY:
614e97ad33aSDoug Rabson 	    ret = P9PROTO_OREAD;
615e97ad33aSDoug Rabson 	    break;
616e97ad33aSDoug Rabson 
617e97ad33aSDoug Rabson 	case O_WRONLY:
618e97ad33aSDoug Rabson 	    ret = P9PROTO_OWRITE;
619e97ad33aSDoug Rabson 	    break;
620e97ad33aSDoug Rabson 
621e97ad33aSDoug Rabson 	case O_RDWR:
622e97ad33aSDoug Rabson 	    ret = P9PROTO_ORDWR;
623e97ad33aSDoug Rabson 	    break;
624e97ad33aSDoug Rabson 	}
625e97ad33aSDoug Rabson 
626e97ad33aSDoug Rabson 	if (extended) {
627e97ad33aSDoug Rabson 		if (uflags & O_EXCL)
628e97ad33aSDoug Rabson 			ret |= P9PROTO_OEXCL;
629e97ad33aSDoug Rabson 
630e97ad33aSDoug Rabson 		if (uflags & O_APPEND)
631e97ad33aSDoug Rabson 			ret |= P9PROTO_OAPPEND;
632e97ad33aSDoug Rabson 	}
633e97ad33aSDoug Rabson 
634e97ad33aSDoug Rabson 	return (ret);
635e97ad33aSDoug Rabson }
636e97ad33aSDoug Rabson 
637e97ad33aSDoug Rabson /*
638e97ad33aSDoug Rabson  * This is the main open VOP for every file open. If the file is already
639e97ad33aSDoug Rabson  * open, then increment and return. If there is no open fid for this file,
640e97ad33aSDoug Rabson  * there needs to be a client_walk which creates a new open fid for this file.
641e97ad33aSDoug Rabson  * Once we have a open fid, call the open on this file with the mode creating
642e97ad33aSDoug Rabson  * the vobject.
643e97ad33aSDoug Rabson  */
644e97ad33aSDoug Rabson static int
645e97ad33aSDoug Rabson p9fs_open(struct vop_open_args *ap)
646e97ad33aSDoug Rabson {
647e97ad33aSDoug Rabson 	int error;
648e97ad33aSDoug Rabson 	struct vnode *vp;
649e97ad33aSDoug Rabson 	struct p9fs_node *np;
650e97ad33aSDoug Rabson 	struct p9fs_session *vses;
651e97ad33aSDoug Rabson 	struct p9_fid *vofid, *vfid;
652e97ad33aSDoug Rabson 	size_t filesize;
653e97ad33aSDoug Rabson 	uint32_t mode;
654e97ad33aSDoug Rabson 
655e97ad33aSDoug Rabson 	error = 0;
656e97ad33aSDoug Rabson 	vp = ap->a_vp;
657e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
658e97ad33aSDoug Rabson 	vses = np->p9fs_ses;
659e97ad33aSDoug Rabson 
660e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp %p\n", __func__, vp);
661e97ad33aSDoug Rabson 
662e97ad33aSDoug Rabson 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
663e97ad33aSDoug Rabson 		return (EOPNOTSUPP);
664e97ad33aSDoug Rabson 
665e97ad33aSDoug Rabson 	error = p9fs_reload_stats_dotl(vp, ap->a_cred);
666e97ad33aSDoug Rabson 	if (error != 0)
667e97ad33aSDoug Rabson 		return (error);
668e97ad33aSDoug Rabson 
669e97ad33aSDoug Rabson 	ASSERT_VOP_LOCKED(vp, __func__);
670e97ad33aSDoug Rabson 	/*
671e97ad33aSDoug Rabson 	 * Invalidate the pages of the vm_object cache if the file is modified
672e97ad33aSDoug Rabson 	 * based on the flag set in reload stats
673e97ad33aSDoug Rabson 	 */
674e97ad33aSDoug Rabson 	if (vp->v_type == VREG && (np->flags & P9FS_NODE_MODIFIED) != 0) {
675e97ad33aSDoug Rabson 		error = vinvalbuf(vp, 0, 0, 0);
676e97ad33aSDoug Rabson 		if (error != 0)
677e97ad33aSDoug Rabson 			return (error);
678e97ad33aSDoug Rabson 		np->flags &= ~P9FS_NODE_MODIFIED;
679e97ad33aSDoug Rabson 	}
680e97ad33aSDoug Rabson 
681e97ad33aSDoug Rabson 	vfid = p9fs_get_fid(vses->clnt, np, ap->a_cred, VFID, -1, &error);
682e97ad33aSDoug Rabson 	if (error != 0)
683e97ad33aSDoug Rabson 		return (error);
684e97ad33aSDoug Rabson 
685e97ad33aSDoug Rabson 	/*
686e97ad33aSDoug Rabson 	 * Translate kernel fflags to 9p mode
687e97ad33aSDoug Rabson 	 */
688e97ad33aSDoug Rabson 	mode = p9fs_uflags_mode(ap->a_mode, 1);
689e97ad33aSDoug Rabson 
690e97ad33aSDoug Rabson 	/*
691e97ad33aSDoug Rabson 	 * Search the fid in vofid_list for current user. If found increase the open
692e97ad33aSDoug Rabson 	 * count and return. If not found clone a new fid and open the file using
693e97ad33aSDoug Rabson 	 * that cloned fid.
694e97ad33aSDoug Rabson 	 */
695e97ad33aSDoug Rabson 	vofid = p9fs_get_fid(vses->clnt, np, ap->a_cred, VOFID, mode, &error);
696e97ad33aSDoug Rabson 	if (vofid != NULL) {
697e97ad33aSDoug Rabson 		vofid->v_opens++;
698e97ad33aSDoug Rabson 		return (0);
699e97ad33aSDoug Rabson 	} else {
700e97ad33aSDoug Rabson 		/*vofid is the open fid for this file.*/
701e97ad33aSDoug Rabson 		vofid = p9_client_walk(vfid, 0, NULL, 1, &error);
702e97ad33aSDoug Rabson 		if (error != 0)
703e97ad33aSDoug Rabson 			return (error);
704e97ad33aSDoug Rabson 	}
705e97ad33aSDoug Rabson 
706e97ad33aSDoug Rabson 	error = p9_client_open(vofid, mode);
707e97ad33aSDoug Rabson 	if (error != 0)
708e97ad33aSDoug Rabson 		p9_client_clunk(vofid);
709e97ad33aSDoug Rabson 	else {
710e97ad33aSDoug Rabson 		vofid->v_opens = 1;
711e97ad33aSDoug Rabson 		filesize = np->inode.i_size;
712e97ad33aSDoug Rabson 		vnode_create_vobject(vp, filesize, ap->a_td);
713e97ad33aSDoug Rabson 		p9fs_fid_add(np, vofid, VOFID);
714e97ad33aSDoug Rabson 	}
715e97ad33aSDoug Rabson 
716e97ad33aSDoug Rabson 	return (error);
717e97ad33aSDoug Rabson }
718e97ad33aSDoug Rabson 
719e97ad33aSDoug Rabson /*
720e97ad33aSDoug Rabson  * Close the open references. Just reduce the open count on vofid and return.
721e97ad33aSDoug Rabson  * Let clunking of VOFID happen in p9fs_reclaim.
722e97ad33aSDoug Rabson  */
723e97ad33aSDoug Rabson static int
724e97ad33aSDoug Rabson p9fs_close(struct vop_close_args *ap)
725e97ad33aSDoug Rabson {
726e97ad33aSDoug Rabson 	struct vnode *vp;
727e97ad33aSDoug Rabson 	struct p9fs_node *np;
728e97ad33aSDoug Rabson 	struct p9fs_session *vses;
729e97ad33aSDoug Rabson 	struct p9_fid *vofid;
730e97ad33aSDoug Rabson 	int error;
731e97ad33aSDoug Rabson 
732e97ad33aSDoug Rabson 	vp = ap->a_vp;
733e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
734e97ad33aSDoug Rabson 
735e97ad33aSDoug Rabson 	if (np == NULL)
736e97ad33aSDoug Rabson 		return (0);
737e97ad33aSDoug Rabson 
738e97ad33aSDoug Rabson 	vses = np->p9fs_ses;
739e97ad33aSDoug Rabson 	error = 0;
740e97ad33aSDoug Rabson 
741e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: file_name %s\n", __func__, np->inode.i_name);
742e97ad33aSDoug Rabson 
743e97ad33aSDoug Rabson 	/*
744e97ad33aSDoug Rabson 	 * Translate kernel fflags to 9p mode
745e97ad33aSDoug Rabson 	 */
746e97ad33aSDoug Rabson 	vofid = p9fs_get_fid(vses->clnt, np, ap->a_cred, VOFID,
747e97ad33aSDoug Rabson 	    p9fs_uflags_mode(ap->a_fflag, 1), &error);
748e97ad33aSDoug Rabson 	if (vofid == NULL)
749e97ad33aSDoug Rabson 		return (0);
750e97ad33aSDoug Rabson 
751e97ad33aSDoug Rabson 	vofid->v_opens--;
752e97ad33aSDoug Rabson 
753e97ad33aSDoug Rabson 	return (0);
754e97ad33aSDoug Rabson }
755e97ad33aSDoug Rabson 
756e97ad33aSDoug Rabson /* Helper routine for checking if fileops are possible on this file */
757e97ad33aSDoug Rabson static int
758e97ad33aSDoug Rabson p9fs_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode)
759e97ad33aSDoug Rabson {
760e97ad33aSDoug Rabson 
761e97ad33aSDoug Rabson 	/* Check if we are allowed to write */
762e97ad33aSDoug Rabson 	switch (vap->va_type) {
763e97ad33aSDoug Rabson 	case VDIR:
764e97ad33aSDoug Rabson 	case VLNK:
765e97ad33aSDoug Rabson 	case VREG:
766e97ad33aSDoug Rabson 		/*
767e97ad33aSDoug Rabson 		 * Normal nodes: check if we're on a read-only mounted
768e97ad33aSDoug Rabson 		 * file system and bail out if we're trying to write.
769e97ad33aSDoug Rabson 		 */
770e97ad33aSDoug Rabson 		if ((mode & VMODIFY_PERMS) && (vp->v_mount->mnt_flag & MNT_RDONLY))
771e97ad33aSDoug Rabson 			return (EROFS);
772e97ad33aSDoug Rabson 		break;
773e97ad33aSDoug Rabson 	case VBLK:
774e97ad33aSDoug Rabson 	case VCHR:
775e97ad33aSDoug Rabson 	case VSOCK:
776e97ad33aSDoug Rabson 	case VFIFO:
777e97ad33aSDoug Rabson 		/*
778e97ad33aSDoug Rabson 		 * Special nodes: even on read-only mounted file systems
779e97ad33aSDoug Rabson 		 * these are allowed to be written to if permissions allow.
780e97ad33aSDoug Rabson 		 */
781e97ad33aSDoug Rabson 		break;
782e97ad33aSDoug Rabson 	default:
783e97ad33aSDoug Rabson 		/* No idea what this is */
784e97ad33aSDoug Rabson 		return (EINVAL);
785e97ad33aSDoug Rabson 	}
786e97ad33aSDoug Rabson 
787e97ad33aSDoug Rabson 	return (0);
788e97ad33aSDoug Rabson }
789e97ad33aSDoug Rabson 
790e97ad33aSDoug Rabson /* Check the access permissions of the file. */
791e97ad33aSDoug Rabson static int
792e97ad33aSDoug Rabson p9fs_access(struct vop_access_args *ap)
793e97ad33aSDoug Rabson {
794e97ad33aSDoug Rabson 	struct vnode *vp;
795e97ad33aSDoug Rabson 	accmode_t accmode;
796e97ad33aSDoug Rabson 	struct ucred *cred;
797e97ad33aSDoug Rabson 	struct vattr vap;
798e97ad33aSDoug Rabson 	int error;
799e97ad33aSDoug Rabson 
800e97ad33aSDoug Rabson 	vp = ap->a_vp;
801e97ad33aSDoug Rabson 	accmode = ap->a_accmode;
802e97ad33aSDoug Rabson 	cred = ap->a_cred;
803e97ad33aSDoug Rabson 
804e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp %p\n", __func__, vp);
805e97ad33aSDoug Rabson 
806e97ad33aSDoug Rabson 	/* make sure getattr is working correctly and is defined.*/
807e97ad33aSDoug Rabson 	error = VOP_GETATTR(vp, &vap, cred);
808e97ad33aSDoug Rabson 	if (error != 0)
809e97ad33aSDoug Rabson 		return (error);
810e97ad33aSDoug Rabson 
811e97ad33aSDoug Rabson 	error = p9fs_check_possible(vp, &vap, accmode);
812e97ad33aSDoug Rabson 	if (error != 0)
813e97ad33aSDoug Rabson 		return (error);
814e97ad33aSDoug Rabson 
815e97ad33aSDoug Rabson 	/* Call the Generic Access check in VOPS*/
816e97ad33aSDoug Rabson 	error = vaccess(vp->v_type, vap.va_mode, vap.va_uid, vap.va_gid, accmode,
817e97ad33aSDoug Rabson 	    cred);
818e97ad33aSDoug Rabson 
819e97ad33aSDoug Rabson 
820e97ad33aSDoug Rabson 	return (error);
821e97ad33aSDoug Rabson }
822e97ad33aSDoug Rabson 
823e97ad33aSDoug Rabson /*
824e97ad33aSDoug Rabson  * Reload the file stats from the server and update the inode structure present
825e97ad33aSDoug Rabson  * in p9fs node.
826e97ad33aSDoug Rabson  */
827e97ad33aSDoug Rabson int
828e97ad33aSDoug Rabson p9fs_reload_stats_dotl(struct vnode *vp, struct ucred *cred)
829e97ad33aSDoug Rabson {
830e97ad33aSDoug Rabson 	struct p9_stat_dotl *stat;
831e97ad33aSDoug Rabson 	int error;
832e97ad33aSDoug Rabson 	struct p9fs_node *node;
833e97ad33aSDoug Rabson 	struct p9fs_session *vses;
834e97ad33aSDoug Rabson 	struct p9_fid *vfid;
835e97ad33aSDoug Rabson 
836e97ad33aSDoug Rabson 	error = 0;
837e97ad33aSDoug Rabson 	node = P9FS_VTON(vp);
838e97ad33aSDoug Rabson 	vses = node->p9fs_ses;
839e97ad33aSDoug Rabson 
840e97ad33aSDoug Rabson 	vfid = p9fs_get_fid(vses->clnt, node, cred, VOFID, P9PROTO_OREAD, &error);
841e97ad33aSDoug Rabson 	if (vfid == NULL) {
842e97ad33aSDoug Rabson 		vfid = p9fs_get_fid(vses->clnt, node, cred, VFID, -1, &error);
843e97ad33aSDoug Rabson 		if (error)
844e97ad33aSDoug Rabson 			return (error);
845e97ad33aSDoug Rabson 	}
846e97ad33aSDoug Rabson 
847e97ad33aSDoug Rabson 	stat = uma_zalloc(p9fs_getattr_zone, M_WAITOK | M_ZERO);
848e97ad33aSDoug Rabson 
849e97ad33aSDoug Rabson 	error = p9_client_getattr(vfid, stat, P9PROTO_STATS_ALL);
850e97ad33aSDoug Rabson 	if (error != 0) {
851e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p9_client_getattr failed: %d\n", __func__, error);
852e97ad33aSDoug Rabson 		goto out;
853e97ad33aSDoug Rabson 	}
854e97ad33aSDoug Rabson 
855e97ad33aSDoug Rabson 	/* Init the vnode with the disk info */
856e97ad33aSDoug Rabson 	p9fs_stat_vnode_dotl(stat, vp);
857e97ad33aSDoug Rabson out:
858e97ad33aSDoug Rabson 	if (stat != NULL) {
859e97ad33aSDoug Rabson 		uma_zfree(p9fs_getattr_zone, stat);
860e97ad33aSDoug Rabson 	}
861e97ad33aSDoug Rabson 
862e97ad33aSDoug Rabson 	return (error);
863e97ad33aSDoug Rabson }
864e97ad33aSDoug Rabson 
865e97ad33aSDoug Rabson /*
866e97ad33aSDoug Rabson  * Read the current inode values into the vap attr. We reload the stats from
867e97ad33aSDoug Rabson  * the server.
868e97ad33aSDoug Rabson  */
869e97ad33aSDoug Rabson static int
870e97ad33aSDoug Rabson p9fs_getattr_dotl(struct vop_getattr_args *ap)
871e97ad33aSDoug Rabson {
872e97ad33aSDoug Rabson 	struct vnode *vp;
873e97ad33aSDoug Rabson 	struct vattr *vap;
874e97ad33aSDoug Rabson 	struct p9fs_node *node;
875e97ad33aSDoug Rabson 	struct p9fs_inode *inode;
876e97ad33aSDoug Rabson 	int error;
877e97ad33aSDoug Rabson 
878e97ad33aSDoug Rabson 	vp = ap->a_vp;
879e97ad33aSDoug Rabson 	vap = ap->a_vap;
880e97ad33aSDoug Rabson 	node = P9FS_VTON(vp);
881e97ad33aSDoug Rabson 
882e97ad33aSDoug Rabson 	if (node == NULL)
883e97ad33aSDoug Rabson 		return (ENOENT);
884e97ad33aSDoug Rabson 
885e97ad33aSDoug Rabson 	inode = &node->inode;
886e97ad33aSDoug Rabson 
887e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: %u %u\n", __func__, inode->i_mode, IFTOVT(inode->i_mode));
888e97ad33aSDoug Rabson 
889e97ad33aSDoug Rabson 	/* Reload our stats once to get the right values.*/
890e97ad33aSDoug Rabson 	error = p9fs_reload_stats_dotl(vp, ap->a_cred);
891e97ad33aSDoug Rabson 	if (error != 0) {
892e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: failed: %d\n", __func__, error);
893e97ad33aSDoug Rabson 		return (error);
894e97ad33aSDoug Rabson 	}
895e97ad33aSDoug Rabson 
896e97ad33aSDoug Rabson 	/* Basic info */
897e97ad33aSDoug Rabson 	VATTR_NULL(vap);
898e97ad33aSDoug Rabson 
899e97ad33aSDoug Rabson 	vap->va_atime.tv_sec = inode->i_atime;
900e97ad33aSDoug Rabson 	vap->va_mtime.tv_sec = inode->i_mtime;
901e97ad33aSDoug Rabson 	vap->va_ctime.tv_sec = inode->i_ctime;
902e97ad33aSDoug Rabson 	vap->va_atime.tv_nsec = inode->i_atime_nsec;
903e97ad33aSDoug Rabson 	vap->va_mtime.tv_nsec = inode->i_mtime_nsec;
904e97ad33aSDoug Rabson 	vap->va_ctime.tv_nsec = inode->i_ctime_nsec;
905e97ad33aSDoug Rabson 	vap->va_type = IFTOVT(inode->i_mode);
906e97ad33aSDoug Rabson 	vap->va_mode = inode->i_mode;
907e97ad33aSDoug Rabson 	vap->va_uid = inode->n_uid;
908e97ad33aSDoug Rabson 	vap->va_gid = inode->n_gid;
909e97ad33aSDoug Rabson 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
910e97ad33aSDoug Rabson 	vap->va_size = inode->i_size;
911e97ad33aSDoug Rabson 	vap->va_nlink = inode->i_links_count;
912e97ad33aSDoug Rabson 	vap->va_blocksize = inode->blksize;
913e97ad33aSDoug Rabson 	vap->va_fileid = inode->i_qid_path;
914e97ad33aSDoug Rabson 	vap->va_flags = inode->i_flags;
915e97ad33aSDoug Rabson 	vap->va_gen = inode->gen;
916e97ad33aSDoug Rabson 	vap->va_filerev = inode->data_version;
917e97ad33aSDoug Rabson 	vap->va_vaflags = 0;
918e97ad33aSDoug Rabson 	vap->va_bytes = inode->blocks * P9PROTO_TGETATTR_BLK;
919e97ad33aSDoug Rabson 
920e97ad33aSDoug Rabson 	return (0);
921e97ad33aSDoug Rabson }
922e97ad33aSDoug Rabson 
923e97ad33aSDoug Rabson /* Convert a standard FreeBSD permission to P9. */
924e97ad33aSDoug Rabson static uint32_t
925e97ad33aSDoug Rabson p9fs_unix2p9_mode(uint32_t mode)
926e97ad33aSDoug Rabson {
927e97ad33aSDoug Rabson 	uint32_t res;
928e97ad33aSDoug Rabson 
929e97ad33aSDoug Rabson 	res = mode & 0777;
930e97ad33aSDoug Rabson 	if (S_ISDIR(mode))
931e97ad33aSDoug Rabson 		res |= P9PROTO_DMDIR;
932e97ad33aSDoug Rabson 	if (S_ISSOCK(mode))
933e97ad33aSDoug Rabson 		res |= P9PROTO_DMSOCKET;
934e97ad33aSDoug Rabson 	if (S_ISLNK(mode))
935e97ad33aSDoug Rabson 		res |= P9PROTO_DMSYMLINK;
936e97ad33aSDoug Rabson 	if (S_ISFIFO(mode))
937e97ad33aSDoug Rabson 		res |= P9PROTO_DMNAMEDPIPE;
938e97ad33aSDoug Rabson 	if ((mode & S_ISUID) == S_ISUID)
939e97ad33aSDoug Rabson 		res |= P9PROTO_DMSETUID;
940e97ad33aSDoug Rabson 	if ((mode & S_ISGID) == S_ISGID)
941e97ad33aSDoug Rabson 		res |= P9PROTO_DMSETGID;
942e97ad33aSDoug Rabson 	if ((mode & S_ISVTX) == S_ISVTX)
943e97ad33aSDoug Rabson 		res |= P9PROTO_DMSETVTX;
944e97ad33aSDoug Rabson 
945e97ad33aSDoug Rabson 	return (res);
946e97ad33aSDoug Rabson }
947e97ad33aSDoug Rabson 
948e97ad33aSDoug Rabson /* Update inode with the stats read from server.(9P2000.L version) */
949e97ad33aSDoug Rabson int
950e97ad33aSDoug Rabson p9fs_stat_vnode_dotl(struct p9_stat_dotl *stat, struct vnode *vp)
951e97ad33aSDoug Rabson {
952e97ad33aSDoug Rabson 	struct p9fs_node *np;
953e97ad33aSDoug Rabson 	struct p9fs_inode *inode;
954e97ad33aSDoug Rabson 
955e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
956e97ad33aSDoug Rabson 	inode = &np->inode;
957e97ad33aSDoug Rabson 
958e97ad33aSDoug Rabson 	ASSERT_VOP_LOCKED(vp, __func__);
959e97ad33aSDoug Rabson 	/* Update the pager size if file size changes on host */
960e97ad33aSDoug Rabson 	if (inode->i_size != stat->st_size) {
961e97ad33aSDoug Rabson 		inode->i_size = stat->st_size;
962e97ad33aSDoug Rabson 		if (vp->v_type == VREG)
963e97ad33aSDoug Rabson 			vnode_pager_setsize(vp, inode->i_size);
964e97ad33aSDoug Rabson 	}
965e97ad33aSDoug Rabson 
966e97ad33aSDoug Rabson 	inode->i_mtime = stat->st_mtime_sec;
967e97ad33aSDoug Rabson 	inode->i_atime = stat->st_atime_sec;
968e97ad33aSDoug Rabson 	inode->i_ctime = stat->st_ctime_sec;
969e97ad33aSDoug Rabson 	inode->i_mtime_nsec = stat->st_mtime_nsec;
970e97ad33aSDoug Rabson 	inode->i_atime_nsec = stat->st_atime_nsec;
971e97ad33aSDoug Rabson 	inode->i_ctime_nsec = stat->st_ctime_nsec;
972e97ad33aSDoug Rabson 	inode->n_uid = stat->st_uid;
973e97ad33aSDoug Rabson 	inode->n_gid = stat->st_gid;
974e97ad33aSDoug Rabson 	inode->i_mode = stat->st_mode;
975e97ad33aSDoug Rabson 	vp->v_type = IFTOVT(inode->i_mode);
976e97ad33aSDoug Rabson 	inode->i_links_count = stat->st_nlink;
977e97ad33aSDoug Rabson 	inode->blksize = stat->st_blksize;
978e97ad33aSDoug Rabson 	inode->blocks = stat->st_blocks;
979e97ad33aSDoug Rabson 	inode->gen = stat->st_gen;
980e97ad33aSDoug Rabson 	inode->data_version = stat->st_data_version;
981e97ad33aSDoug Rabson 
982e97ad33aSDoug Rabson 	ASSERT_VOP_LOCKED(vp, __func__);
983e97ad33aSDoug Rabson 	/* Setting a flag if file changes based on qid version */
984e97ad33aSDoug Rabson 	if (np->vqid.qid_version != stat->qid.version)
985e97ad33aSDoug Rabson 		np->flags |= P9FS_NODE_MODIFIED;
986e97ad33aSDoug Rabson 	memcpy(&np->vqid, &stat->qid, sizeof(stat->qid));
987e97ad33aSDoug Rabson 
988e97ad33aSDoug Rabson 	return (0);
989e97ad33aSDoug Rabson }
990e97ad33aSDoug Rabson 
991e97ad33aSDoug Rabson /*
992e97ad33aSDoug Rabson  * Write the current in memory inode stats into persistent stats structure
993e97ad33aSDoug Rabson  * to write to the server(for linux version).
994e97ad33aSDoug Rabson  */
995e97ad33aSDoug Rabson static int
996e97ad33aSDoug Rabson p9fs_inode_to_iattr(struct p9fs_inode *inode, struct p9_iattr_dotl *p9attr)
997e97ad33aSDoug Rabson {
998e97ad33aSDoug Rabson 	p9attr->size = inode->i_size;
999e97ad33aSDoug Rabson 	p9attr->mode = inode->i_mode;
1000e97ad33aSDoug Rabson 	p9attr->uid = inode->n_uid;
1001e97ad33aSDoug Rabson 	p9attr->gid = inode->n_gid;
1002e97ad33aSDoug Rabson 	p9attr->atime_sec = inode->i_atime;
1003e97ad33aSDoug Rabson 	p9attr->atime_nsec = inode->i_atime_nsec;
1004e97ad33aSDoug Rabson 	p9attr->mtime_sec = inode->i_mtime;
1005e97ad33aSDoug Rabson 	p9attr->mtime_nsec = inode->i_mtime_nsec;
1006e97ad33aSDoug Rabson 
1007e97ad33aSDoug Rabson 	return (0);
1008e97ad33aSDoug Rabson }
1009e97ad33aSDoug Rabson 
1010e97ad33aSDoug Rabson /*
1011e97ad33aSDoug Rabson  * Modify the ownership of a file whenever the chown is called on the
1012e97ad33aSDoug Rabson  * file.
1013e97ad33aSDoug Rabson  */
1014e97ad33aSDoug Rabson static int
1015e97ad33aSDoug Rabson p9fs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred,
1016e97ad33aSDoug Rabson     struct thread *td)
1017e97ad33aSDoug Rabson {
1018e97ad33aSDoug Rabson 	struct p9fs_node *np;
1019e97ad33aSDoug Rabson 	struct p9fs_inode *inode;
1020e97ad33aSDoug Rabson 	uid_t ouid;
1021e97ad33aSDoug Rabson 	gid_t ogid;
1022e97ad33aSDoug Rabson 	int error;
1023e97ad33aSDoug Rabson 
1024e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
1025e97ad33aSDoug Rabson 	inode = &np->inode;
1026e97ad33aSDoug Rabson 
1027e97ad33aSDoug Rabson 	if (uid == (uid_t)VNOVAL)
1028e97ad33aSDoug Rabson 		uid = inode->n_uid;
1029e97ad33aSDoug Rabson 	if (gid == (gid_t)VNOVAL)
1030e97ad33aSDoug Rabson 		gid = inode->n_gid;
1031e97ad33aSDoug Rabson 	/*
1032e97ad33aSDoug Rabson 	 * To modify the ownership of a file, must possess VADMIN for that
1033e97ad33aSDoug Rabson 	 * file.
1034e97ad33aSDoug Rabson 	 */
1035e97ad33aSDoug Rabson 	if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred, td)))
1036e97ad33aSDoug Rabson 		return (error);
1037e97ad33aSDoug Rabson 	/*
1038e97ad33aSDoug Rabson 	 * To change the owner of a file, or change the group of a file to a
1039e97ad33aSDoug Rabson 	 * group of which we are not a member, the caller must have
1040e97ad33aSDoug Rabson 	 * privilege.
1041e97ad33aSDoug Rabson 	 */
1042e97ad33aSDoug Rabson 	if (((uid != inode->n_uid && uid != cred->cr_uid) ||
1043e97ad33aSDoug Rabson 	    (gid != inode->n_gid && !groupmember(gid, cred))) &&
1044e97ad33aSDoug Rabson 	    (error = priv_check_cred(cred, PRIV_VFS_CHOWN)))
1045e97ad33aSDoug Rabson 		return (error);
1046e97ad33aSDoug Rabson 
1047e97ad33aSDoug Rabson 	ogid = inode->n_gid;
1048e97ad33aSDoug Rabson 	ouid = inode->n_uid;
1049e97ad33aSDoug Rabson 
1050e97ad33aSDoug Rabson 	inode->n_gid = gid;
1051e97ad33aSDoug Rabson 	inode->n_uid = uid;
1052e97ad33aSDoug Rabson 
1053e97ad33aSDoug Rabson 	if ((inode->i_mode & (ISUID | ISGID)) &&
1054e97ad33aSDoug Rabson 	    (ouid != uid || ogid != gid)) {
1055e97ad33aSDoug Rabson 
1056e97ad33aSDoug Rabson 		if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID))
1057e97ad33aSDoug Rabson 			inode->i_mode &= ~(ISUID | ISGID);
1058e97ad33aSDoug Rabson 	}
1059e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp %p, cred %p, td %p - ret OK\n", __func__, vp, cred, td);
1060e97ad33aSDoug Rabson 
1061e97ad33aSDoug Rabson 	return (0);
1062e97ad33aSDoug Rabson }
1063e97ad33aSDoug Rabson 
1064e97ad33aSDoug Rabson /*
1065e97ad33aSDoug Rabson  * Update the in memory inode with all chmod new permissions/mode. Typically a
1066e97ad33aSDoug Rabson  * setattr is called to update it to server.
1067e97ad33aSDoug Rabson  */
1068e97ad33aSDoug Rabson static int
1069e97ad33aSDoug Rabson p9fs_chmod(struct vnode *vp, uint32_t  mode, struct ucred *cred, struct thread *td)
1070e97ad33aSDoug Rabson {
1071e97ad33aSDoug Rabson 	struct p9fs_node *np;
1072e97ad33aSDoug Rabson 	struct p9fs_inode *inode;
1073e97ad33aSDoug Rabson 	uint32_t nmode;
1074e97ad33aSDoug Rabson 	int error;
1075e97ad33aSDoug Rabson 
1076e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
1077e97ad33aSDoug Rabson 	inode = &np->inode;
1078e97ad33aSDoug Rabson 
1079e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp %p, mode %x, cred %p, td %p\n",  __func__, vp, mode, cred, td);
1080e97ad33aSDoug Rabson 	/*
1081e97ad33aSDoug Rabson 	 * To modify the permissions on a file, must possess VADMIN
1082e97ad33aSDoug Rabson 	 * for that file.
1083e97ad33aSDoug Rabson 	 */
1084e97ad33aSDoug Rabson 	if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
1085e97ad33aSDoug Rabson 		return (error);
1086e97ad33aSDoug Rabson 
1087e97ad33aSDoug Rabson 	/*
1088e97ad33aSDoug Rabson 	 * Privileged processes may set the sticky bit on non-directories,
1089e97ad33aSDoug Rabson 	 * as well as set the setgid bit on a file with a group that the
1090e97ad33aSDoug Rabson 	 * process is not a member of. Both of these are allowed in
1091e97ad33aSDoug Rabson 	 * jail(8).
1092e97ad33aSDoug Rabson 	 */
1093e97ad33aSDoug Rabson 	if (vp->v_type != VDIR && (mode & S_ISTXT)) {
1094e97ad33aSDoug Rabson 		if (priv_check_cred(cred, PRIV_VFS_STICKYFILE))
1095e97ad33aSDoug Rabson 			return (EFTYPE);
1096e97ad33aSDoug Rabson 	}
1097e97ad33aSDoug Rabson 	if (!groupmember(inode->n_gid, cred) && (mode & ISGID)) {
1098e97ad33aSDoug Rabson 		error = priv_check_cred(cred, PRIV_VFS_SETGID);
1099e97ad33aSDoug Rabson 		if (error != 0)
1100e97ad33aSDoug Rabson 			return (error);
1101e97ad33aSDoug Rabson 	}
1102e97ad33aSDoug Rabson 
1103e97ad33aSDoug Rabson 	/*
1104e97ad33aSDoug Rabson 	 * Deny setting setuid if we are not the file owner.
1105e97ad33aSDoug Rabson 	 */
1106e97ad33aSDoug Rabson 	if ((mode & ISUID) && inode->n_uid != cred->cr_uid) {
1107e97ad33aSDoug Rabson 		error = priv_check_cred(cred, PRIV_VFS_ADMIN);
1108e97ad33aSDoug Rabson 		if (error != 0)
1109e97ad33aSDoug Rabson 			return (error);
1110e97ad33aSDoug Rabson 	}
1111e97ad33aSDoug Rabson 	nmode = inode->i_mode;
1112e97ad33aSDoug Rabson 	nmode &= ~ALLPERMS;
1113e97ad33aSDoug Rabson 	nmode |= (mode & ALLPERMS);
1114e97ad33aSDoug Rabson 	inode->i_mode = nmode;
1115e97ad33aSDoug Rabson 
1116e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: to mode %x  %d \n ", __func__, nmode, error);
1117e97ad33aSDoug Rabson 
1118e97ad33aSDoug Rabson 	return (error);
1119e97ad33aSDoug Rabson }
1120e97ad33aSDoug Rabson 
1121e97ad33aSDoug Rabson /*
1122e97ad33aSDoug Rabson  * Set the attributes of a file referenced by fid. A valid bitmask is sent
1123e97ad33aSDoug Rabson  * in request selecting which fields to set
1124e97ad33aSDoug Rabson  */
1125e97ad33aSDoug Rabson static int
1126e97ad33aSDoug Rabson p9fs_setattr_dotl(struct vop_setattr_args *ap)
1127e97ad33aSDoug Rabson {
1128e97ad33aSDoug Rabson 	struct vnode *vp;
1129e97ad33aSDoug Rabson 	struct vattr *vap;
1130e97ad33aSDoug Rabson 	struct p9fs_node *node;
1131e97ad33aSDoug Rabson 	struct p9fs_inode *inode;
1132e97ad33aSDoug Rabson 	struct ucred *cred;
1133e97ad33aSDoug Rabson 	struct thread *td;
1134e97ad33aSDoug Rabson 	struct p9_iattr_dotl *p9attr;
1135e97ad33aSDoug Rabson 	struct p9fs_session *vses;
1136e97ad33aSDoug Rabson 	struct p9_fid *vfid;
1137e97ad33aSDoug Rabson 	uint64_t oldfilesize;
1138e97ad33aSDoug Rabson 	int error;
1139e97ad33aSDoug Rabson 
1140e97ad33aSDoug Rabson 	vp = ap->a_vp;
1141e97ad33aSDoug Rabson 	vap = ap->a_vap;
1142e97ad33aSDoug Rabson 	node = P9FS_VTON(vp);
1143e97ad33aSDoug Rabson 	inode = &node->inode;
1144e97ad33aSDoug Rabson 	cred = ap->a_cred;
1145e97ad33aSDoug Rabson 	td = curthread;
1146e97ad33aSDoug Rabson 	vses = node->p9fs_ses;
1147e97ad33aSDoug Rabson 	error = 0;
1148e97ad33aSDoug Rabson 
1149e97ad33aSDoug Rabson 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
1150e97ad33aSDoug Rabson 	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
1151e97ad33aSDoug Rabson 	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
1152e97ad33aSDoug Rabson 	    (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
1153e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: unsettable attribute\n", __func__);
1154e97ad33aSDoug Rabson 		return (EINVAL);
1155e97ad33aSDoug Rabson 	}
1156e97ad33aSDoug Rabson 	/* Disallow write attempts on read only filesystem */
1157e97ad33aSDoug Rabson 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1158e97ad33aSDoug Rabson 		return (EROFS);
1159e97ad33aSDoug Rabson 
1160e97ad33aSDoug Rabson 	/* Setting of flags is not supported */
1161e97ad33aSDoug Rabson 	if (vap->va_flags != VNOVAL)
1162e97ad33aSDoug Rabson 		return (EOPNOTSUPP);
1163e97ad33aSDoug Rabson 
1164e97ad33aSDoug Rabson 	/* Allocate p9attr struct */
1165e97ad33aSDoug Rabson 	p9attr = uma_zalloc(p9fs_setattr_zone, M_WAITOK | M_ZERO);
1166e97ad33aSDoug Rabson 	if (p9attr == NULL)
1167e97ad33aSDoug Rabson 		return (ENOMEM);
1168e97ad33aSDoug Rabson 
1169e97ad33aSDoug Rabson 	/* Check if we need to change the ownership of the file*/
1170e97ad33aSDoug Rabson 	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
1171e97ad33aSDoug Rabson 		P9_DEBUG(VOPS, "%s: vp:%p td:%p uid/gid %x/%x\n", __func__,
1172e97ad33aSDoug Rabson 		    vp, td, vap->va_uid, vap->va_gid);
1173e97ad33aSDoug Rabson 
1174e97ad33aSDoug Rabson 		error = p9fs_chown(vp, vap->va_uid, vap->va_gid, cred, td);
1175e97ad33aSDoug Rabson 		p9attr->valid |= P9PROTO_SETATTR_UID | P9PROTO_SETATTR_GID |
1176e97ad33aSDoug Rabson 			P9PROTO_SETATTR_MODE;
1177e97ad33aSDoug Rabson 		if (error)
1178e97ad33aSDoug Rabson 			goto out;
1179e97ad33aSDoug Rabson 	}
1180e97ad33aSDoug Rabson 
1181e97ad33aSDoug Rabson 	/* Check for mode changes */
1182e97ad33aSDoug Rabson 	if (vap->va_mode != (mode_t)VNOVAL) {
1183e97ad33aSDoug Rabson 		P9_DEBUG(VOPS, "%s: vp:%p td:%p mode %x\n", __func__, vp, td,
1184e97ad33aSDoug Rabson 		    vap->va_mode);
1185e97ad33aSDoug Rabson 
1186e97ad33aSDoug Rabson 		error = p9fs_chmod(vp, (int)vap->va_mode, cred, td);
1187e97ad33aSDoug Rabson 		p9attr->valid |= P9PROTO_SETATTR_MODE;
1188e97ad33aSDoug Rabson 		if (error)
1189e97ad33aSDoug Rabson 			goto out;
1190e97ad33aSDoug Rabson 	}
1191e97ad33aSDoug Rabson 
1192e97ad33aSDoug Rabson 	/* Update the size of the file and update mtime */
1193e97ad33aSDoug Rabson 	if (vap->va_size != (uint64_t)VNOVAL) {
1194e97ad33aSDoug Rabson 		P9_DEBUG(VOPS, "%s: vp:%p td:%p size:%jx\n", __func__,
1195e97ad33aSDoug Rabson 		    vp, td, (uintmax_t)vap->va_size);
1196e97ad33aSDoug Rabson 		switch (vp->v_type) {
1197e97ad33aSDoug Rabson 			case VDIR:
1198e97ad33aSDoug Rabson 				error = EISDIR;
1199e97ad33aSDoug Rabson 				goto out;
1200e97ad33aSDoug Rabson 			case VLNK:
1201e97ad33aSDoug Rabson 			case VREG:
1202e97ad33aSDoug Rabson 				/* Invalidate cached pages of vp */
1203e97ad33aSDoug Rabson 				error = vinvalbuf(vp, 0, 0, 0);
1204e97ad33aSDoug Rabson 				if (error)
1205e97ad33aSDoug Rabson 					goto out;
1206e97ad33aSDoug Rabson 				oldfilesize = inode->i_size;
1207e97ad33aSDoug Rabson 				inode->i_size = vap->va_size;
1208e97ad33aSDoug Rabson 				/* Update the p9fs_inode time */
1209e97ad33aSDoug Rabson 				p9fs_itimes(vp);
1210e97ad33aSDoug Rabson 				p9attr->valid |= P9PROTO_SETATTR_SIZE |
1211e97ad33aSDoug Rabson 				    P9PROTO_SETATTR_ATIME |
1212e97ad33aSDoug Rabson 				    P9PROTO_SETATTR_MTIME |
1213e97ad33aSDoug Rabson 				    P9PROTO_SETATTR_ATIME_SET |
1214e97ad33aSDoug Rabson 				    P9PROTO_SETATTR_MTIME_SET ;
1215e97ad33aSDoug Rabson 				break;
1216e97ad33aSDoug Rabson 			default:
1217e97ad33aSDoug Rabson 				goto out;
1218e97ad33aSDoug Rabson 		}
1219e97ad33aSDoug Rabson 	} else if (vap->va_atime.tv_sec != VNOVAL ||
1220e97ad33aSDoug Rabson 		    vap->va_mtime.tv_sec != VNOVAL) {
1221e97ad33aSDoug Rabson 		P9_DEBUG(VOPS, "%s: vp:%p td:%p time a/m %jx/%jx/\n",
1222e97ad33aSDoug Rabson 		    __func__, vp, td, (uintmax_t)vap->va_atime.tv_sec,
1223e97ad33aSDoug Rabson 		    (uintmax_t)vap->va_mtime.tv_sec);
1224e97ad33aSDoug Rabson 		/* Update the p9fs_inode times */
1225e97ad33aSDoug Rabson 		p9fs_itimes(vp);
1226e97ad33aSDoug Rabson 		p9attr->valid |= P9PROTO_SETATTR_ATIME |
1227e97ad33aSDoug Rabson 			P9PROTO_SETATTR_MTIME | P9PROTO_SETATTR_ATIME_SET |
1228e97ad33aSDoug Rabson 			P9PROTO_SETATTR_MTIME_SET;
1229e97ad33aSDoug Rabson 	}
1230e97ad33aSDoug Rabson 
1231e97ad33aSDoug Rabson 	vfid = p9fs_get_fid(vses->clnt, node, cred, VOFID, P9PROTO_OWRITE, &error);
1232e97ad33aSDoug Rabson 	if (vfid == NULL) {
1233e97ad33aSDoug Rabson 		vfid = p9fs_get_fid(vses->clnt, node, cred, VFID, -1, &error);
1234e97ad33aSDoug Rabson 		if (error)
1235e97ad33aSDoug Rabson 			goto out;
1236e97ad33aSDoug Rabson 	}
1237e97ad33aSDoug Rabson 
1238e97ad33aSDoug Rabson 	/* Write the inode structure values into p9attr */
1239e97ad33aSDoug Rabson 	p9fs_inode_to_iattr(inode, p9attr);
1240e97ad33aSDoug Rabson 	error = p9_client_setattr(vfid, p9attr);
1241e97ad33aSDoug Rabson 	if (vap->va_size != (uint64_t)VNOVAL && vp->v_type == VREG) {
1242e97ad33aSDoug Rabson 		if (error)
1243e97ad33aSDoug Rabson 			inode->i_size = oldfilesize;
1244e97ad33aSDoug Rabson 		else
1245e97ad33aSDoug Rabson 			vnode_pager_setsize(vp, inode->i_size);
1246e97ad33aSDoug Rabson 	}
1247e97ad33aSDoug Rabson out:
1248e97ad33aSDoug Rabson 	if (p9attr) {
1249e97ad33aSDoug Rabson 		uma_zfree(p9fs_setattr_zone, p9attr);
1250e97ad33aSDoug Rabson 	}
1251e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: error: %d\n", __func__, error);
1252e97ad33aSDoug Rabson 	return (error);
1253e97ad33aSDoug Rabson }
1254e97ad33aSDoug Rabson 
1255e97ad33aSDoug Rabson struct open_fid_state {
1256e97ad33aSDoug Rabson 	struct p9_fid *vofid;
1257e97ad33aSDoug Rabson 	int fflags;
1258e97ad33aSDoug Rabson 	int opened;
1259e97ad33aSDoug Rabson };
1260e97ad33aSDoug Rabson 
1261e97ad33aSDoug Rabson /*
1262e97ad33aSDoug Rabson  * TODO: change this to take P9PROTO_* mode and avoid routing through
1263e97ad33aSDoug Rabson  * VOP_OPEN, factoring out implementation of p9fs_open.
1264e97ad33aSDoug Rabson  */
1265e97ad33aSDoug Rabson static int
1266e97ad33aSDoug Rabson p9fs_get_open_fid(struct vnode *vp, int fflags, struct ucred *cr, struct open_fid_state *statep)
1267e97ad33aSDoug Rabson {
1268e97ad33aSDoug Rabson 	struct p9fs_node *np;
1269e97ad33aSDoug Rabson 	struct p9fs_session *vses;
1270e97ad33aSDoug Rabson 	struct p9_fid *vofid;
1271e97ad33aSDoug Rabson 	int mode = p9fs_uflags_mode(fflags, TRUE);
1272e97ad33aSDoug Rabson 	int error = 0;
1273e97ad33aSDoug Rabson 
1274e97ad33aSDoug Rabson 	statep->opened = FALSE;
1275e97ad33aSDoug Rabson 
1276e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
1277e97ad33aSDoug Rabson 	vses = np->p9fs_ses;
1278e97ad33aSDoug Rabson 	vofid = p9fs_get_fid(vses->clnt, np, cr, VOFID, mode, &error);
1279e97ad33aSDoug Rabson 	if (vofid == NULL) {
1280e97ad33aSDoug Rabson 		error = VOP_OPEN(vp, fflags, cr, curthread, NULL);
1281e97ad33aSDoug Rabson 		if (error) {
1282e97ad33aSDoug Rabson 			return (error);
1283e97ad33aSDoug Rabson 		}
1284e97ad33aSDoug Rabson 		vofid = p9fs_get_fid(vses->clnt, np, cr, VOFID, mode, &error);
1285e97ad33aSDoug Rabson 		if (vofid == NULL) {
1286e97ad33aSDoug Rabson 			return (EBADF);
1287e97ad33aSDoug Rabson 		}
1288e97ad33aSDoug Rabson 		statep->fflags = fflags;
1289e97ad33aSDoug Rabson 		statep->opened = TRUE;
1290e97ad33aSDoug Rabson 	}
1291e97ad33aSDoug Rabson 	statep->vofid = vofid;
1292e97ad33aSDoug Rabson 	return (0);
1293e97ad33aSDoug Rabson }
1294e97ad33aSDoug Rabson 
1295e97ad33aSDoug Rabson static void
1296e97ad33aSDoug Rabson p9fs_release_open_fid(struct vnode *vp, struct ucred *cr, struct open_fid_state *statep)
1297e97ad33aSDoug Rabson {
1298e97ad33aSDoug Rabson 	if (statep->opened) {
1299e97ad33aSDoug Rabson 		(void) VOP_CLOSE(vp, statep->fflags, cr, curthread);
1300e97ad33aSDoug Rabson 	}
1301e97ad33aSDoug Rabson }
1302e97ad33aSDoug Rabson 
1303e97ad33aSDoug Rabson /*
1304e97ad33aSDoug Rabson  * An I/O buffer is used to to do any transfer. The uio is the vfs structure we
1305e97ad33aSDoug Rabson  * need to copy data into. As long as resid is greater than zero, we call
1306e97ad33aSDoug Rabson  * client_read to read data from offset(offset into the file) in the open fid
1307e97ad33aSDoug Rabson  * for the file into the I/O buffer. The data is read into the user data buffer.
1308e97ad33aSDoug Rabson  */
1309e97ad33aSDoug Rabson static int
1310e97ad33aSDoug Rabson p9fs_read(struct vop_read_args *ap)
1311e97ad33aSDoug Rabson {
1312e97ad33aSDoug Rabson 	struct vnode *vp;
1313e97ad33aSDoug Rabson 	struct uio *uio;
1314e97ad33aSDoug Rabson 	struct p9fs_node *np;
1315e97ad33aSDoug Rabson 	uint64_t offset;
1316e97ad33aSDoug Rabson 	int64_t ret;
1317e97ad33aSDoug Rabson 	uint64_t resid;
1318e97ad33aSDoug Rabson 	uint32_t count;
1319e97ad33aSDoug Rabson 	int error;
1320e97ad33aSDoug Rabson 	char *io_buffer = NULL;
1321e97ad33aSDoug Rabson 	uint64_t filesize;
1322e97ad33aSDoug Rabson 	struct open_fid_state ostate;
1323e97ad33aSDoug Rabson 
1324e97ad33aSDoug Rabson 	vp = ap->a_vp;
1325e97ad33aSDoug Rabson 	uio = ap->a_uio;
1326e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
1327e97ad33aSDoug Rabson 	error = 0;
1328e97ad33aSDoug Rabson 
1329e97ad33aSDoug Rabson 	if (vp->v_type == VCHR || vp->v_type == VBLK)
1330e97ad33aSDoug Rabson 		return (EOPNOTSUPP);
1331e97ad33aSDoug Rabson 	if (vp->v_type != VREG)
1332e97ad33aSDoug Rabson 		return (EISDIR);
1333e97ad33aSDoug Rabson 	if (uio->uio_resid == 0)
1334e97ad33aSDoug Rabson 		return (0);
1335e97ad33aSDoug Rabson 	if (uio->uio_offset < 0)
1336e97ad33aSDoug Rabson 		return (EINVAL);
1337e97ad33aSDoug Rabson 
1338e97ad33aSDoug Rabson 	error = p9fs_get_open_fid(vp, FREAD, ap->a_cred, &ostate);
1339e97ad33aSDoug Rabson 	if (error)
1340e97ad33aSDoug Rabson 		return (error);
1341e97ad33aSDoug Rabson 
1342e97ad33aSDoug Rabson 	/* where in the file are we to start reading */
1343e97ad33aSDoug Rabson 	offset = uio->uio_offset;
1344e97ad33aSDoug Rabson 	filesize = np->inode.i_size;
1345e97ad33aSDoug Rabson 	if (uio->uio_offset >= filesize)
1346e97ad33aSDoug Rabson 		goto out;
1347e97ad33aSDoug Rabson 
1348e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: called %jd at %ju\n",
1349e97ad33aSDoug Rabson 	    __func__, (intmax_t)uio->uio_resid, (uintmax_t)uio->uio_offset);
1350e97ad33aSDoug Rabson 
1351e97ad33aSDoug Rabson 	/* Work with a local buffer from the pool for this vop */
1352e97ad33aSDoug Rabson 
1353e97ad33aSDoug Rabson 	io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK | M_ZERO);
1354e97ad33aSDoug Rabson 	while ((resid = uio->uio_resid) > 0) {
1355e97ad33aSDoug Rabson 		if (offset >= filesize)
1356e97ad33aSDoug Rabson 			break;
1357e97ad33aSDoug Rabson 		count = MIN(filesize - uio->uio_offset , resid);
1358e97ad33aSDoug Rabson 		if (count == 0)
1359e97ad33aSDoug Rabson 			break;
1360e97ad33aSDoug Rabson 
1361e97ad33aSDoug Rabson 		/* Copy count bytes into the uio */
1362e97ad33aSDoug Rabson 		ret = p9_client_read(ostate.vofid, offset, count, io_buffer);
1363e97ad33aSDoug Rabson 		/*
1364e97ad33aSDoug Rabson 		 * This is the only place in the entire p9fs where we check the
1365e97ad33aSDoug Rabson 		 * error for < 0 as p9_client_read/write return the number of
1366e97ad33aSDoug Rabson 		 * bytes instead of an error code. In this case if ret is < 0,
1367e97ad33aSDoug Rabson 		 * it means there is an IO error.
1368e97ad33aSDoug Rabson 		 */
1369e97ad33aSDoug Rabson 		if (ret < 0) {
1370e97ad33aSDoug Rabson 			error = -ret;
1371e97ad33aSDoug Rabson 			goto out;
1372e97ad33aSDoug Rabson 		}
1373e97ad33aSDoug Rabson 		error = uiomove(io_buffer, ret, uio);
1374e97ad33aSDoug Rabson 		if (error != 0)
1375e97ad33aSDoug Rabson 			goto out;
1376e97ad33aSDoug Rabson 
1377e97ad33aSDoug Rabson 		offset += ret;
1378e97ad33aSDoug Rabson 	}
1379e97ad33aSDoug Rabson 	uio->uio_offset = offset;
1380e97ad33aSDoug Rabson out:
1381e97ad33aSDoug Rabson 	uma_zfree(p9fs_io_buffer_zone, io_buffer);
1382e97ad33aSDoug Rabson 	p9fs_release_open_fid(vp, ap->a_cred, &ostate);
1383e97ad33aSDoug Rabson 
1384e97ad33aSDoug Rabson 	return (error);
1385e97ad33aSDoug Rabson }
1386e97ad33aSDoug Rabson 
1387e97ad33aSDoug Rabson /*
1388e97ad33aSDoug Rabson  * The user buffer contains the data to be written. This data is copied first
1389e97ad33aSDoug Rabson  * from uio into I/O buffer. This I/O  buffer is used to do the client_write to
1390e97ad33aSDoug Rabson  * the fid of the file starting from the offset given upto count bytes. The
1391e97ad33aSDoug Rabson  * number of bytes written is returned to the caller.
1392e97ad33aSDoug Rabson  */
1393e97ad33aSDoug Rabson static int
1394e97ad33aSDoug Rabson p9fs_write(struct vop_write_args *ap)
1395e97ad33aSDoug Rabson {
1396e97ad33aSDoug Rabson 	struct vnode *vp;
1397e97ad33aSDoug Rabson 	struct uio *uio;
1398e97ad33aSDoug Rabson 	struct p9fs_node *np;
1399e97ad33aSDoug Rabson 	uint64_t off, offset;
1400e97ad33aSDoug Rabson 	int64_t ret;
1401e97ad33aSDoug Rabson 	uint64_t resid, bytes_written;
1402e97ad33aSDoug Rabson 	uint32_t count;
1403e97ad33aSDoug Rabson 	int error, ioflag;
1404e97ad33aSDoug Rabson 	uint64_t file_size;
1405e97ad33aSDoug Rabson 	char *io_buffer = NULL;
1406e97ad33aSDoug Rabson 	struct open_fid_state ostate;
1407e97ad33aSDoug Rabson 
1408e97ad33aSDoug Rabson 	vp = ap->a_vp;
1409e97ad33aSDoug Rabson 	uio = ap->a_uio;
1410e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
1411e97ad33aSDoug Rabson 	error = 0;
1412e97ad33aSDoug Rabson 	ioflag = ap->a_ioflag;
1413e97ad33aSDoug Rabson 
1414e97ad33aSDoug Rabson 	error = p9fs_get_open_fid(vp, FWRITE, ap->a_cred, &ostate);
1415e97ad33aSDoug Rabson 	if (error)
1416e97ad33aSDoug Rabson 		return (error);
1417e97ad33aSDoug Rabson 
1418e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: %#zx at %#jx\n",
1419e97ad33aSDoug Rabson 	    __func__, uio->uio_resid, (uintmax_t)uio->uio_offset);
1420e97ad33aSDoug Rabson 
1421e97ad33aSDoug Rabson 	if (uio->uio_offset < 0) {
1422e97ad33aSDoug Rabson 		error = EINVAL;
1423e97ad33aSDoug Rabson 		goto out;
1424e97ad33aSDoug Rabson 	}
1425e97ad33aSDoug Rabson 	if (uio->uio_resid == 0)
1426e97ad33aSDoug Rabson 		goto out;
1427e97ad33aSDoug Rabson 
1428e97ad33aSDoug Rabson 	file_size = np->inode.i_size;
1429e97ad33aSDoug Rabson 
1430e97ad33aSDoug Rabson 	switch (vp->v_type) {
1431e97ad33aSDoug Rabson 	case VREG:
1432e97ad33aSDoug Rabson 		if (ioflag & IO_APPEND)
1433e97ad33aSDoug Rabson 			uio->uio_offset = file_size;
1434e97ad33aSDoug Rabson 		break;
1435e97ad33aSDoug Rabson 	case VDIR:
1436e97ad33aSDoug Rabson 		return (EISDIR);
1437e97ad33aSDoug Rabson 	case VLNK:
1438e97ad33aSDoug Rabson 		break;
1439e97ad33aSDoug Rabson 	default:
1440e97ad33aSDoug Rabson 		panic("%s: bad file type vp: %p", __func__, vp);
1441e97ad33aSDoug Rabson 	}
1442e97ad33aSDoug Rabson 
1443e97ad33aSDoug Rabson 	resid = uio->uio_resid;
1444e97ad33aSDoug Rabson 	offset = uio->uio_offset;
1445e97ad33aSDoug Rabson 	bytes_written = 0;
1446e97ad33aSDoug Rabson 	error = 0;
1447e97ad33aSDoug Rabson 
1448e97ad33aSDoug Rabson 	io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK | M_ZERO);
1449e97ad33aSDoug Rabson 	while ((resid = uio->uio_resid) > 0) {
1450e97ad33aSDoug Rabson                 off = 0;
1451e97ad33aSDoug Rabson 		count = MIN(resid, P9FS_IOUNIT);
1452e97ad33aSDoug Rabson 		error = uiomove(io_buffer, count, uio);
1453e97ad33aSDoug Rabson 
1454e97ad33aSDoug Rabson 		if (error != 0) {
1455e97ad33aSDoug Rabson 			P9_DEBUG(ERROR, "%s: uiomove failed: %d\n", __func__, error);
1456e97ad33aSDoug Rabson 			goto out;
1457e97ad33aSDoug Rabson 		}
1458e97ad33aSDoug Rabson 
1459e97ad33aSDoug Rabson 		/* While count still exists, keep writing.*/
1460e97ad33aSDoug Rabson 		while (count > 0) {
1461e97ad33aSDoug Rabson 			/* Copy count bytes from the uio */
1462e97ad33aSDoug Rabson 			ret = p9_client_write(ostate.vofid, offset, count,
1463e97ad33aSDoug Rabson                                 io_buffer + off);
1464e97ad33aSDoug Rabson 			if (ret < 0) {
1465e97ad33aSDoug Rabson 				if (bytes_written == 0) {
1466e97ad33aSDoug Rabson 					error = -ret;
1467e97ad33aSDoug Rabson 					goto out;
1468e97ad33aSDoug Rabson 				} else {
1469e97ad33aSDoug Rabson 					break;
1470e97ad33aSDoug Rabson 				}
1471e97ad33aSDoug Rabson 			}
1472e97ad33aSDoug Rabson 			P9_DEBUG(VOPS, "%s: write %#zx at %#jx\n",
1473e97ad33aSDoug Rabson 			    __func__, uio->uio_resid, (uintmax_t)uio->uio_offset);
1474e97ad33aSDoug Rabson 
1475e97ad33aSDoug Rabson                         off += ret;
1476e97ad33aSDoug Rabson 			offset += ret;
1477e97ad33aSDoug Rabson 			bytes_written += ret;
1478e97ad33aSDoug Rabson 			count -= ret;
1479e97ad33aSDoug Rabson 		}
1480e97ad33aSDoug Rabson 	}
1481e97ad33aSDoug Rabson 	/* Update the fields in the node to reflect the change*/
1482e97ad33aSDoug Rabson 	if (file_size < uio->uio_offset + uio->uio_resid) {
1483e97ad33aSDoug Rabson 		np->inode.i_size = uio->uio_offset + uio->uio_resid;
1484e97ad33aSDoug Rabson 		vnode_pager_setsize(vp, uio->uio_offset + uio->uio_resid);
1485e97ad33aSDoug Rabson 	}
1486e97ad33aSDoug Rabson out:
1487e97ad33aSDoug Rabson 	if (io_buffer)
1488e97ad33aSDoug Rabson 		uma_zfree(p9fs_io_buffer_zone, io_buffer);
1489e97ad33aSDoug Rabson 	p9fs_release_open_fid(vp, ap->a_cred, &ostate);
1490e97ad33aSDoug Rabson 
1491e97ad33aSDoug Rabson 	return (error);
1492e97ad33aSDoug Rabson }
1493e97ad33aSDoug Rabson 
1494e97ad33aSDoug Rabson /*
1495e97ad33aSDoug Rabson  * Common handler of all removal-related VOPs (e.g. rmdir, rm). Perform the
1496e97ad33aSDoug Rabson  * client_remove op to send messages to remove the node's fid on the server.
1497e97ad33aSDoug Rabson  * After that, does a node metadata cleanup on client side.
1498e97ad33aSDoug Rabson  */
1499e97ad33aSDoug Rabson static int
1500*1d99e8d9SMark Johnston remove_common(struct p9fs_node *dnp, struct p9fs_node *np, const char *name,
1501*1d99e8d9SMark Johnston     struct ucred *cred)
1502e97ad33aSDoug Rabson {
1503e97ad33aSDoug Rabson 	int error;
1504e97ad33aSDoug Rabson 	struct p9fs_session *vses;
1505e97ad33aSDoug Rabson 	struct vnode *vp;
1506e97ad33aSDoug Rabson 	struct p9_fid *vfid;
1507e97ad33aSDoug Rabson 
1508e97ad33aSDoug Rabson 	error = 0;
1509e97ad33aSDoug Rabson 	vses = np->p9fs_ses;
1510e97ad33aSDoug Rabson 	vp = P9FS_NTOV(np);
1511e97ad33aSDoug Rabson 
1512*1d99e8d9SMark Johnston 	vfid = p9fs_get_fid(vses->clnt, dnp, cred, VFID, -1, &error);
1513e97ad33aSDoug Rabson 	if (error != 0)
1514e97ad33aSDoug Rabson 		return (error);
1515e97ad33aSDoug Rabson 
1516*1d99e8d9SMark Johnston 	error = p9_client_unlink(vfid, name,
1517*1d99e8d9SMark Johnston 	    np->v_node->v_type == VDIR ? P9PROTO_UNLINKAT_REMOVEDIR : 0);
1518e97ad33aSDoug Rabson 	if (error != 0)
1519e97ad33aSDoug Rabson 		return (error);
1520e97ad33aSDoug Rabson 
1521e97ad33aSDoug Rabson 	/* Remove all non-open fids associated with the vp */
1522*1d99e8d9SMark Johnston 	if (np->inode.i_links_count == 1)
1523e97ad33aSDoug Rabson 		p9fs_fid_remove_all(np, TRUE);
1524e97ad33aSDoug Rabson 
1525e97ad33aSDoug Rabson 	/* Invalidate all entries of vnode from name cache and hash list. */
1526e97ad33aSDoug Rabson 	cache_purge(vp);
1527e97ad33aSDoug Rabson 	vfs_hash_remove(vp);
1528*1d99e8d9SMark Johnston 
1529e97ad33aSDoug Rabson 	np->flags |= P9FS_NODE_DELETED;
1530e97ad33aSDoug Rabson 
1531e97ad33aSDoug Rabson 	return (error);
1532e97ad33aSDoug Rabson }
1533e97ad33aSDoug Rabson 
1534e97ad33aSDoug Rabson /* Remove vop for all files. Call common code for remove and adjust links */
1535e97ad33aSDoug Rabson static int
1536e97ad33aSDoug Rabson p9fs_remove(struct vop_remove_args *ap)
1537e97ad33aSDoug Rabson {
1538e97ad33aSDoug Rabson 	struct vnode *vp;
1539e97ad33aSDoug Rabson 	struct p9fs_node *np;
1540e97ad33aSDoug Rabson 	struct vnode *dvp;
1541e97ad33aSDoug Rabson 	struct p9fs_node *dnp;
1542e97ad33aSDoug Rabson 	struct p9fs_inode *dinode;
1543*1d99e8d9SMark Johnston 	struct componentname *cnp;
1544e97ad33aSDoug Rabson 	int error;
1545e97ad33aSDoug Rabson 
1546*1d99e8d9SMark Johnston 	cnp = ap->a_cnp;
1547e97ad33aSDoug Rabson 	vp = ap->a_vp;
1548e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
1549e97ad33aSDoug Rabson 	dvp = ap->a_dvp;
1550e97ad33aSDoug Rabson 	dnp = P9FS_VTON(dvp);
1551e97ad33aSDoug Rabson 	dinode = &dnp->inode;
1552e97ad33aSDoug Rabson 
1553e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp %p node %p \n", __func__, vp, np);
1554e97ad33aSDoug Rabson 
1555e97ad33aSDoug Rabson 	if (vp->v_type == VDIR)
1556e97ad33aSDoug Rabson 		return (EISDIR);
1557e97ad33aSDoug Rabson 
1558*1d99e8d9SMark Johnston 	error = remove_common(dnp, np, cnp->cn_nameptr, cnp->cn_cred);
1559e97ad33aSDoug Rabson 	if (error == 0)
1560e97ad33aSDoug Rabson 		P9FS_DECR_LINKS(dinode);
1561e97ad33aSDoug Rabson 
1562e97ad33aSDoug Rabson 	return (error);
1563e97ad33aSDoug Rabson }
1564e97ad33aSDoug Rabson 
1565e97ad33aSDoug Rabson /* Remove vop for all directories. Call common code for remove and adjust links */
1566e97ad33aSDoug Rabson static int
1567e97ad33aSDoug Rabson p9fs_rmdir(struct vop_rmdir_args *ap)
1568e97ad33aSDoug Rabson {
1569e97ad33aSDoug Rabson 	struct vnode *vp;
1570e97ad33aSDoug Rabson 	struct p9fs_node *np;
1571e97ad33aSDoug Rabson 	struct vnode *dvp;
1572e97ad33aSDoug Rabson 	struct p9fs_node *dnp;
1573e97ad33aSDoug Rabson 	struct p9fs_inode *dinode;
1574*1d99e8d9SMark Johnston 	struct componentname *cnp;
1575e97ad33aSDoug Rabson 	int error;
1576e97ad33aSDoug Rabson 
1577*1d99e8d9SMark Johnston 	cnp = ap->a_cnp;
1578e97ad33aSDoug Rabson 	vp = ap->a_vp;
1579e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
1580e97ad33aSDoug Rabson 	dvp = ap->a_dvp;
1581e97ad33aSDoug Rabson 	dnp = P9FS_VTON(dvp);
1582e97ad33aSDoug Rabson 	dinode = &dnp->inode;
1583e97ad33aSDoug Rabson 
1584e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp %p node %p \n", __func__, vp, np);
1585e97ad33aSDoug Rabson 
1586*1d99e8d9SMark Johnston 	error = remove_common(dnp, np, cnp->cn_nameptr, cnp->cn_cred);
1587e97ad33aSDoug Rabson 	if (error == 0)
1588e97ad33aSDoug Rabson 		P9FS_DECR_LINKS(dinode);
1589e97ad33aSDoug Rabson 
1590e97ad33aSDoug Rabson 	return (error);
1591e97ad33aSDoug Rabson }
1592e97ad33aSDoug Rabson 
1593e97ad33aSDoug Rabson /*
1594e97ad33aSDoug Rabson  * Create symlinks. Make the permissions and call create_common code
1595e97ad33aSDoug Rabson  * for Soft links.
1596e97ad33aSDoug Rabson  */
1597e97ad33aSDoug Rabson static int
1598e97ad33aSDoug Rabson p9fs_symlink(struct vop_symlink_args *ap)
1599e97ad33aSDoug Rabson {
1600e97ad33aSDoug Rabson 	struct vnode *dvp;
1601e97ad33aSDoug Rabson 	struct vnode **vpp;
1602e97ad33aSDoug Rabson 	struct vattr *vap;
1603e97ad33aSDoug Rabson 	struct componentname *cnp;
1604e97ad33aSDoug Rabson 	char *symtgt;
1605e97ad33aSDoug Rabson 	struct p9fs_node *dnp;
1606e97ad33aSDoug Rabson 	struct p9fs_session *vses;
1607e97ad33aSDoug Rabson 	struct mount *mp;
1608e97ad33aSDoug Rabson 	struct p9_fid *dvfid, *newfid;
1609e97ad33aSDoug Rabson 	int error;
1610e97ad33aSDoug Rabson 	char tmpchr;
1611e97ad33aSDoug Rabson 	gid_t gid;
1612e97ad33aSDoug Rabson 
1613e97ad33aSDoug Rabson 	dvp = ap->a_dvp;
1614e97ad33aSDoug Rabson 	vpp = ap->a_vpp;
1615e97ad33aSDoug Rabson 	vap = ap->a_vap;
1616e97ad33aSDoug Rabson 	cnp = ap->a_cnp;
1617e97ad33aSDoug Rabson 	symtgt = (char*)(uintptr_t) ap->a_target;
1618e97ad33aSDoug Rabson 	dnp = P9FS_VTON(dvp);
1619e97ad33aSDoug Rabson 	vses = dnp->p9fs_ses;
1620e97ad33aSDoug Rabson 	mp = vses->p9fs_mount;
1621e97ad33aSDoug Rabson 	newfid = NULL;
1622e97ad33aSDoug Rabson 	error = 0;
1623e97ad33aSDoug Rabson 	gid = vap->va_gid;
1624e97ad33aSDoug Rabson 
1625e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp);
1626e97ad33aSDoug Rabson 
1627e97ad33aSDoug Rabson 	/*
1628e97ad33aSDoug Rabson 	 * Save the character present at namelen in nameptr string and
1629e97ad33aSDoug Rabson 	 * null terminate the character to get the search name for p9_dir_walk
1630e97ad33aSDoug Rabson 	 */
1631e97ad33aSDoug Rabson 	tmpchr = cnp->cn_nameptr[cnp->cn_namelen];
1632e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = '\0';
1633e97ad33aSDoug Rabson 
1634e97ad33aSDoug Rabson 	dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error);
1635e97ad33aSDoug Rabson 	if (error != 0)
1636e97ad33aSDoug Rabson 		goto out;
1637e97ad33aSDoug Rabson 
1638e97ad33aSDoug Rabson 	error = p9_create_symlink(dvfid, cnp->cn_nameptr, symtgt, gid);
1639e97ad33aSDoug Rabson 	if (error != 0)
1640e97ad33aSDoug Rabson 		goto out;
1641e97ad33aSDoug Rabson 
1642e97ad33aSDoug Rabson 	/*create vnode for symtgt */
1643e97ad33aSDoug Rabson 	newfid = p9_client_walk(dvfid, 1, &cnp->cn_nameptr, 1, &error);
1644e97ad33aSDoug Rabson 	if (newfid != NULL) {
1645e97ad33aSDoug Rabson 		error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags,
1646e97ad33aSDoug Rabson 		    dnp, newfid, vpp, cnp->cn_nameptr);
1647e97ad33aSDoug Rabson 		if (error != 0)
1648e97ad33aSDoug Rabson 			goto out;
1649e97ad33aSDoug Rabson 	} else
1650e97ad33aSDoug Rabson 		goto out;
1651e97ad33aSDoug Rabson 
1652e97ad33aSDoug Rabson 	if ((cnp->cn_flags & MAKEENTRY) != 0) {
1653e97ad33aSDoug Rabson 		cache_enter(P9FS_NTOV(dnp), *vpp, cnp);
1654e97ad33aSDoug Rabson 	}
1655e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: created file under vp %p node %p fid %ju\n",
1656e97ad33aSDoug Rabson 	    __func__, *vpp, dnp, (uintmax_t)dvfid->fid);
1657e97ad33aSDoug Rabson 
1658e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = tmpchr;
1659e97ad33aSDoug Rabson 	return (error);
1660e97ad33aSDoug Rabson 
1661e97ad33aSDoug Rabson out:
1662e97ad33aSDoug Rabson 	if (newfid != NULL)
1663e97ad33aSDoug Rabson 		p9_client_clunk(newfid);
1664e97ad33aSDoug Rabson 	cnp->cn_nameptr[cnp->cn_namelen] = tmpchr;
1665e97ad33aSDoug Rabson 	return (error);
1666e97ad33aSDoug Rabson }
1667e97ad33aSDoug Rabson 
1668e97ad33aSDoug Rabson /* Create hard link */
1669e97ad33aSDoug Rabson static int
1670e97ad33aSDoug Rabson p9fs_link(struct vop_link_args *ap)
1671e97ad33aSDoug Rabson {
1672e97ad33aSDoug Rabson 	struct vnode *vp;
1673e97ad33aSDoug Rabson 	struct vnode *tdvp;
1674e97ad33aSDoug Rabson 	struct componentname *cnp;
1675e97ad33aSDoug Rabson 	struct p9fs_node *dnp;
1676e97ad33aSDoug Rabson 	struct p9fs_node *np;
1677e97ad33aSDoug Rabson 	struct p9fs_inode *inode;
1678e97ad33aSDoug Rabson 	struct p9fs_session *vses;
1679e97ad33aSDoug Rabson 	struct p9_fid *dvfid, *oldvfid;
1680e97ad33aSDoug Rabson 	int error;
1681e97ad33aSDoug Rabson 
1682e97ad33aSDoug Rabson 	vp = ap->a_vp;
1683e97ad33aSDoug Rabson 	tdvp = ap->a_tdvp;
1684e97ad33aSDoug Rabson 	cnp = ap->a_cnp;
1685e97ad33aSDoug Rabson 	dnp = P9FS_VTON(tdvp);
1686e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
1687e97ad33aSDoug Rabson 	inode = &np->inode;
1688e97ad33aSDoug Rabson 	vses = np->p9fs_ses;
1689e97ad33aSDoug Rabson 	error = 0;
1690e97ad33aSDoug Rabson 
1691e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: tdvp %p vp %p\n", __func__, tdvp, vp);
1692e97ad33aSDoug Rabson 
1693e97ad33aSDoug Rabson 	dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error);
1694e97ad33aSDoug Rabson 	if (error != 0)
1695e97ad33aSDoug Rabson 		return (error);
1696e97ad33aSDoug Rabson 	oldvfid = p9fs_get_fid(vses->clnt, np, cnp->cn_cred, VFID, -1, &error);
1697e97ad33aSDoug Rabson 	if (error != 0)
1698e97ad33aSDoug Rabson 		return (error);
1699e97ad33aSDoug Rabson 
1700e97ad33aSDoug Rabson 	error = p9_create_hardlink(dvfid, oldvfid, cnp->cn_nameptr);
1701e97ad33aSDoug Rabson 	if (error != 0)
1702e97ad33aSDoug Rabson 		return (error);
1703e97ad33aSDoug Rabson 	/* Increment ref count on the inode */
1704e97ad33aSDoug Rabson 	P9FS_INCR_LINKS(inode);
1705e97ad33aSDoug Rabson 
1706e97ad33aSDoug Rabson 	return (0);
1707e97ad33aSDoug Rabson }
1708e97ad33aSDoug Rabson 
1709e97ad33aSDoug Rabson /* Read contents of the symbolic link */
1710e97ad33aSDoug Rabson static int
1711e97ad33aSDoug Rabson p9fs_readlink(struct vop_readlink_args *ap)
1712e97ad33aSDoug Rabson {
1713e97ad33aSDoug Rabson 	struct vnode *vp;
1714e97ad33aSDoug Rabson 	struct uio *uio;
1715e97ad33aSDoug Rabson 	struct p9fs_node *dnp;
1716e97ad33aSDoug Rabson 	struct p9fs_session *vses;
1717e97ad33aSDoug Rabson 	struct p9_fid *dvfid;
1718e97ad33aSDoug Rabson 	int error, len;
1719e97ad33aSDoug Rabson 	char *target;
1720e97ad33aSDoug Rabson 
1721e97ad33aSDoug Rabson 	vp = ap->a_vp;
1722e97ad33aSDoug Rabson 	uio = ap->a_uio;
1723e97ad33aSDoug Rabson 	dnp = P9FS_VTON(vp);
1724e97ad33aSDoug Rabson 	vses = dnp->p9fs_ses;
1725e97ad33aSDoug Rabson 	error = 0;
1726e97ad33aSDoug Rabson 
1727e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp %p\n", __func__, vp);
1728e97ad33aSDoug Rabson 
1729e97ad33aSDoug Rabson 	dvfid = p9fs_get_fid(vses->clnt, dnp, ap->a_cred, VFID, -1, &error);
1730e97ad33aSDoug Rabson 	if (error != 0)
1731e97ad33aSDoug Rabson 		return (error);
1732e97ad33aSDoug Rabson 
1733e97ad33aSDoug Rabson 	error = p9_readlink(dvfid, &target);
1734e97ad33aSDoug Rabson 	if (error != 0)
1735e97ad33aSDoug Rabson 		return (error);
1736e97ad33aSDoug Rabson 
1737e97ad33aSDoug Rabson 	len = strlen(target);
1738e97ad33aSDoug Rabson 	error = uiomove(target, len, uio);
1739e97ad33aSDoug Rabson 
1740e97ad33aSDoug Rabson 	return (0);
1741e97ad33aSDoug Rabson }
1742e97ad33aSDoug Rabson 
1743e97ad33aSDoug Rabson /*
1744e97ad33aSDoug Rabson  * Iterate through a directory. An entire 8k data is read into the I/O buffer.
1745e97ad33aSDoug Rabson  * This buffer is parsed to make dir entries and fed to the user buffer to
1746e97ad33aSDoug Rabson  * complete it to the VFS.
1747e97ad33aSDoug Rabson  */
1748e97ad33aSDoug Rabson static int
1749e97ad33aSDoug Rabson p9fs_readdir(struct vop_readdir_args *ap)
1750e97ad33aSDoug Rabson {
1751e97ad33aSDoug Rabson 	struct uio *uio;
1752e97ad33aSDoug Rabson 	struct vnode *vp;
1753e97ad33aSDoug Rabson 	struct dirent cde;
1754e97ad33aSDoug Rabson 	int64_t offset;
1755e97ad33aSDoug Rabson 	uint64_t diroffset;
1756e97ad33aSDoug Rabson 	struct p9fs_node *np;
1757e97ad33aSDoug Rabson 	int error;
1758e97ad33aSDoug Rabson 	int32_t count;
1759e97ad33aSDoug Rabson 	struct p9_client *clnt;
1760e97ad33aSDoug Rabson 	struct p9_dirent dent;
1761e97ad33aSDoug Rabson 	char *io_buffer;
1762e97ad33aSDoug Rabson 	struct p9_fid *vofid;
1763e97ad33aSDoug Rabson 
1764e97ad33aSDoug Rabson 	uio = ap->a_uio;
1765e97ad33aSDoug Rabson 	vp = ap->a_vp;
1766e97ad33aSDoug Rabson 	np = P9FS_VTON(ap->a_vp);
1767e97ad33aSDoug Rabson 	offset = 0;
1768e97ad33aSDoug Rabson 	diroffset = 0;
1769e97ad33aSDoug Rabson 	error = 0;
1770e97ad33aSDoug Rabson 	count = 0;
1771e97ad33aSDoug Rabson 	clnt = np->p9fs_ses->clnt;
1772e97ad33aSDoug Rabson 
1773b2ebcd19SDoug Rabson 	P9_DEBUG(VOPS, "%s: vp %p, offset %jd, resid %zd\n", __func__, vp, (intmax_t) uio->uio_offset, uio->uio_resid);
1774e97ad33aSDoug Rabson 
1775e97ad33aSDoug Rabson 	if (ap->a_uio->uio_iov->iov_len <= 0)
1776e97ad33aSDoug Rabson 		return (EINVAL);
1777e97ad33aSDoug Rabson 
1778e97ad33aSDoug Rabson 	if (vp->v_type != VDIR)
1779e97ad33aSDoug Rabson 		return (ENOTDIR);
1780e97ad33aSDoug Rabson 
1781e97ad33aSDoug Rabson 	vofid = p9fs_get_fid(clnt, np, ap->a_cred, VOFID, P9PROTO_OREAD, &error);
1782e97ad33aSDoug Rabson 	if (vofid == NULL) {
1783e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: NULL FID\n", __func__);
1784e97ad33aSDoug Rabson 		return (EBADF);
1785e97ad33aSDoug Rabson 	}
1786e97ad33aSDoug Rabson 
1787e97ad33aSDoug Rabson 	io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK);
1788e97ad33aSDoug Rabson 
1789e97ad33aSDoug Rabson 	/* We haven't reached the end yet. read more. */
1790e97ad33aSDoug Rabson 	diroffset = uio->uio_offset;
1791e97ad33aSDoug Rabson 	while (uio->uio_resid >= sizeof(struct dirent)) {
1792e97ad33aSDoug Rabson 		/*
1793e97ad33aSDoug Rabson 		 * We need to read more data as what is indicated by filesize because
1794e97ad33aSDoug Rabson 		 * filesize is based on data stored in struct dirent structure but
1795e97ad33aSDoug Rabson 		 * we read data in struct p9_dirent format which has different size.
1796e97ad33aSDoug Rabson 		 * Hence we read max data(P9FS_IOUNIT) everytime from host, convert
1797e97ad33aSDoug Rabson 		 * it into struct dirent structure and send it back.
1798e97ad33aSDoug Rabson 		 */
1799e97ad33aSDoug Rabson 		count = P9FS_IOUNIT;
1800e97ad33aSDoug Rabson 		bzero(io_buffer, P9FS_MTU);
1801e97ad33aSDoug Rabson 		count = p9_client_readdir(vofid, (char *)io_buffer,
1802e97ad33aSDoug Rabson 		    diroffset, count);
1803e97ad33aSDoug Rabson 
1804e97ad33aSDoug Rabson 		if (count == 0)
1805e97ad33aSDoug Rabson 			break;
1806e97ad33aSDoug Rabson 
1807e97ad33aSDoug Rabson 		if (count < 0) {
1808e97ad33aSDoug Rabson 			error = EIO;
1809e97ad33aSDoug Rabson 			goto out;
1810e97ad33aSDoug Rabson 		}
1811e97ad33aSDoug Rabson 
1812e97ad33aSDoug Rabson 		offset = 0;
1813e97ad33aSDoug Rabson 		while (offset + QEMU_DIRENTRY_SZ <= count) {
1814e97ad33aSDoug Rabson 
1815e97ad33aSDoug Rabson 			/*
1816e97ad33aSDoug Rabson 			 * Read and make sense out of the buffer in one dirent
1817e97ad33aSDoug Rabson 			 * This is part of 9p protocol read. This reads one p9_dirent,
1818e97ad33aSDoug Rabson 			 * appends it to dirent(FREEBSD specifc) and continues to parse the buffer.
1819e97ad33aSDoug Rabson 			 */
1820e97ad33aSDoug Rabson 			bzero(&dent, sizeof(dent));
1821e97ad33aSDoug Rabson 			offset = p9_dirent_read(clnt, io_buffer, offset, count,
1822e97ad33aSDoug Rabson 				&dent);
1823e97ad33aSDoug Rabson 			if (offset < 0 || offset > count) {
1824e97ad33aSDoug Rabson 				error = EIO;
1825e97ad33aSDoug Rabson 				goto out;
1826e97ad33aSDoug Rabson 			}
1827e97ad33aSDoug Rabson 
1828e97ad33aSDoug Rabson 			bzero(&cde, sizeof(cde));
1829e97ad33aSDoug Rabson 			strncpy(cde.d_name, dent.d_name, dent.len);
1830e97ad33aSDoug Rabson 			cde.d_fileno = dent.qid.path;
1831e97ad33aSDoug Rabson 			cde.d_type = dent.d_type;
1832e97ad33aSDoug Rabson 			cde.d_namlen = dent.len;
1833e97ad33aSDoug Rabson 			cde.d_reclen = GENERIC_DIRSIZ(&cde);
1834e97ad33aSDoug Rabson 
1835e97ad33aSDoug Rabson                         /*
1836e97ad33aSDoug Rabson                          * If there isn't enough space in the uio to return a
1837e97ad33aSDoug Rabson                          * whole dirent, break off read
1838e97ad33aSDoug Rabson                          */
1839e97ad33aSDoug Rabson                         if (uio->uio_resid < GENERIC_DIRSIZ(&cde))
1840e97ad33aSDoug Rabson                                 break;
1841e97ad33aSDoug Rabson 
1842e97ad33aSDoug Rabson 			/* Transfer */
1843e97ad33aSDoug Rabson 			error = uiomove(&cde, GENERIC_DIRSIZ(&cde), uio);
1844e97ad33aSDoug Rabson 			if (error != 0) {
1845e97ad33aSDoug Rabson 				error = EIO;
1846e97ad33aSDoug Rabson 				goto out;
1847e97ad33aSDoug Rabson 			}
1848e97ad33aSDoug Rabson 			diroffset = dent.d_off;
1849e97ad33aSDoug Rabson 		}
1850e97ad33aSDoug Rabson 	}
1851e97ad33aSDoug Rabson 	/* Pass on last transferred offset */
1852e97ad33aSDoug Rabson 	uio->uio_offset = diroffset;
1853e97ad33aSDoug Rabson 
1854e97ad33aSDoug Rabson out:
1855e97ad33aSDoug Rabson 	uma_zfree(p9fs_io_buffer_zone, io_buffer);
1856e97ad33aSDoug Rabson 
1857e97ad33aSDoug Rabson 	return (error);
1858e97ad33aSDoug Rabson }
1859e97ad33aSDoug Rabson 
1860e97ad33aSDoug Rabson static void
1861e97ad33aSDoug Rabson p9fs_doio(struct vnode *vp, struct buf *bp, struct p9_fid *vofid, struct ucred *cr)
1862e97ad33aSDoug Rabson {
1863e97ad33aSDoug Rabson 	struct uio *uiov;
1864e97ad33aSDoug Rabson 	struct iovec io;
1865e97ad33aSDoug Rabson 	int error;
1866e97ad33aSDoug Rabson 	uint64_t off, offset;
1867e97ad33aSDoug Rabson 	uint64_t filesize;
1868e97ad33aSDoug Rabson 	uint64_t resid;
1869e97ad33aSDoug Rabson 	uint32_t count;
1870e97ad33aSDoug Rabson 	int64_t ret;
1871e97ad33aSDoug Rabson 	struct p9fs_node *np;
1872e97ad33aSDoug Rabson 	char *io_buffer;
1873e97ad33aSDoug Rabson 
1874e97ad33aSDoug Rabson 	error = 0;
1875e97ad33aSDoug Rabson 	np = P9FS_VTON(vp);
1876e97ad33aSDoug Rabson 
1877e97ad33aSDoug Rabson 	filesize = np->inode.i_size;
1878e97ad33aSDoug Rabson 	uiov = malloc(sizeof(struct uio), M_P9UIOV, M_WAITOK);
1879e97ad33aSDoug Rabson 	uiov->uio_iov = &io;
1880e97ad33aSDoug Rabson 	uiov->uio_iovcnt = 1;
1881e97ad33aSDoug Rabson 	uiov->uio_segflg = UIO_SYSSPACE;
1882e97ad33aSDoug Rabson 	io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK | M_ZERO);
1883e97ad33aSDoug Rabson 
1884e97ad33aSDoug Rabson 	if (bp->b_iocmd == BIO_READ) {
1885e97ad33aSDoug Rabson 		io.iov_len = uiov->uio_resid = bp->b_bcount;
1886e97ad33aSDoug Rabson 		io.iov_base = bp->b_data;
1887e97ad33aSDoug Rabson 		uiov->uio_rw = UIO_READ;
1888e97ad33aSDoug Rabson 
1889e97ad33aSDoug Rabson 		switch (vp->v_type) {
1890e97ad33aSDoug Rabson 
1891e97ad33aSDoug Rabson 		case VREG:
1892e97ad33aSDoug Rabson 		{
1893e97ad33aSDoug Rabson 			uiov->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
1894e97ad33aSDoug Rabson 
1895e97ad33aSDoug Rabson 			if (uiov->uio_resid) {
1896e97ad33aSDoug Rabson 				int left = uiov->uio_resid;
1897e97ad33aSDoug Rabson 				int nread = bp->b_bcount - left;
1898e97ad33aSDoug Rabson 
1899e97ad33aSDoug Rabson 				if (left > 0)
1900e97ad33aSDoug Rabson 					bzero((char *)bp->b_data + nread, left);
1901e97ad33aSDoug Rabson 			}
1902e97ad33aSDoug Rabson 			/* where in the file are we to start reading */
1903e97ad33aSDoug Rabson 			offset = uiov->uio_offset;
1904e97ad33aSDoug Rabson 			if (uiov->uio_offset >= filesize)
1905e97ad33aSDoug Rabson 				goto out;
1906e97ad33aSDoug Rabson 
1907e97ad33aSDoug Rabson 			while ((resid = uiov->uio_resid) > 0) {
1908e97ad33aSDoug Rabson 				if (offset >= filesize)
1909e97ad33aSDoug Rabson 					break;
1910e97ad33aSDoug Rabson 				count = min(filesize - uiov->uio_offset, resid);
1911e97ad33aSDoug Rabson 				if (count == 0)
1912e97ad33aSDoug Rabson 					break;
1913e97ad33aSDoug Rabson 
1914e97ad33aSDoug Rabson 				P9_DEBUG(VOPS, "%s: read called %#zx at %#jx\n",
1915e97ad33aSDoug Rabson 				    __func__, uiov->uio_resid, (uintmax_t)uiov->uio_offset);
1916e97ad33aSDoug Rabson 
1917e97ad33aSDoug Rabson 				/* Copy count bytes into the uio */
1918e97ad33aSDoug Rabson 				ret = p9_client_read(vofid, offset, count, io_buffer);
1919e97ad33aSDoug Rabson 				error = uiomove(io_buffer, ret, uiov);
1920e97ad33aSDoug Rabson 
1921e97ad33aSDoug Rabson 				if (error != 0)
1922e97ad33aSDoug Rabson 					goto out;
1923e97ad33aSDoug Rabson 				offset += ret;
1924e97ad33aSDoug Rabson 			}
1925e97ad33aSDoug Rabson 			break;
1926e97ad33aSDoug Rabson 		}
1927e97ad33aSDoug Rabson 		default:
1928e97ad33aSDoug Rabson 			printf("vfs:  type %x unexpected\n", vp->v_type);
1929e97ad33aSDoug Rabson 			break;
1930e97ad33aSDoug Rabson 		}
1931e97ad33aSDoug Rabson 	} else {
1932e97ad33aSDoug Rabson 		if (bp->b_dirtyend > bp->b_dirtyoff) {
1933e97ad33aSDoug Rabson 			io.iov_len = uiov->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
1934e97ad33aSDoug Rabson 			uiov->uio_offset = ((off_t)bp->b_blkno) * PAGE_SIZE + bp->b_dirtyoff;
1935e97ad33aSDoug Rabson 			io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
1936e97ad33aSDoug Rabson 			uiov->uio_rw = UIO_WRITE;
1937e97ad33aSDoug Rabson 
1938e97ad33aSDoug Rabson 			if (uiov->uio_offset < 0) {
1939e97ad33aSDoug Rabson 				error = EINVAL;
1940e97ad33aSDoug Rabson 				goto out;
1941e97ad33aSDoug Rabson 			}
1942e97ad33aSDoug Rabson 
1943e97ad33aSDoug Rabson 			if (uiov->uio_resid == 0)
1944e97ad33aSDoug Rabson 				goto out;
1945e97ad33aSDoug Rabson 
1946e97ad33aSDoug Rabson 			resid = uiov->uio_resid;
1947e97ad33aSDoug Rabson 			offset = uiov->uio_offset;
1948e97ad33aSDoug Rabson 			error = 0;
1949e97ad33aSDoug Rabson 
1950e97ad33aSDoug Rabson 			while ((resid = uiov->uio_resid) > 0) {
1951e97ad33aSDoug Rabson                                 off = 0;
1952e97ad33aSDoug Rabson 				count = MIN(resid, P9FS_IOUNIT);
1953e97ad33aSDoug Rabson 				error = uiomove(io_buffer, count, uiov);
1954e97ad33aSDoug Rabson 				if (error != 0) {
1955e97ad33aSDoug Rabson 					goto out;
1956e97ad33aSDoug Rabson 				}
1957e97ad33aSDoug Rabson 
1958e97ad33aSDoug Rabson 				while (count > 0) {
1959e97ad33aSDoug Rabson 					/* Copy count bytes from the uio */
1960e97ad33aSDoug Rabson 					ret = p9_client_write(vofid, offset, count,
1961e97ad33aSDoug Rabson                                                 io_buffer + off);
1962e97ad33aSDoug Rabson 					if (ret < 0)
1963e97ad33aSDoug Rabson 						goto out;
1964e97ad33aSDoug Rabson 
1965e97ad33aSDoug Rabson 					P9_DEBUG(VOPS, "%s: write called %#zx at %#jx\n",
1966e97ad33aSDoug Rabson 					    __func__, uiov->uio_resid, (uintmax_t)uiov->uio_offset);
1967e97ad33aSDoug Rabson                                         off += ret;
1968e97ad33aSDoug Rabson 					offset += ret;
1969e97ad33aSDoug Rabson 					count -= ret;
1970e97ad33aSDoug Rabson 				}
1971e97ad33aSDoug Rabson 			}
1972e97ad33aSDoug Rabson 
1973e97ad33aSDoug Rabson 			/* Update the fields in the node to reflect the change */
1974e97ad33aSDoug Rabson 			if (filesize < uiov->uio_offset + uiov->uio_resid) {
1975e97ad33aSDoug Rabson 				np->inode.i_size = uiov->uio_offset + uiov->uio_resid;
1976e97ad33aSDoug Rabson 				vnode_pager_setsize(vp, uiov->uio_offset + uiov->uio_resid);
1977e97ad33aSDoug Rabson 				/* update the modified timers. */
1978e97ad33aSDoug Rabson 				p9fs_itimes(vp);
1979e97ad33aSDoug Rabson 			}
1980e97ad33aSDoug Rabson 		} else {
1981e97ad33aSDoug Rabson 			 bp->b_resid = 0;
1982e97ad33aSDoug Rabson 			 goto out1;
1983e97ad33aSDoug Rabson 		}
1984e97ad33aSDoug Rabson 	}
1985e97ad33aSDoug Rabson out:
1986e97ad33aSDoug Rabson 	/* Set the error */
1987e97ad33aSDoug Rabson 	if (error != 0) {
1988e97ad33aSDoug Rabson 		bp->b_error = error;
1989e97ad33aSDoug Rabson 		bp->b_ioflags |= BIO_ERROR;
1990e97ad33aSDoug Rabson 	}
1991e97ad33aSDoug Rabson 	bp->b_resid = uiov->uio_resid;
1992e97ad33aSDoug Rabson out1:
1993e97ad33aSDoug Rabson 	bufdone(bp);
1994e97ad33aSDoug Rabson 	uma_zfree(p9fs_io_buffer_zone, io_buffer);
1995e97ad33aSDoug Rabson 	free(uiov, M_P9UIOV);
1996e97ad33aSDoug Rabson }
1997e97ad33aSDoug Rabson 
1998e97ad33aSDoug Rabson /*
1999e97ad33aSDoug Rabson  * The I/O buffer is mapped to a uio and a client_write/client_read is performed
2000e97ad33aSDoug Rabson  * the same way as p9fs_read and p9fs_write.
2001e97ad33aSDoug Rabson  */
2002e97ad33aSDoug Rabson static int
2003e97ad33aSDoug Rabson p9fs_strategy(struct vop_strategy_args *ap)
2004e97ad33aSDoug Rabson {
2005e97ad33aSDoug Rabson 	struct vnode *vp;
2006e97ad33aSDoug Rabson 	struct buf *bp;
2007e97ad33aSDoug Rabson 	struct ucred *cr;
2008e97ad33aSDoug Rabson 	int error;
2009e97ad33aSDoug Rabson 	struct open_fid_state ostate;
2010e97ad33aSDoug Rabson 
2011e97ad33aSDoug Rabson 	vp = ap->a_vp;
2012e97ad33aSDoug Rabson 	bp = ap->a_bp;
2013e97ad33aSDoug Rabson 	error = 0;
2014e97ad33aSDoug Rabson 
2015e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: vp %p, iocmd %d\n ", __func__, vp, bp->b_iocmd);
2016e97ad33aSDoug Rabson 
2017e97ad33aSDoug Rabson 	if (bp->b_iocmd == BIO_READ)
2018e97ad33aSDoug Rabson 		cr = bp->b_rcred;
2019e97ad33aSDoug Rabson 	else
2020e97ad33aSDoug Rabson 		cr = bp->b_wcred;
2021e97ad33aSDoug Rabson 
2022e97ad33aSDoug Rabson 	error = p9fs_get_open_fid(vp, bp->b_iocmd == BIO_READ ? FREAD : FWRITE, cr, &ostate);
2023e97ad33aSDoug Rabson 	if (error) {
2024e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p9fs_get_open_fid failed: %d\n", __func__, error);
2025e97ad33aSDoug Rabson 		bp->b_error = error;
2026e97ad33aSDoug Rabson 		bp->b_ioflags |= BIO_ERROR;
2027e97ad33aSDoug Rabson 		bufdone(bp);
2028e97ad33aSDoug Rabson 		return (0);
2029e97ad33aSDoug Rabson 	}
2030e97ad33aSDoug Rabson 
2031e97ad33aSDoug Rabson 	p9fs_doio(vp, bp, ostate.vofid, cr);
2032e97ad33aSDoug Rabson 	p9fs_release_open_fid(vp, cr, &ostate);
2033e97ad33aSDoug Rabson 
2034e97ad33aSDoug Rabson 	return (0);
2035e97ad33aSDoug Rabson }
2036e97ad33aSDoug Rabson 
2037e97ad33aSDoug Rabson /* Rename a file */
2038e97ad33aSDoug Rabson static int
2039e97ad33aSDoug Rabson p9fs_rename(struct vop_rename_args *ap)
2040e97ad33aSDoug Rabson {
2041e97ad33aSDoug Rabson 	struct vnode *tvp;
2042e97ad33aSDoug Rabson 	struct vnode *tdvp;
2043e97ad33aSDoug Rabson 	struct vnode *fvp;
2044e97ad33aSDoug Rabson 	struct vnode *fdvp;
2045e97ad33aSDoug Rabson 	struct componentname *tcnp;
2046e97ad33aSDoug Rabson 	struct componentname *fcnp;
2047e97ad33aSDoug Rabson 	struct p9fs_node *tdnode;
2048e97ad33aSDoug Rabson 	struct p9fs_node *fdnode;
2049e97ad33aSDoug Rabson 	struct p9fs_inode *fdinode;
2050e97ad33aSDoug Rabson 	struct p9fs_node *fnode;
2051e97ad33aSDoug Rabson 	struct p9fs_inode *finode;
2052e97ad33aSDoug Rabson 	struct p9fs_session *vses;
2053e97ad33aSDoug Rabson 	struct p9fs_node *tnode;
2054e97ad33aSDoug Rabson 	struct p9fs_inode *tinode;
2055e97ad33aSDoug Rabson 	struct p9_fid *olddirvfid, *newdirvfid ;
2056e97ad33aSDoug Rabson 	int error;
2057e97ad33aSDoug Rabson 
2058e97ad33aSDoug Rabson 	tvp = ap->a_tvp;
2059e97ad33aSDoug Rabson 	tdvp = ap->a_tdvp;
2060e97ad33aSDoug Rabson 	fvp = ap->a_fvp;
2061e97ad33aSDoug Rabson 	fdvp = ap->a_fdvp;
2062e97ad33aSDoug Rabson 	tcnp = ap->a_tcnp;
2063e97ad33aSDoug Rabson 	fcnp = ap->a_fcnp;
2064e97ad33aSDoug Rabson 	tdnode = P9FS_VTON(tdvp);
2065e97ad33aSDoug Rabson 	fdnode = P9FS_VTON(fdvp);
2066e97ad33aSDoug Rabson 	fdinode = &fdnode->inode;
2067e97ad33aSDoug Rabson 	fnode = P9FS_VTON(fvp);
2068e97ad33aSDoug Rabson 	finode = &fnode->inode;
2069e97ad33aSDoug Rabson 	vses = fnode->p9fs_ses;
2070e97ad33aSDoug Rabson 	error = 0;
2071e97ad33aSDoug Rabson 
2072e97ad33aSDoug Rabson 	P9_DEBUG(VOPS, "%s: tvp %p, tdvp %p, fvp %p, fdvp %p\n ", __func__, tvp, tdvp, fvp, fdvp);
2073e97ad33aSDoug Rabson 
2074e97ad33aSDoug Rabson 	/* Check for cross mount operation */
2075e97ad33aSDoug Rabson 	if (fvp->v_mount != tdvp->v_mount ||
2076e97ad33aSDoug Rabson 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
2077e97ad33aSDoug Rabson 		error = EXDEV;
2078e97ad33aSDoug Rabson 		goto out;
2079e97ad33aSDoug Rabson 	}
2080e97ad33aSDoug Rabson 
2081e97ad33aSDoug Rabson 	/* warning  if you are renaming to the same name */
2082e97ad33aSDoug Rabson 	if (fvp == tvp)
2083e97ad33aSDoug Rabson 		error = 0;
2084e97ad33aSDoug Rabson 
2085e97ad33aSDoug Rabson 	olddirvfid = p9fs_get_fid(vses->clnt, fdnode, fcnp->cn_cred, VFID, -1, &error);
2086e97ad33aSDoug Rabson 	if (error != 0)
2087e97ad33aSDoug Rabson 		goto out;
2088e97ad33aSDoug Rabson 	newdirvfid = p9fs_get_fid(vses->clnt, tdnode, tcnp->cn_cred, VFID, -1, &error);
2089e97ad33aSDoug Rabson 	if (error != 0)
2090e97ad33aSDoug Rabson 		goto out;
2091e97ad33aSDoug Rabson 
2092e97ad33aSDoug Rabson 	error = p9_client_renameat(olddirvfid, fcnp->cn_nameptr, newdirvfid, tcnp->cn_nameptr);
2093e97ad33aSDoug Rabson 	if (error != 0)
2094e97ad33aSDoug Rabson 		goto out;
2095e97ad33aSDoug Rabson 
2096e97ad33aSDoug Rabson 	/*
2097e97ad33aSDoug Rabson 	 * decrement the link count on the "from" file whose name is going
2098e97ad33aSDoug Rabson 	 * to be changed if its a directory
2099e97ad33aSDoug Rabson 	 */
2100e97ad33aSDoug Rabson 	if (fvp->v_type == VDIR) {
2101e97ad33aSDoug Rabson 		if (tvp && tvp->v_type == VDIR)
2102e97ad33aSDoug Rabson 			cache_purge(tdvp);
2103e97ad33aSDoug Rabson 		P9FS_DECR_LINKS(fdinode);
2104e97ad33aSDoug Rabson 		cache_purge(fdvp);
2105e97ad33aSDoug Rabson 	}
2106e97ad33aSDoug Rabson 
2107e97ad33aSDoug Rabson 	/* Taking exclusive lock on the from node before decrementing the link count */
2108e97ad33aSDoug Rabson 	if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
2109e97ad33aSDoug Rabson 		goto out;
2110e97ad33aSDoug Rabson 	P9FS_DECR_LINKS(finode);
2111e97ad33aSDoug Rabson 	VOP_UNLOCK(fvp);
2112e97ad33aSDoug Rabson 
2113e97ad33aSDoug Rabson 	if (tvp) {
2114e97ad33aSDoug Rabson 		tnode = P9FS_VTON(tvp);
2115e97ad33aSDoug Rabson 		tinode = &tnode->inode;
2116e97ad33aSDoug Rabson 		P9FS_DECR_LINKS(tinode);
2117e97ad33aSDoug Rabson 	}
2118e97ad33aSDoug Rabson 
2119e97ad33aSDoug Rabson out:
2120e97ad33aSDoug Rabson 	if (tdvp == tvp)
2121e97ad33aSDoug Rabson 		vrele(tdvp);
2122e97ad33aSDoug Rabson 	else
2123e97ad33aSDoug Rabson 		vput(tdvp);
2124e97ad33aSDoug Rabson 	if (tvp)
2125e97ad33aSDoug Rabson 		vput(tvp);
2126e97ad33aSDoug Rabson 	vrele(fdvp);
2127e97ad33aSDoug Rabson 	vrele(fvp);
2128e97ad33aSDoug Rabson 	return (error);
2129e97ad33aSDoug Rabson }
2130e97ad33aSDoug Rabson 
2131daa2c99cSVal Packett /*
2132daa2c99cSVal Packett  * Put VM pages, synchronously.
2133daa2c99cSVal Packett  * XXX: like smbfs, cannot use vop_stdputpages due to mapping requirement
2134daa2c99cSVal Packett  */
2135daa2c99cSVal Packett static int
2136daa2c99cSVal Packett p9fs_putpages(struct vop_putpages_args *ap)
2137daa2c99cSVal Packett {
2138daa2c99cSVal Packett 	struct uio uio;
2139daa2c99cSVal Packett 	struct iovec iov;
2140daa2c99cSVal Packett 	int i, error, npages, count;
2141daa2c99cSVal Packett 	off_t offset;
2142daa2c99cSVal Packett 	int *rtvals;
2143daa2c99cSVal Packett 	struct vnode *vp;
2144daa2c99cSVal Packett 	struct thread *td;
2145daa2c99cSVal Packett 	struct ucred *cred;
2146daa2c99cSVal Packett 	struct p9fs_node *np;
2147daa2c99cSVal Packett 	vm_page_t *pages;
2148daa2c99cSVal Packett 	vm_offset_t kva;
2149daa2c99cSVal Packett 	struct buf *bp;
2150daa2c99cSVal Packett 
2151daa2c99cSVal Packett 	vp = ap->a_vp;
2152daa2c99cSVal Packett 	np = P9FS_VTON(vp);
2153daa2c99cSVal Packett 	td = curthread;
2154daa2c99cSVal Packett 	cred = curthread->td_ucred;
2155daa2c99cSVal Packett 	pages = ap->a_m;
2156daa2c99cSVal Packett 	count = ap->a_count;
2157daa2c99cSVal Packett 	rtvals = ap->a_rtvals;
2158daa2c99cSVal Packett 	npages = btoc(count);
2159daa2c99cSVal Packett 	offset = IDX_TO_OFF(pages[0]->pindex);
2160daa2c99cSVal Packett 
2161daa2c99cSVal Packett 	/*
2162daa2c99cSVal Packett 	 * When putting pages, do not extend file past EOF.
2163daa2c99cSVal Packett 	 */
2164daa2c99cSVal Packett 	if (offset + count > np->inode.i_size) {
2165daa2c99cSVal Packett 		count = np->inode.i_size - offset;
2166daa2c99cSVal Packett 		if (count < 0)
2167daa2c99cSVal Packett 			count = 0;
2168daa2c99cSVal Packett 	}
2169daa2c99cSVal Packett 
2170daa2c99cSVal Packett 	for (i = 0; i < npages; i++)
2171daa2c99cSVal Packett 		rtvals[i] = VM_PAGER_ERROR;
2172daa2c99cSVal Packett 
2173daa2c99cSVal Packett 	bp = uma_zalloc(p9fs_pbuf_zone, M_WAITOK);
2174daa2c99cSVal Packett 	kva = (vm_offset_t) bp->b_data;
2175daa2c99cSVal Packett 	pmap_qenter(kva, pages, npages);
2176daa2c99cSVal Packett 
2177daa2c99cSVal Packett 	VM_CNT_INC(v_vnodeout);
2178daa2c99cSVal Packett 	VM_CNT_ADD(v_vnodepgsout, count);
2179daa2c99cSVal Packett 
2180daa2c99cSVal Packett 	iov.iov_base = (caddr_t) kva;
2181daa2c99cSVal Packett 	iov.iov_len = count;
2182daa2c99cSVal Packett 	uio.uio_iov = &iov;
2183daa2c99cSVal Packett 	uio.uio_iovcnt = 1;
2184daa2c99cSVal Packett 	uio.uio_offset = offset;
2185daa2c99cSVal Packett 	uio.uio_resid = count;
2186daa2c99cSVal Packett 	uio.uio_segflg = UIO_SYSSPACE;
2187daa2c99cSVal Packett 	uio.uio_rw = UIO_WRITE;
2188daa2c99cSVal Packett 	uio.uio_td = td;
2189daa2c99cSVal Packett 
2190daa2c99cSVal Packett 	P9_DEBUG(VOPS, "of=%jd,resid=%zd\n", (intmax_t)uio.uio_offset, uio.uio_resid);
2191daa2c99cSVal Packett 
2192daa2c99cSVal Packett 	error = VOP_WRITE(vp, &uio, vnode_pager_putpages_ioflags(ap->a_sync),
2193daa2c99cSVal Packett 	    cred);
2194daa2c99cSVal Packett 
2195daa2c99cSVal Packett 	pmap_qremove(kva, npages);
2196daa2c99cSVal Packett 	uma_zfree(p9fs_pbuf_zone, bp);
2197daa2c99cSVal Packett 
2198daa2c99cSVal Packett 	if (error == 0)
2199daa2c99cSVal Packett 		vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid,
2200daa2c99cSVal Packett 		    np->inode.i_size - offset, npages * PAGE_SIZE);
2201daa2c99cSVal Packett 
2202daa2c99cSVal Packett 	return (rtvals[0]);
2203daa2c99cSVal Packett }
2204e97ad33aSDoug Rabson 
2205e97ad33aSDoug Rabson struct vop_vector p9fs_vnops = {
2206e97ad33aSDoug Rabson 	.vop_default =		&default_vnodeops,
2207e97ad33aSDoug Rabson 	.vop_lookup =		p9fs_lookup,
2208e97ad33aSDoug Rabson 	.vop_open =		p9fs_open,
2209e97ad33aSDoug Rabson 	.vop_close =		p9fs_close,
2210e97ad33aSDoug Rabson 	.vop_access =		p9fs_access,
2211e97ad33aSDoug Rabson 	.vop_getattr =		p9fs_getattr_dotl,
2212e97ad33aSDoug Rabson 	.vop_setattr =		p9fs_setattr_dotl,
2213e97ad33aSDoug Rabson 	.vop_reclaim =		p9fs_reclaim,
2214e97ad33aSDoug Rabson 	.vop_inactive =		p9fs_inactive,
2215e97ad33aSDoug Rabson 	.vop_readdir =		p9fs_readdir,
2216e97ad33aSDoug Rabson 	.vop_create =		p9fs_create,
2217e97ad33aSDoug Rabson 	.vop_mknod =		p9fs_mknod,
2218e97ad33aSDoug Rabson 	.vop_read =		p9fs_read,
2219e97ad33aSDoug Rabson 	.vop_write =		p9fs_write,
2220e97ad33aSDoug Rabson 	.vop_remove =		p9fs_remove,
2221e97ad33aSDoug Rabson 	.vop_mkdir =		p9fs_mkdir,
2222e97ad33aSDoug Rabson 	.vop_rmdir =		p9fs_rmdir,
2223e97ad33aSDoug Rabson 	.vop_strategy =		p9fs_strategy,
2224e97ad33aSDoug Rabson 	.vop_symlink =		p9fs_symlink,
2225e97ad33aSDoug Rabson 	.vop_rename =           p9fs_rename,
2226e97ad33aSDoug Rabson 	.vop_link =		p9fs_link,
2227e97ad33aSDoug Rabson 	.vop_readlink =		p9fs_readlink,
2228daa2c99cSVal Packett 	.vop_putpages =		p9fs_putpages,
2229e97ad33aSDoug Rabson };
2230e97ad33aSDoug Rabson VFS_VOP_VECTOR_REGISTER(p9fs_vnops);
2231