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