vfs_subr.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,733 行 · 第 1/5 页
C
2,733 行
"vgone", 0, &vp->v_interlock); return; } /* * Clean out the filesystem specific data. */ vclean(vp, DOCLOSE, p); /* * Delete from old mount point vnode list, if on one. */ if (vp->v_mount != NULL) insmntque(vp, (struct mount *)0); /* * If special device, remove it from special device alias list. * if it is on one. */ if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_specinfo != 0) { simple_lock(&spechash_slock); if (vp->v_hashchain != NULL) { if (*vp->v_hashchain == vp) { *vp->v_hashchain = vp->v_specnext; } else { for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { if (vq->v_specnext != vp) continue; vq->v_specnext = vp->v_specnext; break; } if (vq == NULL) panic("missing bdev"); } if (vp->v_flag & VALIASED) { vx = NULL; for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) continue; if (vx) break; vx = vq; } if (vx == NULL) panic("missing alias"); if (vq == NULL) vx->v_flag &= ~VALIASED; vp->v_flag &= ~VALIASED; } } simple_unlock(&spechash_slock); FREE(vp->v_specinfo, M_VNODE); vp->v_specinfo = NULL; } /* * If it is on the freelist and not already at the head, * move it to the head of the list. The test of the back * pointer and the reference count of zero is because * it will be removed from the free list by getnewvnode, * but will not have its reference count incremented until * after calling vgone. If the reference count were * incremented first, vgone would (incorrectly) try to * close the previous instance of the underlying object. * So, the back pointer is explicitly set to `0xdeadb' in * getnewvnode after removing it from the freelist to ensure * that we do not try to move it here. */ if (vp->v_usecount == 0) { simple_lock(&vnode_free_list_slock); if (vp->v_holdcnt > 0) panic("vgonel: not clean, vp %p", vp); if (vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb && TAILQ_FIRST(&vnode_free_list) != vp) { TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); } simple_unlock(&vnode_free_list_slock); } vp->v_type = VBAD;}/* * Lookup a vnode by device number. */intvfinddev(dev, type, vpp) dev_t dev; enum vtype type; struct vnode **vpp;{ struct vnode *vp; int rc = 0; simple_lock(&spechash_slock); for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { if (dev != vp->v_rdev || type != vp->v_type) continue; *vpp = vp; rc = 1; break; } simple_unlock(&spechash_slock); return (rc);}/* * Revoke all the vnodes corresponding to the specified minor number * range (endpoints inclusive) of the specified major. */voidvdevgone(maj, minl, minh, type) int maj, minl, minh; enum vtype type;{ struct vnode *vp; int mn; for (mn = minl; mn <= minh; mn++) if (vfinddev(makedev(maj, mn), type, &vp)) VOP_REVOKE(vp, REVOKEALL);}/* * Calculate the total number of references to a special device. */intvcount(vp) struct vnode *vp;{ struct vnode *vq, *vnext; int count;loop: if ((vp->v_flag & VALIASED) == 0) return (vp->v_usecount); simple_lock(&spechash_slock); for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) { vnext = vq->v_specnext; if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) continue; /* * Alias, but not in use, so flush it out. */ if (vq->v_usecount == 0 && vq != vp) { simple_unlock(&spechash_slock); vgone(vq); goto loop; } count += vq->v_usecount; } simple_unlock(&spechash_slock); return (count);}#endif /*OSKIT*/#ifndef OSKIT/* * Print out a description of a vnode. */static char *typename[] = { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };voidvprint(label, vp) char *label; struct vnode *vp;{ char buf[64]; if (label != NULL) printf("%s: ", label); printf("tag %d type %s, usecount %d, writecount %ld, refcount %ld,", vp->v_tag, typename[vp->v_type], vp->v_usecount, vp->v_writecount, vp->v_holdcnt); buf[0] = '\0'; if (vp->v_flag & VROOT) strcat(buf, "|VROOT"); if (vp->v_flag & VTEXT) strcat(buf, "|VTEXT"); if (vp->v_flag & VSYSTEM) strcat(buf, "|VSYSTEM"); if (vp->v_flag & VXLOCK) strcat(buf, "|VXLOCK"); if (vp->v_flag & VXWANT) strcat(buf, "|VXWANT"); if (vp->v_flag & VBWAIT) strcat(buf, "|VBWAIT"); if (vp->v_flag & VALIASED) strcat(buf, "|VALIASED"); if (buf[0] != '\0') printf(" flags (%s)", &buf[1]); if (vp->v_data == NULL) { printf("\n"); } else { printf("\n\t");#ifndef OSKIT VOP_PRINT(vp);#endif }}#ifdef DEBUG/* * List all of the locked vnodes in the system. * Called when debugging the kernel. */voidprintlockedvnodes(){ struct mount *mp, *nmp; struct vnode *vp; printf("Locked vnodes\n"); simple_lock(&mountlist_slock); for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) { nmp = mp->mnt_list.cqe_next; continue; } for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = vp->v_mntvnodes.le_next) { if (VOP_ISLOCKED(vp)) vprint((char *)0, vp); } simple_lock(&mountlist_slock); nmp = mp->mnt_list.cqe_next; vfs_unbusy(mp); } simple_unlock(&mountlist_slock);}#endifextern const char *mountcompatnames[];extern const int nmountcompatnames;/* * Top level filesystem related information gathering. */intvfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) int *name; u_int namelen; void *oldp; size_t *oldlenp; void *newp; size_t newlen; struct proc *p;{#if defined(COMPAT_09) || defined(COMPAT_43) || defined(COMPAT_44) struct vfsconf vfc;#endif struct vfsops *vfsp; /* all sysctl names at this level are at least name and field */ if (namelen < 2) return (ENOTDIR); /* overloaded */ /* Not generic: goes to file system. */ if (name[0] != VFS_GENERIC) { if (name[0] >= nmountcompatnames || name[0] < 0 || mountcompatnames[name[0]] == NULL) return (EOPNOTSUPP); vfsp = vfs_getopsbyname(mountcompatnames[name[0]]); if (vfsp == NULL || vfsp->vfs_sysctl == NULL) return (EOPNOTSUPP); return ((*vfsp->vfs_sysctl)(&name[1], namelen - 1, oldp, oldlenp, newp, newlen, p)); } /* The rest are generic vfs sysctls. */ switch (name[1]) { case VFS_USERMOUNT: return sysctl_int(oldp, oldlenp, newp, newlen, &dovfsusermount);#if defined(COMPAT_09) || defined(COMPAT_43) || defined(COMPAT_44) case VFS_MAXTYPENUM: /* * Provided for 4.4BSD-Lite2 compatibility. */ return (sysctl_rdint(oldp, oldlenp, newp, nmountcompatnames)); case VFS_CONF: /* * Special: a node, next is a file system name. * Provided for 4.4BSD-Lite2 compatibility. */ if (namelen < 3) return (ENOTDIR); /* overloaded */ if (name[2] >= nmountcompatnames || name[2] < 0 || mountcompatnames[name[2]] == NULL) return (EOPNOTSUPP); vfsp = vfs_getopsbyname(mountcompatnames[name[2]]); if (vfsp == NULL) return (EOPNOTSUPP); vfc.vfc_vfsops = vfsp; strncpy(vfc.vfc_name, vfsp->vfs_name, MFSNAMELEN); vfc.vfc_typenum = name[2]; vfc.vfc_refcount = vfsp->vfs_refcount; vfc.vfc_flags = 0; vfc.vfc_mountroot = vfsp->vfs_mountroot; vfc.vfc_next = NULL; return (sysctl_rdstruct(oldp, oldlenp, newp, &vfc, sizeof(struct vfsconf)));#endif default: break; } return (EOPNOTSUPP);}int kinfo_vdebug = 1;int kinfo_vgetfailed;#define KINFO_VNODESLOP 10/* * Dump vnode list (via sysctl). * Copyout address of vnode followed by vnode. *//* ARGSUSED */intsysctl_vnode(where, sizep, p) char *where; size_t *sizep; struct proc *p;{ struct mount *mp, *nmp; struct vnode *nvp, *vp; char *bp = where, *savebp; char *ewhere; int error;#define VPTRSZ sizeof(struct vnode *)#define VNODESZ sizeof(struct vnode) if (where == NULL) { *sizep = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); return (0); } ewhere = where + *sizep; simple_lock(&mountlist_slock); for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) { nmp = mp->mnt_list.cqe_next; continue; } savebp = bp;again: simple_lock(&mntvnode_slock); for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { /* * Check that the vp is still associated with * this filesystem. RACE: could have been * recycled onto the same filesystem. */ if (vp->v_mount != mp) { simple_unlock(&mntvnode_slock); if (kinfo_vdebug) printf("kinfo: vp changed\n"); bp = savebp; goto again; } nvp = vp->v_mntvnodes.le_next; if (bp + VPTRSZ + VNODESZ > ewhere) { simple_unlock(&mntvnode_slock); *sizep = bp - where; return (ENOMEM); } simple_unlock(&mntvnode_slock); if ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || (error = copyout((caddr_t)vp, bp + VPTRSZ, VNODESZ))) return (error); bp += VPTRSZ + VNODESZ; simple_lock(&mntvnode_slock); } simple_unlock(&mntvnode_slock); simple_lock(&mountlist_slock); nmp = mp->mnt_list.cqe_next; vfs_unbusy(mp); } simple_unlock(&mountlist_slock); *sizep = bp - where; return (0);}/* * Check to see if a filesystem is mounted on a block device. */intvfs_mountedon(vp) struct vnode *vp;{ struct vnode *vq; int error = 0; if (vp->v_specmountpoint != NULL) return (EBUSY); if (vp->v_flag & VALIASED) { simple_lock(&spechash_slock); for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) continue; if (vq->v_specmountpoint != NULL) { error = EBUSY; break; } } simple_unlock(&spechash_slock); } return (error);}/* * Build hash lists of net addresses and hang them off the mount point. * Called by ufs_mount() to set up the lists of export addresses. */static intvfs_hang_addrlist(mp, nep, argp) struct mount *mp; struct netexport *nep; struct export_args *argp;{ struct netcred *np, *enp; struct radix_node_head *rnh; int i; struct radix_node *rn; struct sockaddr *saddr, *smask = 0; struct domain *dom; int error; if (argp->ex_addrlen == 0) { if (mp->mnt_flag & MNT_DEFEXPORTED) return (EPERM); np = &nep->ne_defexported; np->netc_exflags = argp->ex_flags; np->netc_anon = argp->ex_anon; np->netc_anon.cr_ref = 1; mp->mnt_flag |= MNT_DEFEXPORTED; return (0); } i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK); memset((caddr_t)np, 0, i); saddr = (struct sockaddr *)(np + 1); error = copyin(argp->ex_addr, (caddr_t)saddr, argp->ex_addrlen); if (error) goto out; if (saddr->sa_len > argp->ex_addrlen) saddr->sa_len = argp->ex_addrlen; if (argp->ex_masklen) { smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen); error = copyin(argp->ex_mask, (caddr_t)smask, argp->ex_masklen); if (error) goto out; if (smask->sa_len > argp->ex_masklen) smask->sa_len = argp->ex_masklen; } i = saddr->sa_family; if ((rnh = nep->ne_rtable[i]) == 0) { /* * Seems silly to initialize every AF when most are not * used, do so on demand here */ for (dom = domains; dom; dom = dom->dom_next) if (dom->dom_family == i && dom->dom_rtattach) { dom->dom_rtattach((void **)&nep->ne_rtable[i], dom->dom_rtoffset); break; } if ((rnh = nep->ne_rtable[i]) == 0) { error = ENOBUFS; goto out; } } rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh, np->netc_rnodes); if (rn == 0 || np != (struct netcred *)rn) { /* already exists */ if (rn == 0) { enp = (struct netcred *)(*rnh->rnh_lookup)(saddr, smask, rnh); if (enp == 0) { error = EPERM; goto out; } } else enp = (struct netcred *)rn; if (enp->netc_exflags != argp->ex_flags || enp->netc_anon.cr_uid != argp->ex_anon.cr_uid || enp->netc_anon.cr_gid != argp->ex_anon.cr_gid || enp->netc_anon.cr_ngroups != argp->ex_anon.cr_ngroups || memcmp(&enp->netc_anon.cr_groups, &argp->ex_anon.cr_groups, enp->netc_anon.cr_ngroups)) error = EPERM; else error = 0; goto out; } np->netc_exflags = argp->ex_flags; np->netc_anon = argp->ex_anon; np->netc_anon.cr_ref = 1; return (0);out: free(np, M_NETADDR); return (error);}/* ARGSUSED */static intvfs_free_netcred(rn, w) struct radix_node *rn; void *w;{ struct radix_node_head *rnh = (struct radix_node_head *)w; (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh); free((caddr_t)rn, M_NETADDR); return (0);}/* * Free the net address hash lists that are hanging off the mount points. */static voidvfs_free_addrlist(nep) struct netexport *nep;{ int i; struct radix_node_head *rnh; for (i = 0; i <= AF_MAX; i++) if ((rnh = nep->ne_rtable[i]) != NULL) { (*rnh->rnh_walktree)(rnh, vfs_free_netcred, rnh); free((caddr_t)rnh, M_RTABLE); nep->ne_rtable[i] = 0; }}intvfs_export(mp, nep, argp) struct mount *mp; struct netexport *nep; struct export_args *argp;{ int error;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?