/* * Remove a filesystem */ static int mod_removefs(struct modlfs *modl, struct modlinkage *modlp) { struct vfssw *vswp; struct modctl *mcp; char *modname; if (moddebug & MODDEBUG_NOAUL_FS) return (EBUSY); WLOCK_VFSSW(); if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) { mcp = mod_getctl(modlp); ASSERT(mcp != NULL); modname = mcp->mod_modname; WUNLOCK_VFSSW(); cmn_err(CE_WARN, uninstall_err, modname); return (EINVAL); } if (vswp->vsw_count != 1) { vfs_unrefvfssw(vswp); WUNLOCK_VFSSW(); return (EBUSY); } /* XXX - Shouldn't the refcount be sufficient? */ if (vfs_opsinuse(&vswp->vsw_vfsops)) { vfs_unrefvfssw(vswp); WUNLOCK_VFSSW(); return (EBUSY); } vfs_freeopttbl(&vswp->vsw_optproto); vswp->vsw_optproto.mo_count = 0; vswp->vsw_flag = 0; vswp->vsw_init = NULL; vfs_unrefvfssw(vswp); WUNLOCK_VFSSW(); return (0); }
/*ARGSUSED*/ static int mod_infofs(struct modlfs *modl, struct modlinkage *modlp, int *p0) { struct vfssw *vswp; RLOCK_VFSSW(); if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) *p0 = -1; else { *p0 = vswp - vfssw; vfs_unrefvfssw(vswp); } RUNLOCK_VFSSW(); return (0); }
/* * As part of file system hardening, this daemon is awakened * every second to flush cached data which includes the * buffer cache, the inode cache and mapped pages. */ void fsflush() { struct buf *bp, *dwp; struct hbuf *hp; int autoup; unsigned int ix, icount, count = 0; callb_cpr_t cprinfo; uint_t bcount; kmutex_t *hmp; struct vfssw *vswp; proc_fsflush = ttoproc(curthread); proc_fsflush->p_cstime = 0; proc_fsflush->p_stime = 0; proc_fsflush->p_cutime = 0; proc_fsflush->p_utime = 0; bcopy("fsflush", curproc->p_user.u_psargs, 8); bcopy("fsflush", curproc->p_user.u_comm, 7); mutex_init(&fsflush_lock, NULL, MUTEX_DEFAULT, NULL); sema_init(&fsflush_sema, 0, NULL, SEMA_DEFAULT, NULL); /* * Setup page coalescing. */ fsf_npgsz = page_num_pagesizes(); ASSERT(fsf_npgsz < MAX_PAGESIZES); for (ix = 0; ix < fsf_npgsz - 1; ++ix) { fsf_pgcnt[ix] = page_get_pagesize(ix + 1) / page_get_pagesize(ix); fsf_mask[ix] = page_get_pagecnt(ix + 1) - 1; } autoup = v.v_autoup * hz; icount = v.v_autoup / tune.t_fsflushr; CALLB_CPR_INIT(&cprinfo, &fsflush_lock, callb_generic_cpr, "fsflush"); loop: sema_v(&fsflush_sema); mutex_enter(&fsflush_lock); CALLB_CPR_SAFE_BEGIN(&cprinfo); cv_wait(&fsflush_cv, &fsflush_lock); /* wait for clock */ CALLB_CPR_SAFE_END(&cprinfo, &fsflush_lock); mutex_exit(&fsflush_lock); sema_p(&fsflush_sema); /* * Write back all old B_DELWRI buffers on the freelist. */ bcount = 0; for (ix = 0; ix < v.v_hbuf; ix++) { hp = &hbuf[ix]; dwp = (struct buf *)&dwbuf[ix]; bcount += (hp->b_length); if (dwp->av_forw == dwp) { continue; } hmp = &hbuf[ix].b_lock; mutex_enter(hmp); bp = dwp->av_forw; /* * Go down only on the delayed write lists. */ while (bp != dwp) { ASSERT(bp->b_flags & B_DELWRI); if ((bp->b_flags & B_DELWRI) && (ddi_get_lbolt() - bp->b_start >= autoup) && sema_tryp(&bp->b_sem)) { bp->b_flags |= B_ASYNC; hp->b_length--; notavail(bp); mutex_exit(hmp); if (bp->b_vp == NULL) { BWRITE(bp); } else { UFS_BWRITE(VTOI(bp->b_vp)->i_ufsvfs, bp); } mutex_enter(hmp); bp = dwp->av_forw; } else { bp = bp->av_forw; } } mutex_exit(hmp); } /* * * There is no need to wakeup any thread waiting on bio_mem_cv * since brelse will wake them up as soon as IO is complete. */ bfreelist.b_bcount = bcount; if (dopageflush) fsflush_do_pages(); if (!doiflush) goto loop; /* * If the system was not booted to single user mode, skip the * inode flushing until after fsflush_iflush_delay secs have elapsed. */ if ((boothowto & RB_SINGLE) == 0 && (ddi_get_lbolt64() / hz) < fsflush_iflush_delay) goto loop; /* * Flush cached attribute information (e.g. inodes). */ if (++count >= icount) { count = 0; /* * Sync back cached data. */ RLOCK_VFSSW(); for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) { if (ALLOCATED_VFSSW(vswp) && VFS_INSTALLED(vswp)) { vfs_refvfssw(vswp); RUNLOCK_VFSSW(); (void) fsop_sync_by_kind(vswp - vfssw, SYNC_ATTR, kcred); vfs_unrefvfssw(vswp); RLOCK_VFSSW(); } } RUNLOCK_VFSSW(); } goto loop; }
/*ARGSUSED1*/ static int mod_installfs(struct modlfs *modl, struct modlinkage *modlp) { struct vfssw *vswp; struct modctl *mcp; char *fsname; char ksname[KSTAT_STRLEN + 1]; int fstype; /* index into vfssw[] and vsanchor_fstype[] */ int allocated; int err; int vsw_stats_enabled; /* Not for public consumption so these aren't in a header file */ extern int vopstats_enabled; extern vopstats_t **vopstats_fstype; extern kstat_t *new_vskstat(char *, vopstats_t *); extern void initialize_vopstats(vopstats_t *); if (modl->fs_vfsdef->def_version == VFSDEF_VERSION) { /* Version matched */ fsname = modl->fs_vfsdef->name; } else { if ((modl->fs_vfsdef->def_version > 0) && (modl->fs_vfsdef->def_version < VFSDEF_VERSION)) { /* Older VFSDEF_VERSION */ fsname = modl->fs_vfsdef->name; } else if ((mcp = mod_getctl(modlp)) != NULL) { /* Pre-VFSDEF_VERSION */ fsname = mcp->mod_modname; } else { /* If all else fails... */ fsname = "<unknown file system type>"; } cmn_err(CE_WARN, "file system '%s' version mismatch", fsname); return (ENXIO); } allocated = 0; WLOCK_VFSSW(); if ((vswp = vfs_getvfsswbyname(fsname)) == NULL) { if ((vswp = allocate_vfssw(fsname)) == NULL) { WUNLOCK_VFSSW(); /* * See 1095689. If this message appears, then * we either need to make the vfssw table bigger * statically, or make it grow dynamically. */ cmn_err(CE_WARN, "no room for '%s' in vfssw!", fsname); return (ENXIO); } allocated = 1; } ASSERT(vswp != NULL); fstype = vswp - vfssw; /* Pointer arithmetic to get the fstype */ /* Turn on everything by default *except* VSW_STATS */ vswp->vsw_flag = modl->fs_vfsdef->flags & ~(VSW_STATS); if (modl->fs_vfsdef->flags & VSW_HASPROTO) { vfs_mergeopttbl(&vfs_mntopts, modl->fs_vfsdef->optproto, &vswp->vsw_optproto); } else { vfs_copyopttbl(&vfs_mntopts, &vswp->vsw_optproto); } if (modl->fs_vfsdef->flags & VSW_CANRWRO) { /* * This obviously implies VSW_CANREMOUNT. */ vswp->vsw_flag |= VSW_CANREMOUNT; } /* * If stats are enabled system wide and for this fstype, then * set the VSW_STATS flag in the proper vfssw[] table entry. */ if (vopstats_enabled && modl->fs_vfsdef->flags & VSW_STATS) { vswp->vsw_flag |= VSW_STATS; } if (modl->fs_vfsdef->init == NULL) err = EFAULT; else err = (*(modl->fs_vfsdef->init))(fstype, fsname); if (err != 0) { if (allocated) { kmem_free(vswp->vsw_name, strlen(vswp->vsw_name)+1); vswp->vsw_name = ""; } vswp->vsw_flag = 0; vswp->vsw_init = NULL; } /* We don't want to hold the vfssw[] write lock over a kmem_alloc() */ vsw_stats_enabled = vswp->vsw_flag & VSW_STATS; vfs_unrefvfssw(vswp); WUNLOCK_VFSSW(); /* If everything is on, set up the per-fstype vopstats */ if (vsw_stats_enabled && vopstats_enabled && vopstats_fstype && vopstats_fstype[fstype] == NULL) { (void) strlcpy(ksname, VOPSTATS_STR, sizeof (ksname)); (void) strlcat(ksname, vfssw[fstype].vsw_name, sizeof (ksname)); vopstats_fstype[fstype] = kmem_alloc(sizeof (vopstats_t), KM_SLEEP); initialize_vopstats(vopstats_fstype[fstype]); (void) new_vskstat(ksname, vopstats_fstype[fstype]); } return (err); }
int loadrootmodules(void) { struct vfssw *vsw; char *this; char *name; int err; /* ONC_PLUS EXTRACT END */ int i, proplen; extern char *impl_module_list[]; extern char *platform_module_list[]; /* Make sure that the PROM's devinfo tree has been created */ ASSERT(ddi_root_node()); BMDPRINTF(("loadrootmodules: fstype %s\n", rootfs.bo_fstype)); BMDPRINTF(("loadrootmodules: name %s\n", rootfs.bo_name)); BMDPRINTF(("loadrootmodules: flags 0x%x\n", rootfs.bo_flags)); /* * zzz We need to honor what's in rootfs if it's not null. * non-null means use what's there. This way we can * change rootfs with /etc/system AND with tunetool. */ if (root_is_svm) { /* user replaced rootdev, record obp_bootpath */ obp_bootpath[0] = '\0'; (void) getphysdev("root", obp_bootpath, BO_MAXOBJNAME); BMDPRINTF(("loadrootmodules: obp_bootpath %s\n", obp_bootpath)); } else { /* * Get the root fstype and root device path from boot. */ rootfs.bo_fstype[0] = '\0'; rootfs.bo_name[0] = '\0'; } /* * This lookup will result in modloadonly-ing the root * filesystem module - it gets _init-ed in rootconf() */ if ((vsw = getfstype("root", rootfs.bo_fstype, BO_MAXFSNAME)) == NULL) return (ENXIO); /* in case we have no file system types */ (void) strcpy(rootfs.bo_fstype, vsw->vsw_name); vfs_unrefvfssw(vsw); /* * Load the favored drivers of the implementation. * e.g. 'sbus' and possibly 'zs' (even). * * Called whilst boot is still loaded (because boot does * the i/o for us), and DDI services are unavailable. */ BMDPRINTF(("loadrootmodules: impl_module_list\n")); for (i = 0; (this = impl_module_list[i]) != NULL; i++) { if ((err = load_boot_driver(this)) != 0) { cmn_err(CE_WARN, "Cannot load drv/%s", this); return (err); /* NOTREACHED */ } } /* * Now load the platform modules (if any) */ BMDPRINTF(("loadrootmodules: platform_module_list\n")); for (i = 0; (this = platform_module_list[i]) != NULL; i++) { if ((err = load_boot_platform_modules(this)) != 0) { cmn_err(CE_WARN, "Cannot load drv/%s", this); return (err); /* NOTREACHED */ } } loop: (void) getphysdev("root", rootfs.bo_name, BO_MAXOBJNAME); /* * Given a physical pathname, load the correct set of driver * modules into memory, including all possible parents. * * NB: The code sets the variable 'name' for error reporting. */ err = 0; BMDPRINTF(("loadrootmodules: rootfs %s\n", rootfs.bo_name)); if (root_is_svm == 0) { BMDPRINTF(("loadrootmodules: rootfs %s\n", rootfs.bo_name)); name = rootfs.bo_name; err = load_bootpath_drivers(rootfs.bo_name); } /* * Load driver modules in obp_bootpath, this is always * required for mountroot to succeed. obp_bootpath is * is set if rootdev is set via /etc/system, which is * the case if booting of a SVM/VxVM mirror. */ if ((err == 0) && obp_bootpath[0] != '\0') { BMDPRINTF(("loadrootmodules: obp_bootpath %s\n", obp_bootpath)); name = obp_bootpath; err = load_bootpath_drivers(obp_bootpath); } if (err != 0) { cmn_err(CE_CONT, "Cannot load drivers for %s\n", name); goto out; /* NOTREACHED */ } /* * Check to see if the booter performed DHCP configuration * ("bootp-response" boot property exists). If so, then before * bootops disappears we need to save the value of this property * such that the userland dhcpagent can adopt the DHCP management * of our primary network interface. */ proplen = BOP_GETPROPLEN(bootops, "bootp-response"); if (proplen > 0) { dhcack = kmem_zalloc(proplen, KM_SLEEP); if (BOP_GETPROP(bootops, "bootp-response", dhcack) == -1) { cmn_err(CE_WARN, "BOP_GETPROP of " "\"bootp-response\" failed\n"); kmem_free(dhcack, dhcacklen); dhcack = NULL; goto out; } dhcacklen = proplen; /* * Fetch the "netdev-path" boot property (if it exists), and * stash it for later use by sysinfo(SI_DHCP_CACHE, ...). */ proplen = BOP_GETPROPLEN(bootops, "netdev-path"); if (proplen > 0) { netdev_path = kmem_zalloc(proplen, KM_SLEEP); if (BOP_GETPROP(bootops, "netdev-path", (uchar_t *)netdev_path) == -1) { cmn_err(CE_WARN, "BOP_GETPROP of " "\"netdev-path\" failed\n"); kmem_free(netdev_path, proplen); goto out; } } } /* * Preload (load-only, no init) all modules which * were added to the /etc/system file with the * FORCELOAD keyword. */ BMDPRINTF(("loadrootmodules: preload_module\n")); (void) mod_sysctl_type(MOD_FORCELOAD, preload_module, NULL); /* ONC_PLUS EXTRACT START */ /* * If we booted otw then load in the plumbing * routine now while we still can. If we didn't * boot otw then we will load strplumb in main(). * * NFS is actually a set of modules, the core routines, * a diskless helper module, rpcmod, and the tli interface. Load * them now while we still can. * * Because we glomb all versions of nfs into a single module * we check based on the initial string "nfs". * * XXX: A better test for this is to see if device_type * XXX: from the PROM is "network". */ if (strncmp(rootfs.bo_fstype, "nfs", 3) == 0) { ++netboot; if ((err = modload("misc", "tlimod")) < 0) { cmn_err(CE_CONT, "Cannot load misc/tlimod\n"); goto out; /* NOTREACHED */ } if ((err = modload("strmod", "rpcmod")) < 0) { cmn_err(CE_CONT, "Cannot load strmod/rpcmod\n"); goto out; /* NOTREACHED */ } if ((err = modload("misc", "nfs_dlboot")) < 0) { cmn_err(CE_CONT, "Cannot load misc/nfs_dlboot\n"); goto out; /* NOTREACHED */ } if ((err = modload("mac", "mac_ether")) < 0) { cmn_err(CE_CONT, "Cannot load mac/mac_ether\n"); goto out; /* NOTREACHED */ } if ((err = modload("misc", "strplumb")) < 0) { cmn_err(CE_CONT, "Cannot load misc/strplumb\n"); goto out; /* NOTREACHED */ } if ((err = strplumb_load()) < 0) { goto out; /* NOTREACHED */ } } /* * Preload modules needed for booting as a cluster. */ err = clboot_loadrootmodules(); out: if (err != 0 && (boothowto & RB_ASKNAME)) goto loop; return (err); }
/* * Configure root file system. */ int rootconf(void) { int error; struct vfssw *vsw; extern void pm_init(void); BMDPRINTF(("rootconf: fstype %s\n", rootfs.bo_fstype)); BMDPRINTF(("rootconf: name %s\n", rootfs.bo_name)); BMDPRINTF(("rootconf: flags 0x%x\n", rootfs.bo_flags)); BMDPRINTF(("rootconf: obp_bootpath %s\n", obp_bootpath)); /* * Install cluster modules that were only loaded during * loadrootmodules(). */ if (error = clboot_rootconf()) return (error); if (root_is_svm) { (void) strncpy(rootfs.bo_name, obp_bootpath, BO_MAXOBJNAME); BMDPRINTF(("rootconf: svm: rootfs name %s\n", rootfs.bo_name)); BMDPRINTF(("rootconf: svm: svm name %s\n", svm_bootpath)); } /* * Run _init on the root filesystem (we already loaded it * but we've been waiting until now to _init it) which will * have the side-effect of running vsw_init() on this vfs. * Because all the nfs filesystems are lumped into one * module we need to special case it. */ if (strncmp(rootfs.bo_fstype, "nfs", 3) == 0) { if (modload("fs", "nfs") == -1) { cmn_err(CE_CONT, "Cannot initialize %s filesystem\n", rootfs.bo_fstype); return (ENXIO); } } else { if (modload("fs", rootfs.bo_fstype) == -1) { cmn_err(CE_CONT, "Cannot initialize %s filesystem\n", rootfs.bo_fstype); return (ENXIO); } } RLOCK_VFSSW(); vsw = vfs_getvfsswbyname(rootfs.bo_fstype); RUNLOCK_VFSSW(); VFS_INIT(rootvfs, &vsw->vsw_vfsops, (caddr_t)0); VFS_HOLD(rootvfs); if (root_is_svm) { rootvfs->vfs_flag |= VFS_RDONLY; } /* * This pm-releated call has to occur before root is mounted since we * need to power up all devices. It is placed after VFS_INIT() such * that opening a device via ddi_lyr_ interface just before root has * been mounted would work. */ pm_init(); if (netboot) { if ((error = strplumb()) != 0) { cmn_err(CE_CONT, "Cannot plumb network device\n"); return (error); } } /* * ufs_mountroot() ends up calling getrootdev() * (below) which actually triggers the _init, identify, * probe and attach of the drivers that make up root device * bush; these are also quietly waiting in memory. */ BMDPRINTF(("rootconf: calling VFS_MOUNTROOT %s\n", rootfs.bo_fstype)); error = VFS_MOUNTROOT(rootvfs, ROOT_INIT); vfs_unrefvfssw(vsw); rootdev = rootvfs->vfs_dev; if (error) cmn_err(CE_CONT, "Cannot mount root on %s fstype %s\n", rootfs.bo_name, rootfs.bo_fstype); else cmn_err(CE_CONT, "?root on %s fstype %s\n", rootfs.bo_name, rootfs.bo_fstype); return (error); }