diff options
author | Thorsten Lockert <tholo@cvs.openbsd.org> | 1996-06-11 03:25:18 +0000 |
---|---|---|
committer | Thorsten Lockert <tholo@cvs.openbsd.org> | 1996-06-11 03:25:18 +0000 |
commit | 8db8a379747ee056c46b16e020c29c8a5829e357 (patch) | |
tree | 81e2825ca363e3b400b85481997e69efb5f8e1c6 /sys/kern | |
parent | 53c5905b071647ba7a61fb1493f9458f0cc258d9 (diff) |
Kernel-implementation of update(8) my me
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/init_main.c | 32 | ||||
-rw-r--r-- | sys/kern/vfs_bio.c | 181 | ||||
-rw-r--r-- | sys/kern/vfs_cluster.c | 4 |
3 files changed, 214 insertions, 3 deletions
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index eb953d519b3..8cca8948dca 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init_main.c,v 1.10 1996/06/10 07:25:54 deraadt Exp $ */ +/* $OpenBSD: init_main.c,v 1.11 1996/06/11 03:25:12 tholo Exp $ */ /* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */ /* @@ -113,6 +113,7 @@ struct timeval runtime; static void start_init __P((struct proc *)); static void start_pagedaemon __P((struct proc *)); +static void start_update __P((struct proc *)); /* XXX return int so gcc -Werror won't complain */ int main __P((void *)); @@ -372,6 +373,20 @@ main(framep) cpu_set_kpc(pfind(2), start_pagedaemon); #endif + /* Create process 3 (the update daemon). */ + if (sys_fork(p, NULL, rval)) + panic("fork update"); +#ifdef cpu_set_init_frame /* XXX should go away */ + if (rval[1]) { + /* + * Now in process 3. + */ + start_update(curproc); + } +#else + cpu_set_kpc(pfind(3), start_update); +#endif + /* The scheduler is an infinite loop. */ scheduler(); /* NOTREACHED */ @@ -518,3 +533,18 @@ start_pagedaemon(p) vm_pageout(); /* NOTREACHED */ } + +static void +start_update(p) + struct proc *p; +{ + + /* + * Now in process 3. + */ + pageproc = p; + p->p_flag |= P_INMEM | P_SYSTEM; /* XXX */ + bcopy("update", curproc->p_comm, sizeof ("update")); + vn_update(); + /* NOTREACHED */ +} diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 698f645ead3..bc7ce981dc3 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_bio.c,v 1.5 1996/05/02 13:12:29 deraadt Exp $ */ +/* $OpenBSD: vfs_bio.c,v 1.6 1996/06/11 03:25:13 tholo Exp $ */ /* $NetBSD: vfs_bio.c,v 1.43 1996/04/22 01:38:59 christos Exp $ */ /*- @@ -59,6 +59,7 @@ #include <sys/malloc.h> #include <sys/resourcevar.h> #include <sys/conf.h> +#include <sys/kernel.h> #include <vm/vm.h> @@ -143,6 +144,7 @@ bufinit() register int i; int base, residual; + TAILQ_INIT(&bdirties); for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++) TAILQ_INIT(dp); bufhashtbl = hashinit(nbuf, M_CACHE, &bufhash); @@ -298,6 +300,12 @@ bwrite(bp) } wasdelayed = ISSET(bp->b_flags, B_DELWRI); CLR(bp->b_flags, (B_READ | B_DONE | B_ERROR | B_DELWRI)); + /* + * If this was a delayed write, remove it from the + * list of dirty blocks now + */ + if (wasdelayed) + TAILQ_REMOVE(&bdirties, bp, b_synclist); if (!sync) { /* @@ -368,18 +376,51 @@ void bdwrite(bp) struct buf *bp; { + int setit; /* * If the block hasn't been seen before: * (1) Mark it as having been seen, * (2) Charge for the write. * (3) Make sure it's on its vnode's correct block list, + * (4) If a buffer is rewritten, move it to end of dirty list */ + bp->b_synctime = time.tv_sec + 30; if (!ISSET(bp->b_flags, B_DELWRI)) { + /* + * Add the buffer to the list of dirty blocks. + * If it is the first entry on the list, schedule + * a timeout to flush it to disk + */ + TAILQ_INSERT_TAIL(&bdirties, bp, b_synclist); + if (bdirties.tqh_first == bp) + timeout((void (*)__P((void *)))wakeup, + &bdirties, 30 * hz); SET(bp->b_flags, B_DELWRI); curproc->p_stats->p_ru.ru_oublock++; /* XXX */ reassignbuf(bp, bp->b_vp); } + else { + /* + * The buffer has been rewritten. Move it to the + * end of the dirty block list, and if it was the + * first entry before being moved, reschedule the + * timeout + */ + if (bdirties.tqh_first == bp) { + untimeout((void (*)__P((void *)))wakeup, + &bdirties); + setit = 1; + } + else + setit = 0; + TAILQ_REMOVE(&bdirties, bp, b_synclist); + TAILQ_INSERT_TAIL(&bdirties, bp, b_synclist); + if (setit && bdirties.tqh_first != bp) + timeout((void (*)__P((void *)))wakeup, + &bdirties, + (bdirties.tqh_first->b_synctime - time.tv_sec) * hz); + } /* If this is a tape block, write the block now. */ if (bdevsw[major(bp->b_dev)].d_type == D_TAPE) { @@ -406,6 +447,142 @@ bawrite(bp) } /* + * Write out dirty buffers if they have been on the dirty + * list for more than 30 seconds; scan for such buffers + * once a second. + */ +void +vn_update() +{ + struct mount *mp, *nmp; + struct timespec ts; + struct vnode *vp; + struct buf *bp; + int async, s; + + /* + * In case any buffers got scheduled for write before the + * process got started (should never happen) + */ + untimeout((void (*)__P((void *)))wakeup, + &bdirties); + for (;;) { + s = splbio(); + /* + * Schedule a wakeup when the next buffer is to + * be flushed to disk. If no buffers are enqueued, + * a wakeup will be scheduled at the time a new + * buffer is enqueued + */ + if ((bp = bdirties.tqh_first) != NULL) + timeout((void (*)__P((void *)))wakeup, + &bdirties, (bp->b_synctime - time.tv_sec) * hz); + tsleep(&bdirties, PZERO - 1, "dirty", 0); + /* + * Walk the dirty block list, starting an asyncroneous + * write of any block that has timed out + */ + while ((bp = bdirties.tqh_first) != NULL && + bp->b_synctime <= time.tv_sec) { + /* + * If the block is currently busy (perhaps being + * written), move it to the end of the dirty list + * and go to the next block + */ + if (ISSET(bp->b_flags, B_BUSY)) { + TAILQ_REMOVE(&bdirties, bp, b_synclist); + TAILQ_INSERT_TAIL(&bdirties, bp, b_synclist); + bp->b_synctime = time.tv_sec + 30; + continue; + } + /* + * Remove the block from the per-vnode dirty + * list and mark it as busy + */ + bremfree(bp); + SET(bp->b_flags, B_BUSY); + splx(s); + /* + * Start an asyncroneous write of the buffer. + * Note that this will also remove the buffer + * from the dirty list + */ + bawrite(bp); + s = splbio(); + } + splx(s); + /* + * We also need to flush out modified vnodes + */ + for (mp = mountlist.cqh_last; + mp != (void *)&mountlist; + mp = nmp) { + /* + * Get the next pointer in case we hang of vfs_busy() + * while being unmounted + */ + nmp = mp->mnt_list.cqe_prev; + /* + * The lock check below is to avoid races with mount + * and unmount + */ + if ((mp->mnt_flag & (MNT_MLOCK | MNT_RDONLY | MNT_MPBUSY)) == 0 && + !vfs_busy(mp)) { + /* + * Turn off the file system async flag until + * we are done writing out vnodes + */ + async = mp->mnt_flag & MNT_ASYNC; + mp->mnt_flag &= ~MNT_ASYNC; + /* + * Walk the vnode list for the file system, + * writing each modified vnode out + */ +loop: + for (vp = mp->mnt_vnodelist.lh_first; + vp != NULL; + vp = vp->v_mntvnodes.le_next) { + /* + * If the vnode is no longer associated + * with the file system in question, skip + * it + */ + if (vp->v_mount != mp) + goto loop; + /* + * If the vnode is currently locked, + * ignore it + */ + if (VOP_ISLOCKED(vp)) + continue; + /* + * Lock the vnode, start a write and + * release the vnode + */ + if (vget(vp, 1)) + goto loop; + TIMEVAL_TO_TIMESPEC(&time, &ts); + VOP_UPDATE(vp, &ts, &ts, 0); + vput(vp); + } + /* + * Restore the file system async flag if it + * were previously set for this file system + */ + mp->mnt_flag |= async; + /* + * Get the next pointer again as the next + * file system might have been unmounted + * while we were flushing vnodes + */ + nmp = mp->mnt_list.cqe_prev; + vfs_unbusy(mp); + } + } + } +} + +/* * Release a buffer on to the free lists. * Described in Bach (p. 46). */ @@ -450,6 +627,8 @@ brelse(bp) */ if (bp->b_vp) brelvp(bp); + if (ISSET(bp->b_flags, B_DELWRI)) + TAILQ_REMOVE(&bdirties, bp, b_synclist); CLR(bp->b_flags, B_DELWRI); if (bp->b_bufsize <= 0) /* no data */ diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c index e0f8be723b1..ad792afff1f 100644 --- a/sys/kern/vfs_cluster.c +++ b/sys/kern/vfs_cluster.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_cluster.c,v 1.4 1996/05/02 13:12:33 deraadt Exp $ */ +/* $OpenBSD: vfs_cluster.c,v 1.5 1996/06/11 03:25:13 tholo Exp $ */ /* $NetBSD: vfs_cluster.c,v 1.12 1996/04/22 01:39:05 christos Exp $ */ /*- @@ -719,6 +719,8 @@ redo: bp->b_bufsize += size; tbp->b_bufsize -= size; + if (tbp->b_flags & B_DELWRI) + TAILQ_REMOVE(&bdirties, tbp, b_synclist); tbp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI); /* * We might as well AGE the buffer here; it's either empty, or |