From 2a6936fab4d4499a4b812dd330d3db50549029e0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 28 Aug 2009 17:05:55 +0200 Subject: [PATCH] linux-commit: do not unnecessarily open partition device nodes After patching parted with my do-not-use-BLKPG patch, I started to get EBUSY errors on commit_to_os. Note this is not caused by the do-not-use-BLKPG patch, this was already happening, but parted was silently ignoring the errors (and the kernel was not notified of the changes, which is bad). The error now actually gets reported. The problem turns out to be in libparted/arch/linux.c's _flush_cache function, which walks all the partitions of the disk and does BLKFLSBUF calls on them. This causes the following: commit_to_os -> device_open -> fd = open /dev/sda -> _flush_cache -> for each /dev/sda# open, ioctl, close -> ioctl(fd, BLKRRPART) -> EBUSY What is happening here is that the: for each /dev/sda# open, ioctl, close Is causing udev change events for all the /dev/sda# nodes, which causes udev to call blkid on all these nodes (on systems which use DeviceKit), so blkid has /dev/sda# nodes open while BLKRRPART gets called on /dev/sda -> EBUSY. I've checked with two independend storage subsystem kernel developers, and /dev/sda and /dev/sda#, guarantee cache coherency now-a-days. So there is no need to do this for 2.6, which also eliminates the need to call _flush_cache() on device open at all. * libparted/arch/linux.c (_have_kern26): New function. (_flush_cache): For linux kernels 2.6 and newer, don't flush partition devices. (linux_open): Skip _flush_cache on newer kernels here, too. --- libparted/arch/linux.c | 25 ++++++++++++++++++++++--- 1 files changed, 22 insertions(+), 3 deletions(-) Index: parted-1.9.0/libparted/arch/linux.c =================================================================== --- parted-1.9.0.orig/libparted/arch/linux.c 2009-12-03 17:04:44.000000000 +0100 +++ parted-1.9.0/libparted/arch/linux.c 2009-12-03 17:05:06.000000000 +0100 @@ -601,6 +601,19 @@ _have_devfs () return have_devfs = S_ISCHR(sb.st_mode) ? 1 : 0; } +static int +_have_kern26 () +{ + static int have_kern26 = -1; + int kver; + + if (have_kern26 != -1) + return have_kern26; + + kver = _get_linux_version(); + return have_kern26 = kver >= KERNEL_VERSION (2,6,0) ? 1 : 0; +} + static void _device_set_sector_size (PedDevice* dev) { @@ -1374,8 +1387,8 @@ linux_is_busy (PedDevice* dev) return 0; } -/* we need to flush the master device, and all the partition devices, - * because there is no coherency between the caches. +/* we need to flush the master device, and with kernel < 2.6 all the partition + * devices, because there is no coherency between the caches with old kernels. * We should only flush unmounted partition devices, because: * - there is never a need to flush them (we're not doing IO there) * - flushing a device that is mounted causes unnecessary IO, and can @@ -1393,6 +1406,10 @@ _flush_cache (PedDevice* dev) ioctl (arch_specific->fd, BLKFLSBUF); + /* With linux-2.6.0 and newer, we're done. */ + if (_have_kern26()) + return; + for (i = 1; i < 16; i++) { char* name; int fd; @@ -1449,6 +1466,8 @@ retry: dev->read_only = 0; } + /* With kernels < 2.6 flush cache for cache coherence issues */ + if (!_have_kern26()) _flush_cache (dev); return 1;