[PATCH] Use internal pm check for smart poll

Phillip Susi psusi at ubuntu.com
Tue Nov 5 01:49:30 CET 2013


libatasmart apparently has a bug where it will wake up a disk from
sleep just trying to open it, so use our own code to check the pm
state to avoid this.

Signed-off-by: Phillip Susi <psusi at ubuntu.com>
---
 src/udiskslinuxdriveata.c | 101 ++++++++++++++++++++++++----------------------
 1 file changed, 52 insertions(+), 49 deletions(-)

diff --git a/src/udiskslinuxdriveata.c b/src/udiskslinuxdriveata.c
index 48cc6e6..1575b3d 100644
--- a/src/udiskslinuxdriveata.c
+++ b/src/udiskslinuxdriveata.c
@@ -427,6 +427,41 @@ selftest_status_to_string (SkSmartSelfTestExecutionStatus status)
   return ret;
 }
 
+static gboolean get_pm_state (UDisksLinuxDevice *device, GError **error, guchar *count)
+{
+  int fd = open (g_udev_device_get_device_file (device->udev_device), O_RDONLY|O_NONBLOCK);
+  gboolean rc = FALSE;
+  /* ATA8: 7.8 CHECK POWER MODE - E5h, Non-Data */
+  UDisksAtaCommandInput input = {.command = 0xe5};
+  UDisksAtaCommandOutput output = {0};
+
+  if (fd == -1)
+    {
+      g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
+                   "Error opening device file %s: %m",
+                   g_udev_device_get_device_file (device->udev_device));
+      goto out;
+    }
+
+  if (!udisks_ata_send_command_sync (fd,
+                                     -1,
+                                     UDISKS_ATA_COMMAND_PROTOCOL_NONE,
+                                     &input,
+                                     &output,
+                                     error))
+    {
+      g_prefix_error (error, "Error sending ATA command CHECK POWER MODE: ");
+      goto out;
+    }
+  /* count field is used for the state, see ATA8: table 102 */
+  *count = output.count;
+  rc = TRUE;
+ out:
+  if (fd != -1)
+    close(fd);
+  return rc;
+}
+
 /**
  * udisks_linux_drive_ata_refresh_smart_sync:
  * @drive: The #UDisksLinuxDriveAta to refresh.
@@ -519,24 +554,10 @@ udisks_linux_drive_ata_refresh_smart_sync (UDisksLinuxDriveAta  *drive,
     }
   else
     {
-      if (sk_disk_open (g_udev_device_get_device_file (device->udev_device), &d) != 0)
-        {
-          g_set_error (error,
-                       UDISKS_ERROR,
-                       UDISKS_ERROR_FAILED,
-                       "sk_disk_open: %m");
-          goto out;
-        }
-
-      if (sk_disk_check_sleep_mode (d, &awake) != 0)
-        {
-          g_set_error (error,
-                       UDISKS_ERROR,
-                       UDISKS_ERROR_FAILED,
-                       "sk_disk_check_sleep_mode: %m");
-          goto out;
-        }
-
+      guchar count;
+      if (!get_pm_state(device, error, &count))
+        goto out;
+      awake = count == 0xFF || count == 0x80;
       /* don't wake up disk unless specically asked to */
       if (nowakeup && !awake)
         {
@@ -548,6 +569,15 @@ udisks_linux_drive_ata_refresh_smart_sync (UDisksLinuxDriveAta  *drive,
         }
     }
 
+  if (sk_disk_open (g_udev_device_get_device_file (device->udev_device), &d) != 0)
+    {
+      g_set_error (error,
+                   UDISKS_ERROR,
+                   UDISKS_ERROR_FAILED,
+                   "sk_disk_open: %m");
+      goto out;
+    }
+
   if (sk_disk_smart_read_data (d) != 0)
     {
       g_set_error (error,
@@ -1184,10 +1214,10 @@ handle_pm_get_state (UDisksDriveAta        *_drive,
   UDisksLinuxDriveObject  *object = NULL;
   UDisksDaemon *daemon;
   UDisksLinuxDevice *device = NULL;
-  gint fd = -1;
   GError *error = NULL;
   const gchar *message;
   const gchar *action_id;
+  guchar count;
 
   object = udisks_daemon_util_dup_object (drive, &error);
   if (object == NULL)
@@ -1244,38 +1274,11 @@ handle_pm_get_state (UDisksDriveAta        *_drive,
                                              "No udev device");
       goto out;
     }
-
-  fd = open (g_udev_device_get_device_file (device->udev_device), O_RDONLY|O_NONBLOCK);
-  if (fd == -1)
-    {
-      g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
-                                             "Error opening device file %s: %m",
-                                             g_udev_device_get_device_file (device->udev_device));
-      goto out;
-    }
-
-  {
-    /* ATA8: 7.8 CHECK POWER MODE - E5h, Non-Data */
-    UDisksAtaCommandInput input = {.command = 0xe5};
-    UDisksAtaCommandOutput output = {0};
-    if (!udisks_ata_send_command_sync (fd,
-                                       -1,
-                                       UDISKS_ATA_COMMAND_PROTOCOL_NONE,
-                                       &input,
-                                       &output,
-                                       &error))
-      {
-        g_prefix_error (&error, "Error sending ATA command CHECK POWER MODE: ");
-        g_dbus_method_invocation_take_error (invocation, error);
-        goto out;
-      }
-    /* count field is used for the state, see ATA8: table 102 */
-    udisks_drive_ata_complete_pm_get_state (_drive, invocation, output.count);
-  }
+  if (get_pm_state (device, &error, &count))
+    udisks_drive_ata_complete_pm_get_state (_drive, invocation, count);
+  else g_dbus_method_invocation_take_error (invocation, error);
 
  out:
-  if (fd != -1)
-    close (fd);
   g_clear_object (&device);
   g_clear_object (&object);
   return TRUE; /* returning TRUE means that we handled the method invocation */
-- 
1.8.3.2



More information about the devkit-devel mailing list