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