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