summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorThorsten Lockert <tholo@cvs.openbsd.org>1996-06-11 03:25:18 +0000
committerThorsten Lockert <tholo@cvs.openbsd.org>1996-06-11 03:25:18 +0000
commit8db8a379747ee056c46b16e020c29c8a5829e357 (patch)
tree81e2825ca363e3b400b85481997e69efb5f8e1c6 /sys
parent53c5905b071647ba7a61fb1493f9458f0cc258d9 (diff)
Kernel-implementation of update(8) my me
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/init_main.c32
-rw-r--r--sys/kern/vfs_bio.c181
-rw-r--r--sys/kern/vfs_cluster.c4
-rw-r--r--sys/sys/buf.h5
-rw-r--r--sys/sys/vnode.h3
-rw-r--r--sys/ufs/mfs/mfsnode.h4
6 files changed, 222 insertions, 7 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
diff --git a/sys/sys/buf.h b/sys/sys/buf.h
index ef98b8853c8..888eca306c6 100644
--- a/sys/sys/buf.h
+++ b/sys/sys/buf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: buf.h,v 1.4 1996/04/18 21:40:46 niklas Exp $ */
+/* $OpenBSD: buf.h,v 1.5 1996/06/11 03:25:14 tholo Exp $ */
/* $NetBSD: buf.h,v 1.24 1996/02/18 11:55:45 fvdl Exp $ */
/*
@@ -54,6 +54,8 @@ struct buf {
LIST_ENTRY(buf) b_hash; /* Hash chain. */
LIST_ENTRY(buf) b_vnbufs; /* Buffer's associated vnode. */
TAILQ_ENTRY(buf) b_freelist; /* Free list position if not active. */
+ TAILQ_ENTRY(buf) b_synclist; /* List of diry buffers to be written out */
+ long b_synctime; /* Time this buffer should be flushed */
struct buf *b_actf, **b_actb; /* Device driver queue when active. */
struct proc *b_proc; /* Associated proc; NULL if kernel. */
volatile long b_flags; /* B_* flags. */
@@ -158,6 +160,7 @@ struct buf *swbuf; /* Swap I/O buffer headers. */
int nswbuf; /* Number of swap I/O buffer headers. */
struct buf bswlist; /* Head of swap I/O buffer headers free list. */
struct buf *bclnlist; /* Head of cleaned page list. */
+TAILQ_HEAD(, buf) bdirties; /* Dirty buffer list for update daemon */
__BEGIN_DECLS
void allocbuf __P((struct buf *, int));
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index bd7705de932..1ec111930ab 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vnode.h,v 1.4 1996/04/18 21:41:19 niklas Exp $ */
+/* $OpenBSD: vnode.h,v 1.5 1996/06/11 03:25:15 tholo Exp $ */
/* $NetBSD: vnode.h,v 1.38 1996/02/29 20:59:05 cgd Exp $ */
/*
@@ -381,6 +381,7 @@ int vinvalbuf __P((struct vnode *vp, int save, struct ucred *cred,
struct proc *p, int slpflag, int slptimeo));
void vprint __P((char *label, struct vnode *vp));
int vn_bwrite __P((void *ap));
+void vn_update __P((void));
int vn_close __P((struct vnode *vp,
int flags, struct ucred *cred, struct proc *p));
int vn_closefile __P((struct file *fp, struct proc *p));
diff --git a/sys/ufs/mfs/mfsnode.h b/sys/ufs/mfs/mfsnode.h
index 2dddd23056f..d37f7ba4e68 100644
--- a/sys/ufs/mfs/mfsnode.h
+++ b/sys/ufs/mfs/mfsnode.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mfsnode.h,v 1.2 1996/02/27 07:15:49 niklas Exp $ */
+/* $OpenBSD: mfsnode.h,v 1.3 1996/06/11 03:25:15 tholo Exp $ */
/* $NetBSD: mfsnode.h,v 1.3 1996/02/09 22:31:31 christos Exp $ */
/*
@@ -85,5 +85,5 @@ struct mfsnode {
#define mfs_valloc mfs_badop
#define mfs_vfree mfs_badop
#define mfs_truncate mfs_badop
-#define mfs_update mfs_badop
+#define mfs_update nullop
#define mfs_bwrite vn_bwrite