This commit is contained in:
parent
04659b2a46
commit
7829692707
@ -1,5 +1,5 @@
|
||||
--- src/hddown.c
|
||||
+++ src/hddown.c 2007-06-06 15:42:04.799454093 +0200
|
||||
+++ src/hddown.c 2007-06-12 16:19:45.618059522 +0200
|
||||
@@ -5,6 +5,9 @@
|
||||
*/
|
||||
char *v_hddown = "@(#)hddown.c 1.02 22-Apr-2003 miquels@cistron.nl";
|
||||
@ -10,63 +10,96 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@@ -18,6 +21,198 @@ char *v_hddown = "@(#)hddown.c 1.02 22
|
||||
@@ -18,6 +21,315 @@ char *v_hddown = "@(#)hddown.c 1.02 22
|
||||
#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@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)
|
||||
+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;
|
||||
+ int fd, ret;
|
||||
+ size_t len;
|
||||
+ FILE *fp;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = snprintf(buf, sizeof(buf), SYS_BLK "/%s/removable", d->d_name);
|
||||
+ if ((ret >= sizeof(buf)) || (ret < 0))
|
||||
+ goto empty; /* error */
|
||||
+
|
||||
+ fd = open(buf, O_RDONLY|O_NOCTTY);
|
||||
+ if (fd < 0) {
|
||||
+ if (errno != ENOENT)
|
||||
+ fp = hdopen(SYS_BLK "/%s/removable", d->d_name);
|
||||
+ if ((long)fp <= 0) {
|
||||
+ if ((long)fp < 0)
|
||||
+ goto empty; /* error */
|
||||
+ continue; /* no entry `removable' */
|
||||
+ }
|
||||
+
|
||||
+ fp = fdopen(fd, "r");
|
||||
+ if (fp == (FILE*)0) {
|
||||
+ close(fd);
|
||||
+ goto empty; /* error */
|
||||
+ }
|
||||
+
|
||||
+ ret = getc(fp);
|
||||
+ fclose(fp);
|
||||
+
|
||||
+ if (ret != '0')
|
||||
+ continue; /* not a hard disk */
|
||||
+
|
||||
+ if (d->d_name[0] == 'h')
|
||||
+ fp = hdopen(SYS_BLK "/%s/size", d->d_name);
|
||||
+ if ((long)fp <= 0) {
|
||||
+ if ((long)fp < 0)
|
||||
+ goto empty; /* error */
|
||||
+ continue; /* no entry `size' */
|
||||
+ }
|
||||
+
|
||||
+ 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 (((size_t)atoll(buf) >= (1<<28)) && flush_cache_ext(d->d_name))
|
||||
+ (*flags) |= DISK_EXTFLUSH;
|
||||
+
|
||||
+ if (d->d_name[0] == 'h') {
|
||||
+ (*flags) |= DISK_IS_IDE;
|
||||
+ 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))
|
||||
@ -97,40 +130,26 @@
|
||||
+ if (errno != ENOENT)
|
||||
+ goto empty; /* error */
|
||||
+
|
||||
+
|
||||
+ ret = snprintf(buf, sizeof(buf), SYS_BLK "/%s/device/vendor", d->d_name);
|
||||
+ if ((ret >= sizeof(buf)) || (ret < 0))
|
||||
+ goto empty; /* error */
|
||||
+
|
||||
+ fd = open(buf, O_RDONLY|O_NOCTTY);
|
||||
+ if (fd < 0) {
|
||||
+ if (errno != ENOENT)
|
||||
+ 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' */
|
||||
+ }
|
||||
+
|
||||
+ fp = fdopen(fd, "r");
|
||||
+ if (fp == (FILE*)0) {
|
||||
+ close(fd);
|
||||
+ goto empty; /* error */
|
||||
+ }
|
||||
+
|
||||
+ ptr = fgets(buf, sizeof(buf), fp);
|
||||
+ fclose(fp);
|
||||
+ if (ptr == (char*)0)
|
||||
+ continue; /* should not happen */
|
||||
+
|
||||
+ if ((len = strlen(buf)) == 0)
|
||||
+ ptr = strstrip(buf);
|
||||
+ if (*ptr == '\0')
|
||||
+ continue; /* should not happen */
|
||||
+
|
||||
+ ptr = &buf[0] + len - 1;
|
||||
+ while ((ptr != &buf[0]) && ISSPACE(*ptr))
|
||||
+ ptr--;
|
||||
+ *(ptr + 1) = '\0'; /* remove trailing white spaces */
|
||||
+
|
||||
+ if (strncmp(buf, "ATA", sizeof(buf)))
|
||||
+ continue; /* no SATA but a real SCSI disk */
|
||||
+
|
||||
+ (*flags) |= (DISK_IS_IDE|DISK_IS_SATA);
|
||||
+ break; /* new SATA disk to shutdown, out here */
|
||||
+ }
|
||||
+ }
|
||||
@ -145,7 +164,7 @@
|
||||
+ * Put an disk in standby mode.
|
||||
+ * Code stolen from hdparm.c
|
||||
+ */
|
||||
+static int do_standby_idedisk(char *device)
|
||||
+static int do_standby_idedisk(char *device, unsigned int flags)
|
||||
+{
|
||||
+#ifndef WIN_STANDBYNOW1
|
||||
+#define WIN_STANDBYNOW1 0xE0
|
||||
@ -173,9 +192,14 @@
|
||||
+ if ((fd = open(buf, O_RDWR)) < 0)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (ioctl(fd, HDIO_DRIVE_CMD, &flush1)) {
|
||||
+ 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) &&
|
||||
@ -194,22 +218,115 @@
|
||||
+ */
|
||||
+int hddown(void)
|
||||
+{
|
||||
+ DIR *blk;
|
||||
+ unsigned int flags;
|
||||
+ char *disk;
|
||||
+ DIR *blk;
|
||||
+
|
||||
+ if ((blk = opendir(SYS_BLK)) == (DIR*)0)
|
||||
+ return -1;
|
||||
+
|
||||
+ while ((disk = list_disks(blk)))
|
||||
+ do_standby_idedisk(disk);
|
||||
+ 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];
|
||||
+ int fd = -1, ret = 0;
|
||||
+
|
||||
+ ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
|
||||
+ if ((ret >= sizeof(buf)) || (ret < 0))
|
||||
+ return -1;
|
||||
+
|
||||
+ 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"
|
||||
@@ -104,7 +299,7 @@ int hddown(void)
|
||||
@@ -104,7 +416,7 @@ int hddown(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,3 +1,9 @@
|
||||
-------------------------------------------------------------------
|
||||
Tue Jun 12 11:42:43 CEST 2007 - werner@suse.de
|
||||
|
||||
- bug #229210: check for the FLUSH CACHE EXT capability for large
|
||||
disks and use this capability if available.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Jun 6 15:56:46 CEST 2007 - werner@suse.de
|
||||
|
||||
|
@ -22,7 +22,7 @@ Group: System/Base
|
||||
PreReq: coreutils
|
||||
Autoreqprov: on
|
||||
Version: 2.86
|
||||
Release: 76
|
||||
Release: 81
|
||||
Summary: SysV-Style init
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
Source: sysvinit-2.86.tar.bz2
|
||||
@ -282,6 +282,9 @@ rm -rf ${RPM_BUILD_ROOT}
|
||||
%doc %{_mandir}/man8/startpar.8.gz
|
||||
|
||||
%changelog
|
||||
* Tue Jun 12 2007 - werner@suse.de
|
||||
- bug #229210: check for the FLUSH CACHE EXT capability for large
|
||||
disks and use this capability if available.
|
||||
* Wed Jun 06 2007 - werner@suse.de
|
||||
- For bug #229210: skip real SCSI disks, also flush disk cache for
|
||||
SATA and ATA disks.
|
||||
|
Loading…
Reference in New Issue
Block a user