X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/97a33c788e2b7b2a1bdb3c64a1c876e3dc6c34c2..e4c9c0c82658e0eca11c3e516c41021ba48b0093:/sys/vfs/ufs/ffs_vfsops.c diff --git a/sys/vfs/ufs/ffs_vfsops.c b/sys/vfs/ufs/ffs_vfsops.c index 263820b072..ec2711de9b 100644 --- a/sys/vfs/ufs/ffs_vfsops.c +++ b/sys/vfs/ufs/ffs_vfsops.c @@ -32,7 +32,7 @@ * * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 * $FreeBSD: src/sys/ufs/ffs/ffs_vfsops.c,v 1.117.2.10 2002/06/23 22:34:52 iedowse Exp $ - * $DragonFly: src/sys/vfs/ufs/ffs_vfsops.c,v 1.12 2003/09/23 05:03:53 dillon Exp $ + * $DragonFly: src/sys/vfs/ufs/ffs_vfsops.c,v 1.18 2004/05/19 22:53:06 dillon Exp $ */ #include "opt_quota.h" @@ -128,12 +128,11 @@ VFS_SET(ufs_vfsops, ufs, 0); * namei() if it is a genuine NULL from the user. */ static int -ffs_mount( mp, path, data, ndp, td) - struct mount *mp; /* mount struct pointer*/ - char *path; /* path to mount point*/ - caddr_t data; /* arguments to FS specific mount*/ - struct nameidata *ndp; /* mount point credentials*/ - struct thread *td; /* process requesting mount*/ +ffs_mount(struct mount *mp, /* mount struct pointer */ + char *path, /* path to mount point */ + caddr_t data, /* arguments to FS specific mount */ + struct nameidata *ndp, /* mount point credentials */ + struct thread *td) /* process requesting mount */ { size_t size; int err = 0; @@ -224,13 +223,13 @@ ffs_mount( mp, path, data, ndp, td) * that user has necessary permissions on the device. */ if (cred->cr_uid != 0) { - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); if ((error = VOP_ACCESS(devvp, VREAD | VWRITE, cred, td)) != 0) { - VOP_UNLOCK(devvp, 0, td); + VOP_UNLOCK(devvp, NULL, 0, td); return (error); } - VOP_UNLOCK(devvp, 0, td); + VOP_UNLOCK(devvp, NULL, 0, td); } fs->fs_flags &= ~FS_UNCLEAN; @@ -304,12 +303,12 @@ ffs_mount( mp, path, data, ndp, td) accessmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accessmode |= VWRITE; - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); if ((error = VOP_ACCESS(devvp, accessmode, cred, td)) != 0) { vput(devvp); return (error); } - VOP_UNLOCK(devvp, 0, td); + VOP_UNLOCK(devvp, NULL, 0, td); } if (mp->mnt_flag & MNT_UPDATE) { @@ -317,18 +316,22 @@ ffs_mount( mp, path, data, ndp, td) ******************** * UPDATE * If it's not the same vnode, or at least the same device - * then it's not correct. + * then it's not correct. NOTE: devvp->v_rdev may be NULL + * since we haven't opened it, so we compare udev instead. ******************** */ - if (devvp != ump->um_devvp) { - if ( devvp->v_rdev == ump->um_devvp->v_rdev) { + if (devvp->v_udev == ump->um_devvp->v_udev) { vrele(devvp); } else { + printf("cannot update mount, udev does" + " not match %08x vs %08x\n", + devvp->v_udev, ump->um_devvp->v_udev); err = EINVAL; /* needs translation */ } - } else + } else { vrele(devvp); + } /* * Update device name only on success */ @@ -419,19 +422,32 @@ success: * 5) invalidate all cached file data. * 6) re-read inode data for all active vnodes. */ + +static int ffs_reload_scan1(struct mount *mp, struct vnode *vp, void *data); +static int ffs_reload_scan2(struct mount *mp, struct vnode *vp, + lwkt_tokref_t vlock, void *data); + +struct scaninfo { + int rescan; + struct fs *fs; + struct vnode *devvp; + thread_t td; + int waitfor; + int allerror; +}; + static int ffs_reload(struct mount *mp, struct ucred *cred, struct thread *td) { - struct vnode *vp, *nvp, *devvp; - struct inode *ip; + struct vnode *devvp; void *space; struct buf *bp; struct fs *fs, *newfs; struct partinfo dpart; dev_t dev; int i, blks, size, error; - int gen; - int vgen; + lwkt_tokref vlock; + struct scaninfo scaninfo; int32_t *lp; if ((mp->mnt_flag & MNT_RDONLY) == 0) @@ -440,23 +456,22 @@ ffs_reload(struct mount *mp, struct ucred *cred, struct thread *td) * Step 1: invalidate all cached meta-data. */ devvp = VFSTOUFS(mp)->um_devvp; - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); error = vinvalbuf(devvp, 0, td, 0, 0); - VOP_UNLOCK(devvp, 0, td); + VOP_UNLOCK(devvp, NULL, 0, td); if (error) panic("ffs_reload: dirty1"); dev = devvp->v_rdev; - /* * Only VMIO the backing device if the backing device is a real * block device. See ffs_mountmfs() for more details. */ if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) { - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); vfs_object_create(devvp, td); - lwkt_gettoken(&devvp->v_interlock); - VOP_UNLOCK(devvp, LK_INTERLOCK, td); + lwkt_gettoken(&vlock, devvp->v_interlock); + VOP_UNLOCK(devvp, &vlock, LK_INTERLOCK, td); } /* @@ -483,6 +498,8 @@ ffs_reload(struct mount *mp, struct ucred *cred, struct thread *td) newfs->fs_csp = fs->fs_csp; newfs->fs_maxcluster = fs->fs_maxcluster; newfs->fs_contigdirs = fs->fs_contigdirs; + /* The file system is still read-only. */ + newfs->fs_ronly = 1; bcopy(newfs, fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; @@ -520,68 +537,77 @@ ffs_reload(struct mount *mp, struct ucred *cred, struct thread *td) *lp++ = fs->fs_contigsumsize; } - gen = lwkt_gettoken(&mntvnode_token); -loop: - for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) { - if (vp->v_mount != mp) { - lwkt_gentoken(&mntvnode_token, &gen); - goto loop; - } - nvp = TAILQ_NEXT(vp, v_nmntvnodes); - /* - * Step 4: invalidate all inactive vnodes. - */ - if (vrecycle(vp, NULL, td)) { - lwkt_gentoken(&mntvnode_token, &gen); - goto loop; - } - /* - * Step 5: invalidate all cached file data. - */ - vgen = lwkt_gettoken(&vp->v_interlock); - if (lwkt_gentoken(&mntvnode_token, &gen) != 0 || - lwkt_gentoken(&vp->v_interlock, &vgen) != 0) { - lwkt_reltoken(&vp->v_interlock); - lwkt_gentoken(&mntvnode_token, &gen); - goto loop; - } - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { - lwkt_gentoken(&mntvnode_token, &gen); - goto loop; - } - if (vinvalbuf(vp, 0, td, 0, 0)) - panic("ffs_reload: dirty2"); - /* - * Step 6: re-read inode data for all active vnodes. - */ - ip = VTOI(vp); - error = - bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), - (int)fs->fs_bsize, &bp); - if (error) { - vput(vp); - lwkt_reltoken(&mntvnode_token); - return (error); - } - ip->i_din = *((struct dinode *)bp->b_data + - ino_to_fsbo(fs, ip->i_number)); - ip->i_effnlink = ip->i_nlink; - brelse(bp); + scaninfo.rescan = 0; + scaninfo.fs = fs; + scaninfo.devvp = devvp; + scaninfo.td = td; + while (error == 0 && scaninfo.rescan) { + scaninfo.rescan = 0; + error = vmntvnodescan(mp, ffs_reload_scan1, + ffs_reload_scan2, &scaninfo); + } + return(error); +} + +static +int +ffs_reload_scan1(struct mount *mp, struct vnode *vp, void *data) +{ + struct scaninfo *info = data; + + /* + * Step 4: invalidate all inactive vnodes. + */ + if (vrecycle(vp, NULL, info->td)) { + info->rescan = 1; + return(-1); /* continue loop, do not call scan2 */ + } + return(0); +} + +static +int +ffs_reload_scan2(struct mount *mp, struct vnode *vp, lwkt_tokref_t vlock, void *data) +{ + struct scaninfo *info = data; + struct inode *ip; + struct buf *bp; + int error; + + /* + * Step 5: invalidate all cached file data. + */ + if (vget(vp, vlock, LK_EXCLUSIVE | LK_INTERLOCK, info->td)) { + info->rescan = 1; + return(0); + } + if (vinvalbuf(vp, 0, info->td, 0, 0)) + panic("ffs_reload: dirty2"); + /* + * Step 6: re-read inode data for all active vnodes. + */ + ip = VTOI(vp); + error = bread(info->devvp, + fsbtodb(info->fs, ino_to_fsba(info->fs, ip->i_number)), + (int)info->fs->fs_bsize, &bp); + if (error) { vput(vp); + return (error); } - lwkt_reltoken(&mntvnode_token); - return (0); + ip->i_din = *((struct dinode *)bp->b_data + + ino_to_fsbo(info->fs, ip->i_number)); + ip->i_effnlink = ip->i_nlink; + brelse(bp); + vput(vp); + return(0); } /* * Common code for mount and mountroot */ int -ffs_mountfs(devvp, mp, td, malloctype) - struct vnode *devvp; - struct mount *mp; - struct thread *td; - struct malloc_type *malloctype; +ffs_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td, + struct malloc_type *malloctype) { struct ufsmount *ump; struct buf *bp; @@ -590,12 +616,11 @@ ffs_mountfs(devvp, mp, td, malloctype) struct partinfo dpart; void *space; int error, i, blks, size, ronly; + lwkt_tokref vlock; int32_t *lp; u_int64_t maxfilesize; /* XXX */ size_t strsize; - int ncount; - dev = devvp->v_rdev; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use @@ -605,13 +630,11 @@ ffs_mountfs(devvp, mp, td, malloctype) error = vfs_mountedon(devvp); if (error) return (error); - ncount = vcount(devvp); - - if (ncount > 1 && devvp != rootvp) + if (count_udev(devvp->v_udev) > 0 && devvp != rootvp) return (EBUSY); - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); error = vinvalbuf(devvp, V_SAVE, td, 0, 0); - VOP_UNLOCK(devvp, 0, td); + VOP_UNLOCK(devvp, NULL, 0, td); if (error) return (error); @@ -622,20 +645,21 @@ ffs_mountfs(devvp, mp, td, malloctype) * increases the opportunity for metadata caching. */ if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) { - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); vfs_object_create(devvp, td); - lwkt_gettoken(&devvp->v_interlock); - VOP_UNLOCK(devvp, LK_INTERLOCK, td); + lwkt_gettoken(&vlock, devvp->v_interlock); + VOP_UNLOCK(devvp, &vlock, LK_INTERLOCK, td); } ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td); - VOP_UNLOCK(devvp, 0, td); + VOP_UNLOCK(devvp, NULL, 0, td); if (error) return (error); - if (devvp->v_rdev->si_iosize_max != 0) - mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; + dev = devvp->v_rdev; + if (dev->si_iosize_max != 0) + mp->mnt_iosize_max = dev->si_iosize_max; if (mp->mnt_iosize_max > MAXPHYS) mp->mnt_iosize_max = MAXPHYS; @@ -744,7 +768,7 @@ ffs_mountfs(devvp, mp, td, malloctype) ump->um_seqinc = fs->fs_frag; for (i = 0; i < MAXQUOTAS; i++) ump->um_quotas[i] = NULLVP; - devvp->v_specmountpoint = mp; + dev->si_mountpoint = mp; ffs_oldfscompat(fs); /* @@ -784,10 +808,10 @@ ffs_mountfs(devvp, mp, td, malloctype) } return (0); out: - devvp->v_specmountpoint = NULL; + dev->si_mountpoint = NULL; if (bp) brelse(bp); - (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, td); + VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, td); if (ump) { free(ump->um_fs, M_UFSMNT); free(ump, M_UFSMNT); @@ -802,10 +826,8 @@ out: * XXX - goes away some day. */ static int -ffs_oldfscompat(fs) - struct fs *fs; +ffs_oldfscompat(struct fs *fs) { - fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ @@ -859,7 +881,7 @@ ffs_unmount(struct mount *mp, int mntflags, struct thread *td) return (error); } } - ump->um_devvp->v_specmountpoint = NULL; + ump->um_devvp->v_rdev->si_mountpoint = NULL; vinvalbuf(ump->um_devvp, V_SAVE, td, 0, 0); error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, td); @@ -909,9 +931,9 @@ ffs_flushfiles(struct mount *mp, int flags, struct thread *td) /* * Flush filesystem metadata. */ - vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(ump->um_devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); error = VOP_FSYNC(ump->um_devvp, MNT_WAIT, td); - VOP_UNLOCK(ump->um_devvp, 0, td); + VOP_UNLOCK(ump->um_devvp, NULL, 0, td); return (error); } @@ -953,88 +975,47 @@ ffs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) * * Note: we are always called with the filesystem marked `MPBUSY'. */ + + +static int ffs_sync_scan1(struct mount *mp, struct vnode *vp, void *data); +static int ffs_sync_scan2(struct mount *mp, struct vnode *vp, + lwkt_tokref_t vlock, void *data); + int ffs_sync(struct mount *mp, int waitfor, struct thread *td) { - struct vnode *nvp, *vp; - struct inode *ip; struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs; - int error, allerror = 0; + int error; + struct scaninfo scaninfo; fs = ump->um_fs; if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ printf("fs = %s\n", fs->fs_fsmnt); panic("ffs_sync: rofs mod"); } + /* * Write back each (modified) inode. */ - lwkt_gettoken(&mntvnode_token); -loop: - for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) { - /* - * If the vnode that we are about to sync is no longer - * associated with this mount point, start over. - */ - if (vp->v_mount != mp) - goto loop; - - /* - * Depend on the mntvnode_token to keep things stable enough - * for a quick test. Since there might be hundreds of - * thousands of vnodes, we cannot afford even a subroutine - * call unless there's a good chance that we have work to do. - */ - nvp = TAILQ_NEXT(vp, v_nmntvnodes); - ip = VTOI(vp); - if (vp->v_type == VNON || ((ip->i_flag & - (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && - TAILQ_EMPTY(&vp->v_dirtyblkhd))) { - continue; - } - if (vp->v_type != VCHR) { - lwkt_reltoken(&mntvnode_token); - error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT, td); - if (error) { - lwkt_gettoken(&mntvnode_token); - if (error == ENOENT) - goto loop; - } else { - if ((error = VOP_FSYNC(vp, waitfor, td)) != 0) - allerror = error; - VOP_UNLOCK(vp, 0, td); - vrele(vp); - lwkt_gettoken(&mntvnode_token); - } - } else { - /* - * We must reference the vp to prevent it from - * getting ripped out from under UFS_UPDATE, since - * we are not holding a vnode lock. XXX why aren't - * we holding a vnode lock? - */ - VREF(vp); - lwkt_reltoken(&mntvnode_token); - /* UFS_UPDATE(vp, waitfor == MNT_WAIT); */ - UFS_UPDATE(vp, 0); - vrele(vp); - lwkt_gettoken(&mntvnode_token); - } - if (TAILQ_NEXT(vp, v_nmntvnodes) != nvp) - goto loop; + scaninfo.allerror = 0; + scaninfo.rescan = 1; + scaninfo.waitfor = waitfor; + while (scaninfo.rescan) { + scaninfo.rescan = 0; + vmntvnodescan(mp, ffs_sync_scan1, ffs_sync_scan2, &scaninfo); } - lwkt_reltoken(&mntvnode_token); + /* * Force stale file system control information to be flushed. */ if (waitfor != MNT_LAZY) { if (ump->um_mountp->mnt_flag & MNT_SOFTDEP) waitfor = MNT_NOWAIT; - vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, td); + vn_lock(ump->um_devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); if ((error = VOP_FSYNC(ump->um_devvp, waitfor, td)) != 0) - allerror = error; - VOP_UNLOCK(ump->um_devvp, 0, td); + scaninfo.allerror = error; + VOP_UNLOCK(ump->um_devvp, NULL, 0, td); } #ifdef QUOTA qsync(mp); @@ -1043,8 +1024,75 @@ loop: * Write back modified superblock. */ if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0) - allerror = error; - return (allerror); + scaninfo.allerror = error; + return (scaninfo.allerror); +} + +static +int +ffs_sync_scan1(struct mount *mp, struct vnode *vp, void *data) +{ + struct inode *ip; + + /* + * Depend on the mount list's vnode lock to keep things stable + * enough for a quick test. Since there might be hundreds of + * thousands of vnodes, we cannot afford even a subroutine + * call unless there's a good chance that we have work to do. + */ + ip = VTOI(vp); + if (vp->v_type == VNON || ((ip->i_flag & + (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && + TAILQ_EMPTY(&vp->v_dirtyblkhd))) { + return(-1); + } + return(0); +} + +static +int +ffs_sync_scan2(struct mount *mp, struct vnode *vp, + lwkt_tokref_t vlock, void *data) +{ + struct scaninfo *info = data; + thread_t td = curthread; /* XXX */ + struct inode *ip; + int error; + + /* + * We have to recheck after having obtained the vnode interlock. + */ + ip = VTOI(vp); + if (vp->v_type == VNON || ((ip->i_flag & + (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && + TAILQ_EMPTY(&vp->v_dirtyblkhd))) { + lwkt_reltoken(vlock); + return(0); + } + if (vp->v_type != VCHR) { + error = vget(vp, vlock, LK_INTERLOCK|LK_EXCLUSIVE|LK_NOWAIT, td); + if (error) { + if (error == ENOENT) + info->rescan = 1; + } else { + if ((error = VOP_FSYNC(vp, info->waitfor, td)) != 0) + info->allerror = error; + VOP_UNLOCK(vp, NULL, 0, td); + vrele(vp); + } + } else { + /* + * We must reference the vp to prevent it from + * getting ripped out from under UFS_UPDATE, since + * we are not holding a vnode lock. + */ + vref(vp); + lwkt_reltoken(vlock); + /* UFS_UPDATE(vp, waitfor == MNT_WAIT); */ + UFS_UPDATE(vp, 0); + vrele(vp); + } + return(0); } /* @@ -1056,10 +1104,7 @@ loop: static int ffs_inode_hash_lock; int -ffs_vget(mp, ino, vpp) - struct mount *mp; - ino_t ino; - struct vnode **vpp; +ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) { struct fs *fs; struct inode *ip; @@ -1176,7 +1221,7 @@ restart: * Finish inode initialization now that aliasing has been resolved. */ ip->i_devvp = ump->um_devvp; - VREF(ip->i_devvp); + vref(ip->i_devvp); /* * Set up a generation number for this inode if it does not * already have one. This should only happen on old filesystems. @@ -1210,10 +1255,7 @@ restart: * those rights via. exflagsp and credanonp */ int -ffs_fhtovp(mp, fhp, vpp) - struct mount *mp; - struct fid *fhp; - struct vnode **vpp; +ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) { struct ufid *ufhp; struct fs *fs; @@ -1231,9 +1273,7 @@ ffs_fhtovp(mp, fhp, vpp) */ /* ARGSUSED */ int -ffs_vptofh(vp, fhp) - struct vnode *vp; - struct fid *fhp; +ffs_vptofh(struct vnode *vp, struct fid *fhp) { struct inode *ip; struct ufid *ufhp; @@ -1250,10 +1290,8 @@ ffs_vptofh(vp, fhp) * Initialize the filesystem; just use ufs_init. */ static int -ffs_init(vfsp) - struct vfsconf *vfsp; +ffs_init(struct vfsconf *vfsp) { - softdep_initialize(); return (ufs_init(vfsp)); } @@ -1262,9 +1300,7 @@ ffs_init(vfsp) * Write a superblock and associated information back to disk. */ static int -ffs_sbupdate(mp, waitfor) - struct ufsmount *mp; - int waitfor; +ffs_sbupdate(struct ufsmount *mp, int waitfor) { struct fs *dfs, *fs = mp->um_fs; struct buf *bp;