summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhillip Susi <psusi@ubuntu.com>2014-06-22 19:23:05 -0400
committerMartin Pitt <martin.pitt@ubuntu.com>2014-12-18 11:11:32 +0100
commit46da39c15f365192a30b8e25ed0ebd625506e532 (patch)
tree7aa14c4cdec7e1119c5c503e0c1ec0d57b6356c7
parent0d24350ca598d5c7f5cee8e41ee2cae45b85d531 (diff)
Fix standby timers
If the drive was set to standby after >= 10 minutes of inactivity, it would never standby because udisks would check every 10 minutes to see if it was already in standby, and if not, update the SMART stats, which would reset the standby timer. This is especially problematic since many drives enforce a 10 minute minimum standby timer even if a lower value is specified. This patch checks the kernel IO stats to see if any other IO has been done on the drive since the last check, and if not, behaves as if the drive is already sleeping. https://bugs.freedesktop.org/show_bug.cgi?id=80170 https://launchpad.net/bugs/1281588
-rw-r--r--src/udiskslinuxdriveata.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/src/udiskslinuxdriveata.c b/src/udiskslinuxdriveata.c
index 9148dee..444acc1 100644
--- a/src/udiskslinuxdriveata.c
+++ b/src/udiskslinuxdriveata.c
@@ -88,6 +88,8 @@ struct _UDisksLinuxDriveAta
UDisksThreadedJob *selftest_job;
gboolean secure_erase_in_progress;
+ unsigned long drive_read, drive_write;
+ gboolean standby_enabled;
};
struct _UDisksLinuxDriveAtaClass
@@ -463,6 +465,32 @@ static gboolean get_pm_state (UDisksLinuxDevice *device, GError **error, guchar
return rc;
}
+static gboolean update_io_stats (UDisksLinuxDriveAta *drive, UDisksLinuxDevice *device)
+{
+ const gchar *drivepath = g_udev_device_get_sysfs_path (device->udev_device);
+ gchar statpath[PATH_MAX];
+ unsigned long drive_read, drive_write;
+ FILE *statf;
+ gboolean noio = FALSE;
+ snprintf (statpath, sizeof(statpath), "%s/stat", drivepath);
+ statf = fopen (statpath, "r");
+ if (statf == NULL)
+ {
+ udisks_warning ("Failed to open %s\n", statpath);
+ }
+ else
+ {
+ fscanf (statf, "%lu %*u %*u %*u %lu", &drive_read, &drive_write);
+ fclose (statf);
+ noio = drive_read == drive->drive_read && drive_write == drive->drive_write;
+ udisks_debug ("drive_read=%lu, drive_write=%lu, old_drive_read=%lu, old_drive_write=%lu\n",
+ drive_read, drive_write, drive->drive_read, drive->drive_write);
+ drive->drive_read = drive_read;
+ drive->drive_write = drive_write;
+ }
+ return noio;
+}
+
/**
* udisks_linux_drive_ata_refresh_smart_sync:
* @drive: The #UDisksLinuxDriveAta to refresh.
@@ -556,11 +584,14 @@ udisks_linux_drive_ata_refresh_smart_sync (UDisksLinuxDriveAta *drive,
else
{
guchar count;
+ gboolean noio = FALSE;
if (!get_pm_state(device, error, &count))
goto out;
awake = count == 0xFF || count == 0x80;
+ if (drive->standby_enabled)
+ noio = update_io_stats (drive, device);
/* don't wake up disk unless specically asked to */
- if (nowakeup && !awake)
+ if (nowakeup && (!awake || noio))
{
g_set_error (error,
UDISKS_ERROR,
@@ -634,6 +665,8 @@ udisks_linux_drive_ata_refresh_smart_sync (UDisksLinuxDriveAta *drive,
update_smart (drive, device);
ret = TRUE;
+ /* update stats again to account for the IO we just did to read the SMART info */
+ update_io_stats (drive, device);
out:
g_clear_object (&device);
@@ -1660,6 +1693,7 @@ apply_configuration_thread_func (gpointer user_data)
udisks_notice ("Set standby timer to %s (value %d) on %s [%s]",
pretty, data->ata_pm_standby, device_file, udisks_drive_get_id (data->drive));
g_free (pretty);
+ data->ata->standby_enabled = data->ata_pm_standby != 0;
}
}