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