📄 vfs_subr.c
字号:
void vgone(vp) register struct vnode *vp;{ register struct vnode *vq; struct vnode *vx; /* * If a vgone (or vclean) is already in progress, * wait until it is done and return. */ if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; sleep((caddr_t)vp, PINOD); return; } /* * Clean out the filesystem specific data. */ vclean(vp, DOCLOSE); /* * Delete from old mount point vnode list, if on one. */ if (vp->v_mount != NULL) { LIST_REMOVE(vp, v_mntvnodes); vp->v_mount = NULL; } /* * If special device, remove it from special device alias list. */ if (vp->v_type == VBLK || vp->v_type == VCHR) { 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; } 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 && vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb && vnode_free_list.tqh_first != vp) { TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); } vp->v_type = VBAD;}/* * Lookup a vnode by device number. */vfinddev(dev, type, vpp) dev_t dev; enum vtype type; struct vnode **vpp;{ register struct vnode *vp; for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { if (dev != vp->v_rdev || type != vp->v_type) continue; *vpp = vp; return (1); } return (0);}/* * Calculate the total number of references to a special device. */vcount(vp) register struct vnode *vp;{ register struct vnode *vq, *vnext; int count;loop: if ((vp->v_flag & VALIASED) == 0) return (vp->v_usecount); 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) { vgone(vq); goto loop; } count += vq->v_usecount; } return (count);}/* * Print out a description of a vnode. */static char *typename[] = { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };vprint(label, vp) char *label; register struct vnode *vp;{ char buf[64]; if (label != NULL) printf("%s: ", label); printf("type %s, usecount %d, writecount %d, refcount %d,", 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"); VOP_PRINT(vp); }}#ifdef DEBUG/* * List all of the locked vnodes in the system. * Called when debugging the kernel. */printlockedvnodes(){ register struct mount *mp; register struct vnode *vp; printf("Locked vnodes\n"); for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) { for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = vp->v_mntvnodes.le_next) if (VOP_ISLOCKED(vp)) vprint((char *)0, vp); }}#endifint kinfo_vdebug = 1;int kinfo_vgetfailed;#define KINFO_VNODESLOP 10/* * Dump vnode list (via sysctl). * Copyout address of vnode followed by vnode. *//* ARGSUSED */sysctl_vnode(where, sizep) char *where; size_t *sizep;{ register struct mount *mp, *nmp; struct vnode *vp; register 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; for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { nmp = mp->mnt_list.tqe_next; if (vfs_busy(mp)) continue; savebp = bp;again: for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = vp->v_mntvnodes.le_next) { /* * Check that the vp is still associated with * this filesystem. RACE: could have been * recycled onto the same filesystem. */ if (vp->v_mount != mp) { if (kinfo_vdebug) printf("kinfo: vp changed\n"); bp = savebp; goto again; } if (bp + VPTRSZ + VNODESZ > ewhere) { *sizep = bp - where; return (ENOMEM); } if ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || (error = copyout((caddr_t)vp, bp + VPTRSZ, VNODESZ))) return (error); bp += VPTRSZ + VNODESZ; } vfs_unbusy(mp); } *sizep = bp - where; return (0);}/* * Check to see if a filesystem is mounted on a block device. */intvfs_mountedon(vp) register struct vnode *vp;{ register struct vnode *vq; if (vp->v_specflags & SI_MOUNTEDON) return (EBUSY); if (vp->v_flag & VALIASED) { 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_specflags & SI_MOUNTEDON) return (EBUSY); } } return (0);}/* * 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;{ register struct netcred *np; register struct radix_node_head *rnh; register 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); bzero((caddr_t)np, i); saddr = (struct sockaddr *)(np + 1); if (error = copyin(argp->ex_addr, (caddr_t)saddr, argp->ex_addrlen)) 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_addr, (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 */ error = EPERM; 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; caddr_t w;{ register 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;{ register int i; register struct radix_node_head *rnh; for (i = 0; i <= AF_MAX; i++) if (rnh = nep->ne_rtable[i]) { (*rnh->rnh_walktree)(rnh, vfs_free_netcred, (caddr_t)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; if (argp->ex_flags & MNT_DELEXPORT) { vfs_free_addrlist(nep); mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); } if (argp->ex_flags & MNT_EXPORTED) { if (error = vfs_hang_addrlist(mp, nep, argp)) return (error); mp->mnt_flag |= MNT_EXPORTED; } return (0);}struct netcred *vfs_export_lookup(mp, nep, nam) register struct mount *mp; struct netexport *nep; struct mbuf *nam;{ register struct netcred *np; register struct radix_node_head *rnh; struct sockaddr *saddr; np = NULL; if (mp->mnt_flag & MNT_EXPORTED) { /* * Lookup in the export list first. */ if (nam != NULL) { saddr = mtod(nam, struct sockaddr *); rnh = nep->ne_rtable[saddr->sa_family]; if (rnh != NULL) { np = (struct netcred *) (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh); if (np && np->netc_rnodes->rn_flags & RNF_ROOT) np = NULL; } } /* * If no address match, use the default if it exists. */ if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED) np = &nep->ne_defexported; } return (np);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -