vfs_subr.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,733 行 · 第 1/5 页
C
2,733 行
if (argp->ex_flags & MNT_DELEXPORT) { if (mp->mnt_flag & MNT_EXPUBLIC) { vfs_setpublicfs(NULL, NULL, NULL); mp->mnt_flag &= ~MNT_EXPUBLIC; } vfs_free_addrlist(nep); mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); } if (argp->ex_flags & MNT_EXPORTED) { if (argp->ex_flags & MNT_EXPUBLIC) { if ((error = vfs_setpublicfs(mp, nep, argp)) != 0) return (error); mp->mnt_flag |= MNT_EXPUBLIC; } if ((error = vfs_hang_addrlist(mp, nep, argp)) != 0) return (error); mp->mnt_flag |= MNT_EXPORTED; } return (0);}/* * Set the publicly exported filesystem (WebNFS). Currently, only * one public filesystem is possible in the spec (RFC 2054 and 2055) */intvfs_setpublicfs(mp, nep, argp) struct mount *mp; struct netexport *nep; struct export_args *argp;{ int error; struct vnode *rvp; char *cp; /* * mp == NULL -> invalidate the current info, the FS is * no longer exported. May be called from either vfs_export * or unmount, so check if it hasn't already been done. */ if (mp == NULL) { if (nfs_pub.np_valid) { nfs_pub.np_valid = 0; if (nfs_pub.np_index != NULL) { FREE(nfs_pub.np_index, M_TEMP); nfs_pub.np_index = NULL; } } return (0); } /* * Only one allowed at a time. */ if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount) return (EBUSY); /* * Get real filehandle for root of exported FS. */ memset((caddr_t)&nfs_pub.np_handle, 0, sizeof(nfs_pub.np_handle)); nfs_pub.np_handle.fh_fsid = mp->mnt_stat.f_fsid; if ((error = VFS_ROOT(mp, &rvp))) return (error); if ((error = VFS_VPTOFH(rvp, &nfs_pub.np_handle.fh_fid))) return (error); vput(rvp); /* * If an indexfile was specified, pull it in. */ if (argp->ex_indexfile != NULL) { MALLOC(nfs_pub.np_index, char *, MAXNAMLEN + 1, M_TEMP, M_WAITOK); error = copyinstr(argp->ex_indexfile, nfs_pub.np_index, MAXNAMLEN, (size_t *)0); if (!error) { /* * Check for illegal filenames. */ for (cp = nfs_pub.np_index; *cp; cp++) { if (*cp == '/') { error = EINVAL; break; } } } if (error) { FREE(nfs_pub.np_index, M_TEMP); return (error); } } nfs_pub.np_mount = mp; nfs_pub.np_valid = 1; return (0);}struct netcred *vfs_export_lookup(mp, nep, nam) struct mount *mp; struct netexport *nep; struct mbuf *nam;{ struct netcred *np; 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);}/* * Do the usual access checking. * file_mode, uid and gid are from the vnode in question, * while acc_mode and cred are from the VOP_ACCESS parameter list */intvaccess(type, file_mode, uid, gid, acc_mode, cred) enum vtype type; mode_t file_mode; uid_t uid; gid_t gid; mode_t acc_mode; struct ucred *cred;{ mode_t mask; /* * Super-user always gets read/write access, but execute access depends * on at least one execute bit being set. */ if (cred->cr_uid == 0) { if ((acc_mode & VEXEC) && type != VDIR && (file_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) return (EACCES); return (0); } mask = 0; /* Otherwise, check the owner. */ if (cred->cr_uid == uid) { if (acc_mode & VEXEC) mask |= S_IXUSR; if (acc_mode & VREAD) mask |= S_IRUSR; if (acc_mode & VWRITE) mask |= S_IWUSR; return ((file_mode & mask) == mask ? 0 : EACCES); } /* Otherwise, check the groups. */ if (cred->cr_gid == gid || groupmember(gid, cred)) { if (acc_mode & VEXEC) mask |= S_IXGRP; if (acc_mode & VREAD) mask |= S_IRGRP; if (acc_mode & VWRITE) mask |= S_IWGRP; return ((file_mode & mask) == mask ? 0 : EACCES); } /* Otherwise, check everyone else. */ if (acc_mode & VEXEC) mask |= S_IXOTH; if (acc_mode & VREAD) mask |= S_IROTH; if (acc_mode & VWRITE) mask |= S_IWOTH; return ((file_mode & mask) == mask ? 0 : EACCES);}/* * Unmount all file systems. * We traverse the list in reverse order under the assumption that doing so * will avoid needing to worry about dependencies. */voidvfs_unmountall(p) struct proc *p;{ struct mount *mp, *nmp; int allerror, error; for (allerror = 0, mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) { nmp = mp->mnt_list.cqe_prev;#ifdef DEBUG printf("unmounting %s (%s)...\n", mp->mnt_stat.f_mntonname, mp->mnt_stat.f_mntfromname);#endif if (vfs_busy(mp, 0, 0)) continue; if ((error = dounmount(mp, MNT_FORCE, p)) != 0) { printf("unmount of %s failed with error %d\n", mp->mnt_stat.f_mntonname, error); allerror = 1; } } if (allerror) printf("WARNING: some file systems would not unmount\n");}/* * Sync and unmount file systems before shutting down. */voidvfs_shutdown(){ struct buf *bp; int iter, nbusy, nbusy_prev = 0, dcount, s; struct proc *p = curproc; /* XXX we're certainly not running in proc0's context! */ if (p == NULL) p = &proc0; printf("syncing disks... "); /* remove user process from run queue */ suspendsched(); (void) spl0(); /* avoid coming back this way again if we panic. */ doing_shutdown = 1; sys_sync(p, NULL, NULL); /* Wait for sync to finish. */ dcount = 10000; for (iter = 0; iter < 20;) { nbusy = 0; for (bp = &buf[nbuf]; --bp >= buf; ) { if ((bp->b_flags & (B_BUSY|B_INVAL|B_READ)) == B_BUSY) nbusy++; /* * With soft updates, some buffers that are * written will be remarked as dirty until other * buffers are written. */ if (bp->b_vp && bp->b_vp->v_mount && (bp->b_vp->v_mount->mnt_flag & MNT_SOFTDEP) && (bp->b_flags & B_DELWRI)) { s = splbio(); bremfree(bp); bp->b_flags |= B_BUSY; splx(s); nbusy++; bawrite(bp); if (dcount-- <= 0) { printf("softdep "); goto fail; } } } if (nbusy == 0) break; if (nbusy_prev == 0) nbusy_prev = nbusy; printf("%d ", nbusy); tsleep(&nbusy, PRIBIO, "bflush", (iter == 0) ? 1 : hz / 25 * iter); if (nbusy >= nbusy_prev) /* we didn't flush anything */ iter++; else nbusy_prev = nbusy; } if (nbusy) {fail:#if defined(DEBUG) || defined(DEBUG_HALT_BUSY) printf("giving up\nPrinting vnodes for busy buffers\n"); for (bp = &buf[nbuf]; --bp >= buf; ) if ((bp->b_flags & (B_BUSY|B_INVAL|B_READ)) == B_BUSY) vprint(NULL, bp->b_vp);#if defined(DDB) && defined(DEBUG_HALT_BUSY) Debugger();#endif#else /* defined(DEBUG) || defined(DEBUG_HALT_BUSY) */ printf("giving up\n");#endif /* defined(DEBUG) || defined(DEBUG_HALT_BUSY) */ return; } else printf("done\n"); /* * If we've panic'd, don't make the situation potentially * worse by unmounting the file systems. */ if (panicstr != NULL) return; /* Release inodes held by texts before update. */#ifdef notdef vnshutdown();#endif /* Unmount file systems. */ vfs_unmountall(p);}/* * Mount the root file system. If the operator didn't specify a * file system to use, try all possible file systems until one * succeeds. */intvfs_mountroot(){ extern int (*mountroot) __P((void)); struct vfsops *v; if (root_device == NULL) panic("vfs_mountroot: root device unknown"); switch (root_device->dv_class) { case DV_IFNET: if (rootdev != NODEV) panic("vfs_mountroot: rootdev set for DV_IFNET"); break; case DV_DISK: if (rootdev == NODEV) panic("vfs_mountroot: rootdev not set for DV_DISK"); break; default: printf("%s: inappropriate for root file system\n", root_device->dv_xname); return (ENODEV); } /* * If user specified a file system, use it. */ if (mountroot != NULL) return ((*mountroot)()); /* * Try each file system currently configured into the kernel. */ for (v = LIST_FIRST(&vfs_list); v != NULL; v = LIST_NEXT(v, vfs_list)) { if (v->vfs_mountroot == NULL) continue;#ifdef DEBUG printf("mountroot: trying %s...\n", v->vfs_name);#endif if ((*v->vfs_mountroot)() == 0) { printf("root file system type: %s\n", v->vfs_name); break; } } if (v == NULL) { printf("no file system for %s", root_device->dv_xname); if (root_device->dv_class == DV_DISK) printf(" (dev 0x%x)", rootdev); printf("\n"); return (EFTYPE); } return (0);}/* * Given a file system name, look up the vfsops for that * file system, or return NULL if file system isn't present * in the kernel. */struct vfsops *vfs_getopsbyname(name) const char *name;{ struct vfsops *v; for (v = LIST_FIRST(&vfs_list); v != NULL; v = LIST_NEXT(v, vfs_list)) { if (strcmp(v->vfs_name, name) == 0) break; } return (v);}/* * Establish a file system and initialize it. */intvfs_attach(vfs) struct vfsops *vfs;{ struct vfsops *v; int error = 0; /* * Make sure this file system doesn't already exist. */ for (v = LIST_FIRST(&vfs_list); v != NULL; v = LIST_NEXT(v, vfs_list)) { if (strcmp(vfs->vfs_name, v->vfs_name) == 0) { error = EEXIST; goto out; } } /* * Initialize the vnode operations for this file system. */ vfs_opv_init(vfs->vfs_opv_descs); /* * Now initialize the file system itself. */ (*vfs->vfs_init)(); /* * ...and link it into the kernel's list. */ LIST_INSERT_HEAD(&vfs_list, vfs, vfs_list); /* * Sanity: make sure the reference count is 0. */ vfs->vfs_refcount = 0; out: return (error);}/* * Remove a file system from the kernel. */intvfs_detach(vfs) struct vfsops *vfs;{ struct vfsops *v; /* * Make sure no one is using the filesystem. */ if (vfs->vfs_refcount != 0) return (EBUSY); /* * ...and remove it from the kernel's list. */ for (v = LIST_FIRST(&vfs_list); v != NULL; v = LIST_NEXT(v, vfs_list)) { if (v == vfs) { LIST_REMOVE(v, vfs_list); break; } } if (v == NULL) return (ESRCH); /* * Now run the file system-specific cleanups. */ (*vfs->vfs_done)(); /* * Free the vnode operations vector. */ vfs_opv_free(vfs->vfs_opv_descs); return (0);}#ifdef DDBconst char buf_flagbits[] = "\20\1AGE\2NEEDCOMMIT\3ASYNC\4BAD\5BUSY\6SCANNED\7CALL\10DELWRI" "\11DIRTY\12DONE\13EINTR\14ERROR\15GATHERED\16INVAL\17LOCKED\20NOCACHE" "\21ORDERED\22CACHE\23PHYS\24RAW\25READ\26TAPE\30WANTED" "\32XXX\33VFLUSH";voidvfs_buf_print(bp, full, pr) struct buf *bp; int full; void (*pr) __P((const char *, ...));{ char buf[1024]; (*pr)(" vp %p lblkno 0x%x blkno 0x%x dev 0x%x\n", bp->b_vp, bp->b_lblkno, bp->b_blkno, bp->b_dev); bitmask_snprintf(bp->b_flags, buf_flagbits, buf, sizeof(buf)); (*pr)(" error %d flags 0x%s\n", bp->b_error, buf); (*pr)(" bufsize 0x%x bcount 0x%x resid 0x%x\n", bp->b_bufsize, bp->b_bcount, bp->b_resid); (*pr)(" data %p saveaddr %p dep %p\n", bp->b_data, bp->b_saveaddr, LIST_FIRST(&bp->b_dep)); (*pr)(" iodone %p\n", bp->b_iodone);}const char vnode_flagbits[] = "\20\1ROOT\2TEXT\3SYSTEM\4ISTTY\11XLOCK\12XWANT\13BWAIT\14ALIASED" "\15DIROP\17DIRTY";const char *vnode_types[] = { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD",};const char *vnode_tags[] = { "VT_NON", "VT_UFS", "VT_NFS", "VT_MFS", "VT_MSDOSFS", "VT_LFS", "V
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?