[Pkg-sysvinit-devel] [SRM] sysvinit update for etchnhalf

dann frazier dannf at debian.org
Thu May 15 00:13:28 UTC 2008


The sysvinit team (or at least the one member who had time to reply)
has given me their nod to go ahead and request this update for
etchnhalf.

The issue this resolves and the fix is best described here:
 http://linux-ata.org/shutdown.html

This patch has been in sysvinit since 2.86.ds1-40, first entering
unstable in 2.86.ds1-47 on 2007.12.31 and into testing on 2008.01.11
with no known regressions.

Testing of this update has been performed on both etch and etchnhalf
kernels, on both an IDE system and one that uses libata:
 http://teams.debian.net/lurker/message/20080430.232539.ef917353.en.html

May I upload to p-u?

diff -u sysvinit-2.86.ds1/debian/patches/00list sysvinit-2.86.ds1/debian/patches/00list
--- sysvinit-2.86.ds1/debian/patches/00list
+++ sysvinit-2.86.ds1/debian/patches/00list
@@ -35,0 +36 @@
+92_sata-hddown
diff -u sysvinit-2.86.ds1/debian/changelog sysvinit-2.86.ds1/debian/changelog
--- sysvinit-2.86.ds1/debian/changelog
+++ sysvinit-2.86.ds1/debian/changelog
@@ -1,3 +1,11 @@
+sysvinit (2.86.ds1-38+etchnhalf.1) UNRELEASED; urgency=high
+
+  * Include patch from Werner Fink at SuSe to handle each disk individually
+    and automatically instead of guessing in the init.d script how
+    to handle them collectively (Closes: #426224).
+
+ -- dann frazier <dannf at debian.org>  Wed, 09 Apr 2008 16:18:20 -0600
+
 sysvinit (2.86.ds1-38) unstable; urgency=medium
 
   * Medium urgency as it solve an RC bug in etch.
only in patch2:
unchanged:
--- sysvinit-2.86.ds1.orig/debian/patches/92_sata-hddown.dpatch
+++ sysvinit-2.86.ds1/debian/patches/92_sata-hddown.dpatch
@@ -0,0 +1,357 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 92_sata-hddown.dpatch by Werner Fink and SuSe
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Make sure to shut down SATA disks properly, and handle each
+## DP: disk individually.  See also http://linux-ata.org/shutdown.html
+
+ at DPATCH@
+diff -urNad trunk~/src/hddown.c trunk/src/hddown.c
+--- trunk~/src/hddown.c	2008-03-26 09:32:51.000000000 +0100
++++ trunk/src/hddown.c	2008-03-26 09:32:51.000000000 +0100
+@@ -5,6 +5,9 @@
+  */
+ char *v_hddown = "@(#)hddown.c  1.02  22-Apr-2003  miquels at cistron.nl";
+ 
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE
++#endif
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+@@ -18,6 +21,326 @@
+ #include <sys/ioctl.h>
+ #include <linux/hdreg.h>
+ 
++#define USE_SYSFS
++#ifdef USE_SYSFS
++/*
++ * sysfs part	Find all disks on the system, list out IDE and unmanaged
++ *		SATA disks, flush the cache of those and shut them down.
++ * Author:	Werner Fink <werner at suse.de>, 2007/06/12
++ *
++ */
++#include <limits.h>
++#include <errno.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#ifdef WORDS_BIGENDIAN
++#include <byteswap.h>
++#endif
++
++#define SYS_BLK		"/sys/block"
++#define SYS_CLASS	"/sys/class/scsi_disk"
++#define DEV_BASE	"/dev"
++#define ISSPACE(c)	(((c)==' ')||((c)=='\n')||((c)=='\t')||((c)=='\v')||((c)=='\r')||((c)=='\f'))
++
++/* Used in flush_cache_ext(), compare with <linux/hdreg.h> */
++#define IDBYTES		512
++#define MASK_EXT	0xE000		/* Bit 15 shall be zero, bit 14 shall be one, bit 13 flush cache ext */
++#define TEST_EXT	0x6000
++
++/* Maybe set in list_disks() and used in do_standby_idedisk() */
++#define DISK_IS_IDE	0x00000001
++#define DISK_IS_SATA	0x00000002
++#define DISK_EXTFLUSH	0x00000004
++
++static char *strstrip(char *str);
++static FILE *hdopen(const char* const format, const char* const name);
++static int flush_cache_ext(const char *device);
++
++/*
++ *	Find all disks through /sys/block.
++ */
++static char *list_disks(DIR* blk, unsigned int* flags)
++{
++	struct dirent *d;
++
++	while ((d = readdir(blk))) {
++		*flags = 0;
++		if (d->d_name[1] == 'd' && (d->d_name[0] == 'h' || d->d_name[0] == 's')) {
++			char buf[NAME_MAX+1], lnk[NAME_MAX+1], *ptr;
++			struct stat st;
++			FILE *fp;
++			int ret;
++
++			fp = hdopen(SYS_BLK "/%s/removable", d->d_name);
++			if ((long)fp <= 0) {
++				if ((long)fp < 0)
++					goto empty;	/* error */
++				continue;		/* no entry `removable' */
++			}
++
++			ret = getc(fp);
++			fclose(fp);
++
++			if (ret != '0')
++				continue;		/* not a hard disk */
++
++			if (d->d_name[0] == 'h') {
++				(*flags) |= DISK_IS_IDE;
++				if ((ret = flush_cache_ext(d->d_name))) {
++					if (ret < 0)
++						goto empty;
++					(*flags) |= DISK_EXTFLUSH;
++				}
++				break;			/* old IDE disk not managed by kernel, out here */
++			}
++
++			ret = snprintf(buf, sizeof(buf), SYS_BLK "/%s/device", d->d_name);
++			if ((ret >= sizeof(buf)) || (ret < 0))
++				goto empty;		/* error */
++
++			ret = readlink(buf, lnk, sizeof(lnk));
++			if (ret >= sizeof(lnk))
++				goto empty;		/* error */
++			if (ret < 0) {
++				if (errno != ENOENT)
++					goto empty;	/* error */
++				continue;		/* no entry `device' */
++			}
++			lnk[ret] = '\0';
++
++			ptr = basename(lnk);
++			if (!ptr || !*ptr)
++				continue;		/* should not happen */
++
++			ret = snprintf(buf, sizeof(buf), SYS_CLASS "/%s/manage_start_stop", ptr);
++			if ((ret >= sizeof(buf)) || (ret < 0))
++				goto empty;		/* error */
++
++			ret = stat(buf, &st);
++			if (ret == 0)
++				continue;		/* disk found but managed by kernel */
++
++			if (errno != ENOENT)
++				goto empty;		/* error */
++
++			fp = hdopen(SYS_BLK "/%s/device/vendor", d->d_name);
++			if ((long)fp <= 0) {
++				if ((long)fp < 0)
++					goto empty;	/* error */
++				continue;		/* no entry `device/vendor' */
++			}
++
++			ptr = fgets(buf, sizeof(buf), fp);
++			fclose(fp);
++			if (ptr == (char*)0)
++				continue;		/* should not happen */
++
++			ptr = strstrip(buf);
++			if (*ptr == '\0')
++				continue;		/* should not happen */
++
++			if (strncmp(buf, "ATA", sizeof(buf)))
++				continue;		/* no SATA but a real SCSI disk */
++
++			(*flags) |= (DISK_IS_IDE|DISK_IS_SATA);
++			if ((ret = flush_cache_ext(d->d_name))) {
++				if (ret < 0)
++					goto empty;
++				(*flags) |= DISK_EXTFLUSH;
++			}
++			break;				/* new SATA disk to shutdown, out here */
++		}
++	}
++	if (d == (struct dirent*)0)
++		goto empty;
++	return d->d_name;
++empty:
++	return (char*)0;
++}
++
++/*
++ *	Put an disk in standby mode.
++ *	Code stolen from hdparm.c
++ */
++static int do_standby_idedisk(char *device, unsigned int flags)
++{
++#ifndef WIN_STANDBYNOW1
++#define WIN_STANDBYNOW1		0xE0
++#endif
++#ifndef WIN_STANDBYNOW2
++#define WIN_STANDBYNOW2		0x94
++#endif
++#ifndef WIN_FLUSH_CACHE_EXT
++#define WIN_FLUSH_CACHE_EXT	0xEA
++#endif
++#ifndef WIN_FLUSH_CACHE
++#define WIN_FLUSH_CACHE		0xE7
++#endif
++	unsigned char flush1[4] = {WIN_FLUSH_CACHE_EXT,0,0,0};
++	unsigned char flush2[4] = {WIN_FLUSH_CACHE,0,0,0};
++	unsigned char stdby1[4] = {WIN_STANDBYNOW1,0,0,0};
++	unsigned char stdby2[4] = {WIN_STANDBYNOW2,0,0,0};
++	char buf[NAME_MAX+1];
++	int fd, ret;
++
++	ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
++	if ((ret >= sizeof(buf)) || (ret < 0))
++		return -1;
++
++	if ((fd = open(buf, O_RDWR)) < 0)
++		return -1;
++
++	switch (flags & DISK_EXTFLUSH) {
++	case DISK_EXTFLUSH:
++		if (ioctl(fd, HDIO_DRIVE_CMD, &flush1) == 0)
++			break;
++		/* Extend flush rejected, try standard flush */
++	default:
++		ioctl(fd, HDIO_DRIVE_CMD, &flush2);
++		break;
++	}
++
++	ret = ioctl(fd, HDIO_DRIVE_CMD, &stdby1) &&
++	      ioctl(fd, HDIO_DRIVE_CMD, &stdby2);
++	close(fd);
++
++	if (ret)
++		return -1;
++	return 0;
++}
++
++/*
++ *	List all disks and put them in standby mode.
++ *	This has the side-effect of flushing the writecache,
++ *	which is exactly what we want on poweroff.
++ */
++int hddown(void)
++{
++	unsigned int flags;
++	char *disk;
++	DIR *blk;
++
++	if ((blk = opendir(SYS_BLK)) == (DIR*)0)
++		return -1;
++
++	while ((disk = list_disks(blk, &flags)))
++		do_standby_idedisk(disk, flags);
++
++	return closedir(blk);
++}
++
++/*
++ * Strip off trailing white spaces
++ */
++static char *strstrip(char *str)
++{
++	const size_t len = strlen(str);
++	if (len) {
++		char* end = str + len - 1;
++		while ((end != str) && ISSPACE(*end))
++			end--;
++		*(end + 1) = '\0';			/* remove trailing white spaces */
++	}
++	return str;
++}
++
++/*
++ * Open a sysfs file without getting a controlling tty
++ * and return FILE* pointer.
++ */
++static FILE *hdopen(const char* const format, const char* const name)
++{
++	char buf[NAME_MAX+1];
++	FILE *fp = (FILE*)-1;
++	int fd, ret;
++	
++	ret = snprintf(buf, sizeof(buf), format, name);
++	if ((ret >= sizeof(buf)) || (ret < 0))
++		goto error;		/* error */
++
++	fd = open(buf, O_RDONLY|O_NOCTTY);
++	if (fd < 0) {
++		if (errno != ENOENT)
++			goto error;	/* error */
++		fp = (FILE*)0;
++		goto error;		/* no entry `removable' */
++	}
++
++	fp = fdopen(fd, "r");
++	if (fp == (FILE*)0)
++		close(fd);		/* should not happen */
++error:
++	return fp;
++}
++
++/*
++ * Check IDE/(S)ATA hard disk identity for
++ * the FLUSH CACHE EXT bit set.
++ */
++static int flush_cache_ext(const char *device)
++{
++#ifndef WIN_IDENTIFY
++#define WIN_IDENTIFY		0xEC
++#endif
++	unsigned char args[4+IDBYTES];
++	unsigned short *id = (unsigned short*)(&args[4]);
++	char buf[NAME_MAX+1], *ptr;
++	int fd = -1, ret = 0;
++	FILE *fp;
++
++	fp = hdopen(SYS_BLK "/%s/size", device);
++	if ((long)fp <= 0) {
++		if ((long)fp < 0)
++			return -1;	/* error */
++		goto out;		/* no entry `size' */
++	}
++
++	ptr = fgets(buf, sizeof(buf), fp);
++	fclose(fp);
++	if (ptr == (char*)0)
++		goto out;		/* should not happen */
++
++	ptr = strstrip(buf);
++	if (*ptr == '\0')
++		goto out;		/* should not happen */
++
++	if ((size_t)atoll(buf) < (1<<28))
++		goto out;		/* small disk */
++		
++	ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
++	if ((ret >= sizeof(buf)) || (ret < 0))
++		return -1;		/* error */
++
++	if ((fd = open(buf, O_RDONLY|O_NONBLOCK)) < 0)
++		goto out;
++
++	memset(&args[0], 0, sizeof(args));
++	args[0] = WIN_IDENTIFY;
++	args[3] = 1;
++	if (ioctl(fd, HDIO_DRIVE_CMD, &args))
++		goto out;
++#ifdef WORDS_BIGENDIAN
++# if 0
++	{
++		const unsigned short *end = id + IDBYTES/2;
++		const unsigned short *from = id;
++		unsigned short *to = id;
++
++		while (from < end)
++			*to++ = bswap_16(*from++);
++	}
++# else
++	id[83] = bswap_16(id[83]);
++# endif
++#endif
++	if ((id[83] & MASK_EXT) == TEST_EXT)
++		ret = 1;
++out:
++	if (fd >= 0)
++		close(fd);
++	return ret;
++}
++#else /* ! USE_SYSFS */
+ #define MAX_DISKS	64
+ #define PROC_IDE	"/proc/ide"
+ #define DEV_BASE	"/dev"
+@@ -154,7 +477,7 @@
+ 
+ 	return (result1 ? result1 : result2);
+ }
+-
++#endif /* ! USE_SYSFS */
+ #else /* __linux__ */
+ 
+ int hddown(void)






More information about the Pkg-sysvinit-devel mailing list