int ffs_wapbl_stop(struct mount *mp, int force) { struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs = ump->um_fs; int error; if (mp->mnt_wapbl) { KDASSERT(fs->fs_ronly == 0); /* * Make sure turning off FS_DOWAPBL is only removed * as the only change in the final flush since otherwise * a transaction may reorder writes. */ error = wapbl_flush(mp->mnt_wapbl, 1); if (error && !force) return error; if (error && force) goto forceout; error = UFS_WAPBL_BEGIN(mp); if (error && !force) return error; if (error && force) goto forceout; KASSERT(fs->fs_flags & FS_DOWAPBL); fs->fs_flags &= ~FS_DOWAPBL; error = ffs_sbupdate(ump, MNT_WAIT); KASSERT(error == 0); /* XXX a bit drastic! */ UFS_WAPBL_END(mp); forceout: error = wapbl_stop(mp->mnt_wapbl, force); if (error) { KASSERT(!force); fs->fs_flags |= FS_DOWAPBL; return error; } fs->fs_flags &= ~FS_DOWAPBL; /* Repeat in case of forced error */ mp->mnt_wapbl = NULL; #ifdef WAPBL_DEBUG printf("%s: disabled logging\n", fs->fs_fsmnt); #endif } return 0; }
static int g_journal_ufs_clean(struct mount *mp) { struct ufsmount *ump; struct fs *fs; int flags; ump = VFSTOUFS(mp); fs = ump->um_fs; flags = fs->fs_flags; fs->fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); ffs_sbupdate(ump, MNT_WAIT, 1); fs->fs_flags = flags; return (0); }
/* * unmount system call */ int ffs_unmount(struct mount *mp, int mntflags, struct proc *p) { struct ufsmount *ump; struct fs *fs; int error, flags; flags = 0; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; ump = VFSTOUFS(mp); fs = ump->um_fs; if (mp->mnt_flag & MNT_SOFTDEP) error = softdep_flushfiles(mp, flags, p); else error = ffs_flushfiles(mp, flags, p); if (error != 0) return (error); if (fs->fs_ronly == 0) { fs->fs_clean = (fs->fs_flags & FS_UNCLEAN) ? 0 : 1; error = ffs_sbupdate(ump, MNT_WAIT); /* ignore write errors if mounted RW on read-only device */ if (error && error != EROFS) { fs->fs_clean = 0; return (error); } free(fs->fs_contigdirs, M_UFSMNT); } ump->um_devvp->v_specmountpoint = NULL; vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0); error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, NOCRED, p); VOP_UNLOCK(ump->um_devvp, 0, p); vrele(ump->um_devvp); free(fs->fs_csp, M_UFSMNT); free(fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; mp->mnt_flag &= ~MNT_LOCAL; return (error); }
/* * Common code for mount and mountroot */ int ffs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p) { struct ufsmount *ump; struct buf *bp; struct fs *fs; dev_t dev; struct partinfo dpart; caddr_t space; ufs2_daddr_t sbloc; int error, i, blks, size, ronly; int32_t *lp; size_t strsize; struct ucred *cred; u_int64_t maxfilesize; /* XXX */ dev = devvp->v_rdev; cred = p ? p->p_ucred : NOCRED; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use * (except for root, which might share swap device for miniroot). * Flush out any old buffers remaining from a previous use. */ if ((error = vfs_mountedon(devvp)) != 0) return (error); if (vcount(devvp) > 1 && devvp != rootvp) return (EBUSY); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0); VOP_UNLOCK(devvp, 0, p); if (error) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); if (error) return (error); if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) size = DEV_BSIZE; else size = dpart.disklab->d_secsize; bp = NULL; ump = NULL; /* * Try reading the super-block in each of its possible locations. */ for (i = 0; sbtry[i] != -1; i++) { if (bp != NULL) { bp->b_flags |= B_NOCACHE; brelse(bp); bp = NULL; } error = bread(devvp, sbtry[i] / size, SBSIZE, cred, &bp); if (error) goto out; fs = (struct fs *) bp->b_data; sbloc = sbtry[i]; #if 0 if (fs->fs_magic == FS_UFS2_MAGIC) { printf("ffs_mountfs(): Sorry, no UFS2 support (yet)\n"); error = EFTYPE; goto out; } #endif /* * Do not look for an FFS1 file system at SBLOCK_UFS2. Doing so * will find the wrong super-block for file systems with 64k * block size. */ if (fs->fs_magic == FS_UFS1_MAGIC && sbloc == SBLOCK_UFS2) continue; if (ffs_validate(fs)) break; /* Super block validated */ } if (sbtry[i] == -1) { error = EINVAL; goto out; } fs->fs_fmod = 0; fs->fs_flags &= ~FS_UNCLEAN; if (fs->fs_clean == 0) { fs->fs_flags |= FS_UNCLEAN; #if 0 /* * It is safe mount unclean file system * if it was previously mounted with softdep * but we may loss space and must * sometimes run fsck manually. */ if (fs->fs_flags & FS_DOSOFTDEP) printf( "WARNING: %s was not properly unmounted\n", fs->fs_fsmnt); else #endif if (ronly || (mp->mnt_flag & MNT_FORCE)) { printf( "WARNING: %s was not properly unmounted\n", fs->fs_fsmnt); } else { printf( "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", fs->fs_fsmnt); error = EROFS; goto out; } } if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { #ifndef SMALL_KERNEL printf("ffs_mountfs(): obsolete rotational table format, " "please use fsck_ffs(8) -c 1\n"); #endif error = EFTYPE; goto out; } ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); bzero(ump, sizeof *ump); ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, M_WAITOK); if (fs->fs_magic == FS_UFS1_MAGIC) ump->um_fstype = UM_UFS1; #ifdef FFS2 else ump->um_fstype = UM_UFS2; #endif bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; brelse(bp); bp = NULL; fs = ump->um_fs; ffs1_compat_read(fs, ump, sbloc); fs->fs_ronly = ronly; size = fs->fs_cssize; blks = howmany(size, fs->fs_fsize); if (fs->fs_contigsumsize > 0) size += fs->fs_ncg * sizeof(int32_t); space = malloc((u_long)size, M_UFSMNT, M_WAITOK); fs->fs_csp = (struct csum *)space; for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, cred, &bp); if (error) { free(fs->fs_csp, M_UFSMNT); goto out; } bcopy(bp->b_data, space, (u_int)size); space += size; brelse(bp); bp = NULL; } if (fs->fs_contigsumsize > 0) { fs->fs_maxcluster = lp = (int32_t *)space; for (i = 0; i < fs->fs_ncg; i++) *lp++ = fs->fs_contigsumsize; } mp->mnt_data = (qaddr_t)ump; mp->mnt_stat.f_fsid.val[0] = (long)dev; /* Use on-disk fsid if it exists, else fake it */ if (fs->fs_id[0] != 0 && fs->fs_id[1] != 0) mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1]; else mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; ump->um_nindir = fs->fs_nindir; ump->um_bptrtodb = fs->fs_fsbtodb; ump->um_seqinc = fs->fs_frag; for (i = 0; i < MAXQUOTAS; i++) ump->um_quotas[i] = NULLVP; devvp->v_specmountpoint = mp; ffs_oldfscompat(fs); if (ronly) fs->fs_contigdirs = NULL; else { fs->fs_contigdirs = (u_int8_t*)malloc((u_long)fs->fs_ncg, M_UFSMNT, M_WAITOK); bzero(fs->fs_contigdirs, fs->fs_ncg); } /* * Set FS local "last mounted on" information (NULL pad) */ copystr(mp->mnt_stat.f_mntonname, /* mount point*/ fs->fs_fsmnt, /* copy area*/ sizeof(fs->fs_fsmnt) - 1, /* max size*/ &strsize); /* real size*/ bzero(fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize); #if 0 if( mp->mnt_flag & MNT_ROOTFS) { /* * Root mount; update timestamp in mount structure. * this will be used by the common root mount code * to update the system clock. */ mp->mnt_time = fs->fs_time; } #endif /* * XXX * Limit max file size. Even though ffs can handle files up to 16TB, * we do limit the max file to 2^31 pages to prevent overflow of * a 32-bit unsigned int. The buffer cache has its own checks but * a little added paranoia never hurts. */ ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ maxfilesize = (u_int64_t)0x80000000 * MIN(PAGE_SIZE, fs->fs_bsize) - 1; if (fs->fs_maxfilesize > maxfilesize) /* XXX */ fs->fs_maxfilesize = maxfilesize; /* XXX */ if (ronly == 0) { if ((fs->fs_flags & FS_DOSOFTDEP) && (error = softdep_mount(devvp, mp, fs, cred)) != 0) { free(fs->fs_csp, M_UFSMNT); free(fs->fs_contigdirs, M_UFSMNT); goto out; } fs->fs_fmod = 1; fs->fs_clean = 0; if (mp->mnt_flag & MNT_SOFTDEP) fs->fs_flags |= FS_DOSOFTDEP; else fs->fs_flags &= ~FS_DOSOFTDEP; (void) ffs_sbupdate(ump, MNT_WAIT); } return (0); out: devvp->v_specmountpoint = NULL; if (bp) brelse(bp); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); VOP_UNLOCK(devvp, 0, p); if (ump) { free(ump->um_fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; } return (error); }
/* * VFS Operations. * * mount system call */ int ffs_mount(struct mount *mp, const char *path, void *data, struct nameidata *ndp, struct proc *p) { struct vnode *devvp; struct ufs_args args; struct ufsmount *ump = NULL; struct fs *fs; int error = 0, flags; int ronly; mode_t accessmode; size_t size; error = copyin(data, &args, sizeof (struct ufs_args)); if (error) return (error); #ifndef FFS_SOFTUPDATES if (mp->mnt_flag & MNT_SOFTDEP) { printf("WARNING: soft updates isn't compiled in\n"); mp->mnt_flag &= ~MNT_SOFTDEP; } #endif /* * Soft updates is incompatible with "async", * so if we are doing softupdates stop the user * from setting the async flag. */ if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) == (MNT_SOFTDEP | MNT_ASYNC)) { return (EINVAL); } /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { ump = VFSTOUFS(mp); fs = ump->um_fs; devvp = ump->um_devvp; error = 0; ronly = fs->fs_ronly; if (ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { /* Flush any dirty data */ mp->mnt_flag &= ~MNT_RDONLY; VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p); mp->mnt_flag |= MNT_RDONLY; /* * Get rid of files open for writing. */ flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; if (fs->fs_flags & FS_DOSOFTDEP) { error = softdep_flushfiles(mp, flags, p); mp->mnt_flag &= ~MNT_SOFTDEP; } else error = ffs_flushfiles(mp, flags, p); ronly = 1; } /* * Flush soft dependencies if disabling it via an update * mount. This may leave some items to be processed, * so don't do this yet XXX. */ if ((fs->fs_flags & FS_DOSOFTDEP) && !(mp->mnt_flag & MNT_SOFTDEP) && !(mp->mnt_flag & MNT_RDONLY) && fs->fs_ronly == 0) { #if 0 flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = softdep_flushfiles(mp, flags, p); #elif FFS_SOFTUPDATES mp->mnt_flag |= MNT_SOFTDEP; #endif } /* * When upgrading to a softdep mount, we must first flush * all vnodes. (not done yet -- see above) */ if (!(fs->fs_flags & FS_DOSOFTDEP) && (mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) { #if 0 flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = ffs_flushfiles(mp, flags, p); #else mp->mnt_flag &= ~MNT_SOFTDEP; #endif } if (!error && (mp->mnt_flag & MNT_RELOAD)) error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); if (error) goto error_1; if (ronly && (mp->mnt_flag & MNT_WANTRDWR)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ if (suser(p, 0)) { vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p); VOP_UNLOCK(devvp, 0, p); if (error) goto error_1; } if (fs->fs_clean == 0) { #if 0 /* * It is safe mount unclean file system * if it was previously mounted with softdep * but we may loss space and must * sometimes run fsck manually. */ if (fs->fs_flags & FS_DOSOFTDEP) printf( "WARNING: %s was not properly unmounted\n", fs->fs_fsmnt); else #endif if (mp->mnt_flag & MNT_FORCE) { printf( "WARNING: %s was not properly unmounted\n", fs->fs_fsmnt); } else { printf( "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", fs->fs_fsmnt); error = EROFS; goto error_1; } } if ((fs->fs_flags & FS_DOSOFTDEP)) { error = softdep_mount(devvp, mp, fs, p->p_ucred); if (error) goto error_1; } fs->fs_contigdirs=(u_int8_t*)malloc((u_long)fs->fs_ncg, M_UFSMNT, M_WAITOK); bzero(fs->fs_contigdirs, fs->fs_ncg); ronly = 0; } if (args.fspec == 0) { /* * Process export requests. */ error = vfs_export(mp, &ump->um_export, &args.export_info); if (error) goto error_1; else goto success; } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); if ((error = namei(ndp)) != 0) goto error_1; devvp = ndp->ni_vp; if (devvp->v_type != VBLK) { error = ENOTBLK; goto error_2; } if (major(devvp->v_rdev) >= nblkdev) { error = ENXIO; goto error_2; } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ if (suser(p, 0)) { accessmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accessmode |= VWRITE; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); VOP_UNLOCK(devvp, 0, p); if (error) goto error_2; } if (mp->mnt_flag & MNT_UPDATE) { /* * UPDATE * If it's not the same vnode, or at least the same device * then it's not correct. */ if (devvp != ump->um_devvp) { if (devvp->v_rdev == ump->um_devvp->v_rdev) { vrele(devvp); } else { error = EINVAL; /* needs translation */ } } else vrele(devvp); /* * Update device name only on success */ if (!error) { /* * Save "mounted from" info for mount point (NULL pad) */ copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); } } else { /* * Since this is a new mount, we want the names for * the device and the mount point copied in. If an * error occurs, the mountpoint is discarded by the * upper level code. */ /* Save "last mounted on" info for mount point (NULL pad)*/ copyinstr(path, /* mount point*/ mp->mnt_stat.f_mntonname, /* save area*/ MNAMELEN - 1, /* max size*/ &size); /* real size*/ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); /* Save "mounted from" info for mount point (NULL pad)*/ copyinstr(args.fspec, /* device name*/ mp->mnt_stat.f_mntfromname, /* save area*/ MNAMELEN - 1, /* max size*/ &size); /* real size*/ bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); error = ffs_mountfs(devvp, mp, p); } if (error) goto error_2; /* * Initialize FS stat information in mount struct; uses both * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname * * This code is common to root and non-root mounts */ bcopy(&args, &mp->mnt_stat.mount_info.ufs_args, sizeof(args)); (void)VFS_STATFS(mp, &mp->mnt_stat, p); success: if (path && (mp->mnt_flag & MNT_UPDATE)) { /* Update clean flag after changing read-onlyness. */ fs = ump->um_fs; if (ronly != fs->fs_ronly) { fs->fs_ronly = ronly; fs->fs_clean = ronly && (fs->fs_flags & FS_UNCLEAN) == 0 ? 1 : 0; if (ronly) free(fs->fs_contigdirs, M_UFSMNT); } if (!ronly) { if (mp->mnt_flag & MNT_SOFTDEP) fs->fs_flags |= FS_DOSOFTDEP; else fs->fs_flags &= ~FS_DOSOFTDEP; } ffs_sbupdate(ump, MNT_WAIT); } return (0); error_2: /* error with devvp held */ vrele (devvp); error_1: /* no state to back out */ return (error); }
/* * Go through the disk queues to initiate sandbagged IO; * go through the inodes to write those that have been modified; * initiate the writing of the super block if it has been modified. * * Should always be called with the mount point locked. */ int ffs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p) { struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs; int error, allerror = 0, count; struct ffs_sync_args fsa; fs = ump->um_fs; /* * Write back modified superblock. * Consistency check that the superblock * is still in the buffer cache. */ if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { printf("fs = %s\n", fs->fs_fsmnt); panic("update: rofs mod"); } loop: /* * Write back each (modified) inode. */ fsa.allerror = 0; fsa.p = p; fsa.cred = cred; fsa.waitfor = waitfor; /* * Don't traverse the vnode list if we want to skip all of them. */ if (waitfor != MNT_LAZY) { vfs_mount_foreach_vnode(mp, ffs_sync_vnode, &fsa); allerror = fsa.allerror; } /* * Force stale file system control information to be flushed. */ if ((ump->um_mountp->mnt_flag & MNT_SOFTDEP) && waitfor == MNT_WAIT) { if ((error = softdep_flushworklist(ump->um_mountp, &count, p))) allerror = error; /* Flushed work items may create new vnodes to clean */ if (count) goto loop; } if (waitfor != MNT_LAZY) { if (ump->um_mountp->mnt_flag & MNT_SOFTDEP) waitfor = MNT_NOWAIT; vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0) allerror = error; VOP_UNLOCK(ump->um_devvp, 0, p); } qsync(mp); /* * Write back modified superblock. */ if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0) allerror = error; return (allerror); }
/* * If the superblock doesn't already have a recorded journal location * then we allocate the journal in one of two positions: * * - At the end of the partition after the filesystem if there's * enough space. "Enough space" is defined as >= 1MB of journal * per 1GB of filesystem or 64MB, whichever is smaller. * * - Inside the filesystem. We try to allocate a contiguous journal * based on the total filesystem size - the target is 1MB of journal * per 1GB of filesystem, up to a maximum journal size of 64MB. As * a worst case allowing for fragmentation, we'll allocate a journal * 1/4 of the desired size but never smaller than 1MB. * * XXX In the future if we allow for non-contiguous journal files we * can tighten the above restrictions. * * XXX * These seems like a lot of duplication both here and in some of * the userland tools (fsck_ffs, dumpfs, tunefs) with similar * "switch (fs_journal_location)" constructs. Can we centralise * this sort of code somehow/somewhere? */ int wapbl_log_position(struct mount *mp, struct fs *fs, struct vnode *devvp, daddr_t *startp, size_t *countp, size_t *blksizep, uint64_t *extradatap) { struct ufsmount *ump = VFSTOUFS(mp); daddr_t logstart, logend, desired_logsize; uint64_t numsecs; unsigned secsize; int error, location; if (fs->fs_journal_version == UFS_WAPBL_VERSION) { switch (fs->fs_journal_location) { case UFS_WAPBL_JOURNALLOC_END_PARTITION: DPRINTF("found existing end-of-partition log\n"); *startp = fs->fs_journallocs[UFS_WAPBL_EPART_ADDR]; *countp = fs->fs_journallocs[UFS_WAPBL_EPART_COUNT]; *blksizep = fs->fs_journallocs[UFS_WAPBL_EPART_BLKSZ]; DPRINTF(" start = %lld, size = %zu, " "blksize = %zu\n", *startp, *countp, *blksizep); return 0; case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM: DPRINTF("found existing in-filesystem log\n"); *startp = fs->fs_journallocs[UFS_WAPBL_INFS_ADDR]; *countp = fs->fs_journallocs[UFS_WAPBL_INFS_COUNT]; *blksizep = fs->fs_journallocs[UFS_WAPBL_INFS_BLKSZ]; DPRINTF(" start = %lld, size = %zu, " "blksize = %zu\n", *startp, *countp, *blksizep); return 0; default: printf("ffs_wapbl: unknown journal type %d\n", fs->fs_journal_location); return EINVAL; } } desired_logsize = lfragtosize(fs, fs->fs_size) / UFS_WAPBL_JOURNAL_SCALE; DPRINTF("desired log size = %lld kB\n", desired_logsize / 1024); desired_logsize = max(desired_logsize, UFS_WAPBL_MIN_JOURNAL_SIZE); desired_logsize = min(desired_logsize, UFS_WAPBL_MAX_JOURNAL_SIZE); DPRINTF("adjusted desired log size = %lld kB\n", desired_logsize / 1024); /* Is there space after after filesystem on partition for log? */ logstart = fsbtodb(fs, fs->fs_size); error = wapbl_getdisksize(devvp, &numsecs, &secsize); if (error) return error; KDASSERT(secsize != 0); logend = btodb(numsecs * secsize); if (dbtob(logend - logstart) >= desired_logsize) { DPRINTF("enough space, use end-of-partition log\n"); location = UFS_WAPBL_JOURNALLOC_END_PARTITION; *blksizep = secsize; *startp = logstart; *countp = (logend - logstart); *extradatap = 0; /* convert to physical block numbers */ *startp = dbtob(*startp) / secsize; *countp = dbtob(*countp) / secsize; fs->fs_journallocs[UFS_WAPBL_EPART_ADDR] = *startp; fs->fs_journallocs[UFS_WAPBL_EPART_COUNT] = *countp; fs->fs_journallocs[UFS_WAPBL_EPART_BLKSZ] = *blksizep; fs->fs_journallocs[UFS_WAPBL_EPART_UNUSED] = *extradatap; } else { DPRINTF("end-of-partition has only %lld free\n", logend - logstart); location = UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM; *blksizep = secsize; error = wapbl_create_infs_log(mp, fs, devvp, startp, countp, extradatap); ffs_sync(mp, MNT_WAIT, FSCRED, curproc); /* convert to physical block numbers */ *startp = dbtob(*startp) / secsize; *countp = dbtob(*countp) / secsize; fs->fs_journallocs[UFS_WAPBL_INFS_ADDR] = *startp; fs->fs_journallocs[UFS_WAPBL_INFS_COUNT] = *countp; fs->fs_journallocs[UFS_WAPBL_INFS_BLKSZ] = *blksizep; fs->fs_journallocs[UFS_WAPBL_INFS_INO] = *extradatap; } if (error == 0) { /* update superblock with log location */ fs->fs_journal_version = UFS_WAPBL_VERSION; fs->fs_journal_location = location; fs->fs_journal_flags = 0; error = ffs_sbupdate(ump, MNT_WAIT); } return error; }
int ffs_wapbl_start(struct mount *mp) { struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs = ump->um_fs; struct vnode *devvp = ump->um_devvp; daddr_t off; size_t count; size_t blksize; uint64_t extradata; int error; if (mp->mnt_wapbl == NULL) { if (fs->fs_journal_flags & UFS_WAPBL_FLAGS_CLEAR_LOG) { /* Clear out any existing journal file */ error = wapbl_remove_log(mp); if (error != 0) return error; } if (mp->mnt_flag & MNT_LOG) { KDASSERT(fs->fs_ronly == 0); /* WAPBL needs UFS2 format super block */ if (ffs_superblock_layout(fs) < 2) { printf("%s fs superblock in old format, " "not journaling\n", VFSTOUFS(mp)->um_fs->fs_fsmnt); mp->mnt_flag &= ~MNT_LOG; return EINVAL; } error = wapbl_log_position(mp, fs, devvp, &off, &count, &blksize, &extradata); if (error) return error; error = wapbl_start(&mp->mnt_wapbl, mp, devvp, off, count, blksize, mp->mnt_wapbl_replay, ffs_wapbl_sync_metadata, ffs_wapbl_abort_sync_metadata); if (error) return error; mp->mnt_wapbl_op = &wapbl_ops; #ifdef WAPBL_DEBUG printf("%s: enabling logging\n", fs->fs_fsmnt); #endif if ((fs->fs_flags & FS_DOWAPBL) == 0) { UFS_WAPBL_BEGIN(mp); fs->fs_flags |= FS_DOWAPBL; error = ffs_sbupdate(ump, MNT_WAIT); if (error) { UFS_WAPBL_END(mp); ffs_wapbl_stop(mp, MNT_FORCE); return error; } UFS_WAPBL_END(mp); error = wapbl_flush(mp->mnt_wapbl, 1); if (error) { ffs_wapbl_stop(mp, MNT_FORCE); return error; } } } else if (fs->fs_flags & FS_DOWAPBL) { fs->fs_fmod = 1; fs->fs_flags &= ~FS_DOWAPBL; } } /* * It is recommended that you finish replay with logging enabled. * However, even if logging is not enabled, the remaining log * replay should be safely recoverable with an fsck, so perform * it anyway. */ if ((fs->fs_ronly == 0) && mp->mnt_wapbl_replay) { int saveflag = mp->mnt_flag & MNT_RDONLY; /* * Make sure MNT_RDONLY is not set so that the inode * cleanup in ufs_inactive will actually do its work. */ mp->mnt_flag &= ~MNT_RDONLY; ffs_wapbl_replay_finish(mp); mp->mnt_flag |= saveflag; KASSERT(fs->fs_ronly == 0); } return 0; }
int wapbl_remove_log(struct mount *mp) { struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs = ump->um_fs; struct vnode *vp; struct inode *ip; ino_t log_ino; int error; /* If super block layout is too old to support WAPBL, return */ if (ffs_superblock_layout(fs) < 2) return 0; /* If all the log locators are 0, just clean up */ if (fs->fs_journallocs[0] == 0 && fs->fs_journallocs[1] == 0 && fs->fs_journallocs[2] == 0 && fs->fs_journallocs[3] == 0) { DPRINTF("empty locators, just clear\n"); goto done; } switch (fs->fs_journal_location) { case UFS_WAPBL_JOURNALLOC_NONE: /* nothing! */ DPRINTF("no log\n"); break; case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM: log_ino = fs->fs_journallocs[UFS_WAPBL_INFS_INO]; DPRINTF("in-fs log, ino = %lld\n",log_ino); /* if no existing log inode, just clear all fields and bail */ if (log_ino == 0) goto done; error = VFS_VGET(mp, log_ino, &vp); if (error != 0) { printf("ffs_wapbl: vget failed %d\n", error); /* clear out log info on error */ goto done; } ip = VTOI(vp); KASSERT(log_ino == ip->i_number); if ((DIP(ip, flags) & SF_LOG) == 0) { printf("ffs_wapbl: try to clear non-log inode " "%lld\n", log_ino); vput(vp); /* clear out log info on error */ goto done; } /* * remove the log inode by setting its link count back * to zero and bail. */ ip->i_effnlink = 0; DIP_ASSIGN(ip, nlink, 0); vput(vp); case UFS_WAPBL_JOURNALLOC_END_PARTITION: DPRINTF("end-of-partition log\n"); /* no extra work required */ break; default: printf("ffs_wapbl: unknown journal type %d\n", fs->fs_journal_location); break; } done: /* Clear out all previous knowledge of journal */ fs->fs_journal_version = 0; fs->fs_journal_location = 0; fs->fs_journal_flags = 0; fs->fs_journallocs[0] = 0; fs->fs_journallocs[1] = 0; fs->fs_journallocs[2] = 0; fs->fs_journallocs[3] = 0; (void) ffs_sbupdate(ump, MNT_WAIT); return 0; }
static int ntfs_mount ( struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p ) { u_int size; int err = 0; struct vnode *devvp; struct ntfs_args args; /* * Use NULL path to flag a root mount */ if( path == NULL) { /* *** * Mounting root file system *** */ /* Get vnode for root device*/ if( bdevvp( rootdev, &rootvp)) panic("ffs_mountroot: can't setup bdevvp for root"); /* * FS specific handling */ mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/ /* * Attempt mount */ if( ( err = ntfs_mountfs(rootvp, mp, &args, p)) != 0) { /* fs specific cleanup (if any)*/ goto error_1; } goto dostatfs; /* success*/ } /* *** * Mounting non-root file system or updating a file system *** */ /* copy in user arguments*/ err = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args)); if (err) goto error_1; /* can't get arguments*/ /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { printf("ntfs_mount(): MNT_UPDATE not supported\n"); err = EINVAL; goto error_1; #if 0 ump = VFSTOUFS(mp); fs = ump->um_fs; err = 0; if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; if (vfs_busy(mp)) { err = EBUSY; goto error_1; } err = ffs_flushfiles(mp, flags, p); vfs_unbusy(mp); } if (!err && (mp->mnt_flag & MNT_RELOAD)) err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); if (err) { goto error_1; } if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { if (!fs->fs_clean) { if (mp->mnt_flag & MNT_FORCE) { printf("WARNING: %s was not properly dismounted.\n",fs->fs_fsmnt); } else { printf("WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck.\n", fs->fs_fsmnt); err = EPERM; goto error_1; } } fs->fs_ronly = 0; } if (fs->fs_ronly == 0) { fs->fs_clean = 0; ffs_sbupdate(ump, MNT_WAIT); } /* if not updating name...*/ if (args.fspec == 0) { /* * Process export requests. Jumping to "success" * will return the vfs_export() error code. */ err = vfs_export(mp, &ump->um_export, &args.export); goto success; }