Artur Szymiec | 4 Nov 2007 12:47
Picon

Debian Sysvinit hdd down patch for libata


Gretings all,

please find in attachment a modified version of hdd.c
and also 67_init_hddown.dpatch which makes Debian halt
command comply with http://linux-ata.org/shutdown.html.
I've tested this patch on my system with 2 hdd's - one SATA and one PATA.
Please let me know it this patch is going to be included in next release.

Best regards
Artur Szymiec

--
--------------------------------------------------------------------------
Registered User No 397465
Linux Debian 2.6.21-2-k7 i686 AMD Athlon(tm) XP 2800+
Conquer your Desktop! http://www.spreadkde.org/try_kde
Reclaim Your Inbox!   http://www.mozilla.org/products/thunderbird/
--------------------------------------------------------------------------
Attachment (hddown.c): text/x-csrc, 4066 bytes
#! /bin/sh /usr/share/dpatch/dpatch-run
# 67_init_hddown.dpatch by Sebastian Reichelt
#
# Make sure SATA disks are powered down as well as IDE disks.  This
# patch could use some more work to make it more dynamic when
# detecting SATA/SCSI disks.  Closes: #348172

 <at> DPATCH <at> 
--- sysvinit-2.86.ds1/src/hddown.c	2004-06-09 14:47:45.000000000 +0200
+++ sysvinit-2.86.ds1-new/src/hddown.c	2007-11-04 12:12:38.000000000 +0100
 <at>  <at>  -25,18 +25,17  <at>  <at> 
 /*
  *	Find all IDE disks through /proc.
 */
-static int find_idedisks(char **dev, int maxdev)
+static int find_idedisks(const char **dev, int maxdev, int *count)
{
 	DIR *dd;
 	FILE *fp;
 	struct dirent *d;
 	char buf[256];
-	int i = 0;

 	if ((dd = opendir(PROC_IDE)) == NULL)
 		return -1;

-	while ((d = readdir(dd)) != NULL) {
+	while (*count < maxdev && (d = readdir(dd)) != NULL) {
 		if (strncmp(d->d_name, "hd", 2) != 0)
 			continue;
 		buf[0] = 0;
 <at>  <at>  -50,21 +49,81  <at>  <at> 
}
 		fclose(fp);
 		snprintf(buf, sizeof(buf), DEV_BASE "/%s", d->d_name);
-		dev[i++] = strdup(buf);
-		if (i >= maxdev)
-			break;
+		dev[(*count)++] = strdup(buf);
}
 	closedir(dd);
-	if (i < maxdev) dev[i] = NULL;

 	return 0;
}

 /*
- *	Put an IDE disk in standby mode.
+ *	Find all SCSI/SATA disks.
+ */
+static int find_scsidisks(const char **dev, int maxdev, int *count)
+{
+        char mbuf[256],nbuf[256];
+        DIR *dp;
+        struct dirent *ep;
+        int i=97; //set first sd letter to a
+        while (*count<maxdev && i<123) {
+          mbuf[0] = 0;
+          snprintf(mbuf,sizeof(mbuf),DEV_BASE "/sd%c",i);
+          if(access(mbuf,F_OK)==0)
+          {
+            nbuf[0] = 0;
+            snprintf(nbuf,sizeof(nbuf),"/sys/block/sd%c/device/",i);
+            if((dp = opendir(nbuf))){
+                while ((ep = readdir(dp))){
+                  if(strstr(ep->d_name,"scsi_disk:")){
+                    nbuf[0]=0;
+                    snprintf(nbuf,sizeof(nbuf),"/sys/block/sd%c/device/%s/manage_start_stop",i,ep->d_name);
+                    if(access(nbuf,F_OK)==0){
+                      break;
+                      }else{
+                      dev[(*count)++] = strdup(mbuf);
+                      }
+                    }
+                }
+            closedir (dp);
+            }
+          }
+          else
+          {
+            break; 
+          }
+        i++;
+        }
+	return 0;
+}
+
+/*
+ *	Open the device node of a disk.
+ */
+static int open_disk(const char *device)
+{
+	return open(device, O_RDWR);
+}
+
+/*
+ *	Open device nodes of all disks, and store the file descriptors in fds.
+ *	This has to be done in advance because accessing the device nodes
+ *	might cause a disk to spin back up.
+ */
+static int open_disks(const char **disks, int *fds, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		fds[i] = open_disk(disks[i]);
+
+	return 0;
+}
+
+/*
+ *	Put an IDE/SCSI/SATA disk in standby mode.
  *	Code stolen from hdparm.c
 */
-static int do_standby_idedisk(char *device)
+static int do_standby_disk(int fd)
{
#ifndef WIN_STANDBYNOW1
#define WIN_STANDBYNOW1 0xE0
 <at>  <at>  -74,9 +133,8  <at>  <at> 
#endif
 	unsigned char args1[4] = {WIN_STANDBYNOW1,0,0,0};
 	unsigned char args2[4] = {WIN_STANDBYNOW2,0,0,0};
-	int fd;

-	if ((fd = open(device, O_RDWR)) < 0)
+	if (fd < 0)
 		return -1;

 	if (ioctl(fd, HDIO_DRIVE_CMD, &args1) &&
 <at>  <at>  -87,22 +145,37  <at>  <at> 
}

 /*
- *	First find all IDE disks, then put them in standby mode.
+ *	Put all specified disks in standby mode.
+ */
+static int do_standby_disks(const int *fds, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		do_standby_disk(fds[i]);
+
+	return 0;
+}
+
+/*
+ *	First find all IDE/SCSI/SATA disks, then 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)
{
-	char *disks[MAX_DISKS+1];
-	int i;
+	const char *disks[MAX_DISKS];
+	int fds[MAX_DISKS];
+	int count = 0;
+	int result1, result2;

-	if (find_idedisks(disks, MAX_DISKS) < 0)
-		return -1;
+	result1 = find_idedisks(disks, MAX_DISKS, &count);
+	result2 = find_scsidisks(disks, MAX_DISKS, &count);

-	for (i = 0; disks[i] && i < MAX_DISKS; i++)
-		do_standby_idedisk(disks[i]);
+	open_disks(disks, fds, count);
+	do_standby_disks(fds, count);

-	return 0;
+	return (result1 ? result1 : result2);
}

#else /* __linux__ */
#! /bin/sh /usr/share/dpatch/dpatch-run
# 67_init_hddown.dpatch by Sebastian Reichelt
#
# Make sure SATA disks are powered down as well as IDE disks.  This
# patch could use some more work to make it more dynamic when
# detecting SATA/SCSI disks.  Closes: #348172

 <at> DPATCH <at> 
--- sysvinit-2.86.ds1/src/hddown.c	2004-06-09 14:47:45.000000000 +0200
+++ sysvinit-2.86.ds1-new/src/hddown.c	2007-11-04 12:12:38.000000000 +0100
 <at>  <at>  -25,18 +25,17  <at>  <at> 
 /*
  *	Find all IDE disks through /proc.
 */
-static int find_idedisks(char **dev, int maxdev)
+static int find_idedisks(const char **dev, int maxdev, int *count)
{
 	DIR *dd;
 	FILE *fp;
 	struct dirent *d;
 	char buf[256];
-	int i = 0;

 	if ((dd = opendir(PROC_IDE)) == NULL)
 		return -1;

-	while ((d = readdir(dd)) != NULL) {
+	while (*count < maxdev && (d = readdir(dd)) != NULL) {
 		if (strncmp(d->d_name, "hd", 2) != 0)
 			continue;
 		buf[0] = 0;
 <at>  <at>  -50,21 +49,81  <at>  <at> 
}
 		fclose(fp);
 		snprintf(buf, sizeof(buf), DEV_BASE "/%s", d->d_name);
-		dev[i++] = strdup(buf);
-		if (i >= maxdev)
-			break;
+		dev[(*count)++] = strdup(buf);
}
 	closedir(dd);
-	if (i < maxdev) dev[i] = NULL;

 	return 0;
}

 /*
- *	Put an IDE disk in standby mode.
+ *	Find all SCSI/SATA disks.
+ */
+static int find_scsidisks(const char **dev, int maxdev, int *count)
+{
+        char mbuf[256],nbuf[256];
+        DIR *dp;
+        struct dirent *ep;
+        int i=97; //set first sd letter to a
+        while (*count<maxdev && i<123) {
+          mbuf[0] = 0;
+          snprintf(mbuf,sizeof(mbuf),DEV_BASE "/sd%c",i);
+          if(access(mbuf,F_OK)==0)
+          {
+            nbuf[0] = 0;
+            snprintf(nbuf,sizeof(nbuf),"/sys/block/sd%c/device/",i);
+            if((dp = opendir(nbuf))){
+                while ((ep = readdir(dp))){
+                  if(strstr(ep->d_name,"scsi_disk:")){
+                    nbuf[0]=0;
+                    snprintf(nbuf,sizeof(nbuf),"/sys/block/sd%c/device/%s/manage_start_stop",i,ep->d_name);
+                    if(access(nbuf,F_OK)==0){
+                      break;
+                      }else{
+                      dev[(*count)++] = strdup(mbuf);
+                      }
+                    }
+                }
+            closedir (dp);
+            }
+          }
+          else
+          {
+            break; 
+          }
+        i++;
+        }
+	return 0;
+}
+
+/*
+ *	Open the device node of a disk.
+ */
+static int open_disk(const char *device)
+{
+	return open(device, O_RDWR);
+}
+
+/*
+ *	Open device nodes of all disks, and store the file descriptors in fds.
+ *	This has to be done in advance because accessing the device nodes
+ *	might cause a disk to spin back up.
+ */
+static int open_disks(const char **disks, int *fds, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		fds[i] = open_disk(disks[i]);
+
+	return 0;
+}
+
+/*
+ *	Put an IDE/SCSI/SATA disk in standby mode.
  *	Code stolen from hdparm.c
 */
-static int do_standby_idedisk(char *device)
+static int do_standby_disk(int fd)
{
#ifndef WIN_STANDBYNOW1
#define WIN_STANDBYNOW1 0xE0
 <at>  <at>  -74,9 +133,8  <at>  <at> 
#endif
 	unsigned char args1[4] = {WIN_STANDBYNOW1,0,0,0};
 	unsigned char args2[4] = {WIN_STANDBYNOW2,0,0,0};
-	int fd;

-	if ((fd = open(device, O_RDWR)) < 0)
+	if (fd < 0)
 		return -1;

 	if (ioctl(fd, HDIO_DRIVE_CMD, &args1) &&
 <at>  <at>  -87,22 +145,37  <at>  <at> 
}

 /*
- *	First find all IDE disks, then put them in standby mode.
+ *	Put all specified disks in standby mode.
+ */
+static int do_standby_disks(const int *fds, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		do_standby_disk(fds[i]);
+
+	return 0;
+}
+
+/*
+ *	First find all IDE/SCSI/SATA disks, then 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)
{
-	char *disks[MAX_DISKS+1];
-	int i;
+	const char *disks[MAX_DISKS];
+	int fds[MAX_DISKS];
+	int count = 0;
+	int result1, result2;

-	if (find_idedisks(disks, MAX_DISKS) < 0)
-		return -1;
+	result1 = find_idedisks(disks, MAX_DISKS, &count);
+	result2 = find_scsidisks(disks, MAX_DISKS, &count);

-	for (i = 0; disks[i] && i < MAX_DISKS; i++)
-		do_standby_idedisk(disks[i]);
+	open_disks(disks, fds, count);
+	do_standby_disks(fds, count);

-	return 0;
+	return (result1 ? result1 : result2);
}

#else /* __linux__ */

Gmane