/* Create single-use devices for /dev/apm and /dev/apmctl. */ static void apm_clone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) { int ctl_dev, unit; if (*dev != NULL) return; if (strcmp(name, "apmctl") == 0) ctl_dev = TRUE; else if (strcmp(name, "apm") == 0) ctl_dev = FALSE; else return; /* Always create a new device and unit number. */ unit = -1; if (clone_create(&apm_clones, &apm_cdevsw, &unit, dev, 0)) { if (ctl_dev) { *dev = make_dev(&apm_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0660, "apmctl%d", unit); } else { *dev = make_dev(&apm_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0664, "apm%d", unit); } if (*dev != NULL) { dev_ref(*dev); (*dev)->si_flags |= SI_CHEAPCLONE; } } }
static void dtrace_clone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) { int u = -1; size_t len; if (*dev != NULL) return; len = strlen(name); if (len != 6 && len != 13) return; if (bcmp(name,"dtrace",6) != 0) return; if (len == 13 && bcmp(name,"dtrace/dtrace",13) != 0) return; /* Clone the device to the new minor number. */ if (clone_create(&dtrace_clones, &dtrace_cdevsw, &u, dev, 0) != 0) /* Create the /dev/dtrace/dtraceNN entry. */ *dev = make_dev_cred(&dtrace_cdevsw, u, cred, UID_ROOT, GID_WHEEL, 0600, "dtrace/dtrace%d", u); if (*dev != NULL) { dev_ref(*dev); (*dev)->si_flags |= SI_CHEAPCLONE; } }
/* * allocate the device */ int wav_init(struct wav *f) { if (!dev_ref(f->dev)) { wav_exit(f); return 0; } if (!f->mmc) f->dev->autostart = 1; if (f->mode & MODE_MIDIMASK) { wav_midiattach(f); return 1; } f->slot = dev_slotnew(f->dev, "wav", &ctl_wavops, f, 1); f->pstate = WAV_INIT; if ((f->mode & f->dev->mode) != f->mode) { #ifdef DEBUG if (debug_level >= 1) { wav_dbg(f); dbg_puts(": "); dbg_puts(": operation not supported by device\n"); } #endif wav_exit(f); return 0; } wav_allocbuf(f); return 1; }
/* * 关闭 socket */ static int socket_close(void *ctx, file_t *file) { privinfo_t *priv = ctx; reg_t reg; if (priv == NULL) { seterrno(EINVAL); return -1; } reg = interrupt_disable(); atomic_dec(dev_ref(file)); device_remove(file->ctx); file->ctx = NULL; lwip_close(priv->sock_fd); kfree(priv); interrupt_resume(reg); return 0; }
/* See: old_dev_pager_ctor() in device_pager.c as an example. */ static int cheri_compositor_cfb_pg_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff, struct ucred *cred, u_short *color) { struct cfb_vm_object *cfb_vm_obj; struct cdev *dev; struct cheri_compositor_softc *sc; struct cdevsw *csw; vm_ooffset_t top_offset; /* offset of the first byte above the alloc. */ unsigned int npages; int ref; int retval = 0; cfb_vm_obj = handle; dev = cfb_vm_obj->dev; sc = dev->si_drv1; CHERI_COMPOSITOR_DEBUG(sc, "handle: %p, size: %lu, prot: %i, foff: %lu, cred: %p", handle, size, prot, foff, cred); /* Make sure this device can be mapped. */ csw = dev_refthread(dev, &ref); if (csw == NULL) { retval = ENXIO; goto done_unreffed; } /* Protection, alignment and bounds checks. */ npages = OFF_TO_IDX(size); top_offset = foff + (npages - 1) * PAGE_SIZE; retval = validate_prot_and_offset(sc, cfb_vm_obj->pool->mapped_fd, prot, top_offset); if (retval != 0) { goto done; } /* Hold a reference to the device until this mapping is destroyed in * cheri_compositor_cfb_pg_dtor(). */ dev_ref(dev); /* All compositor pages are uncached, so colouring them (to reduce cache * collisions; see * http://docs.freebsd.org/doc/4.4-RELEASE/usr/share/doc/en/articles/vm-design/x103.html) * is pointless. */ *color = 0; /* Success. */ retval = 0; done: dev_relthread(dev, ref); done_unreffed: CHERI_COMPOSITOR_DEBUG(sc, "Finished with color: %u (retval: %u).", *color, retval); return (retval); }
/* * 关闭 xxx */ static int xxx_close(void *ctx, file_t *file) { privinfo_t *priv = ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } if (atomic_read(dev_ref(file)) == 1) { /* * TODO: 加上最后一次关闭时的清理代码 */ } atomic_dec(dev_ref(file)); return 0; }
/* * 打开 socket */ static int socket_open(void *ctx, file_t *file, int oflag, mode_t mode) { privinfo_t *priv = ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } if (atomic_inc_return(dev_ref(file)) == 1) { return 0; } else { /* * 如果设备不允许同时打开多次, 请使用如下代码: */ atomic_dec(dev_ref(file)); seterrno(EBUSY); return -1; } }
/********************************************************************************************************* ** Function name: mtdblock_open ** Descriptions: 打开 mtdblock ** input parameters: ctx 私有信息 ** file 文件结构 ** oflag 打开标志 ** mode 模式 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ static int mtdblock_open(void *ctx, file_t *file, int oflag, mode_t mode) { privinfo_t *priv = ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } atomic_inc(dev_ref(file)); return 0; }
/********************************************************************************************************* ** Function name: mtdblock_close ** Descriptions: 关闭 mtdblock ** input parameters: ctx 私有信息 ** file 文件结构 ** output parameters: NONE ** Returned value: 0 OR -1 *********************************************************************************************************/ static int mtdblock_close(void *ctx, file_t *file) { privinfo_t *priv = ctx; if (priv == NULL) { seterrno(EINVAL); return -1; } atomic_dec(dev_ref(file)); return 0; }
static int netmap_dev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff, struct ucred *cred, u_short *color) { struct netmap_vm_handle_t *vmh = handle; (void)vmh; D("handle %p size %jd prot %d foff %jd", handle, (intmax_t)size, prot, (intmax_t)foff); #if 0 dev_ref(vmh->dev); #endif return 0; }
/** * DEVFS event handler. */ static void vgdrvFreeBSDClone(void *pvArg, struct ucred *pCred, char *pszName, int cchName, struct cdev **ppDev) { int iUnit; int rc; Log(("vgdrvFreeBSDClone: pszName=%s ppDev=%p\n", pszName, ppDev)); /* * One device node per user, si_drv1 points to the session. * /dev/vboxguest<N> where N = {0...255}. */ if (!ppDev) return; if (strcmp(pszName, "vboxguest") == 0) iUnit = -1; else if (dev_stdclone(pszName, NULL, "vboxguest", &iUnit) != 1) return; if (iUnit >= 256) { Log(("vgdrvFreeBSDClone: iUnit=%d >= 256 - rejected\n", iUnit)); return; } Log(("vgdrvFreeBSDClone: pszName=%s iUnit=%d\n", pszName, iUnit)); rc = clone_create(&g_pvgdrvFreeBSDClones, &g_vgdrvFreeBSDChrDevSW, &iUnit, ppDev, 0); Log(("vgdrvFreeBSDClone: clone_create -> %d; iUnit=%d\n", rc, iUnit)); if (rc) { *ppDev = make_dev(&g_vgdrvFreeBSDChrDevSW, iUnit, UID_ROOT, GID_WHEEL, 0664, "vboxguest%d", iUnit); if (*ppDev) { dev_ref(*ppDev); (*ppDev)->si_flags |= SI_CHEAPCLONE; Log(("vgdrvFreeBSDClone: Created *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n", *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2)); (*ppDev)->si_drv1 = (*ppDev)->si_drv2 = NULL; } else Log(("vgdrvFreeBSDClone: make_dev iUnit=%d failed\n", iUnit)); } else Log(("vgdrvFreeBSDClone: Existing *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n", *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2)); }
/** * DEVFS event handler. */ static void VBoxDrvFreeBSDClone(void *pvArg, struct ucred *pCred, char *pszName, int cchName, struct cdev **ppDev) { int iUnit; int rc; Log(("VBoxDrvFreeBSDClone: pszName=%s ppDev=%p\n", pszName, ppDev)); /* * One device node per user, si_drv1 points to the session. * /dev/vboxdrv<N> where N = {0...255}. */ if (!ppDev) return; if (dev_stdclone(pszName, NULL, "vboxdrv", &iUnit) != 1) return; if (iUnit >= 256 || iUnit < 0) { Log(("VBoxDrvFreeBSDClone: iUnit=%d >= 256 - rejected\n", iUnit)); return; } Log(("VBoxDrvFreeBSDClone: pszName=%s iUnit=%d\n", pszName, iUnit)); rc = clone_create(&g_pVBoxDrvFreeBSDClones, &g_VBoxDrvFreeBSDChrDevSW, &iUnit, ppDev, 0); Log(("VBoxDrvFreeBSDClone: clone_create -> %d; iUnit=%d\n", rc, iUnit)); if (rc) { #if __FreeBSD_version > 800061 *ppDev = make_dev(&g_VBoxDrvFreeBSDChrDevSW, iUnit, UID_ROOT, GID_WHEEL, VBOXDRV_PERM, "vboxdrv%d", iUnit); #else *ppDev = make_dev(&g_VBoxDrvFreeBSDChrDevSW, unit2minor(iUnit), UID_ROOT, GID_WHEEL, VBOXDRV_PERM, "vboxdrv%d", iUnit); #endif if (*ppDev) { dev_ref(*ppDev); (*ppDev)->si_flags |= SI_CHEAPCLONE; Log(("VBoxDrvFreeBSDClone: Created *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n", *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2)); (*ppDev)->si_drv1 = (*ppDev)->si_drv2 = NULL; } else OSDBGPRINT(("VBoxDrvFreeBSDClone: make_dev iUnit=%d failed\n", iUnit)); } else Log(("VBoxDrvFreeBSDClone: Existing *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n", *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2)); }
static void nsmb_dev_clone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) { int i, u; if (*dev != NULL) return; if (strcmp(name, NSMB_NAME) == 0) u = -1; else if (dev_stdclone(name, NULL, NSMB_NAME, &u) != 1) return; i = clone_create(&nsmb_clones, &nsmb_cdevsw, &u, dev, 0); if (i) { *dev = make_dev(&nsmb_cdevsw, u, UID_ROOT, GID_WHEEL, 0600, "%s%d", NSMB_NAME, u); if (*dev != NULL) { dev_ref(*dev); (*dev)->si_flags |= SI_CHEAPCLONE; } } }
static int fuse_getdevice(const char *fspec, struct thread *td, struct cdev **fdevp) { struct nameidata nd, *ndp = &nd; struct vnode *devvp; struct cdev *fdev; int err; /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible disk device. */ NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td); if ((err = namei(ndp)) != 0) return err; NDFREE(ndp, NDF_ONLY_PNBUF); devvp = ndp->ni_vp; if (devvp->v_type != VCHR) { vrele(devvp); return ENXIO; } fdev = devvp->v_rdev; dev_ref(fdev); if (fuse_enforce_dev_perms) { /* * Check if mounter can open the fuse device. * * This has significance only if we are doing a secondary mount * which doesn't involve actually opening fuse devices, but we * still want to enforce the permissions of the device (in * order to keep control over the circle of fuse users). * * (In case of primary mounts, we are either the superuser so * we can do anything anyway, or we can mount only if the * device is already opened by us, ie. we are permitted to open * the device.) */ #if 0 #ifdef MAC err = mac_check_vnode_open(td->td_ucred, devvp, VREAD | VWRITE); if (!err) #endif #endif /* 0 */ err = VOP_ACCESS(devvp, VREAD | VWRITE, td->td_ucred, td); if (err) { vrele(devvp); dev_rel(fdev); return err; } } /* * according to coda code, no extra lock is needed -- * although in sys/vnode.h this field is marked "v" */ vrele(devvp); if (!fdev->si_devsw || strcmp("fuse", fdev->si_devsw->d_name)) { dev_rel(fdev); return ENXIO; } *fdevp = fdev; return 0; }
/* * Common code for mount and mountroot */ static int reiserfs_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) { int error, old_format = 0; struct reiserfs_mount *rmp; struct reiserfs_sb_info *sbi; struct reiserfs_super_block *rs; struct cdev *dev; struct g_consumer *cp; struct bufobj *bo; //ronly = (mp->mnt_flag & MNT_RDONLY) != 0; dev = devvp->v_rdev; dev_ref(dev); DROP_GIANT(); g_topology_lock(); error = g_vfs_open(devvp, &cp, "reiserfs", /* read-only */ 0); g_topology_unlock(); PICKUP_GIANT(); VOP_UNLOCK(devvp, 0); if (error) { dev_rel(dev); return (error); } bo = &devvp->v_bufobj; bo->bo_private = cp; bo->bo_ops = g_vfs_bufops; if (devvp->v_rdev->si_iosize_max != 0) mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; if (mp->mnt_iosize_max > MAXPHYS) mp->mnt_iosize_max = MAXPHYS; rmp = NULL; sbi = NULL; /* rmp contains any information about this specific mount */ rmp = malloc(sizeof *rmp, M_REISERFSMNT, M_WAITOK | M_ZERO); if (!rmp) { error = (ENOMEM); goto out; } sbi = malloc(sizeof *sbi, M_REISERFSMNT, M_WAITOK | M_ZERO); if (!sbi) { error = (ENOMEM); goto out; } rmp->rm_reiserfs = sbi; rmp->rm_mountp = mp; rmp->rm_devvp = devvp; rmp->rm_dev = dev; rmp->rm_bo = &devvp->v_bufobj; rmp->rm_cp = cp; /* Set default values for options: non-aggressive tails */ REISERFS_SB(sbi)->s_mount_opt = (1 << REISERFS_SMALLTAIL); REISERFS_SB(sbi)->s_rd_only = 1; REISERFS_SB(sbi)->s_devvp = devvp; /* Read the super block */ if ((error = read_super_block(rmp, REISERFS_OLD_DISK_OFFSET)) == 0) { /* The read process succeeded, it's an old format */ old_format = 1; } else if ((error = read_super_block(rmp, REISERFS_DISK_OFFSET)) != 0) { reiserfs_log(LOG_ERR, "can not find a ReiserFS filesystem\n"); goto out; } rs = SB_DISK_SUPER_BLOCK(sbi); /* * Let's do basic sanity check to verify that underlying device is * not smaller than the filesystem. If the check fails then abort and * scream, because bad stuff will happen otherwise. */ #if 0 if (s->s_bdev && s->s_bdev->bd_inode && i_size_read(s->s_bdev->bd_inode) < sb_block_count(rs) * sb_blocksize(rs)) { reiserfs_log(LOG_ERR, "reiserfs: filesystem cannot be mounted because it is " "bigger than the device.\n"); reiserfs_log(LOG_ERR, "reiserfs: you may need to run fsck " "rr may be you forgot to reboot after fdisk when it " "told you to.\n"); goto out; } #endif /* * XXX This is from the original Linux code, but why affecting 2 values * to the same variable? */ sbi->s_mount_state = SB_REISERFS_STATE(sbi); sbi->s_mount_state = REISERFS_VALID_FS; if ((error = (old_format ? read_old_bitmaps(rmp) : read_bitmaps(rmp)))) { reiserfs_log(LOG_ERR, "unable to read bitmap\n"); goto out; } /* Make data=ordered the default */ if (!reiserfs_data_log(sbi) && !reiserfs_data_ordered(sbi) && !reiserfs_data_writeback(sbi)) { REISERFS_SB(sbi)->s_mount_opt |= (1 << REISERFS_DATA_ORDERED); } if (reiserfs_data_log(sbi)) { reiserfs_log(LOG_INFO, "using journaled data mode\n"); } else if (reiserfs_data_ordered(sbi)) { reiserfs_log(LOG_INFO, "using ordered data mode\n"); } else { reiserfs_log(LOG_INFO, "using writeback data mode\n"); } /* TODO Not yet supported */ #if 0 if(journal_init(sbi, jdev_name, old_format, commit_max_age)) { reiserfs_log(LOG_ERR, "unable to initialize journal space\n"); goto out; } else { jinit_done = 1 ; /* once this is set, journal_release must be called if we error out of the mount */ } if (reread_meta_blocks(sbi)) { reiserfs_log(LOG_ERR, "unable to reread meta blocks after journal init\n"); goto out; } #endif /* Define and initialize hash function */ sbi->s_hash_function = hash_function(rmp); if (sbi->s_hash_function == NULL) { reiserfs_log(LOG_ERR, "couldn't determined hash function\n"); error = (EINVAL); goto out; } if (is_reiserfs_3_5(rs) || (is_reiserfs_jr(rs) && SB_VERSION(sbi) == REISERFS_VERSION_1)) bit_set(&(sbi->s_properties), REISERFS_3_5); else bit_set(&(sbi->s_properties), REISERFS_3_6); mp->mnt_data = rmp; mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_MPSAFE; MNT_IUNLOCK(mp); #if defined(si_mountpoint) devvp->v_rdev->si_mountpoint = mp; #endif return (0); out: reiserfs_log(LOG_INFO, "*** error during mount ***\n"); if (sbi) { if (SB_AP_BITMAP(sbi)) { int i; for (i = 0; i < SB_BMAP_NR(sbi); i++) { if (!SB_AP_BITMAP(sbi)[i].bp_data) break; free(SB_AP_BITMAP(sbi)[i].bp_data, M_REISERFSMNT); } free(SB_AP_BITMAP(sbi), M_REISERFSMNT); } if (sbi->s_rs) { free(sbi->s_rs, M_REISERFSMNT); sbi->s_rs = NULL; } } if (cp != NULL) { DROP_GIANT(); g_topology_lock(); g_vfs_close(cp); g_topology_unlock(); PICKUP_GIANT(); } if (sbi) free(sbi, M_REISERFSMNT); if (rmp) free(rmp, M_REISERFSMNT); dev_rel(dev); return (error); }
static int udf_mountfs(struct vnode *devvp, struct mount *mp) { struct buf *bp = NULL; struct cdev *dev; struct anchor_vdp avdp; struct udf_mnt *udfmp = NULL; struct part_desc *pd; struct logvol_desc *lvd; struct fileset_desc *fsd; struct file_entry *root_fentry; uint32_t sector, size, mvds_start, mvds_end; uint32_t logical_secsize; uint32_t fsd_offset = 0; uint16_t part_num = 0, fsd_part = 0; int error = EINVAL; int logvol_found = 0, part_found = 0, fsd_found = 0; int bsize; struct g_consumer *cp; struct bufobj *bo; dev = devvp->v_rdev; dev_ref(dev); DROP_GIANT(); g_topology_lock(); error = g_vfs_open(devvp, &cp, "udf", 0); g_topology_unlock(); PICKUP_GIANT(); VOP_UNLOCK(devvp, 0); if (error) goto bail; bo = &devvp->v_bufobj; if (devvp->v_rdev->si_iosize_max != 0) mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; if (mp->mnt_iosize_max > MAXPHYS) mp->mnt_iosize_max = MAXPHYS; /* XXX: should be M_WAITOK */ udfmp = malloc(sizeof(struct udf_mnt), M_UDFMOUNT, M_NOWAIT | M_ZERO); if (udfmp == NULL) { printf("Cannot allocate UDF mount struct\n"); error = ENOMEM; goto bail; } mp->mnt_data = udfmp; mp->mnt_stat.f_fsid.val[0] = dev2udev(devvp->v_rdev); mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED; MNT_IUNLOCK(mp); udfmp->im_mountp = mp; udfmp->im_dev = dev; udfmp->im_devvp = devvp; udfmp->im_d2l = NULL; udfmp->im_cp = cp; udfmp->im_bo = bo; #if 0 udfmp->im_l2d = NULL; #endif /* * The UDF specification defines a logical sectorsize of 2048 * for DVD media. */ logical_secsize = 2048; if (((logical_secsize % cp->provider->sectorsize) != 0) || (logical_secsize < cp->provider->sectorsize)) { error = EINVAL; goto bail; } bsize = cp->provider->sectorsize; /* * Get the Anchor Volume Descriptor Pointer from sector 256. * XXX Should also check sector n - 256, n, and 512. */ sector = 256; if ((error = bread(devvp, sector * btodb(logical_secsize), bsize, NOCRED, &bp)) != 0) goto bail; if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR))) goto bail; bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp)); brelse(bp); bp = NULL; /* * Extract the Partition Descriptor and Logical Volume Descriptor * from the Volume Descriptor Sequence. * XXX Should we care about the partition type right now? * XXX What about multiple partitions? */ mvds_start = le32toh(avdp.main_vds_ex.loc); mvds_end = mvds_start + (le32toh(avdp.main_vds_ex.len) - 1) / bsize; for (sector = mvds_start; sector < mvds_end; sector++) { if ((error = bread(devvp, sector * btodb(logical_secsize), bsize, NOCRED, &bp)) != 0) { printf("Can't read sector %d of VDS\n", sector); goto bail; } lvd = (struct logvol_desc *)bp->b_data; if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) { udfmp->bsize = le32toh(lvd->lb_size); udfmp->bmask = udfmp->bsize - 1; udfmp->bshift = ffs(udfmp->bsize) - 1; fsd_part = le16toh(lvd->_lvd_use.fsd_loc.loc.part_num); fsd_offset = le32toh(lvd->_lvd_use.fsd_loc.loc.lb_num); if (udf_find_partmaps(udfmp, lvd)) break; logvol_found = 1; } pd = (struct part_desc *)bp->b_data; if (!udf_checktag(&pd->tag, TAGID_PARTITION)) { part_found = 1; part_num = le16toh(pd->part_num); udfmp->part_len = le32toh(pd->part_len); udfmp->part_start = le32toh(pd->start_loc); } brelse(bp); bp = NULL; if ((part_found) && (logvol_found)) break; } if (!part_found || !logvol_found) { error = EINVAL; goto bail; } if (fsd_part != part_num) { printf("FSD does not lie within the partition!\n"); error = EINVAL; goto bail; } /* * Grab the Fileset Descriptor * Thanks to Chuck McCrobie <*****@*****.**> for pointing * me in the right direction here. */ sector = udfmp->part_start + fsd_offset; if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) { printf("Cannot read sector %d of FSD\n", sector); goto bail; } fsd = (struct fileset_desc *)bp->b_data; if (!udf_checktag(&fsd->tag, TAGID_FSD)) { fsd_found = 1; bcopy(&fsd->rootdir_icb, &udfmp->root_icb, sizeof(struct long_ad)); } brelse(bp); bp = NULL; if (!fsd_found) { printf("Couldn't find the fsd\n"); error = EINVAL; goto bail; } /* * Find the file entry for the root directory. */ sector = le32toh(udfmp->root_icb.loc.lb_num) + udfmp->part_start; size = le32toh(udfmp->root_icb.len); if ((error = udf_readdevblks(udfmp, sector, size, &bp)) != 0) { printf("Cannot read sector %d\n", sector); goto bail; } root_fentry = (struct file_entry *)bp->b_data; if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) { printf("Invalid root file entry!\n"); goto bail; } brelse(bp); bp = NULL; return 0; bail: if (udfmp != NULL) free(udfmp, M_UDFMOUNT); if (bp != NULL) brelse(bp); if (cp != NULL) { DROP_GIANT(); g_topology_lock(); g_vfs_close(cp); g_topology_unlock(); PICKUP_GIANT(); } dev_rel(dev); return error; };
static int mountmsdosfs(struct vnode *devvp, struct mount *mp) { struct msdosfsmount *pmp; struct buf *bp; struct cdev *dev; union bootsector *bsp; struct byte_bpb33 *b33; struct byte_bpb50 *b50; struct byte_bpb710 *b710; u_int8_t SecPerClust; u_long clusters; int ronly, error; struct g_consumer *cp; struct bufobj *bo; bp = NULL; /* This and pmp both used in error_exit. */ pmp = NULL; ronly = (mp->mnt_flag & MNT_RDONLY) != 0; dev = devvp->v_rdev; dev_ref(dev); DROP_GIANT(); g_topology_lock(); error = g_vfs_open(devvp, &cp, "msdosfs", ronly ? 0 : 1); g_topology_unlock(); PICKUP_GIANT(); VOP_UNLOCK(devvp, 0); if (error) goto error_exit; bo = &devvp->v_bufobj; /* * Read the boot sector of the filesystem, and then check the * boot signature. If not a dos boot sector then error out. * * NOTE: 8192 is a magic size that works for ffs. */ error = bread(devvp, 0, 8192, NOCRED, &bp); if (error) goto error_exit; bp->b_flags |= B_AGE; bsp = (union bootsector *)bp->b_data; b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; #ifndef MSDOSFS_NOCHECKSIG if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { error = EINVAL; goto error_exit; } #endif pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO); pmp->pm_mountp = mp; pmp->pm_cp = cp; pmp->pm_bo = bo; lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0); /* * Initialize ownerships and permissions, since nothing else will * initialize them iff we are mounting root. */ pmp->pm_uid = UID_ROOT; pmp->pm_gid = GID_WHEEL; pmp->pm_mask = pmp->pm_dirmask = S_IXUSR | S_IXGRP | S_IXOTH | S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR; /* * Experimental support for large MS-DOS filesystems. * WARNING: This uses at least 32 bytes of kernel memory (which is not * reclaimed until the FS is unmounted) for each file on disk to map * between the 32-bit inode numbers used by VFS and the 64-bit * pseudo-inode numbers used internally by msdosfs. This is only * safe to use in certain controlled situations (e.g. read-only FS * with less than 1 million files). * Since the mappings do not persist across unmounts (or reboots), these * filesystems are not suitable for exporting through NFS, or any other * application that requires fixed inode numbers. */ vfs_flagopt(mp->mnt_optnew, "large", &pmp->pm_flags, MSDOSFS_LARGEFS); /* * Compute several useful quantities from the bpb in the * bootsector. Copy in the dos 5 variant of the bpb then fix up * the fields that are different between dos 5 and dos 3.3. */ SecPerClust = b50->bpbSecPerClust; pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); if (pmp->pm_BytesPerSec < DEV_BSIZE) { error = EINVAL; goto error_exit; } pmp->pm_ResSectors = getushort(b50->bpbResSectors); pmp->pm_FATs = b50->bpbFATs; pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); pmp->pm_Sectors = getushort(b50->bpbSectors); pmp->pm_FATsecs = getushort(b50->bpbFATsecs); pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); pmp->pm_Heads = getushort(b50->bpbHeads); pmp->pm_Media = b50->bpbMedia; /* calculate the ratio of sector size to DEV_BSIZE */ pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE; /* * We don't check pm_Heads nor pm_SecPerTrack, because * these may not be set for EFI file systems. We don't * use these anyway, so we're unaffected if they are * invalid. */ if (!pmp->pm_BytesPerSec || !SecPerClust) { error = EINVAL; goto error_exit; } if (pmp->pm_Sectors == 0) { pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); } else { pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); pmp->pm_HugeSectors = pmp->pm_Sectors; } if (!(pmp->pm_flags & MSDOSFS_LARGEFS)) { if (pmp->pm_HugeSectors > 0xffffffff / (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) { /* * We cannot deal currently with this size of disk * due to fileid limitations (see msdosfs_getattr and * msdosfs_readdir) */ error = EINVAL; vfs_mount_error(mp, "Disk too big, try '-o large' mount option"); goto error_exit; } } if (pmp->pm_RootDirEnts == 0) { if (pmp->pm_FATsecs || getushort(b710->bpbFSVers)) { error = EINVAL; #ifdef MSDOSFS_DEBUG printf("mountmsdosfs(): bad FAT32 filesystem\n"); #endif goto error_exit; } pmp->pm_fatmask = FAT32_MASK; pmp->pm_fatmult = 4; pmp->pm_fatdiv = 1; pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); if (getushort(b710->bpbExtFlags) & FATMIRROR) pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; else pmp->pm_flags |= MSDOSFS_FATMIRROR; } else pmp->pm_flags |= MSDOSFS_FATMIRROR; /* * Check a few values (could do some more): * - logical sector size: power of 2, >= block size * - sectors per cluster: power of 2, >= 1 * - number of sectors: >= 1, <= size of partition * - number of FAT sectors: >= 1 */ if ( (SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) || (pmp->pm_BytesPerSec < DEV_BSIZE) || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) || (pmp->pm_HugeSectors == 0) || (pmp->pm_FATsecs == 0) || (SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE) ) { error = EINVAL; goto error_exit; } pmp->pm_HugeSectors *= pmp->pm_BlkPerSec; pmp->pm_HiddenSects *= pmp->pm_BlkPerSec; /* XXX not used? */ pmp->pm_FATsecs *= pmp->pm_BlkPerSec; SecPerClust *= pmp->pm_BlkPerSec; pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec; if (FAT32(pmp)) { pmp->pm_rootdirblk = getulong(b710->bpbRootClust); pmp->pm_firstcluster = pmp->pm_fatblk + (pmp->pm_FATs * pmp->pm_FATsecs); pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec; } else { pmp->pm_rootdirblk = pmp->pm_fatblk + (pmp->pm_FATs * pmp->pm_FATsecs); pmp->pm_rootdirsize = howmany(pmp->pm_RootDirEnts * sizeof(struct direntry), DEV_BSIZE); /* in blocks */ pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; } pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / SecPerClust + 1; pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ if (pmp->pm_fatmask == 0) { if (pmp->pm_maxcluster <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { /* * This will usually be a floppy disk. This size makes * sure that one fat entry will not be split across * multiple blocks. */ pmp->pm_fatmask = FAT12_MASK; pmp->pm_fatmult = 3; pmp->pm_fatdiv = 2; } else { pmp->pm_fatmask = FAT16_MASK; pmp->pm_fatmult = 2; pmp->pm_fatdiv = 1; } } clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; if (pmp->pm_maxcluster >= clusters) { #ifdef MSDOSFS_DEBUG printf("Warning: number of clusters (%ld) exceeds FAT " "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); #endif pmp->pm_maxcluster = clusters - 1; } if (FAT12(pmp)) pmp->pm_fatblocksize = 3 * 512; else pmp->pm_fatblocksize = PAGE_SIZE; pmp->pm_fatblocksize = roundup(pmp->pm_fatblocksize, pmp->pm_BytesPerSec); pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE; pmp->pm_bnshift = ffs(DEV_BSIZE) - 1; /* * Compute mask and shift value for isolating cluster relative byte * offsets and cluster numbers from a file offset. */ pmp->pm_bpcluster = SecPerClust * DEV_BSIZE; pmp->pm_crbomask = pmp->pm_bpcluster - 1; pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; /* * Check for valid cluster size * must be a power of 2 */ if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { error = EINVAL; goto error_exit; } /* * Release the bootsector buffer. */ brelse(bp); bp = NULL; /* * Check the fsinfo sector if we have one. Silently fix up our * in-core copy of fp->fsinxtfree if it is unknown (0xffffffff) * or too large. Ignore fp->fsinfree for now, since we need to * read the entire FAT anyway to fill the inuse map. */ if (pmp->pm_fsinfo) { struct fsinfo *fp; if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, NOCRED, &bp)) != 0) goto error_exit; fp = (struct fsinfo *)bp->b_data; if (!bcmp(fp->fsisig1, "RRaA", 4) && !bcmp(fp->fsisig2, "rrAa", 4) && !bcmp(fp->fsisig3, "\0\0\125\252", 4)) { pmp->pm_nxtfree = getulong(fp->fsinxtfree); if (pmp->pm_nxtfree > pmp->pm_maxcluster) pmp->pm_nxtfree = CLUST_FIRST; } else pmp->pm_fsinfo = 0; brelse(bp); bp = NULL; } /* * Finish initializing pmp->pm_nxtfree (just in case the first few * sectors aren't properly reserved in the FAT). This completes * the fixup for fp->fsinxtfree, and fixes up the zero-initialized * value if there is no fsinfo. We will use pmp->pm_nxtfree * internally even if there is no fsinfo. */ if (pmp->pm_nxtfree < CLUST_FIRST) pmp->pm_nxtfree = CLUST_FIRST; /* * Allocate memory for the bitmap of allocated clusters, and then * fill it in. */ pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, N_INUSEBITS) * sizeof(*pmp->pm_inusemap), M_MSDOSFSFAT, M_WAITOK); /* * fillinusemap() needs pm_devvp. */ pmp->pm_devvp = devvp; pmp->pm_dev = dev; /* * Have the inuse map filled in. */ MSDOSFS_LOCK_MP(pmp); error = fillinusemap(pmp); MSDOSFS_UNLOCK_MP(pmp); if (error != 0) goto error_exit; /* * If they want fat updates to be synchronous then let them suffer * the performance degradation in exchange for the on disk copy of * the fat being correct just about all the time. I suppose this * would be a good thing to turn on if the kernel is still flakey. */ if (mp->mnt_flag & MNT_SYNCHRONOUS) pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; /* * Finish up. */ if (ronly) pmp->pm_flags |= MSDOSFSMNT_RONLY; else { if ((error = markvoldirty(pmp, 1)) != 0) { (void)markvoldirty(pmp, 0); goto error_exit; } pmp->pm_fmod = 1; } mp->mnt_data = pmp; mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_USES_BCACHE; MNT_IUNLOCK(mp); if (pmp->pm_flags & MSDOSFS_LARGEFS) msdosfs_fileno_init(mp); return 0; error_exit: if (bp) brelse(bp); if (cp != NULL) { DROP_GIANT(); g_topology_lock(); g_vfs_close(cp); g_topology_unlock(); PICKUP_GIANT(); } if (pmp) { lockdestroy(&pmp->pm_fatlock); if (pmp->pm_inusemap) free(pmp->pm_inusemap, M_MSDOSFSFAT); free(pmp, M_MSDOSFSMNT); mp->mnt_data = NULL; } dev_rel(dev); return (error); }