diff -u -r update.old/update.8 update/update.8 --- update.old/update.8 Fri Jul 26 22:22:31 1996 +++ update/update.8 Mon Jun 8 18:10:22 1998 @@ -1,6 +1,7 @@ .\" Copyright (c) 1986 Torsten Poulin +.\" Copyright (c) 1998 Jan Gyselinck (HD spindown support) .\" May be distributed under the GNU General Public License -.TH UPDATE 8 "July 26, 1996" "Linux 2.0" "Linux Programmer's Manual" +.TH UPDATE 8 "June 08, 1998" "Linux 2.0" "Linux Programmer's Manual" .SH NAME update \- periodically flush filesystem buffers. .SH SYNOPSIS @@ -12,7 +13,11 @@ two modes of operation. By default it will wake up every 5 seconds and flush some dirty buffers. If this is not possible, it will automatically fall back to the traditional behavior of waking up every -30 seconds to call +30 seconds to call. It will also delay the flushing and syncing when no +harddisk activity has occured, so that a harddisk will effectively spindown. +It can handle more than one harddisk, but +.B update +will only stop writing, when there was no activity on any of those drives .BR sync (2). .PP The following options are accepted by @@ -32,13 +37,37 @@ Unless using sync, wake up and flush some buffers every .I secs seconds. The default is every 5 seconds. +.TP +.BI \-y " secs" +If using sync, wake up and call it every +.I secs +seconds, when there is no harddisk activity detected. The default +is every 3600 seconds (1 hour). +.TP +.BI \-l " secs" +Unless using sync, wake up and flush some buffers every +.I secs +seconds, when there is no harddisk activity detected. The default +is every 3600 seconds (1 hour). +.TP +.BI \-d " disks" +Number of harddisks to monitor for activity. The default is 1. +If the number is 0, then no activity-checking will occur. .PP .B update should be started as early as possible during the boot process. If it is invoked by a non\-privileged user, it calls sync and exits. +.SH "BUGS" +As it is written right now, it will check for changing numbers in /prac/stat +(the "disk"-line), so if your harddisk's activity is not shown there, +.B update +won't detect any activity. .SH "SEE ALSO" .BR init (8), .BR sync (2), .BR sync (8) .SH AUTHOR -Torsten Poulin (torsten@diku.dk) +.nf +Torsten Poulin +Jan Gyselinck (HD spindown support) +.fi diff -u -r update.old/update.c update/update.c --- update.old/update.c Thu Feb 13 18:33:36 1997 +++ update/update.c Sat Jun 6 21:15:05 1998 @@ -3,6 +3,13 @@ * Update Daemon for Linux (and possibly other Unixen). * Copyright (c) 1996, 1997 Torsten Poulin. * + * April the 11th, 1998 HD-spindown support by Jan Gyselinck (lector@dds.nl) + * last modified on June the 6th + * Procedure get_irq hacked out of procps-1.2.5 + * (that version was maintained by Michael K. Johnson ) + * and modified update to check whether harddisk activity occured, and whether + * it should do normal flushing or delayed flushing + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -29,6 +36,40 @@ #include #include +#include +#include +#include +#include + +#define BAD_OPEN_MESSAGE \ +"Error: /proc must be mounted\n" \ +" To mount /proc at boot you need an /etc/fstab line like:\n" \ +" /proc /proc proc defaults\n" \ +" In the meantime, mount /proc /proc -t proc\n" + +#define STAT_FILE "/proc/stat" + +/* This macro opens FILE only if necessary and seeks to 0 so that successive + calls to the functions are more efficient. It also reads the current + contents of the file into the global buf. +*/ +#define FILE_TO_BUF(FILE) { \ + static int n, fd = -1; \ + if (fd == -1 && (fd = open(FILE, O_RDONLY)) == -1) { \ + fprintf(stderr, BAD_OPEN_MESSAGE); \ + close(fd); \ + return 0; \ + } \ + lseek(fd, 0L, SEEK_SET); \ + if ((n = read(fd, buf, sizeof buf - 1)) < 0) { \ + perror(FILE); \ + close(fd); \ + fd = -1; \ + return 0; \ + } \ + buf[n] = '\0'; \ +} + /* * If NO_BDFLUSH is defined, make this a traditional update * daemon that calls sync(). This is the default for systems @@ -38,20 +79,20 @@ #ifdef __linux__ # include # if defined(__GLIBC__) && __GLIBC__ >= 2 -# include +# include # else - _syscall2(int, bdflush, int, func, int, data); + _syscall2(int, bdflush, int, func, int, data); # endif #else # ifndef NO_BDFLUSH -# define NO_BDFLUSH +# define NO_BDFLUSH # endif #endif #ifdef NO_BDFLUSH -# define ARGS "s:" +# define ARGS "s:y:d:" #else -# define ARGS "Ss:f:" +# define ARGS "Ss:y:f:l:d:" # include #endif @@ -59,27 +100,73 @@ * OPEN_MAX is POSIX.1 */ #ifndef OPEN_MAX -# define OPEN_MAX 256 /* anybody's guess */ +# define OPEN_MAX 256 /* anybody's guess */ #endif static const char RCS[] = "@(#) $Revision: 1.3 $"; unsigned int sync_duration = 30; unsigned int flush_duration = 5; +unsigned int down_sync_dur = 3600; +unsigned int down_flush_dur = 3600; +unsigned int disks = 1; +unsigned int check_duration; +unsigned long act_mark,act_check; +time_t time_mark; +static char buf[1024]; + int use_sync = 0; void usage(char *name) { fprintf(stderr, #ifdef NO_BDFLUSH - "Usage: %s [-s secs]\n", + "Usage: %s [-s secs] [-y secs] [-d disk-count]\n", #else - "Usage: %s [-S] [-s secs] [-f secs]\n", + "Usage: %s [-S] [-s secs] [-f secs] [-y secs] [-l secs] [-d disk-count]\n", #endif - name); + name); exit (1); } +/* Read the values behind "disk" in /proc/stat, add the 'disks' numbers + together, and report that as the disk activity */ + +int read_activity(unsigned long *countr) { + char *p; + char fieldbuf[60]; /* bigger than any line */ + int k; + unsigned long countr2; + + FILE_TO_BUF(STAT_FILE) + p = buf; + while(*p) { + sscanf(p,"%59s%n",fieldbuf,&k); + if(!strcmp(fieldbuf,"disk")) { + p+=k; + if(disks!=1) { + sscanf(p,"%li%n",&countr2,&k); + p+=k; + if(disks!=2) { + sscanf(p,"%li%n",countr,&k); + countr2+=*countr; + p+=k; + if(disks!=3) { + sscanf(p,"%li%n",countr,&k); + countr2+=*countr; + p+=k; + } + } + } + sscanf(p,"%li",countr); + if(disks!=1) *countr=*countr+countr2; + break; + } else + while(*p++ != '\n'); /* ignore lines we don't understand */ + } + return 0; +} + /* * The update() function never returns. * If bdflush() fails, it reverts to sync() instead. @@ -88,24 +175,63 @@ void update(void) { - for (;;) { #ifndef NO_BDFLUSH - if (use_sync) { + if (bdflush(1, 0) < 0) { + use_sync = 1; + openlog("update", LOG_CONS, LOG_DAEMON); + syslog(LOG_INFO, "Switching to sync(2) instead of bdflush(2)"); + closelog(); + } #endif - sleep(sync_duration); - sync(); + + read_activity(&act_mark); /* initial disk-activity count */ + time(&time_mark); /* mark when we messured disk-activity */ #ifndef NO_BDFLUSH - } else { - sleep(flush_duration); - if (bdflush(1, 0) < 0) { - use_sync = 1; - openlog("update", LOG_CONS, LOG_DAEMON); - syslog(LOG_INFO, "Switching to sync(2) instead of bdflush(2)"); - closelog(); - } - } + if (use_sync) { #endif + if (disks!=0) { /* if disks=0, don't check act. */ + check_duration=sync_duration*10; /* sleeptime if no act. occured */ + for (;;) { + sleep(sync_duration); + read_activity(&act_check); /* again measure disk-activity */ + while (act_mark == act_check) { /* no act? keep waiting ... */ + sleep(check_duration); + if ((time(0) - time_mark) > down_sync_dur) + break; /* time-out, so we'll sync */ + read_activity(&act_check); + } + read_activity(&act_mark); /* read count and mark time */ + time(&time_mark); + sync(); + } + } else + for (;;) { /* just sync 'n sleep */ + sleep(sync_duration); + sync(); + } +#ifndef NO_BDFLUSH + } else { /* same structures here, but we flush instead */ + if (disks!=0) { + check_duration=flush_duration*10; + for (;;) { + sleep(flush_duration); + read_activity(&act_check); + while (act_mark == act_check) { + sleep(check_duration); + if ((time(0) - time_mark) > down_flush_dur) break; + read_activity(&act_check); + } + read_activity(&act_mark); + time(&time_mark); + bdflush(1,0); + } + } else + for (;;) { + sleep(flush_duration); + bdflush(1,0); + } } +#endif } int @@ -115,20 +241,28 @@ while ((c = getopt(argc, argv, ARGS)) != -1) switch (c) { - case 'S': use_sync = 1; break; - case 's': sync_duration = atoi(optarg); break; - case 'f': flush_duration = atoi(optarg); break; - case '?': usage(argv[0]); - default: abort(); + case 'S': use_sync = 1; break; + case 's': sync_duration = atoi(optarg); break; + case 'f': flush_duration = atoi(optarg); break; + case 'y': down_sync_dur = atoi(optarg); break; + case 'l': down_flush_dur = atoi(optarg); break; + case 'd': disks = atoi(optarg); break; + case '?': usage(argv[0]); + default: abort(); } - if (sync_duration == 0 || flush_duration == 0) { + if (sync_duration == 0 || flush_duration == 0 || down_sync_dur == 0 || down_flush_dur == 0 ) { fprintf(stderr, "%s: argument must be positive integer.\n", argv[0]); exit(1); } + if (disks < 0 || disks > 4) { + fprintf(stderr, "%s: argument must be 0, 1, 2, 3 or 4.\n", argv[0]); + exit(1); + } + if (optind < argc) - usage(argv[0]); + usage(argv[0]); /* * Prevent people from launching more update daemons. @@ -146,8 +280,7 @@ signal(SIGTERM, SIG_IGN); signal(SIGINT, SIG_IGN); - if (fork() > 0) - exit(0); + if (fork() > 0) exit(0); /* * Become session leader (get rid of controlling terminal). @@ -159,12 +292,9 @@ */ chdir("/"); - for (f = 0; f < OPEN_MAX; f++) - close(f); + for (f = 0; f < OPEN_MAX; f++) close(f); update(); return 0; } - - diff -u -r update.old/update.lsm update/update.lsm --- update.old/update.lsm Fri Jul 26 22:22:31 1996 +++ update/update.lsm Tue Jun 9 01:05:21 1998 @@ -1,15 +1,15 @@ Begin3 -Title: Update - an update daemon for Linux 2.0 or newer. -Version: 1.1 -Entered-date: 26JUL96 -Description: The update daemon periodically flushes filesystem - buffers. This version does not spawn a bdflush - daemon, as this is now done by the kernel (kflushd). -Keywords: update daemon Linux source -Author: torsten@diku.dk (Torsten Poulin) -Maintained-by: torsten@diku.dk (Torsten Poulin) +Title: Update-spindown-patch +Version: 1.3-spindown +Entered-date: 09JULY98 +Description: This patch enables HD's to effectively spin down + by delaying the flushing. (it checks int 14, + that is your first HD controller) +Keywords: update daemon notebook Linux source +Author: lector@dds.nl (Jan Gyselinck) +Maintained-by: lector@dds.nl (Jan Gyselinck) Primary-site: sunsite.unc.edu /pub/Linux/system/Daemons - updated-1.1.tar.gz - updated-1.1.lsm + 4k updated-1.3-spindown-patch.gz + 1k updated-1.3-spindown-patch.lsm Copying-policy: GPL End