static int cgdinit(struct cgd_softc *cs, const char *cpath, struct vnode *vp, struct lwp *l) { struct disk_geom *dg; int ret; char *tmppath; uint64_t psize; unsigned secsize; struct dk_softc *dksc = &cs->sc_dksc; cs->sc_tvn = vp; cs->sc_tpath = NULL; tmppath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); ret = copyinstr(cpath, tmppath, MAXPATHLEN, &cs->sc_tpathlen); if (ret) goto bail; cs->sc_tpath = malloc(cs->sc_tpathlen, M_DEVBUF, M_WAITOK); memcpy(cs->sc_tpath, tmppath, cs->sc_tpathlen); cs->sc_tdev = vp->v_rdev; if ((ret = getdisksize(vp, &psize, &secsize)) != 0) goto bail; if (psize == 0) { ret = ENODEV; goto bail; } /* * XXX here we should probe the underlying device. If we * are accessing a partition of type RAW_PART, then * we should populate our initial geometry with the * geometry that we discover from the device. */ dg = &dksc->sc_dkdev.dk_geom; memset(dg, 0, sizeof(*dg)); dg->dg_secperunit = psize; // XXX: Inherit? dg->dg_secsize = DEV_BSIZE; dg->dg_ntracks = 1; dg->dg_nsectors = 1024 * (1024 / dg->dg_secsize); dg->dg_ncylinders = dg->dg_secperunit / dg->dg_nsectors; bail: free(tmppath, M_TEMP); if (ret && cs->sc_tpath) free(cs->sc_tpath, M_DEVBUF); return ret; }
int adosfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l) { struct disklabel dl; struct partition *parp; struct adosfsmount *amp; struct buf *bp; struct vnode *rvp; size_t bitmap_sz = 0; int error, i; uint64_t numsecs; unsigned secsize; unsigned long secsperblk, blksperdisk, resvblks; amp = NULL; if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0) return (error); /* * open blkdev and read boot and root block */ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); if ((error = VOP_OPEN(devvp, FREAD, NOCRED)) != 0) { VOP_UNLOCK(devvp); return (error); } error = getdisksize(devvp, &numsecs, &secsize); if (error) goto fail; amp = kmem_zalloc(sizeof(struct adosfsmount), KM_SLEEP); /* * compute filesystem parameters from disklabel * on arch/amiga the disklabel is computed from the native * partition tables * - p_fsize is the filesystem block size * - p_frag is the number of sectors per filesystem block * - p_cpg is the number of reserved blocks (boot blocks) * - p_psize is reduced by the number of preallocated blocks * at the end of a partition * * XXX * - bsize and secsperblk could be computed from the first sector * of the root block * - resvblks (the number of boot blocks) can only be guessed * by scanning for the root block as its position moves * with resvblks */ error = VOP_IOCTL(devvp, DIOCGDINFO, &dl, FREAD, NOCRED); VOP_UNLOCK(devvp); if (error) goto fail; parp = &dl.d_partitions[DISKPART(devvp->v_rdev)]; if (dl.d_type == DTYPE_FLOPPY) { amp->bsize = secsize; secsperblk = 1; resvblks = 2; } else if (parp->p_fsize > 0 && parp->p_frag > 0) { amp->bsize = parp->p_fsize * parp->p_frag; secsperblk = parp->p_frag; resvblks = parp->p_cpg; } else { error = EINVAL; goto fail; } blksperdisk = numsecs / secsperblk; /* The filesytem variant ('dostype') is stored in the boot block */ bp = NULL; if ((error = bread(devvp, (daddr_t)BBOFF, amp->bsize, NOCRED, 0, &bp)) != 0) { goto fail; } amp->dostype = adoswordn(bp, 0); brelse(bp, 0); /* basic sanity checks */ if (amp->dostype < 0x444f5300 || amp->dostype > 0x444f5305) { error = EINVAL; goto fail; } amp->rootb = (blksperdisk - 1 + resvblks) / 2; amp->numblks = blksperdisk - resvblks; amp->nwords = amp->bsize >> 2; amp->dbsize = amp->bsize - (IS_FFS(amp) ? 0 : OFS_DATA_OFFSET); amp->devvp = devvp; amp->mp = mp; mp->mnt_data = amp; mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)devvp->v_rdev; mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_ADOSFS); mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; mp->mnt_stat.f_namemax = ADMAXNAMELEN; mp->mnt_fs_bshift = ffs(amp->bsize) - 1; mp->mnt_dev_bshift = DEV_BSHIFT; mp->mnt_flag |= MNT_LOCAL; /* * init anode table. */ for (i = 0; i < ANODEHASHSZ; i++) LIST_INIT(&->anodetab[i]); /* * get the root anode, if not a valid fs this will fail. */ if ((error = VFS_ROOT(mp, &rvp)) != 0) goto fail; /* allocate and load bitmap, set free space */ bitmap_sz = ((amp->numblks + 31) / 32) * sizeof(*amp->bitmap); amp->bitmap = kmem_alloc(bitmap_sz, KM_SLEEP); if (amp->bitmap) adosfs_loadbitmap(amp); if (mp->mnt_flag & MNT_RDONLY && amp->bitmap) { /* * Don't need the bitmap any more if it's read-only. */ kmem_free(amp->bitmap, bitmap_sz); amp->bitmap = NULL; } vput(rvp); return(0); fail: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); (void) VOP_CLOSE(devvp, FREAD, NOCRED); VOP_UNLOCK(devvp); if (amp && amp->bitmap) kmem_free(amp->bitmap, bitmap_sz); if (amp) kmem_free(amp, sizeof(*amp)); return (error); }
/* * Calculate a prototype superblock based on information in the disk label. * When done the cgsblock macro can be calculated and the fs_ncg field * can be used. Do NOT attempt to use other macros without verifying that * their needed information is available! * * In BSD, the disk label includes all sorts of useful information, * like cpg. Solaris doesn't have that, and deriving it (as well as * some other parameters) is difficult. Rather than duplicate the * code, just ask mkfs what it would've come up with by default. * Ideally, we'd just link in the code, but given the source base * involved, it's more practical to just get a binary dump. * * The one minor drawback to the above approach is that newfs and mkfs * will produce vastly different layouts for the same partition if * they're allowed to default everything. So, if the superblock that * mkfs gives us doesn't work for guessing where the alternates are, * we need to try newfs. */ static int calcsb(calcsb_t style, caddr_t dev, int devfd, struct fs *fs) { #define FROM_CHILD 0 #define TO_FSCK 1 #define CMD_IDX 0 #define DEV_IDX 3 #define SIZE_IDX 4 int child_pipe[2]; caddr_t mkfsline[] = { "", /* CMD_IDX */ "-o", "calcbinsb,N", NULL, /* DEV_IDX */ NULL, /* SIZE_IDX */ NULL }; caddr_t newfsline[] = { "", /* CMD_IDX */ "-B", "-N", NULL, /* DEV_IDX */ NULL }; int pending, transferred; caddr_t *cmdline; caddr_t target; caddr_t sizestr = NULL; caddr_t path_old, path_new, mkfs_dir, mkfs_path, newfs_path; caddr_t slash; diskaddr_t size; int devnull; switch (style) { case MKFS_STYLE: if (debug) (void) printf("calcsb() going with style MKFS\n"); cmdline = mkfsline; break; case NEWFS_STYLE: if (debug) (void) printf("calcsb() going with style NEWFS\n"); cmdline = newfsline; break; default: if (debug) (void) printf("calcsb() doesn't undestand style %d\n", style); return (0); } cmdline[DEV_IDX] = dev; /* * Normally, only use the stock versions of the utilities. * However, if we're debugging, the odds are that we're * using experimental versions of them as well, so allow * some flexibility. */ mkfs_path = getenv("MKFS_PATH"); if (!debug || (mkfs_path == NULL)) mkfs_path = MKFS_PATH; newfs_path = getenv("NEWFS_PATH"); if (!debug || (newfs_path == NULL)) newfs_path = NEWFS_PATH; if (style == MKFS_STYLE) { cmdline[CMD_IDX] = mkfs_path; size = getdisksize(dev, devfd); if (size == 0) return (0); (void) fsck_asprintf(&sizestr, "%lld", (longlong_t)size); cmdline[SIZE_IDX] = sizestr; } else if (style == NEWFS_STYLE) { /* * Make sure that newfs will find the right version of mkfs. */ cmdline[CMD_IDX] = newfs_path; path_old = getenv("PATH"); /* mkfs_path is always initialized, despite lint's concerns */ mkfs_dir = strdup(mkfs_path); if (mkfs_dir == NULL) return (0); /* * If no location data for mkfs, don't need to do * anything about PATH. */ slash = strrchr(mkfs_dir, '/'); if (slash != NULL) { /* * Just want the dir, so discard the executable name. */ *slash = '\0'; /* * newfs uses system() to find mkfs, so make sure * that the one we want to use is first on the * list. Don't free path_new upon success, as it * has become part of the environment. */ (void) fsck_asprintf(&path_new, "PATH=%s:%s", mkfs_dir, path_old); if (putenv(path_new) != 0) { free(mkfs_dir); free(path_new); return (0); } } free(mkfs_dir); } else { /* * Bad search style, quietly return failure. */ if (debug) { (void) printf("calcsb: got bad style number %d\n", (int)style); } return (0); } if (pipe(child_pipe) < 0) { pfatal("calcsb: could not create pipe: %s\n", strerror(errno)); if (sizestr != NULL) free(sizestr); return (0); } switch (fork()) { case -1: pfatal("calcsb: fork failed: %s\n", strerror(errno)); if (sizestr != NULL) free(sizestr); return (0); case 0: if (dup2(child_pipe[TO_FSCK], fileno(stdout)) < 0) { (void) printf( "calcsb: could not rename file descriptor: %s\n", strerror(errno)); exit(EXBADPARM); } devnull = open("/dev/null", O_WRONLY); if (devnull == -1) { (void) printf("calcsb: could not open /dev/null: %s\n", strerror(errno)); exit(EXBADPARM); } if (dup2(devnull, fileno(stderr)) < 0) { (void) printf( "calcsb: could not rename file descriptor: %s\n", strerror(errno)); exit(EXBADPARM); } (void) close(child_pipe[FROM_CHILD]); (void) execv(cmdline[CMD_IDX], cmdline); (void) printf("calcsb: could not exec %s: %s\n", cmdline[CMD_IDX], strerror(errno)); exit(EXBADPARM); /* NOTREACHED */ default: break; } (void) close(child_pipe[TO_FSCK]); if (sizestr != NULL) free(sizestr); pending = sizeof (struct fs); target = (caddr_t)fs; do { transferred = read(child_pipe[FROM_CHILD], target, pending); pending -= transferred; target += transferred; } while ((pending > 0) && (transferred > 0)); if (pending > 0) { if (transferred < 0) pfatal( "calcsb: binary read of superblock from %s failed: %s\n", (style == MKFS_STYLE) ? "mkfs" : "newfs", (transferred < 0) ? strerror(errno) : ""); else pfatal( "calcsb: short read of superblock from %s\n", (style == MKFS_STYLE) ? "mkfs" : "newfs"); return (0); } (void) close(child_pipe[FROM_CHILD]); (void) wait(NULL); if ((fs->fs_magic != FS_MAGIC) && (fs->fs_magic != MTB_UFS_MAGIC)) return (0); return (1); }
int msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l, struct msdosfs_args *argp) { struct msdosfsmount *pmp; struct buf *bp; dev_t dev = devvp->v_rdev; union bootsector *bsp; struct byte_bpb33 *b33; struct byte_bpb50 *b50; struct byte_bpb710 *b710; uint8_t SecPerClust; int ronly, error, tmp; int bsize; uint64_t psize; unsigned secsize; /* Flush out any old buffers remaining from a previous use. */ if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; bp = NULL; /* both used in error_exit */ pmp = NULL; error = fstrans_mount(mp); if (error) goto error_exit; error = getdisksize(devvp, &psize, &secsize); if (error) { if (argp->flags & MSDOSFSMNT_GEMDOSFS) goto error_exit; /* ok, so it failed. we most likely don't need the info */ secsize = DEV_BSIZE; psize = 0; error = 0; } if (argp->flags & MSDOSFSMNT_GEMDOSFS) { bsize = secsize; if (bsize != 512) { DPRINTF(("Invalid block bsize %d for GEMDOS\n", bsize)); error = EINVAL; goto error_exit; } } else bsize = 0; /* * Read the boot sector of the filesystem, and then check the * boot signature. If not a dos boot sector then error out. */ if ((error = bread(devvp, 0, secsize, NOCRED, 0, &bp)) != 0) goto error_exit; 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; if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { DPRINTF(("bootsig0 %d bootsig1 %d\n", bsp->bs50.bsBootSectSig0, bsp->bs50.bsBootSectSig1)); error = EINVAL; goto error_exit; } } pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); memset(pmp, 0, sizeof *pmp); pmp->pm_mountp = mp; /* * 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); 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; if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { /* XXX - We should probably check more values here */ if (!pmp->pm_BytesPerSec || !SecPerClust || pmp->pm_SecPerTrack > 63) { DPRINTF(("bytespersec %d secperclust %d " "secpertrack %d\n", pmp->pm_BytesPerSec, SecPerClust, pmp->pm_SecPerTrack)); 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_RootDirEnts == 0) { unsigned short vers = getushort(b710->bpbFSVers); /* * Some say that bsBootSectSig[23] must be zero, but * Windows does not require this and some digital cameras * do not set these to zero. Therefore, do not insist. */ if (pmp->pm_Sectors || pmp->pm_FATsecs || vers) { DPRINTF(("sectors %d fatsecs %lu vers %d\n", pmp->pm_Sectors, pmp->pm_FATsecs, vers)); error = EINVAL; goto error_exit; } pmp->pm_fatmask = FAT32_MASK; pmp->pm_fatmult = 4; pmp->pm_fatdiv = 1; pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); /* mirrorring is enabled if the FATMIRROR bit is not set */ if ((getushort(b710->bpbExtFlags) & FATMIRROR) == 0) pmp->pm_flags |= MSDOSFS_FATMIRROR; else pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; } else pmp->pm_flags |= MSDOSFS_FATMIRROR; if (argp->flags & MSDOSFSMNT_GEMDOSFS) { if (FAT32(pmp)) { DPRINTF(("FAT32 for GEMDOS\n")); /* * GEMDOS doesn't know FAT32. */ error = EINVAL; goto error_exit; } /* * 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 */ if ( (SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) || (pmp->pm_BytesPerSec < bsize) || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) || (pmp->pm_HugeSectors == 0) || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize) > psize)) { DPRINTF(("consistency checks for GEMDOS\n")); error = EINVAL; goto error_exit; } /* * XXX - Many parts of the msdosfs driver seem to assume that * the number of bytes per logical sector (BytesPerSec) will * always be the same as the number of bytes per disk block * Let's pretend it is. */ tmp = pmp->pm_BytesPerSec / bsize; pmp->pm_BytesPerSec = bsize; pmp->pm_HugeSectors *= tmp; pmp->pm_HiddenSects *= tmp; pmp->pm_ResSectors *= tmp; pmp->pm_Sectors *= tmp; pmp->pm_FATsecs *= tmp; SecPerClust *= tmp; } /* Check that fs has nonzero FAT size */ if (pmp->pm_FATsecs == 0) { DPRINTF(("FATsecs is 0\n")); error = EINVAL; goto error_exit; } pmp->pm_fatblk = pmp->pm_ResSectors; 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); } else { pmp->pm_rootdirblk = pmp->pm_fatblk + (pmp->pm_FATs * pmp->pm_FATsecs); pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) + pmp->pm_BytesPerSec - 1) / pmp->pm_BytesPerSec;/* in sectors */ pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; } pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / SecPerClust; pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; if (argp->flags & MSDOSFSMNT_GEMDOSFS) { if (pmp->pm_nmbrofclusters <= (0xff0 - 2)) { 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; } } else 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; } } if (FAT12(pmp)) pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; else pmp->pm_fatblocksize = MAXBSIZE; pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1; /* * Compute mask and shift value for isolating cluster relative byte * offsets and cluster numbers from a file offset. */ pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec; 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)) { DPRINTF(("bpcluster %lu cnshift %lu\n", pmp->pm_bpcluster, pmp->pm_cnshift)); error = EINVAL; goto error_exit; } /* * Cluster size must be within limit of MAXBSIZE. * Many FAT filesystems will not have clusters larger than * 32KiB due to limits in Windows versions before Vista. */ if (pmp->pm_bpcluster > MAXBSIZE) { DPRINTF(("bpcluster %lu > MAXBSIZE %d\n", pmp->pm_bpcluster, MAXBSIZE)); error = EINVAL; goto error_exit; } /* * Release the bootsector buffer. */ brelse(bp, BC_AGE); bp = NULL; /* * Check FSInfo. */ if (pmp->pm_fsinfo) { struct fsinfo *fp; /* * XXX If the fsinfo block is stored on media with * 2KB or larger sectors, is the fsinfo structure * padded at the end or in the middle? */ if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo), pmp->pm_BytesPerSec, NOCRED, 0, &bp)) != 0) goto error_exit; fp = (struct fsinfo *)bp->b_data; if (!memcmp(fp->fsisig1, "RRaA", 4) && !memcmp(fp->fsisig2, "rrAa", 4) && !memcmp(fp->fsisig3, "\0\0\125\252", 4) && !memcmp(fp->fsisig4, "\0\0\125\252", 4)) pmp->pm_nxtfree = getulong(fp->fsinxtfree); else pmp->pm_fsinfo = 0; brelse(bp, 0); bp = NULL; } /* * Check and validate (or perhaps invalidate?) the fsinfo structure? * XXX */ if (pmp->pm_fsinfo) { if ((pmp->pm_nxtfree == 0xffffffffUL) || (pmp->pm_nxtfree > pmp->pm_maxcluster)) pmp->pm_fsinfo = 0; } /* * Allocate memory for the bitmap of allocated clusters, and then * fill it in. */ pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS) * sizeof(*pmp->pm_inusemap), M_MSDOSFSFAT, M_WAITOK); /* * fillinusemap() needs pm_devvp. */ pmp->pm_dev = dev; pmp->pm_devvp = devvp; /* * Have the inuse map filled in. */ if ((error = fillinusemap(pmp)) != 0) { DPRINTF(("fillinusemap %d\n", error)); 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 pmp->pm_fmod = 1; mp->mnt_data = pmp; mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_MSDOS); mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; mp->mnt_stat.f_namemax = MSDOSFS_NAMEMAX(pmp); mp->mnt_flag |= MNT_LOCAL; mp->mnt_dev_bshift = pmp->pm_bnshift; mp->mnt_fs_bshift = pmp->pm_cnshift; /* * If we ever do quotas for DOS filesystems this would be a place * to fill in the info in the msdosfsmount structure. You dolt, * quotas on dos filesystems make no sense because files have no * owners on dos filesystems. of course there is some empty space * in the directory entry where we could put uid's and gid's. */ spec_node_setmountedfs(devvp, mp); return (0); error_exit: fstrans_unmount(mp); if (bp) brelse(bp, BC_AGE); if (pmp) { if (pmp->pm_inusemap) free(pmp->pm_inusemap, M_MSDOSFSFAT); free(pmp, M_MSDOSFSMNT); mp->mnt_data = NULL; } return (error); }
/* * Lookup and open needed files. * * For file system internal snapshot initializes sc_mntname, sc_mount, * sc_bs_vp and sc_time. * * Otherwise returns dev and size of the underlying block device. * Initializes sc_mntname, sc_mount, sc_bdev, sc_bs_vp and sc_mount */ static int fss_create_files(struct fss_softc *sc, struct fss_set *fss, off_t *bsize, struct lwp *l) { int error, bits, fsbsize; uint64_t numsec; unsigned int secsize; struct timespec ts; /* nd -> nd2 to reduce mistakes while updating only some namei calls */ struct pathbuf *pb2; struct nameidata nd2; struct vnode *vp; /* * Get the mounted file system. */ error = namei_simple_user(fss->fss_mount, NSM_FOLLOW_NOEMULROOT, &vp); if (error != 0) return error; if ((vp->v_vflag & VV_ROOT) != VV_ROOT) { vrele(vp); return EINVAL; } sc->sc_mount = vp->v_mount; memcpy(sc->sc_mntname, sc->sc_mount->mnt_stat.f_mntonname, MNAMELEN); vrele(vp); /* * Check for file system internal snapshot. */ error = namei_simple_user(fss->fss_bstore, NSM_FOLLOW_NOEMULROOT, &vp); if (error != 0) return error; if (vp->v_type == VREG && vp->v_mount == sc->sc_mount) { sc->sc_flags |= FSS_PERSISTENT; sc->sc_bs_vp = vp; fsbsize = sc->sc_bs_vp->v_mount->mnt_stat.f_iosize; bits = sizeof(sc->sc_bs_bshift)*NBBY; for (sc->sc_bs_bshift = 1; sc->sc_bs_bshift < bits; sc->sc_bs_bshift++) if (FSS_FSBSIZE(sc) == fsbsize) break; if (sc->sc_bs_bshift >= bits) return EINVAL; sc->sc_bs_bmask = FSS_FSBSIZE(sc)-1; sc->sc_clshift = 0; if ((fss->fss_flags & FSS_UNLINK_ON_CREATE) != 0) { error = do_sys_unlink(fss->fss_bstore, UIO_USERSPACE); if (error) return error; } error = vn_lock(vp, LK_EXCLUSIVE); if (error != 0) return error; error = VFS_SNAPSHOT(sc->sc_mount, sc->sc_bs_vp, &ts); TIMESPEC_TO_TIMEVAL(&sc->sc_time, &ts); VOP_UNLOCK(sc->sc_bs_vp); return error; } vrele(vp); /* * Get the block device it is mounted on and its size. */ error = spec_node_lookup_by_mount(sc->sc_mount, &vp); if (error) return error; sc->sc_bdev = vp->v_rdev; error = getdisksize(vp, &numsec, &secsize); vrele(vp); if (error) return error; *bsize = (off_t)numsec*secsize; /* * Get the backing store */ error = pathbuf_copyin(fss->fss_bstore, &pb2); if (error) { return error; } NDINIT(&nd2, LOOKUP, FOLLOW, pb2); if ((error = vn_open(&nd2, FREAD|FWRITE, 0)) != 0) { pathbuf_destroy(pb2); return error; } VOP_UNLOCK(nd2.ni_vp); sc->sc_bs_vp = nd2.ni_vp; if (nd2.ni_vp->v_type != VREG && nd2.ni_vp->v_type != VCHR) { pathbuf_destroy(pb2); return EINVAL; } pathbuf_destroy(pb2); if ((fss->fss_flags & FSS_UNLINK_ON_CREATE) != 0) { error = do_sys_unlink(fss->fss_bstore, UIO_USERSPACE); if (error) return error; } if (sc->sc_bs_vp->v_type == VREG) { fsbsize = sc->sc_bs_vp->v_mount->mnt_stat.f_iosize; if (fsbsize & (fsbsize-1)) /* No power of two */ return EINVAL; for (sc->sc_bs_bshift = 1; sc->sc_bs_bshift < 32; sc->sc_bs_bshift++) if (FSS_FSBSIZE(sc) == fsbsize) break; if (sc->sc_bs_bshift >= 32) return EINVAL; sc->sc_bs_bmask = FSS_FSBSIZE(sc)-1; } else { sc->sc_bs_bshift = DEV_BSHIFT; sc->sc_bs_bmask = FSS_FSBSIZE(sc)-1; } return 0; }