kern/127717: ata(4) - support write cache toggling per device

Jeremy Chadwick koitsu at FreeBSD.org
Mon Sep 29 13:20:01 UTC 2008


>Number:         127717
>Category:       kern
>Synopsis:       ata(4) - support write cache toggling per device
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Sep 29 13:20:00 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Jeremy Chadwick
>Release:        FreeBSD 7.1-PRERELEASE amd64
>Organization:
>Environment:
System: FreeBSD icarus.home.lan 7.1-PRERELEASE FreeBSD 7.1-PRERELEASE #0: Wed Sep 24 19:35:59 PDT 2008 root at icarus.home.lan:/usr/obj/usr/src/sys/PDSMI_PLUS_amd64 amd64
>Description:
	At present, there is no way to disable/enable write caching on a
	disk, on a per-disk basis.  There is the tunable hw.ata.wc which
	you can set to 0, but that disables WC on all disks.  Some users
	may want to disable WC on specific disks, or if using hw.ata.wc=0,
	enable WC on specific disks.

	The below patch addresses this limitation.  It does the following:

	1) Adds an ATA ioctl called IOCATASETWC, which allows one to
	   disable/enable write caching on a specific device.  Devices
	   which do not support toggling the capability (e.g. CD/DVD
	   drives) will return ENODEV, causing ioctl() to return -1.
	2) Extends atacontrol(8) to support toggling of write caching,
	3) Updates the atacontrol(8) man page to reflect things.

	Ultimately this should be useful to administrators who use
	gjournal(8) with the async mount option (where disabling disk
	write caching is sometimes advised).

	This patch is against HEAD, but has been fully tested on RELENG_7
	i386 and amd64, and can be MFC'd safely.
>How-To-Repeat:
	n/a, but here's confirmation that it does in fact work and is
	not just a cosmetic thing:

testbox# atacontrol wc ad0 on
testbox# dd if=/dev/urandom of=/usr/testfile bs=64k count=10000
10000+0 records in
10000+0 records out
655360000 bytes transferred in 19.294844 secs (33965551 bytes/sec)
testbox# rm /usr/testfile
testbox# sync
testbox# sync
testbox# atacontrol wc ad0 off
testbox# dd if=/dev/urandom of=/usr/testfile bs=64k count=10000
10000+0 records in
10000+0 records out
655360000 bytes transferred in 95.172770 secs (6886003 bytes/sec)

>Fix:
	Apply below patch.


Index: sbin/atacontrol/atacontrol.8
===================================================================
RCS file: /home/ncvs/src/sbin/atacontrol/atacontrol.8,v
retrieving revision 1.31
diff -u -r1.31 atacontrol.8
--- sbin/atacontrol/atacontrol.8	25 Jun 2008 18:11:22 -0000	1.31
+++ sbin/atacontrol/atacontrol.8	29 Sep 2008 12:56:55 -0000
@@ -74,6 +74,10 @@
 .Ar device
 .Op Ar seconds
 .Nm
+.Ic wc
+.Ar device
+.Op Ar on|off
+.Nm
 .Ic list
 .Sh DESCRIPTION
 The
@@ -202,6 +206,9 @@
 setting the timeout.
 To disable spindown, set the timeout to zero.
 No further actions are needed in this case.
+.It Ic wc
+Enable or disable write caching on the specific
+.Ar device .
 .It Ic info
 Show info about the attached devices on the
 .Ar channel .
@@ -354,6 +361,18 @@
 .Pa /
 or syslog logging on it as the disk will be worn out spinning down and
 up all the time.
+.Pp
+To disable write caching on a specific disk, run
+.Pp
+.Dl "atacontrol wc ad6 off"
+.Pp
+Write cache toggling may be useful to individuals using
+.Xr gjournal 8
+with the
+.Pa async
+.Xr mount 8
+option on a filesystem.
+.Pp
 .Sh SEE ALSO
 .Xr ata 4
 .Sh HISTORY
Index: sbin/atacontrol/atacontrol.c
===================================================================
RCS file: /home/ncvs/src/sbin/atacontrol/atacontrol.c,v
retrieving revision 1.49
diff -u -r1.49 atacontrol.c
--- sbin/atacontrol/atacontrol.c	6 Aug 2008 18:08:02 -0000	1.49
+++ sbin/atacontrol/atacontrol.c	29 Sep 2008 12:56:55 -0000
@@ -104,6 +104,7 @@
 		"        atacontrol mode device [mode]\n"
 		"        atacontrol cap device\n"
 		"        atacontrol spindown device [seconds]\n"
+		"        atacontrol wc device [on|off]\n"
 	);
 	exit(EX_USAGE);
 }
@@ -374,6 +375,24 @@
 		}
 		exit(EX_OK);
 	}
+
+	if (!strcmp(argv[1], "wc") && argc == 4) {
+		fd = open_dev(argv[2], O_RDONLY);
+		if (!strcmp(argv[3], "on")) {
+			mode = 1;
+		}
+		else if (!strcmp(argv[3], "off")) {
+			mode = 0;
+		}
+		else {
+			usage();
+			exit(EX_USAGE);
+		}
+		if (ioctl(fd, IOCATASETWC, &mode) < 0)
+			err(1, "ioctl(IOCATASETWC)");
+		exit(EX_OK);
+	}
+
 	if (!strcmp(argv[1], "cap") && argc == 3) {
 		fd = open_dev(argv[2], O_RDONLY);
 		ata_cap_print(fd);
Index: sys/dev/ata/ata-all.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/ata/ata-all.c,v
retrieving revision 1.290
diff -u -r1.290 ata-all.c
--- sys/dev/ata/ata-all.c	15 Aug 2008 10:55:11 -0000	1.290
+++ sys/dev/ata/ata-all.c	29 Sep 2008 12:56:55 -0000
@@ -532,6 +532,22 @@
     case IOCATAGSPINDOWN:
 	*mode = atadev->spindown;
 	return 0;
+    case IOCATASETWC:
+	ATA_SETMODE(device_get_parent(dev), dev);
+
+	/* enable write caching if supported and configured */
+	if (atadev->param.support.command1 & ATA_SUPPORT_WRITECACHE) {
+		if (*mode == 1) {
+			ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0);
+		}
+		else {
+			ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0);
+		}
+	}
+	else {
+		return ENODEV;
+	}
+	return 0;
     default:
 	return ENOTTY;
     }
Index: sys/sys/ata.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/ata.h,v
retrieving revision 1.40
diff -u -r1.40 ata.h
--- sys/sys/ata.h	10 Apr 2008 13:01:17 -0000	1.40
+++ sys/sys/ata.h	29 Sep 2008 12:56:55 -0000
@@ -438,6 +438,8 @@
 #define IOCATAGSPINDOWN		_IOR('a', 104, int)
 #define IOCATASSPINDOWN		_IOW('a', 105, int)
 
+#define IOCATASETWC		_IOW('a', 106, int)
+
 
 struct ata_ioc_raid_config {
 	    int                 lun;
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list