From ba333f16e2355573b79e73d1675aae2eef925d08 Mon Sep 17 00:00:00 2001
From: chrfranke <chrfranke@4ea69e1a-61f1-4043-bf83-b5c94c648137>
Date: Fri, 26 Jun 2009 20:37:35 +0000
Subject: [PATCH] smartd: Don't ignore the '-n' directive when a self-test is
 scheduled. Start the self-test later when the disk is active again.

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@2813 4ea69e1a-61f1-4043-bf83-b5c94c648137
---
 sm5/CHANGELOG        |  6 ++++-
 sm5/smartd.8.in      | 11 ++++----
 sm5/smartd.conf.5.in | 11 ++++----
 sm5/smartd.cpp       | 60 +++++++++++++++++++-------------------------
 4 files changed, 43 insertions(+), 45 deletions(-)

diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index d0e8974b7..f0cbb9ad2 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.812 2009/06/26 18:57:59 chrfranke Exp $
+$Id: CHANGELOG,v 1.813 2009/06/26 20:37:35 chrfranke Exp $
 
 The most recent version of this file is:
 http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup
@@ -41,6 +41,10 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] smartd: Don't ignore the '-n' directive when a self-test is
+       scheduled. Start the self-test later when the disk is active
+       again.
+
   [DG] SCSI (SAS): implement '-l sasphy,reset' (reset part was stub
        prior to this)
 
diff --git a/sm5/smartd.8.in b/sm5/smartd.8.in
index 27fd943c8..c44e0ad3f 100644
--- a/sm5/smartd.8.in
+++ b/sm5/smartd.8.in
@@ -1,7 +1,7 @@
 .ig
 Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  
-$Id: smartd.8.in,v 1.136 2009/04/07 19:39:34 chrfranke Exp $
+$Id: smartd.8.in,v 1.137 2009/06/26 20:37:35 chrfranke Exp $
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -878,9 +878,6 @@ this is probably what you want.
 In the IDLE state, most disks are still spinning, so this is probably
 not what you want.
 
-When a self test is scheduled (see \'\-s\' Directive below), the
-\'\fB\-n\fP\' Directive is ignored, and all tests are carried out.
-
 Maximum number of skipped checks (in a row) can be specified by
 appending positive number \',N\' to POWERMODE (like \'\-n standby,15\').
 After N checks are skipped in a row, powermode is ignored and the
@@ -1083,6 +1080,10 @@ shutdown (or 90 days at most). If any test would have been started
 during downtime, the longest (see above) of these tests is run after
 second device polling.
 
+If the \'\-n\' directive is used and any test would have been started
+during disk standby time, the longest of these tests is run when the
+disk is active again.
+
 Unix users: please beware that the rules for extended regular
 expressions [regex(7)] are \fBnot\fP the same as the rules for
 file\-name pattern matching by the shell [glob(7)].  \fBsmartd\fP will
@@ -2115,4 +2116,4 @@ smartmontools home page at \fBhttp://smartmontools.sourceforge.net/#references\f
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartd.8.in,v 1.136 2009/04/07 19:39:34 chrfranke Exp $
+$Id: smartd.8.in,v 1.137 2009/06/26 20:37:35 chrfranke Exp $
diff --git a/sm5/smartd.conf.5.in b/sm5/smartd.conf.5.in
index 1e4b0ed52..42a3bf80f 100644
--- a/sm5/smartd.conf.5.in
+++ b/sm5/smartd.conf.5.in
@@ -1,7 +1,7 @@
 .ig
 Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
-$Id: smartd.conf.5.in,v 1.100 2009/04/07 19:39:34 chrfranke Exp $
+$Id: smartd.conf.5.in,v 1.101 2009/06/26 20:37:35 chrfranke Exp $
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the Free
@@ -463,9 +463,6 @@ this is probably what you want.
 In the IDLE state, most disks are still spinning, so this is probably
 not what you want.
 
-When a self test is scheduled (see \'\-s\' Directive below), the
-\'\fB\-n\fP\' Directive is ignored, and all tests are carried out.
-
 Maximum number of skipped checks (in a row) can be specified by
 appending positive number \',N\' to POWERMODE (like \'\-n standby,15\').
 After N checks are skipped in a row, powermode is ignored and the
@@ -668,6 +665,10 @@ shutdown (or 90 days at most). If any test would have been started
 during downtime, the longest (see above) of these tests is run after
 second device polling.
 
+If the \'\-n\' directive is used and any test would have been started
+during disk standby time, the longest of these tests is run when the
+disk is active again.
+
 Unix users: please beware that the rules for extended regular
 expressions [regex(7)] are \fBnot\fP the same as the rules for
 file\-name pattern matching by the shell [glob(7)].  \fBsmartd\fP will
@@ -1470,4 +1471,4 @@ SEE ALSO:
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartd.conf.5.in,v 1.100 2009/04/07 19:39:34 chrfranke Exp $
+$Id: smartd.conf.5.in,v 1.101 2009/06/26 20:37:35 chrfranke Exp $
diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp
index 61bc727f1..37412de54 100644
--- a/sm5/smartd.cpp
+++ b/sm5/smartd.cpp
@@ -136,7 +136,7 @@ extern const char *os_solaris_ata_s_cvsid;
 #ifdef _WIN32
 extern const char *daemon_win32_c_cvsid, *hostname_win32_c_cvsid, *syslog_win32_c_cvsid;
 #endif
-const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.446 2009/06/20 19:11:04 chrfranke Exp $"
+const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.447 2009/06/26 20:37:35 chrfranke Exp $"
 ATACMDS_H_CVSID CONFIG_H_CVSID
 #ifdef DAEMON_WIN32_H_CVSID
 DAEMON_WIN32_H_CVSID
@@ -1846,6 +1846,10 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
     }
   }
 
+  // Start self-test regex check now if time was not read from state file
+  if (!cfg.test_regex.empty() && !state.scheduled_test_next_check)
+    state.scheduled_test_next_check = time(0);
+
   return 0;
 }
 
@@ -2166,9 +2170,7 @@ static char next_scheduled_test(const dev_config & cfg, dev_state & state, bool
   
   // Is it time for next check?
   time_t now = (!usetime ? time(0) : usetime);
-  if (!state.scheduled_test_next_check)
-    state.scheduled_test_next_check = now;
-  else if (now < state.scheduled_test_next_check)
+  if (now < state.scheduled_test_next_check)
     return 0;
 
   // Limit time check interval to 90 days
@@ -2565,9 +2567,7 @@ static void CheckTemperature(const dev_config & cfg, dev_state & state, unsigned
 
 static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device * atadev, bool allow_selftests)
 {
-  int i;
   const char * name = cfg.name.c_str();
-  char testtype=0;
 
   // If user has asked, test the email warning system
   if (cfg.emailtest)
@@ -2584,13 +2584,6 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
   } else if (debugmode)
     PrintOut(LOG_INFO,"Device: %s, opened ATA device\n", name);
 
-  // if the user has asked, and device is capable (or we're not yet
-  // sure) check whether a self test should be done now.
-  // This check is done before powermode check to avoid missing self
-  // tests on idle or sleeping disks.
-  if (allow_selftests && !cfg.test_regex.empty())
-    testtype = next_scheduled_test(cfg, state, false/*!scsi*/);
-
   // user may have requested (with the -n Directive) to leave the disk
   // alone if it is in idle or sleeping mode.  In this case check the
   // power mode and exit without check if needed
@@ -2640,21 +2633,16 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
 
     // if we are going to skip a check, return now
     if (dontcheck){
-      // but ignore powermode on scheduled selftest
-      if (!testtype) {
-        // skip at most powerskipmax checks
-        if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) {
-          CloseDevice(atadev, name);
-          if (!state.powerskipcnt && !cfg.powerquiet) // report first only and avoid waking up system disk
-            PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, mode);
-          state.powerskipcnt++;
-          return 0;
-        } else {
-          PrintOut(LOG_INFO, "Device: %s, %s mode ignored due to reached limit of skipped checks (%d check%s skipped)\n",
-            name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s"));
-        }
-      } else {
-        PrintOut(LOG_INFO, "Device: %s, %s mode ignored due to scheduled self test (%d check%s skipped)\n",
+      // skip at most powerskipmax checks
+      if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) {
+        CloseDevice(atadev, name);
+        if (!state.powerskipcnt && !cfg.powerquiet) // report first only and avoid waking up system disk
+          PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, mode);
+        state.powerskipcnt++;
+        return 0;
+      }
+      else {
+        PrintOut(LOG_INFO, "Device: %s, %s mode ignored due to reached limit of skipped checks (%d check%s skipped)\n",
           name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s"));
       }
       state.powerskipcnt = 0;
@@ -2715,7 +2703,7 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
       if (cfg.usagefailed || cfg.prefail || cfg.usage) {
 
 	// look for failed usage attributes, or track usage or prefail attributes
-	for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){
+        for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
 	  int att;
 	  changedattribute_t delta;
 	  
@@ -2831,11 +2819,15 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
     if (newc>=0)
       state.ataerrorcount=newc;
   }
-  
-  // carry out scheduled self-test
-  if (testtype)
-    DoATASelfTest(cfg, state, atadev, testtype);
-  
+
+  // if the user has asked, and device is capable (or we're not yet
+  // sure) check whether a self test should be done now.
+  if (allow_selftests && !cfg.test_regex.empty()) {
+    char testtype = next_scheduled_test(cfg, state, false/*!scsi*/);
+    if (testtype)
+      DoATASelfTest(cfg, state, atadev, testtype);
+  }
+
   // Don't leave device open -- the OS/user may want to access it
   // before the next smartd cycle!
   CloseDevice(atadev, name);
-- 
GitLab