Changeset View
Changeset View
Standalone View
Standalone View
sys/ufs/ffs/ffs_softdep.c
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 3,438 Lines • ▼ Show 20 Lines | jseg_write(ump, jseg, data) | ||||
uint8_t *data; | uint8_t *data; | ||||
{ | { | ||||
struct jsegrec *rec; | struct jsegrec *rec; | ||||
rec = (struct jsegrec *)data; | rec = (struct jsegrec *)data; | ||||
rec->jsr_seq = jseg->js_seq; | rec->jsr_seq = jseg->js_seq; | ||||
rec->jsr_oldest = jseg->js_oldseq; | rec->jsr_oldest = jseg->js_oldseq; | ||||
rec->jsr_cnt = jseg->js_cnt; | rec->jsr_cnt = jseg->js_cnt; | ||||
rec->jsr_blocks = jseg->js_size / ump->um_devvp->v_bufobj.bo_bsize; | rec->jsr_blocks = jseg->js_size / vp2bo(ump->um_devvp)->bo_bsize; | ||||
rec->jsr_crc = 0; | rec->jsr_crc = 0; | ||||
rec->jsr_time = ump->um_fs->fs_mtime; | rec->jsr_time = ump->um_fs->fs_mtime; | ||||
} | } | ||||
static inline void | static inline void | ||||
inoref_write(inoref, jseg, rec) | inoref_write(inoref, jseg, rec) | ||||
struct inoref *inoref; | struct inoref *inoref; | ||||
struct jseg *jseg; | struct jseg *jseg; | ||||
▲ Show 20 Lines • Show All 250 Lines • ▼ Show 20 Lines | if (MOUNTEDSUJ(mp) == 0) | ||||
return; | return; | ||||
shouldflush = softdep_flushcache; | shouldflush = softdep_flushcache; | ||||
bio = NULL; | bio = NULL; | ||||
jseg = NULL; | jseg = NULL; | ||||
ump = VFSTOUFS(mp); | ump = VFSTOUFS(mp); | ||||
LOCK_OWNED(ump); | LOCK_OWNED(ump); | ||||
fs = ump->um_fs; | fs = ump->um_fs; | ||||
jblocks = ump->softdep_jblocks; | jblocks = ump->softdep_jblocks; | ||||
devbsize = ump->um_devvp->v_bufobj.bo_bsize; | devbsize = vp2bo(ump->um_devvp)->bo_bsize; | ||||
/* | /* | ||||
* We write anywhere between a disk block and fs block. The upper | * We write anywhere between a disk block and fs block. The upper | ||||
* bound is picked to prevent buffer cache fragmentation and limit | * bound is picked to prevent buffer cache fragmentation and limit | ||||
* processing time per I/O. | * processing time per I/O. | ||||
*/ | */ | ||||
jrecmin = (devbsize / JREC_SIZE) - 1; /* -1 for seg header */ | jrecmin = (devbsize / JREC_SIZE) - 1; /* -1 for seg header */ | ||||
jrecmax = (fs->fs_bsize / devbsize) * jrecmin; | jrecmax = (fs->fs_bsize / devbsize) * jrecmin; | ||||
segwritten = 0; | segwritten = 0; | ||||
▲ Show 20 Lines • Show All 3,660 Lines • ▼ Show 20 Lines | trunc_pages(ip, length, extblocks, flags) | ||||
vp = ITOV(ip); | vp = ITOV(ip); | ||||
fs = ITOFS(ip); | fs = ITOFS(ip); | ||||
extend = OFF_TO_IDX(lblktosize(fs, -extblocks)); | extend = OFF_TO_IDX(lblktosize(fs, -extblocks)); | ||||
if ((flags & IO_EXT) != 0) | if ((flags & IO_EXT) != 0) | ||||
vn_pages_remove(vp, extend, 0); | vn_pages_remove(vp, extend, 0); | ||||
if ((flags & IO_NORMAL) == 0) | if ((flags & IO_NORMAL) == 0) | ||||
return; | return; | ||||
BO_LOCK(&vp->v_bufobj); | BO_LOCK(vp2bo(vp)); | ||||
drain_output(vp); | drain_output(vp); | ||||
BO_UNLOCK(&vp->v_bufobj); | BO_UNLOCK(vp2bo(vp)); | ||||
/* | /* | ||||
* The vnode pager eliminates file pages we eliminate indirects | * The vnode pager eliminates file pages we eliminate indirects | ||||
* below. | * below. | ||||
*/ | */ | ||||
vnode_pager_setsize(vp, length); | vnode_pager_setsize(vp, length); | ||||
/* | /* | ||||
* Calculate the end based on the last indirect we want to keep. If | * Calculate the end based on the last indirect we want to keep. If | ||||
* the block extends into indirects we can just use the negative of | * the block extends into indirects we can just use the negative of | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | trunc_dependencies(ip, freeblks, lastlbn, lastoff, flags) | ||||
/* | /* | ||||
* We must wait for any I/O in progress to finish so that | * We must wait for any I/O in progress to finish so that | ||||
* all potential buffers on the dirty list will be visible. | * all potential buffers on the dirty list will be visible. | ||||
* Once they are all there, walk the list and get rid of | * Once they are all there, walk the list and get rid of | ||||
* any dependencies. | * any dependencies. | ||||
*/ | */ | ||||
vp = ITOV(ip); | vp = ITOV(ip); | ||||
bo = &vp->v_bufobj; | bo = vp2bo(vp); | ||||
BO_LOCK(bo); | BO_LOCK(bo); | ||||
drain_output(vp); | drain_output(vp); | ||||
TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) | TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) | ||||
bp->b_vflags &= ~BV_SCANNED; | bp->b_vflags &= ~BV_SCANNED; | ||||
restart: | restart: | ||||
TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) { | TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) { | ||||
if (bp->b_vflags & BV_SCANNED) | if (bp->b_vflags & BV_SCANNED) | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 995 Lines • ▼ Show 20 Lines | indir_trunc(freework, dbn, lbn) | ||||
indirdep = NULL; | indirdep = NULL; | ||||
if (freework->fw_indir != NULL) { | if (freework->fw_indir != NULL) { | ||||
goingaway = 0; | goingaway = 0; | ||||
indirdep = freework->fw_indir; | indirdep = freework->fw_indir; | ||||
bp = indirdep->ir_savebp; | bp = indirdep->ir_savebp; | ||||
if (bp == NULL || bp->b_blkno != dbn) | if (bp == NULL || bp->b_blkno != dbn) | ||||
panic("indir_trunc: Bad saved buf %p blkno %jd", | panic("indir_trunc: Bad saved buf %p blkno %jd", | ||||
bp, (intmax_t)dbn); | bp, (intmax_t)dbn); | ||||
} else if ((bp = incore(&freeblks->fb_devvp->v_bufobj, dbn)) != NULL) { | } else if ((bp = incore(vp2bo(freeblks->fb_devvp), dbn)) != NULL) { | ||||
/* | /* | ||||
* The lock prevents the buf dep list from changing and | * The lock prevents the buf dep list from changing and | ||||
* indirects on devvp should only ever have one dependency. | * indirects on devvp should only ever have one dependency. | ||||
*/ | */ | ||||
indirdep = WK_INDIRDEP(LIST_FIRST(&bp->b_dep)); | indirdep = WK_INDIRDEP(LIST_FIRST(&bp->b_dep)); | ||||
if (indirdep == NULL || (indirdep->ir_state & GOINGAWAY) == 0) | if (indirdep == NULL || (indirdep->ir_state & GOINGAWAY) == 0) | ||||
panic("indir_trunc: Bad indirdep %p from buf %p", | panic("indir_trunc: Bad indirdep %p from buf %p", | ||||
indirdep, bp); | indirdep, bp); | ||||
▲ Show 20 Lines • Show All 4,483 Lines • ▼ Show 20 Lines | softdep_fsync_mountdev(vp) | ||||
struct vnode *vp; | struct vnode *vp; | ||||
{ | { | ||||
struct buf *bp, *nbp; | struct buf *bp, *nbp; | ||||
struct worklist *wk; | struct worklist *wk; | ||||
struct bufobj *bo; | struct bufobj *bo; | ||||
if (!vn_isdisk(vp)) | if (!vn_isdisk(vp)) | ||||
panic("softdep_fsync_mountdev: vnode not a disk"); | panic("softdep_fsync_mountdev: vnode not a disk"); | ||||
bo = &vp->v_bufobj; | bo = vp2bo(vp); | ||||
restart: | restart: | ||||
BO_LOCK(bo); | BO_LOCK(bo); | ||||
TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { | TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { | ||||
/* | /* | ||||
* If it is already scheduled, skip to the next buffer. | * If it is already scheduled, skip to the next buffer. | ||||
*/ | */ | ||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) | if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 384 Lines • ▼ Show 20 Lines | flush_newblk_dep(vp, mp, lbn) | ||||
struct ufsmount *ump; | struct ufsmount *ump; | ||||
struct bufobj *bo; | struct bufobj *bo; | ||||
struct inode *ip; | struct inode *ip; | ||||
struct buf *bp; | struct buf *bp; | ||||
ufs2_daddr_t blkno; | ufs2_daddr_t blkno; | ||||
int error; | int error; | ||||
error = 0; | error = 0; | ||||
bo = &vp->v_bufobj; | bo = vp2bo(vp); | ||||
ip = VTOI(vp); | ip = VTOI(vp); | ||||
blkno = DIP(ip, i_db[lbn]); | blkno = DIP(ip, i_db[lbn]); | ||||
if (blkno == 0) | if (blkno == 0) | ||||
panic("flush_newblk_dep: Missing block"); | panic("flush_newblk_dep: Missing block"); | ||||
ump = VFSTOUFS(mp); | ump = VFSTOUFS(mp); | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
/* | /* | ||||
* Loop until all dependencies related to this block are satisfied. | * Loop until all dependencies related to this block are satisfied. | ||||
▲ Show 20 Lines • Show All 543 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
struct vnode *lvp, *mvp; | struct vnode *lvp, *mvp; | ||||
int failed_vnode; | int failed_vnode; | ||||
failed_vnode = 0; | failed_vnode = 0; | ||||
td = curthread; | td = curthread; | ||||
MNT_VNODE_FOREACH_ALL(lvp, mp, mvp) { | MNT_VNODE_FOREACH_ALL(lvp, mp, mvp) { | ||||
if (TAILQ_FIRST(&lvp->v_bufobj.bo_dirty.bv_hd) == 0) { | if (TAILQ_FIRST(&vp2bo(lvp)->bo_dirty.bv_hd) == NULL) { | ||||
VI_UNLOCK(lvp); | VI_UNLOCK(lvp); | ||||
continue; | continue; | ||||
} | } | ||||
if (vget(lvp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT) != 0) { | if (vget(lvp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT) != 0) { | ||||
failed_vnode = 1; | failed_vnode = 1; | ||||
continue; | continue; | ||||
} | } | ||||
if (lvp->v_vflag & VV_NOSYNC) { /* unlinked */ | if (lvp->v_vflag & VV_NOSYNC) { /* unlinked */ | ||||
▲ Show 20 Lines • Show All 308 Lines • ▼ Show 20 Lines | LIST_FOREACH(pagedep, pagedephd, pd_hash) { | ||||
vfs_unbusy(mp); | vfs_unbusy(mp); | ||||
if (error != 0) { | if (error != 0) { | ||||
softdep_error("clear_remove: vget", error); | softdep_error("clear_remove: vget", error); | ||||
goto finish_write; | goto finish_write; | ||||
} | } | ||||
MPASS(VTOI(vp)->i_mode != 0); | MPASS(VTOI(vp)->i_mode != 0); | ||||
if ((error = ffs_syncvnode(vp, MNT_NOWAIT, 0))) | if ((error = ffs_syncvnode(vp, MNT_NOWAIT, 0))) | ||||
softdep_error("clear_remove: fsync", error); | softdep_error("clear_remove: fsync", error); | ||||
bo = &vp->v_bufobj; | bo = vp2bo(vp); | ||||
BO_LOCK(bo); | BO_LOCK(bo); | ||||
drain_output(vp); | drain_output(vp); | ||||
BO_UNLOCK(bo); | BO_UNLOCK(bo); | ||||
vput(vp); | vput(vp); | ||||
finish_write: | finish_write: | ||||
vn_finished_write(mp); | vn_finished_write(mp); | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | if (VTOI(vp)->i_mode == 0) { | ||||
do { | do { | ||||
error = ffs_syncvnode(vp, MNT_WAIT, 0); | error = ffs_syncvnode(vp, MNT_WAIT, 0); | ||||
} while (error == ERELOOKUP); | } while (error == ERELOOKUP); | ||||
if (error != 0) | if (error != 0) | ||||
softdep_error("clear_inodedeps: fsync1", error); | softdep_error("clear_inodedeps: fsync1", error); | ||||
} else { | } else { | ||||
if ((error = ffs_syncvnode(vp, MNT_NOWAIT, 0))) | if ((error = ffs_syncvnode(vp, MNT_NOWAIT, 0))) | ||||
softdep_error("clear_inodedeps: fsync2", error); | softdep_error("clear_inodedeps: fsync2", error); | ||||
BO_LOCK(&vp->v_bufobj); | BO_LOCK(vp2bo(vp)); | ||||
drain_output(vp); | drain_output(vp); | ||||
BO_UNLOCK(&vp->v_bufobj); | BO_UNLOCK(vp2bo(vp)); | ||||
} | } | ||||
vput(vp); | vput(vp); | ||||
vn_finished_write(mp); | vn_finished_write(mp); | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
} | } | ||||
} | } | ||||
void | void | ||||
▲ Show 20 Lines • Show All 353 Lines • ▼ Show 20 Lines | softdep_check_suspend(struct mount *mp, | ||||
int secondary_writes, | int secondary_writes, | ||||
int secondary_accwrites) | int secondary_accwrites) | ||||
{ | { | ||||
struct bufobj *bo; | struct bufobj *bo; | ||||
struct ufsmount *ump; | struct ufsmount *ump; | ||||
struct inodedep *inodedep; | struct inodedep *inodedep; | ||||
int error, unlinked; | int error, unlinked; | ||||
bo = &devvp->v_bufobj; | bo = vp2bo(devvp); | ||||
ASSERT_BO_WLOCKED(bo); | ASSERT_BO_WLOCKED(bo); | ||||
/* | /* | ||||
* If we are not running with soft updates, then we need only | * If we are not running with soft updates, then we need only | ||||
* deal with secondary writes as we try to suspend. | * deal with secondary writes as we try to suspend. | ||||
*/ | */ | ||||
if (MOUNTEDSOFTDEP(mp) == 0) { | if (MOUNTEDSOFTDEP(mp) == 0) { | ||||
MNT_ILOCK(mp); | MNT_ILOCK(mp); | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | |||||
* Wait for pending output on a vnode to complete. | * Wait for pending output on a vnode to complete. | ||||
*/ | */ | ||||
static void | static void | ||||
drain_output(vp) | drain_output(vp) | ||||
struct vnode *vp; | struct vnode *vp; | ||||
{ | { | ||||
ASSERT_VOP_LOCKED(vp, "drain_output"); | ASSERT_VOP_LOCKED(vp, "drain_output"); | ||||
(void)bufobj_wwait(&vp->v_bufobj, 0, 0); | (void)bufobj_wwait(vp2bo(vp), 0, 0); | ||||
} | } | ||||
/* | /* | ||||
* Called whenever a buffer that is being invalidated or reallocated | * Called whenever a buffer that is being invalidated or reallocated | ||||
* contains dependencies. This should only happen if an I/O error has | * contains dependencies. This should only happen if an I/O error has | ||||
* occurred. The routine is called with the buffer locked. | * occurred. The routine is called with the buffer locked. | ||||
*/ | */ | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 279 Lines • Show Last 20 Lines |