pseudofs_vnops.c (341074) | pseudofs_vnops.c (75295) |
---|---|
1/*- | 1/*- |
2 * Copyright (c) 2001 Dag-Erling Co��dan Sm��rgrav | 2 * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav |
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 * in this position and unchanged. --- 8 unchanged lines hidden (view full) --- 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 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 * in this position and unchanged. --- 8 unchanged lines hidden (view full) --- 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 * 28 * $FreeBSD: head/sys/fs/pseudofs/pseudofs_vnops.c 75295 2001-04-07 19:51:12Z des $ |
|
27 */ 28 | 29 */ 30 |
29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/11/sys/fs/pseudofs/pseudofs_vnops.c 341074 2018-11-27 16:51:18Z markj $"); 31 32#include "opt_pseudofs.h" 33 | |
34#include <sys/param.h> 35#include <sys/kernel.h> 36#include <sys/systm.h> 37#include <sys/ctype.h> 38#include <sys/dirent.h> | 31#include <sys/param.h> 32#include <sys/kernel.h> 33#include <sys/systm.h> 34#include <sys/ctype.h> 35#include <sys/dirent.h> |
39#include <sys/fcntl.h> 40#include <sys/limits.h> 41#include <sys/lock.h> 42#include <sys/malloc.h> | |
43#include <sys/mount.h> | 36#include <sys/mount.h> |
44#include <sys/mutex.h> | |
45#include <sys/namei.h> 46#include <sys/proc.h> 47#include <sys/sbuf.h> 48#include <sys/sx.h> 49#include <sys/sysctl.h> 50#include <sys/vnode.h> 51 52#include <fs/pseudofs/pseudofs.h> 53#include <fs/pseudofs/pseudofs_internal.h> 54 | 37#include <sys/namei.h> 38#include <sys/proc.h> 39#include <sys/sbuf.h> 40#include <sys/sx.h> 41#include <sys/sysctl.h> 42#include <sys/vnode.h> 43 44#include <fs/pseudofs/pseudofs.h> 45#include <fs/pseudofs/pseudofs_internal.h> 46 |
55#define KASSERT_PN_IS_DIR(pn) \ 56 KASSERT((pn)->pn_type == pfstype_root || \ 57 (pn)->pn_type == pfstype_dir || \ 58 (pn)->pn_type == pfstype_procdir, \ 59 ("%s(): VDIR vnode refers to non-directory pfs_node", __func__)) 60 61#define KASSERT_PN_IS_FILE(pn) \ 62 KASSERT((pn)->pn_type == pfstype_file, \ 63 ("%s(): VREG vnode refers to non-file pfs_node", __func__)) 64 65#define KASSERT_PN_IS_LINK(pn) \ 66 KASSERT((pn)->pn_type == pfstype_symlink, \ 67 ("%s(): VLNK vnode refers to non-link pfs_node", __func__)) 68 | |
69/* | 47/* |
70 * Returns the fileno, adjusted for target pid 71 */ 72static uint32_t 73pn_fileno(struct pfs_node *pn, pid_t pid) 74{ 75 76 KASSERT(pn->pn_fileno > 0, 77 ("%s(): no fileno allocated", __func__)); 78 if (pid != NO_PID) 79 return (pn->pn_fileno * NO_PID + pid); 80 return (pn->pn_fileno); 81} 82 83/* 84 * Returns non-zero if given file is visible to given thread. 85 */ 86static int 87pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc) 88{ 89 int visible; 90 91 if (proc == NULL) 92 return (0); 93 94 PROC_LOCK_ASSERT(proc, MA_OWNED); 95 96 visible = ((proc->p_flag & P_WEXIT) == 0); 97 if (visible) 98 visible = (p_cansee(td, proc) == 0); 99 if (visible && pn->pn_vis != NULL) 100 visible = pn_vis(td, proc, pn); 101 if (!visible) 102 return (0); 103 return (1); 104} 105 106static int 107pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid, 108 bool allproc_locked, struct proc **p) 109{ 110 struct proc *proc; 111 112 PFS_TRACE(("%s (pid: %d, req: %d)", 113 pn->pn_name, pid, td->td_proc->p_pid)); 114 115 if (p) 116 *p = NULL; 117 if (pid == NO_PID) 118 PFS_RETURN (1); 119 proc = allproc_locked ? pfind_locked(pid) : pfind(pid); 120 if (proc == NULL) 121 PFS_RETURN (0); 122 if (pfs_visible_proc(td, pn, proc)) { 123 if (p) 124 *p = proc; 125 else 126 PROC_UNLOCK(proc); 127 PFS_RETURN (1); 128 } 129 PROC_UNLOCK(proc); 130 PFS_RETURN (0); 131} 132 133/* | |
134 * Verify permissions 135 */ 136static int 137pfs_access(struct vop_access_args *va) 138{ 139 struct vnode *vn = va->a_vp; | 48 * Verify permissions 49 */ 50static int 51pfs_access(struct vop_access_args *va) 52{ 53 struct vnode *vn = va->a_vp; |
140 struct pfs_vdata *pvd = vn->v_data; | |
141 struct vattr vattr; 142 int error; | 54 struct vattr vattr; 55 int error; |
143 144 PFS_TRACE(("%s", pvd->pvd_pn->pn_name)); 145 (void)pvd; 146 147 error = VOP_GETATTR(vn, &vattr, va->a_cred); | 56 57 error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_p); |
148 if (error) | 58 if (error) |
149 PFS_RETURN (error); | 59 return (error); |
150 error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, | 60 error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, |
151 vattr.va_gid, va->a_accmode, va->a_cred, NULL); 152 PFS_RETURN (error); | 61 vattr.va_gid, va->a_mode, va->a_cred, NULL); 62 return (error); |
153} 154 155/* 156 * Close a file or directory 157 */ 158static int 159pfs_close(struct vop_close_args *va) 160{ | 63} 64 65/* 66 * Close a file or directory 67 */ 68static int 69pfs_close(struct vop_close_args *va) 70{ |
161 struct vnode *vn = va->a_vp; 162 struct pfs_vdata *pvd = vn->v_data; 163 struct pfs_node *pn = pvd->pvd_pn; 164 struct proc *proc; 165 int error; 166 167 PFS_TRACE(("%s", pn->pn_name)); 168 pfs_assert_not_owned(pn); 169 170 /* 171 * Do nothing unless this is the last close and the node has a 172 * last-close handler. 173 */ 174 if (vrefcnt(vn) > 1 || pn->pn_close == NULL) 175 PFS_RETURN (0); 176 177 if (pvd->pvd_pid != NO_PID) { 178 proc = pfind(pvd->pvd_pid); 179 } else { 180 proc = NULL; 181 } 182 183 error = pn_close(va->a_td, proc, pn); 184 185 if (proc != NULL) 186 PROC_UNLOCK(proc); 187 188 PFS_RETURN (error); | 71 return (0); |
189} 190 191/* 192 * Get file attributes 193 */ 194static int 195pfs_getattr(struct vop_getattr_args *va) 196{ 197 struct vnode *vn = va->a_vp; | 72} 73 74/* 75 * Get file attributes 76 */ 77static int 78pfs_getattr(struct vop_getattr_args *va) 79{ 80 struct vnode *vn = va->a_vp; |
198 struct pfs_vdata *pvd = vn->v_data; 199 struct pfs_node *pn = pvd->pvd_pn; | 81 struct pfs_node *pn = (struct pfs_node *)vn->v_data; |
200 struct vattr *vap = va->a_vap; | 82 struct vattr *vap = va->a_vap; |
201 struct proc *proc; 202 int error = 0; | |
203 | 83 |
204 PFS_TRACE(("%s", pn->pn_name)); 205 pfs_assert_not_owned(pn); 206 207 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) 208 PFS_RETURN (ENOENT); 209 | 84 VATTR_NULL(vap); |
210 vap->va_type = vn->v_type; | 85 vap->va_type = vn->v_type; |
211 vap->va_fileid = pn_fileno(pn, pvd->pvd_pid); | 86 vap->va_mode = pn->pn_mode; 87 vap->va_fileid = pn->pn_fileno; |
212 vap->va_flags = 0; 213 vap->va_blocksize = PAGE_SIZE; 214 vap->va_bytes = vap->va_size = 0; | 88 vap->va_flags = 0; 89 vap->va_blocksize = PAGE_SIZE; 90 vap->va_bytes = vap->va_size = 0; |
215 vap->va_filerev = 0; | |
216 vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0]; 217 vap->va_nlink = 1; 218 nanotime(&vap->va_ctime); 219 vap->va_atime = vap->va_mtime = vap->va_ctime; | 91 vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0]; 92 vap->va_nlink = 1; 93 nanotime(&vap->va_ctime); 94 vap->va_atime = vap->va_mtime = vap->va_ctime; |
95 vap->va_uid = pn->pn_uid; 96 vap->va_gid = pn->pn_gid; |
|
220 | 97 |
221 switch (pn->pn_type) { 222 case pfstype_procdir: 223 case pfstype_root: 224 case pfstype_dir: 225#if 0 226 pfs_lock(pn); 227 /* compute link count */ 228 pfs_unlock(pn); 229#endif 230 vap->va_mode = 0555; 231 break; 232 case pfstype_file: 233 case pfstype_symlink: 234 vap->va_mode = 0444; 235 break; 236 default: 237 printf("shouldn't be here!\n"); 238 vap->va_mode = 0; 239 break; 240 } 241 242 if (proc != NULL) { 243 vap->va_uid = proc->p_ucred->cr_ruid; 244 vap->va_gid = proc->p_ucred->cr_rgid; 245 } else { 246 vap->va_uid = 0; 247 vap->va_gid = 0; 248 } 249 250 if (pn->pn_attr != NULL) 251 error = pn_attr(curthread, proc, pn, vap); 252 253 if(proc != NULL) 254 PROC_UNLOCK(proc); 255 256 PFS_RETURN (error); | 98 return (0); |
257} 258 259/* | 99} 100 101/* |
260 * Perform an ioctl 261 */ 262static int 263pfs_ioctl(struct vop_ioctl_args *va) 264{ 265 struct vnode *vn; 266 struct pfs_vdata *pvd; 267 struct pfs_node *pn; 268 struct proc *proc; 269 int error; 270 271 vn = va->a_vp; 272 vn_lock(vn, LK_SHARED | LK_RETRY); 273 if (vn->v_iflag & VI_DOOMED) { 274 VOP_UNLOCK(vn, 0); 275 return (EBADF); 276 } 277 pvd = vn->v_data; 278 pn = pvd->pvd_pn; 279 280 PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command)); 281 pfs_assert_not_owned(pn); 282 283 if (vn->v_type != VREG) { 284 VOP_UNLOCK(vn, 0); 285 PFS_RETURN (EINVAL); 286 } 287 KASSERT_PN_IS_FILE(pn); 288 289 if (pn->pn_ioctl == NULL) { 290 VOP_UNLOCK(vn, 0); 291 PFS_RETURN (ENOTTY); 292 } 293 294 /* 295 * This is necessary because process' privileges may 296 * have changed since the open() call. 297 */ 298 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) { 299 VOP_UNLOCK(vn, 0); 300 PFS_RETURN (EIO); 301 } 302 303 error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data); 304 305 if (proc != NULL) 306 PROC_UNLOCK(proc); 307 308 VOP_UNLOCK(vn, 0); 309 PFS_RETURN (error); 310} 311 312/* 313 * Perform getextattr 314 */ 315static int 316pfs_getextattr(struct vop_getextattr_args *va) 317{ 318 struct vnode *vn = va->a_vp; 319 struct pfs_vdata *pvd = vn->v_data; 320 struct pfs_node *pn = pvd->pvd_pn; 321 struct proc *proc; 322 int error; 323 324 PFS_TRACE(("%s", pn->pn_name)); 325 pfs_assert_not_owned(pn); 326 327 /* 328 * This is necessary because either process' privileges may 329 * have changed since the open() call. 330 */ 331 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) 332 PFS_RETURN (EIO); 333 334 if (pn->pn_getextattr == NULL) 335 error = EOPNOTSUPP; 336 else 337 error = pn_getextattr(curthread, proc, pn, 338 va->a_attrnamespace, va->a_name, va->a_uio, 339 va->a_size, va->a_cred); 340 341 if (proc != NULL) 342 PROC_UNLOCK(proc); 343 344 PFS_RETURN (error); 345} 346 347/* 348 * Convert a vnode to its component name 349 */ 350static int 351pfs_vptocnp(struct vop_vptocnp_args *ap) 352{ 353 struct vnode *vp = ap->a_vp; 354 struct vnode **dvp = ap->a_vpp; 355 struct pfs_vdata *pvd = vp->v_data; 356 struct pfs_node *pd = pvd->pvd_pn; 357 struct pfs_node *pn; 358 struct mount *mp; 359 char *buf = ap->a_buf; 360 int *buflen = ap->a_buflen; 361 char pidbuf[PFS_NAMELEN]; 362 pid_t pid = pvd->pvd_pid; 363 int len, i, error, locked; 364 365 i = *buflen; 366 error = 0; 367 368 pfs_lock(pd); 369 370 if (vp->v_type == VDIR && pd->pn_type == pfstype_root) { 371 *dvp = vp; 372 vhold(*dvp); 373 pfs_unlock(pd); 374 PFS_RETURN (0); 375 } else if (vp->v_type == VDIR && pd->pn_type == pfstype_procdir) { 376 len = snprintf(pidbuf, sizeof(pidbuf), "%d", pid); 377 i -= len; 378 if (i < 0) { 379 error = ENOMEM; 380 goto failed; 381 } 382 bcopy(pidbuf, buf + i, len); 383 } else { 384 len = strlen(pd->pn_name); 385 i -= len; 386 if (i < 0) { 387 error = ENOMEM; 388 goto failed; 389 } 390 bcopy(pd->pn_name, buf + i, len); 391 } 392 393 pn = pd->pn_parent; 394 pfs_unlock(pd); 395 396 mp = vp->v_mount; 397 error = vfs_busy(mp, 0); 398 if (error) 399 return (error); 400 401 /* 402 * vp is held by caller. 403 */ 404 locked = VOP_ISLOCKED(vp); 405 VOP_UNLOCK(vp, 0); 406 407 error = pfs_vncache_alloc(mp, dvp, pn, pid); 408 if (error) { 409 vn_lock(vp, locked | LK_RETRY); 410 vfs_unbusy(mp); 411 PFS_RETURN(error); 412 } 413 414 *buflen = i; 415 VOP_UNLOCK(*dvp, 0); 416 vn_lock(vp, locked | LK_RETRY); 417 vfs_unbusy(mp); 418 419 PFS_RETURN (0); 420failed: 421 pfs_unlock(pd); 422 PFS_RETURN(error); 423} 424 425/* | |
426 * Look up a file or directory 427 */ 428static int | 102 * Look up a file or directory 103 */ 104static int |
429pfs_lookup(struct vop_cachedlookup_args *va) | 105pfs_lookup(struct vop_lookup_args *va) |
430{ | 106{ |
431 struct vnode *vn = va->a_dvp; | 107 struct vnode *dvp = va->a_dvp; |
432 struct vnode **vpp = va->a_vpp; 433 struct componentname *cnp = va->a_cnp; | 108 struct vnode **vpp = va->a_vpp; 109 struct componentname *cnp = va->a_cnp; |
434 struct pfs_vdata *pvd = vn->v_data; 435 struct pfs_node *pd = pvd->pvd_pn; 436 struct pfs_node *pn, *pdn = NULL; 437 struct mount *mp; 438 pid_t pid = pvd->pvd_pid; | 110#if 0 111 struct pfs_info *pi = (struct pfs_info *)dvp->v_mount->mnt_data; 112#endif 113 struct pfs_node *pd = (struct pfs_node *)dvp->v_data, *pn; 114 struct proc *p; |
439 char *pname; | 115 char *pname; |
440 int error, i, namelen, visible; | 116 int error, i; 117 pid_t pid; |
441 | 118 |
442 PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr)); 443 pfs_assert_not_owned(pd); | 119 if (dvp->v_type != VDIR) 120 return (ENOTDIR); 121 122 /* don't support CREATE, RENAME or DELETE */ 123 if (cnp->cn_nameiop != LOOKUP) 124 return (EROFS); |
444 | 125 |
445 if (vn->v_type != VDIR) 446 PFS_RETURN (ENOTDIR); 447 KASSERT_PN_IS_DIR(pd); 448 449 error = VOP_ACCESS(vn, VEXEC, cnp->cn_cred, cnp->cn_thread); 450 if (error) 451 PFS_RETURN (error); 452 453 /* 454 * Don't support DELETE or RENAME. CREATE is supported so 455 * that O_CREAT will work, but the lookup will still fail if 456 * the file does not exist. 457 */ 458 if ((cnp->cn_flags & ISLASTCN) && 459 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 460 PFS_RETURN (EOPNOTSUPP); 461 462 /* shortcut: check if the name is too long */ | 126 /* shortcut */ |
463 if (cnp->cn_namelen >= PFS_NAMELEN) | 127 if (cnp->cn_namelen >= PFS_NAMELEN) |
464 PFS_RETURN (ENOENT); 465 466 /* check that parent directory is visible... */ 467 if (!pfs_visible(curthread, pd, pvd->pvd_pid, false, NULL)) 468 PFS_RETURN (ENOENT); 469 | 128 return (ENOENT); 129 |
470 /* self */ | 130 /* self */ |
471 namelen = cnp->cn_namelen; | |
472 pname = cnp->cn_nameptr; | 131 pname = cnp->cn_nameptr; |
473 if (namelen == 1 && pname[0] == '.') { | 132 if (cnp->cn_namelen == 1 && *pname == '.') { |
474 pn = pd; | 133 pn = pd; |
475 *vpp = vn; 476 VREF(vn); 477 PFS_RETURN (0); | 134 *vpp = dvp; 135 VREF(dvp); 136 goto got_vnode; |
478 } 479 | 137 } 138 |
480 mp = vn->v_mount; 481 | |
482 /* parent */ 483 if (cnp->cn_flags & ISDOTDOT) { 484 if (pd->pn_type == pfstype_root) | 139 /* parent */ 140 if (cnp->cn_flags & ISDOTDOT) { 141 if (pd->pn_type == pfstype_root) |
485 PFS_RETURN (EIO); 486 error = vfs_busy(mp, MBF_NOWAIT); 487 if (error != 0) { 488 vfs_ref(mp); 489 VOP_UNLOCK(vn, 0); 490 error = vfs_busy(mp, 0); 491 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY); 492 vfs_rel(mp); 493 if (error != 0) 494 PFS_RETURN(ENOENT); 495 if (vn->v_iflag & VI_DOOMED) { 496 vfs_unbusy(mp); 497 PFS_RETURN(ENOENT); 498 } 499 } 500 VOP_UNLOCK(vn, 0); 501 KASSERT(pd->pn_parent != NULL, 502 ("%s(): non-root directory has no parent", __func__)); 503 /* 504 * This one is tricky. Descendents of procdir nodes 505 * inherit their parent's process affinity, but 506 * there's no easy reverse mapping. For simplicity, 507 * we assume that if this node is a procdir, its 508 * parent isn't (which is correct as long as 509 * descendents of procdir nodes are never procdir 510 * nodes themselves) 511 */ 512 if (pd->pn_type == pfstype_procdir) 513 pid = NO_PID; 514 pfs_lock(pd); 515 pn = pd->pn_parent; 516 pfs_unlock(pd); 517 goto got_pnode; | 142 return (EIO); 143 KASSERT(pd->pn_parent, ("non-root directory has no parent")); 144 return pfs_vncache_alloc(dvp->v_mount, vpp, pd->pn_parent); |
518 } 519 | 145 } 146 |
520 pfs_lock(pd); 521 522 /* named node */ 523 for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next) 524 if (pn->pn_type == pfstype_procdir) 525 pdn = pn; 526 else if (pn->pn_name[namelen] == '\0' && 527 bcmp(pname, pn->pn_name, namelen) == 0) { 528 pfs_unlock(pd); | 147 /* process dependent */ 148 for (i = 0, pid = 0; i < cnp->cn_namelen && isdigit(pname[i]); ++i) 149 pid = pid * 10 + pname[i] - '0'; 150 /* XXX assume that 8 digits is the maximum safe length for a pid */ 151 if (i == cnp->cn_namelen && i < 8) { 152 /* see if this directory has process-dependent children */ 153 for (pn = pd->pn_nodes; pn->pn_type; ++pn) 154 if (pn->pn_type == pfstype_procdep) 155 break; 156 if (pn->pn_type) { 157 /* XXX pfind(0) should DTRT here */ 158 p = pid ? pfind(pid) : &proc0; 159 if (p == NULL) 160 return (ENOENT); 161 if (p_can(cnp->cn_proc, p, P_CAN_SEE, NULL)) 162 /* pretend it doesn't exist */ 163 return (ENOENT); 164#if 0 165 if (!pn->pn_shadow) 166 pfs_create_shadow(pn, p); 167 pn = pn->pn_shadow; |
529 goto got_pnode; | 168 goto got_pnode; |
169#else 170 /* not yet implemented */ 171 return (EIO); 172#endif |
|
530 } | 173 } |
531 532 /* process dependent node */ 533 if ((pn = pdn) != NULL) { 534 pid = 0; 535 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i) 536 if ((pid = pid * 10 + pname[i] - '0') > PID_MAX) | 174 } 175 176 /* something else */ 177 for (pn = pd->pn_nodes; pn->pn_type; ++pn) { 178 for (i = 0; i < cnp->cn_namelen && pn->pn_name[i]; ++i) 179 if (pname[i] != pn->pn_name[i]) |
537 break; | 180 break; |
538 if (i == cnp->cn_namelen) { 539 pfs_unlock(pd); | 181 if (i == cnp->cn_namelen) |
540 goto got_pnode; | 182 goto got_pnode; |
541 } | |
542 } 543 | 183 } 184 |
544 pfs_unlock(pd); 545 546 PFS_RETURN (ENOENT); 547 | 185 return (ENOENT); |
548 got_pnode: | 186 got_pnode: |
549 pfs_assert_not_owned(pd); 550 pfs_assert_not_owned(pn); 551 visible = pfs_visible(curthread, pn, pid, false, NULL); 552 if (!visible) { 553 error = ENOENT; 554 goto failed; 555 } 556 557 error = pfs_vncache_alloc(mp, vpp, pn, pid); | 187 if (!pn->pn_parent) 188 pn->pn_parent = pd; 189 error = pfs_vncache_alloc(dvp->v_mount, vpp, pn); |
558 if (error) | 190 if (error) |
559 goto failed; 560 561 if (cnp->cn_flags & ISDOTDOT) { 562 vfs_unbusy(mp); 563 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY); 564 if (vn->v_iflag & VI_DOOMED) { 565 vput(*vpp); 566 *vpp = NULL; 567 PFS_RETURN(ENOENT); 568 } 569 } 570 if (cnp->cn_flags & MAKEENTRY && !(vn->v_iflag & VI_DOOMED)) 571 cache_enter(vn, *vpp, cnp); 572 PFS_RETURN (0); 573 failed: 574 if (cnp->cn_flags & ISDOTDOT) { 575 vfs_unbusy(mp); 576 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY); 577 *vpp = NULL; 578 } 579 PFS_RETURN(error); | 191 return error; 192 got_vnode: 193 if (cnp->cn_flags & MAKEENTRY) 194 cache_enter(dvp, *vpp, cnp); 195 return (0); |
580} 581 582/* 583 * Open a file or directory. 584 */ 585static int 586pfs_open(struct vop_open_args *va) 587{ | 196} 197 198/* 199 * Open a file or directory. 200 */ 201static int 202pfs_open(struct vop_open_args *va) 203{ |
588 struct vnode *vn = va->a_vp; 589 struct pfs_vdata *pvd = vn->v_data; 590 struct pfs_node *pn = pvd->pvd_pn; 591 int mode = va->a_mode; 592 593 PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode)); 594 pfs_assert_not_owned(pn); 595 596 /* check if the requested mode is permitted */ 597 if (((mode & FREAD) && !(mode & PFS_RD)) || 598 ((mode & FWRITE) && !(mode & PFS_WR))) 599 PFS_RETURN (EPERM); 600 601 /* we don't support locking */ 602 if ((mode & O_SHLOCK) || (mode & O_EXLOCK)) 603 PFS_RETURN (EOPNOTSUPP); 604 605 PFS_RETURN (0); | 204 /* XXX */ 205 return (0); |
606} 607 608/* 609 * Read from a file 610 */ 611static int 612pfs_read(struct vop_read_args *va) 613{ 614 struct vnode *vn = va->a_vp; | 206} 207 208/* 209 * Read from a file 210 */ 211static int 212pfs_read(struct vop_read_args *va) 213{ 214 struct vnode *vn = va->a_vp; |
615 struct pfs_vdata *pvd = vn->v_data; 616 struct pfs_node *pn = pvd->pvd_pn; | 215 struct pfs_node *pn = vn->v_data; |
617 struct uio *uio = va->a_uio; | 216 struct uio *uio = va->a_uio; |
618 struct proc *proc; 619 struct sbuf *sb = NULL; 620 int error, locked; 621 off_t buflen; | 217 struct sbuf sb; 218 char *ps; 219 int error, xlen; |
622 | 220 |
623 PFS_TRACE(("%s", pn->pn_name)); 624 pfs_assert_not_owned(pn); 625 | |
626 if (vn->v_type != VREG) | 221 if (vn->v_type != VREG) |
627 PFS_RETURN (EINVAL); 628 KASSERT_PN_IS_FILE(pn); | 222 return (EINVAL); |
629 | 223 |
630 if (!(pn->pn_flags & PFS_RD)) 631 PFS_RETURN (EBADF); | 224 error = sbuf_new(&sb, NULL, uio->uio_offset + uio->uio_resid, 0); 225 if (error) 226 return (EIO); |
632 | 227 |
633 if (pn->pn_fill == NULL) 634 PFS_RETURN (EIO); 635 636 /* 637 * This is necessary because either process' privileges may 638 * have changed since the open() call. 639 */ 640 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) 641 PFS_RETURN (EIO); 642 if (proc != NULL) { 643 _PHOLD(proc); 644 PROC_UNLOCK(proc); 645 } 646 647 vhold(vn); 648 locked = VOP_ISLOCKED(vn); 649 VOP_UNLOCK(vn, 0); 650 651 if (pn->pn_flags & PFS_RAWRD) { 652 PFS_TRACE(("%zd resid", uio->uio_resid)); 653 error = pn_fill(curthread, proc, pn, NULL, uio); 654 PFS_TRACE(("%zd resid", uio->uio_resid)); 655 goto ret; 656 } 657 658 if (uio->uio_resid < 0 || uio->uio_offset < 0 || 659 uio->uio_resid > OFF_MAX - uio->uio_offset) { 660 error = EINVAL; 661 goto ret; 662 } 663 buflen = uio->uio_offset + uio->uio_resid; 664 if (buflen > MAXPHYS) 665 buflen = MAXPHYS; 666 667 sb = sbuf_new(sb, NULL, buflen + 1, 0); 668 if (sb == NULL) { 669 error = EIO; 670 goto ret; 671 } 672 673 error = pn_fill(curthread, proc, pn, sb, uio); 674 675 if (error) { 676 sbuf_delete(sb); 677 goto ret; 678 } 679 680 /* 681 * XXX: If the buffer overflowed, sbuf_len() will not return 682 * the data length. Then just use the full length because an 683 * overflowed sbuf must be full. 684 */ 685 if (sbuf_finish(sb) == 0) 686 buflen = sbuf_len(sb); 687 error = uiomove_frombuf(sbuf_data(sb), buflen, uio); 688 sbuf_delete(sb); 689ret: 690 vn_lock(vn, locked | LK_RETRY); 691 vdrop(vn); 692 if (proc != NULL) 693 PRELE(proc); 694 PFS_RETURN (error); | 228 error = (pn->pn_func)(pn, curproc, &sb); 229 230 /* XXX we should possibly detect and handle overflows */ 231 sbuf_finish(&sb); 232 ps = sbuf_data(&sb) + uio->uio_offset; 233 xlen = sbuf_len(&sb) - uio->uio_offset; 234 xlen = imin(xlen, uio->uio_resid); 235 error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 236 sbuf_delete(&sb); 237 return (error); |
695} 696 697/* | 238} 239 240/* |
698 * Iterate through directory entries 699 */ 700static int 701pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd, 702 struct pfs_node **pn, struct proc **p) 703{ 704 int visible; 705 706 sx_assert(&allproc_lock, SX_SLOCKED); 707 pfs_assert_owned(pd); 708 again: 709 if (*pn == NULL) { 710 /* first node */ 711 *pn = pd->pn_nodes; 712 } else if ((*pn)->pn_type != pfstype_procdir) { 713 /* next node */ 714 *pn = (*pn)->pn_next; 715 } 716 if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) { 717 /* next process */ 718 if (*p == NULL) 719 *p = LIST_FIRST(&allproc); 720 else 721 *p = LIST_NEXT(*p, p_list); 722 /* out of processes: next node */ 723 if (*p == NULL) 724 *pn = (*pn)->pn_next; 725 else 726 PROC_LOCK(*p); 727 } 728 729 if ((*pn) == NULL) 730 return (-1); 731 732 if (*p != NULL) { 733 visible = pfs_visible_proc(td, *pn, *p); 734 PROC_UNLOCK(*p); 735 } else if (proc != NULL) { 736 visible = pfs_visible_proc(td, *pn, proc); 737 } else { 738 visible = 1; 739 } 740 if (!visible) 741 goto again; 742 743 return (0); 744} 745 746/* Directory entry list */ 747struct pfsentry { 748 STAILQ_ENTRY(pfsentry) link; 749 struct dirent entry; 750}; 751STAILQ_HEAD(pfsdirentlist, pfsentry); 752 753/* | |
754 * Return directory entries. 755 */ 756static int 757pfs_readdir(struct vop_readdir_args *va) 758{ 759 struct vnode *vn = va->a_vp; | 241 * Return directory entries. 242 */ 243static int 244pfs_readdir(struct vop_readdir_args *va) 245{ 246 struct vnode *vn = va->a_vp; |
760 struct pfs_vdata *pvd = vn->v_data; 761 struct pfs_node *pd = pvd->pvd_pn; 762 pid_t pid = pvd->pvd_pid; 763 struct proc *p, *proc; 764 struct pfs_node *pn; | 247 struct pfs_info *pi; 248 struct pfs_node *pd, *pn; 249 struct dirent entry; |
765 struct uio *uio; | 250 struct uio *uio; |
766 struct pfsentry *pfsent, *pfsent2; 767 struct pfsdirentlist lst; | 251#if 0 252 struct proc *p; 253#endif |
768 off_t offset; 769 int error, i, resid; 770 | 254 off_t offset; 255 int error, i, resid; 256 |
771 STAILQ_INIT(&lst); 772 error = 0; 773 KASSERT(pd->pn_info == vn->v_mount->mnt_data, 774 ("%s(): pn_info does not match mountpoint", __func__)); 775 PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid)); 776 pfs_assert_not_owned(pd); 777 | |
778 if (vn->v_type != VDIR) | 257 if (vn->v_type != VDIR) |
779 PFS_RETURN (ENOTDIR); 780 KASSERT_PN_IS_DIR(pd); | 258 return (ENOTDIR); 259 pi = (struct pfs_info *)vn->v_mount->mnt_data; 260 pd = (struct pfs_node *)vn->v_data; 261 pn = pd->pn_nodes; |
781 uio = va->a_uio; 782 783 /* only allow reading entire entries */ 784 offset = uio->uio_offset; 785 resid = uio->uio_resid; | 262 uio = va->a_uio; 263 264 /* only allow reading entire entries */ 265 offset = uio->uio_offset; 266 resid = uio->uio_resid; |
786 if (offset < 0 || offset % PFS_DELEN != 0 || 787 (resid && resid < PFS_DELEN)) 788 PFS_RETURN (EINVAL); 789 if (resid == 0) 790 PFS_RETURN (0); | 267 if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN) 268 return (EINVAL); |
791 | 269 |
792 sx_slock(&allproc_lock); 793 pfs_lock(pd); 794 795 /* check if the directory is visible to the caller */ 796 if (!pfs_visible(curthread, pd, pid, true, &proc)) { 797 sx_sunlock(&allproc_lock); 798 pfs_unlock(pd); 799 PFS_RETURN (ENOENT); 800 } 801 KASSERT(pid == NO_PID || proc != NULL, 802 ("%s(): no process for pid %lu", __func__, (unsigned long)pid)); 803 | |
804 /* skip unwanted entries */ | 270 /* skip unwanted entries */ |
805 for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) { 806 if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) { 807 /* nothing left... */ 808 if (proc != NULL) 809 PROC_UNLOCK(proc); 810 pfs_unlock(pd); 811 sx_sunlock(&allproc_lock); 812 PFS_RETURN (0); 813 } 814 } | 271 for (; pn->pn_type && offset > 0; ++pn, offset -= PFS_DELEN) 272 /* nothing */ ; |
815 816 /* fill in entries */ | 273 274 /* fill in entries */ |
817 while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 && 818 resid >= PFS_DELEN) { 819 if ((pfsent = malloc(sizeof(struct pfsentry), M_IOV, 820 M_NOWAIT | M_ZERO)) == NULL) { 821 error = ENOMEM; 822 break; 823 } 824 pfsent->entry.d_reclen = PFS_DELEN; 825 pfsent->entry.d_fileno = pn_fileno(pn, pid); | 275 entry.d_reclen = PFS_DELEN; 276 for (; pn->pn_type && resid > 0; ++pn) { 277 if (!pn->pn_parent) 278 pn->pn_parent = pd; 279 if (!pn->pn_fileno) 280 pfs_fileno_alloc(pi, pn); 281 entry.d_fileno = pn->pn_fileno; |
826 /* PFS_DELEN was picked to fit PFS_NAMLEN */ 827 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i) | 282 /* PFS_DELEN was picked to fit PFS_NAMLEN */ 283 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i) |
828 pfsent->entry.d_name[i] = pn->pn_name[i]; 829 pfsent->entry.d_namlen = i; | 284 entry.d_name[i] = pn->pn_name[i]; 285 entry.d_name[i] = 0; 286 entry.d_namlen = i; |
830 switch (pn->pn_type) { | 287 switch (pn->pn_type) { |
831 case pfstype_procdir: 832 KASSERT(p != NULL, 833 ("reached procdir node with p == NULL")); 834 pfsent->entry.d_namlen = snprintf(pfsent->entry.d_name, 835 PFS_NAMELEN, "%d", p->p_pid); 836 /* fall through */ | |
837 case pfstype_root: 838 case pfstype_dir: 839 case pfstype_this: 840 case pfstype_parent: | 288 case pfstype_root: 289 case pfstype_dir: 290 case pfstype_this: 291 case pfstype_parent: |
841 pfsent->entry.d_type = DT_DIR; | 292 entry.d_type = DT_DIR; |
842 break; 843 case pfstype_file: | 293 break; 294 case pfstype_file: |
844 pfsent->entry.d_type = DT_REG; | 295 entry.d_type = DT_REG; |
845 break; 846 case pfstype_symlink: | 296 break; 297 case pfstype_symlink: |
847 pfsent->entry.d_type = DT_LNK; | 298 entry.d_type = DT_LNK; |
848 break; | 299 break; |
300 case pfstype_procdep: 301 /* don't handle process-dependent nodes here */ 302 continue; |
|
849 default: 850 panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type); 851 } | 303 default: 304 panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type); 305 } |
852 PFS_TRACE(("%s", pfsent->entry.d_name)); 853 dirent_terminate(&pfsent->entry); 854 STAILQ_INSERT_TAIL(&lst, pfsent, link); | 306 if ((error = uiomove((caddr_t)&entry, PFS_DELEN, uio))) 307 return (error); |
855 offset += PFS_DELEN; 856 resid -= PFS_DELEN; 857 } | 308 offset += PFS_DELEN; 309 resid -= PFS_DELEN; 310 } |
858 if (proc != NULL) 859 PROC_UNLOCK(proc); 860 pfs_unlock(pd); 861 sx_sunlock(&allproc_lock); 862 i = 0; 863 STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) { 864 if (error == 0) 865 error = uiomove(&pfsent->entry, PFS_DELEN, uio); 866 free(pfsent, M_IOV); 867 i++; | 311#if 0 312 for (pn = pd->pn_nodes; pn->pn_type && resid > 0; ++pn) { 313 if (pn->pn_type != pfstype_procdep) 314 continue; 315 316 sx_slock(&allproc_lock); 317 p = LIST_FIRST(&allproc); 318 319 sx_sunlock(&allproc_lock); 320 offset += PFS_DELEN; 321 resid -= PFS_DELEN; 322 break; |
868 } | 323 } |
869 PFS_TRACE(("%d bytes", i * PFS_DELEN)); 870 PFS_RETURN (error); | 324#endif 325 326 uio->uio_offset += offset; 327 return (0); |
871} 872 873/* 874 * Read a symbolic link 875 */ 876static int 877pfs_readlink(struct vop_readlink_args *va) 878{ 879 struct vnode *vn = va->a_vp; | 328} 329 330/* 331 * Read a symbolic link 332 */ 333static int 334pfs_readlink(struct vop_readlink_args *va) 335{ 336 struct vnode *vn = va->a_vp; |
880 struct pfs_vdata *pvd = vn->v_data; 881 struct pfs_node *pn = pvd->pvd_pn; | 337 struct pfs_node *pn = vn->v_data; |
882 struct uio *uio = va->a_uio; | 338 struct uio *uio = va->a_uio; |
883 struct proc *proc = NULL; 884 char buf[PATH_MAX]; | 339 char buf[MAXPATHLEN], *ps; |
885 struct sbuf sb; | 340 struct sbuf sb; |
886 int error, locked; | 341 int error, xlen; |
887 | 342 |
888 PFS_TRACE(("%s", pn->pn_name)); 889 pfs_assert_not_owned(pn); 890 | |
891 if (vn->v_type != VLNK) | 343 if (vn->v_type != VLNK) |
892 PFS_RETURN (EINVAL); 893 KASSERT_PN_IS_LINK(pn); | 344 return (EINVAL); |
894 | 345 |
895 if (pn->pn_fill == NULL) 896 PFS_RETURN (EIO); 897 898 if (pvd->pvd_pid != NO_PID) { 899 if ((proc = pfind(pvd->pvd_pid)) == NULL) 900 PFS_RETURN (EIO); 901 if (proc->p_flag & P_WEXIT) { 902 PROC_UNLOCK(proc); 903 PFS_RETURN (EIO); 904 } 905 _PHOLD(proc); 906 PROC_UNLOCK(proc); 907 } 908 vhold(vn); 909 locked = VOP_ISLOCKED(vn); 910 VOP_UNLOCK(vn, 0); 911 | |
912 /* sbuf_new() can't fail with a static buffer */ 913 sbuf_new(&sb, buf, sizeof buf, 0); 914 | 346 /* sbuf_new() can't fail with a static buffer */ 347 sbuf_new(&sb, buf, sizeof buf, 0); 348 |
915 error = pn_fill(curthread, proc, pn, &sb, NULL); 916 917 if (proc != NULL) 918 PRELE(proc); 919 vn_lock(vn, locked | LK_RETRY); 920 vdrop(vn); 921 922 if (error) { 923 sbuf_delete(&sb); 924 PFS_RETURN (error); 925 } 926 927 if (sbuf_finish(&sb) != 0) { 928 sbuf_delete(&sb); 929 PFS_RETURN (ENAMETOOLONG); 930 } 931 932 error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio); | 349 error = (pn->pn_func)(pn, curproc, &sb); 350 351 /* XXX we should detect and handle overflows */ 352 sbuf_finish(&sb); 353 ps = sbuf_data(&sb) + uio->uio_offset; 354 xlen = sbuf_len(&sb) - uio->uio_offset; 355 xlen = imin(xlen, uio->uio_resid); 356 error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); |
933 sbuf_delete(&sb); | 357 sbuf_delete(&sb); |
934 PFS_RETURN (error); | 358 return (error); |
935} 936 937/* 938 * Reclaim a vnode 939 */ 940static int 941pfs_reclaim(struct vop_reclaim_args *va) 942{ | 359} 360 361/* 362 * Reclaim a vnode 363 */ 364static int 365pfs_reclaim(struct vop_reclaim_args *va) 366{ |
943 struct vnode *vn = va->a_vp; 944 struct pfs_vdata *pvd = vn->v_data; 945 struct pfs_node *pn = pvd->pvd_pn; 946 947 PFS_TRACE(("%s", pn->pn_name)); 948 pfs_assert_not_owned(pn); 949 | |
950 return (pfs_vncache_free(va->a_vp)); 951} 952 953/* 954 * Set attributes 955 */ 956static int 957pfs_setattr(struct vop_setattr_args *va) 958{ | 367 return (pfs_vncache_free(va->a_vp)); 368} 369 370/* 371 * Set attributes 372 */ 373static int 374pfs_setattr(struct vop_setattr_args *va) 375{ |
959 struct vnode *vn = va->a_vp; 960 struct pfs_vdata *pvd = vn->v_data; 961 struct pfs_node *pn = pvd->pvd_pn; 962 963 PFS_TRACE(("%s", pn->pn_name)); 964 pfs_assert_not_owned(pn); 965 966 PFS_RETURN (EOPNOTSUPP); | 376 if (va->a_vap->va_flags != VNOVAL) 377 return (EOPNOTSUPP); 378 return (0); |
967} 968 969/* | 379} 380 381/* |
970 * Write to a file | 382 * Dummy operations |
971 */ | 383 */ |
972static int 973pfs_write(struct vop_write_args *va) 974{ 975 struct vnode *vn = va->a_vp; 976 struct pfs_vdata *pvd = vn->v_data; 977 struct pfs_node *pn = pvd->pvd_pn; 978 struct uio *uio = va->a_uio; 979 struct proc *proc; 980 struct sbuf sb; 981 int error; | 384static int pfs_erofs(void *va) { return (EROFS); } 385static int pfs_null(void *va) { return (0); } |
982 | 386 |
983 PFS_TRACE(("%s", pn->pn_name)); 984 pfs_assert_not_owned(pn); 985 986 if (vn->v_type != VREG) 987 PFS_RETURN (EINVAL); 988 KASSERT_PN_IS_FILE(pn); 989 990 if (!(pn->pn_flags & PFS_WR)) 991 PFS_RETURN (EBADF); 992 993 if (pn->pn_fill == NULL) 994 PFS_RETURN (EIO); 995 996 /* 997 * This is necessary because either process' privileges may 998 * have changed since the open() call. 999 */ 1000 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) 1001 PFS_RETURN (EIO); 1002 if (proc != NULL) { 1003 _PHOLD(proc); 1004 PROC_UNLOCK(proc); 1005 } 1006 1007 if (pn->pn_flags & PFS_RAWWR) { 1008 error = pn_fill(curthread, proc, pn, NULL, uio); 1009 if (proc != NULL) 1010 PRELE(proc); 1011 PFS_RETURN (error); 1012 } 1013 1014 sbuf_uionew(&sb, uio, &error); 1015 if (error) { 1016 if (proc != NULL) 1017 PRELE(proc); 1018 PFS_RETURN (error); 1019 } 1020 1021 error = pn_fill(curthread, proc, pn, &sb, uio); 1022 1023 sbuf_delete(&sb); 1024 if (proc != NULL) 1025 PRELE(proc); 1026 PFS_RETURN (error); 1027} 1028 | |
1029/* 1030 * Vnode operations 1031 */ | 387/* 388 * Vnode operations 389 */ |
1032struct vop_vector pfs_vnodeops = { 1033 .vop_default = &default_vnodeops, 1034 1035 .vop_access = pfs_access, 1036 .vop_cachedlookup = pfs_lookup, 1037 .vop_close = pfs_close, 1038 .vop_create = VOP_EOPNOTSUPP, 1039 .vop_getattr = pfs_getattr, 1040 .vop_getextattr = pfs_getextattr, 1041 .vop_ioctl = pfs_ioctl, 1042 .vop_link = VOP_EOPNOTSUPP, 1043 .vop_lookup = vfs_cache_lookup, 1044 .vop_mkdir = VOP_EOPNOTSUPP, 1045 .vop_mknod = VOP_EOPNOTSUPP, 1046 .vop_open = pfs_open, 1047 .vop_read = pfs_read, 1048 .vop_readdir = pfs_readdir, 1049 .vop_readlink = pfs_readlink, 1050 .vop_reclaim = pfs_reclaim, 1051 .vop_remove = VOP_EOPNOTSUPP, 1052 .vop_rename = VOP_EOPNOTSUPP, 1053 .vop_rmdir = VOP_EOPNOTSUPP, 1054 .vop_setattr = pfs_setattr, 1055 .vop_symlink = VOP_EOPNOTSUPP, 1056 .vop_vptocnp = pfs_vptocnp, 1057 .vop_write = pfs_write, 1058 /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */ | 390vop_t **pfs_vnodeop_p; 391static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = { 392 { &vop_default_desc, (vop_t *)vop_defaultop }, 393 { &vop_access_desc, (vop_t *)pfs_access }, 394 { &vop_close_desc, (vop_t *)pfs_close }, 395 { &vop_create_desc, (vop_t *)pfs_erofs }, 396 { &vop_getattr_desc, (vop_t *)pfs_getattr }, 397 { &vop_link_desc, (vop_t *)pfs_erofs }, 398 { &vop_lookup_desc, (vop_t *)pfs_lookup }, 399 { &vop_mkdir_desc, (vop_t *)pfs_erofs }, 400 { &vop_open_desc, (vop_t *)pfs_open }, 401 { &vop_read_desc, (vop_t *)pfs_read }, 402 { &vop_readdir_desc, (vop_t *)pfs_readdir }, 403 { &vop_readlink_desc, (vop_t *)pfs_readlink }, 404 { &vop_reclaim_desc, (vop_t *)pfs_reclaim }, 405 { &vop_remove_desc, (vop_t *)pfs_erofs }, 406 { &vop_rename_desc, (vop_t *)pfs_erofs }, 407 { &vop_rmdir_desc, (vop_t *)pfs_erofs }, 408 { &vop_setattr_desc, (vop_t *)pfs_setattr }, 409 { &vop_symlink_desc, (vop_t *)pfs_erofs }, 410 { &vop_write_desc, (vop_t *)pfs_erofs }, 411 /* XXX I've probably forgotten a few that need pfs_erofs */ 412 { NULL, (vop_t *)NULL } |
1059}; | 413}; |
414 415static struct vnodeopv_desc pfs_vnodeop_opv_desc = 416 { &pfs_vnodeop_p, pfs_vnodeop_entries }; 417 418VNODEOP_SET(pfs_vnodeop_opv_desc); 419 |
|