diff options
author | Phillip Susi <psusi@ubuntu.com> | 2014-06-22 19:23:05 -0400 |
---|---|---|
committer | Martin Pitt <martin.pitt@ubuntu.com> | 2014-12-18 11:11:32 +0100 |
commit | 46da39c15f365192a30b8e25ed0ebd625506e532 (patch) | |
tree | 7aa14c4cdec7e1119c5c503e0c1ec0d57b6356c7 | |
parent | 0d24350ca598d5c7f5cee8e41ee2cae45b85d531 (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.c | 36 |
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; } } |