Fixing halt/shutdown for libata spindown handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I just took a quick look into modifying halt to work as suggested for the new libata spindown code.

Here's how it works in Gentoo at the moment: /sbin/halt is called typically with the "-d -p -i -h" arguments. After doing some halt-specific things (such as spinning down disks per the -h argument), halt calls /sbin/shutdown which presumably finishes the task. This is with sysvinit-2.86

So, I was expecting to jump into the halt source code, find the "-h" argument parsing, and see code for it spinning down all the disks.

I was surprised to find that the /sbin/halt spin down implementation is very limited, it only works for IDE disks (by working through /proc/ide). This doesn't make sense to me, the libata commits state that userspace shutdown is spinning down libata disks.

So, this means that other distro's do it differently? I'd appreciate some pointers to what happens elsewhere.

I have attached the code from sysvinit which spins down the disks. It's not modified by the patches below.

Gentoo uses sysvinit from here:
ftp://sunsite.unc.edu/pub/Linux/system/daemons/init/sysvinit-2.86.tar.gz

Patched with:
http://sources.gentoo.org/viewcvs.py/*checkout*/gentoo-x86/sys-apps/sysvinit/files/sysvinit-2.86-docs.patch
http://sources.gentoo.org/viewcvs.py/*checkout*/gentoo-x86/sys-apps/sysvinit/files/sysvinit-2.86-shutdown-usage.patch
http://sources.gentoo.org/viewcvs.py/*checkout*/gentoo-x86/sys-apps/sysvinit/files/sysvinit-2.86-off-by-one.patch
http://distfiles.gentoo.org/distfiles/sysvinit-2.86-kexec.patch
http://sources.gentoo.org/viewcvs.py/*checkout*/gentoo-x86/sys-apps/sysvinit/files/sysvinit-2.86-execl.patch
http://sources.gentoo.org/viewcvs.py/*checkout*/gentoo-x86/sys-apps/sysvinit/files/sysvinit-2.86-utmp-64bit.patch
http://sources.gentoo.org/viewcvs.py/*checkout*/gentoo-x86/sys-apps/sysvinit/files/sysvinit-2.86-shutdown-single.patch

If I'm right and Gentoo is currently not spinning down SCSI/libata disks, the only /sbin/halt modification required is to write 0 into
/sys/modules/libata/parameters/spindown_compat right?

Final question: should spindown_compat be set to 0 for both shutdown and reboot, or just shutdown?

Thanks,
Daniel
/*
 * hddown.c	Find all disks on the system and
 *		shut them down.
 *
 */
char *v_hddown = "@(#)hddown.c  1.02  22-Apr-2003  miquels@xxxxxxxxxx";

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>

#ifdef __linux__

#include <sys/ioctl.h>
#include <linux/hdreg.h>

#define MAX_DISKS	64
#define PROC_IDE	"/proc/ide"
#define DEV_BASE	"/dev"

/*
 *	Find all IDE disks through /proc.
 */
static int find_idedisks(char **dev, int maxdev)
{
	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) {
		if (strncmp(d->d_name, "hd", 2) != 0)
			continue;
		buf[0] = 0;
		snprintf(buf, sizeof(buf), PROC_IDE "/%s/media", d->d_name);
		if ((fp = fopen(buf, "r")) == NULL)
			continue;
		if (fgets(buf, sizeof(buf), fp) == 0 ||
		    strcmp(buf, "disk\n") != 0) {
			fclose(fp);
			continue;
		}
		fclose(fp);
		snprintf(buf, sizeof(buf), DEV_BASE "/%s", d->d_name);
		dev[i++] = strdup(buf);
		if (i >= maxdev)
			break;
	}
	closedir(dd);
	if (i < maxdev) dev[i] = NULL;

	return 0;
}

/*
 *	Put an IDE disk in standby mode.
 *	Code stolen from hdparm.c
 */
static int do_standby_idedisk(char *device)
{
#ifndef WIN_STANDBYNOW1
#define WIN_STANDBYNOW1 0xE0
#endif
#ifndef WIN_STANDBYNOW2
#define WIN_STANDBYNOW2 0x94
#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)
		return -1;

	if (ioctl(fd, HDIO_DRIVE_CMD, &args1) &&
	    ioctl(fd, HDIO_DRIVE_CMD, &args2))
		return -1;

	return 0;
}

/*
 *	First find all IDE 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;

	if (find_idedisks(disks, MAX_DISKS) < 0)
		return -1;

	for (i = 0; disks[i] && i < MAX_DISKS; i++)
		do_standby_idedisk(disks[i]);

	return 0;
}

#else /* __linux__ */

int hddown(void)
{
	return 0;
}

#endif /* __linux__ */

#ifdef STANDALONE
int main(int argc, char **argv)
{
	return (hddown() == 0);
}
#endif


[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux