3604df
From 922a57492cd16e6c2a1105b91ff3c53f50dfde09 Mon Sep 17 00:00:00 2001
3604df
From: Kotresh HR <khiremat@redhat.com>
3604df
Date: Fri, 5 Aug 2016 09:03:22 +0530
3604df
Subject: [PATCH 27/86] feature/bitrot: Ondemand scrub option for bitrot
3604df
3604df
The bitrot scrubber takes 'hourly/daily/biweekly/monthly'
3604df
as the values for 'scrub-frequency'. There is no way
3604df
to schedule the scrubbing when the admin wants it.
3604df
3604df
Ondemand scrubbing brings in the new option 'ondemand'
3604df
with which the admin can start scrubbing ondemand.
3604df
It starts the scrubbing immediately.
3604df
3604df
Ondemand scrubbing is successful only if the scrubber
3604df
is in 'Active (Idle)' (waiting for it's next frequency
3604df
cycle to start scrubbing). It is not entertained when
3604df
the scrubber is in 'Paused' or already running.
3604df
3604df
Here is the command line syntax.
3604df
3604df
gluster volume bitrot <vol name> scrub ondemand
3604df
3604df
>Change-Id: I84c28904367eed827a7dae8d6a535c14b28e9f4d
3604df
>BUG: 1366195
3604df
>Signed-off-by: Kotresh HR <khiremat@redhat.com>
3604df
>Reviewed-on: http://review.gluster.org/15111
3604df
>Smoke: Gluster Build System <jenkins@build.gluster.org>
3604df
>NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
3604df
>CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
3604df
>Reviewed-by: Venky Shankar <vshankar@redhat.com>
3604df
3604df
Change-Id: I84c28904367eed827a7dae8d6a535c14b28e9f4d
3604df
BUG: 1359588
3604df
Signed-off-by: Kotresh HR <khiremat@redhat.com>
3604df
Reviewed-on: https://code.engineering.redhat.com/gerrit/84665
3604df
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
3604df
Tested-by: Atin Mukherjee <amukherj@redhat.com>
3604df
---
3604df
 cli/src/cli-cmd-parser.c                          |    5 ++-
3604df
 cli/src/cli-cmd-volume.c                          |    2 +-
3604df
 doc/gluster.8                                     |    6 +--
3604df
 glusterfsd/src/glusterfsd-messages.h              |    4 +-
3604df
 glusterfsd/src/glusterfsd-mgmt.c                  |   24 +++++++++-
3604df
 libglusterfs/src/globals.h                        |    4 +-
3604df
 rpc/xdr/src/cli1-xdr.x                            |    1 +
3604df
 rpc/xdr/src/glusterfs-fops.x                      |    1 +
3604df
 tests/bitrot/bug-1207627-bitrot-scrub-status.t    |   20 +++++++-
3604df
 tests/volume.rc                                   |    6 +++
3604df
 xlators/features/bit-rot/src/bitd/bit-rot-scrub.c |   50 ++++++++++++++++++++-
3604df
 xlators/features/bit-rot/src/bitd/bit-rot-scrub.h |    1 +
3604df
 xlators/features/bit-rot/src/bitd/bit-rot-ssm.c   |   25 +++++++---
3604df
 xlators/features/bit-rot/src/bitd/bit-rot-ssm.h   |    3 +-
3604df
 xlators/features/bit-rot/src/bitd/bit-rot.c       |   29 +++++++++++-
3604df
 xlators/features/bit-rot/src/bitd/bit-rot.h       |    2 +-
3604df
 xlators/mgmt/glusterd/src/glusterd-bitrot.c       |   29 ++++++++++++
3604df
 xlators/mgmt/glusterd/src/glusterd-op-sm.c        |   16 +++++--
3604df
 xlators/mgmt/glusterd/src/glusterd-rpc-ops.c      |    1 +
3604df
 xlators/mgmt/glusterd/src/glusterd-syncop.c       |    4 ++
3604df
 xlators/mgmt/glusterd/src/glusterd.h              |    1 +
3604df
 21 files changed, 205 insertions(+), 29 deletions(-)
3604df
3604df
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c
3604df
index 692bd26..b20cea6 100644
3604df
--- a/cli/src/cli-cmd-parser.c
3604df
+++ b/cli/src/cli-cmd-parser.c
3604df
@@ -5188,7 +5188,8 @@ cli_cmd_bitrot_parse (const char **words, int wordcount, dict_t **options)
3604df
                                                      "biweekly", "monthly",
3604df
                                                      "minute",  NULL};
3604df
         char               *scrub_values[]        = {"pause", "resume",
3604df
-                                                     "status", NULL};
3604df
+                                                     "status", "ondemand",
3604df
+                                                     NULL};
3604df
         dict_t             *dict                  = NULL;
3604df
         gf_bitrot_type     type                   = GF_BITROT_OPTION_TYPE_NONE;
3604df
         int32_t            expiry_time            = 0;
3604df
@@ -5320,6 +5321,8 @@ cli_cmd_bitrot_parse (const char **words, int wordcount, dict_t **options)
3604df
                         } else {
3604df
                                 if (strcmp (words[4], "status") == 0) {
3604df
                                         type = GF_BITROT_CMD_SCRUB_STATUS;
3604df
+                                } else if (strcmp (words[4], "ondemand") == 0) {
3604df
+                                        type = GF_BITROT_CMD_SCRUB_ONDEMAND;
3604df
                                 } else {
3604df
                                         type = GF_BITROT_OPTION_TYPE_SCRUB;
3604df
                                 }
3604df
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
3604df
index c721171..129d9b9 100644
3604df
--- a/cli/src/cli-cmd-volume.c
3604df
+++ b/cli/src/cli-cmd-volume.c
3604df
@@ -2703,7 +2703,7 @@ struct cli_cmd volume_cmds[] = {
3604df
          "volume bitrot <volname> scrub-throttle {lazy|normal|aggressive} |\n"
3604df
          "volume bitrot <volname> scrub-frequency {hourly|daily|weekly|biweekly"
3604df
          "|monthly} |\n"
3604df
-         "volume bitrot <volname> scrub {pause|resume|status}",
3604df
+         "volume bitrot <volname> scrub {pause|resume|status|ondemand}",
3604df
          cli_cmd_bitrot_cbk,
3604df
          "Bitrot translator specific operation. For more information about "
3604df
          "bitrot command type  'man gluster'"
3604df
diff --git a/doc/gluster.8 b/doc/gluster.8
3604df
index 9780264..89bf5c3 100644
3604df
--- a/doc/gluster.8
3604df
+++ b/doc/gluster.8
3604df
@@ -162,11 +162,9 @@ Scrub-throttle value is a measure of how fast or slow the scrubber scrubs the fi
3604df
 \fB\ volume bitrot <VOLNAME> scrub-frequency {daily|weekly|biweekly|monthly} \fR
3604df
 Scrub frequency for volume <VOLNAME>
3604df
 .TP
3604df
-\fB\ volume bitrot <VOLNAME> scrub {pause|resume} \fR
3604df
-Pause/Resume scrub. Upon resume, scrubber continues where it left off.
3604df
+\fB\ volume bitrot <VOLNAME> scrub {pause|resume|status|ondemand} \fR
3604df
+Pause/Resume scrub. Upon resume, scrubber continues where it left off. status option shows the statistics of scrubber. ondemand option starts the scrubbing immediately if the scrubber is not paused or already running.
3604df
 .TP
3604df
-\fB\ volume bitrot <VOLNAME> scrub status \fR
3604df
-Show the statistics of scrubber status
3604df
 .SS "Snapshot Commands"
3604df
 .PP
3604df
 .TP
3604df
diff --git a/glusterfsd/src/glusterfsd-messages.h b/glusterfsd/src/glusterfsd-messages.h
3604df
index caa9995..e9c28f7 100644
3604df
--- a/glusterfsd/src/glusterfsd-messages.h
3604df
+++ b/glusterfsd/src/glusterfsd-messages.h
3604df
@@ -36,7 +36,7 @@
3604df
  */
3604df
 
3604df
 #define GLFS_COMP_BASE          GLFS_MSGID_COMP_GLUSTERFSD
3604df
-#define GLFS_NUM_MESSAGES       36
3604df
+#define GLFS_NUM_MESSAGES       37
3604df
 #define GLFS_MSGID_END          (GLFS_COMP_BASE + GLFS_NUM_MESSAGES + 1)
3604df
 /* Messaged with message IDs */
3604df
 #define glfs_msg_start_x GLFS_COMP_BASE, "Invalid: Start of messages"
3604df
@@ -108,6 +108,8 @@
3604df
                         " unserialization failed."
3604df
 #define glusterfsd_msg_36 (GLFS_COMP_BASE + 36), "problem in xlator " \
3604df
                         " loading."
3604df
+#define glusterfsd_msg_37 (GLFS_COMP_BASE + 37), "failed to get dict value"
3604df
+
3604df
 /*------------*/
3604df
 #define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages"
3604df
 
3604df
diff --git a/glusterfsd/src/glusterfsd-mgmt.c b/glusterfsd/src/glusterfsd-mgmt.c
3604df
index 61309f9..e257659 100644
3604df
--- a/glusterfsd/src/glusterfsd-mgmt.c
3604df
+++ b/glusterfsd/src/glusterfsd-mgmt.c
3604df
@@ -660,6 +660,7 @@ glusterfs_handle_bitrot (rpcsvc_request_t *req)
3604df
         char                     xname[1024]  = {0,};
3604df
         glusterfs_ctx_t          *ctx         = NULL;
3604df
         glusterfs_graph_t        *active      = NULL;
3604df
+        char                     *scrub_opt   = NULL;
3604df
 
3604df
         GF_ASSERT (req);
3604df
         this = THIS;
3604df
@@ -713,8 +714,27 @@ glusterfs_handle_bitrot (rpcsvc_request_t *req)
3604df
                 goto out;
3604df
         }
3604df
 
3604df
-        ret = xlator->notify (xlator, GF_EVENT_SCRUB_STATUS, input,
3604df
-                              output);
3604df
+        ret = dict_get_str (input, "scrub-value", &scrub_opt);
3604df
+        if (ret) {
3604df
+                snprintf (msg, sizeof (msg), "Failed to get scrub value");
3604df
+                gf_msg (this->name, GF_LOG_ERROR, 0, glusterfsd_msg_37);
3604df
+                ret = -1;
3604df
+                goto out;
3604df
+        }
3604df
+
3604df
+        if (!strncmp (scrub_opt, "status", strlen ("status"))) {
3604df
+                ret = xlator->notify (xlator, GF_EVENT_SCRUB_STATUS, input,
3604df
+                                      output);
3604df
+        } else if (!strncmp (scrub_opt, "ondemand", strlen ("ondemand"))) {
3604df
+                ret = xlator->notify (xlator, GF_EVENT_SCRUB_ONDEMAND, input,
3604df
+                                      output);
3604df
+                if (ret == -2) {
3604df
+                        snprintf (msg, sizeof (msg), "Scrubber is in "
3604df
+                                  "Pause/Inactive/Running state");
3604df
+                        ret = -1;
3604df
+                        goto out;
3604df
+                }
3604df
+        }
3604df
 out:
3604df
         glusterfs_translator_info_response_send (req, ret, msg, output);
3604df
 
3604df
diff --git a/libglusterfs/src/globals.h b/libglusterfs/src/globals.h
3604df
index 5853e46..b4ad9b2 100644
3604df
--- a/libglusterfs/src/globals.h
3604df
+++ b/libglusterfs/src/globals.h
3604df
@@ -43,7 +43,7 @@
3604df
  */
3604df
 #define GD_OP_VERSION_MIN  1 /* MIN is the fresh start op-version, mostly
3604df
                                 should not change */
3604df
-#define GD_OP_VERSION_MAX  GD_OP_VERSION_3_8_0 /* MAX VERSION is the maximum
3604df
+#define GD_OP_VERSION_MAX  GD_OP_VERSION_3_9_0 /* MAX VERSION is the maximum
3604df
                                                   count in VME table, should
3604df
                                                   keep changing with
3604df
                                                   introduction of newer
3604df
@@ -79,6 +79,8 @@
3604df
 
3604df
 #define GD_OP_VERSION_3_8_0    30800 /* Op-version for GlusterFS 3.8.0 */
3604df
 
3604df
+#define GD_OP_VERSION_3_9_0    30900 /* Op-version for GlusterFS 3.9.0 */
3604df
+
3604df
 #include "xlator.h"
3604df
 
3604df
 /* THIS */
3604df
diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x
3604df
index 66d399b..80151d4 100644
3604df
--- a/rpc/xdr/src/cli1-xdr.x
3604df
+++ b/rpc/xdr/src/cli1-xdr.x
3604df
@@ -45,6 +45,7 @@ enum gf_bitrot_type {
3604df
         GF_BITROT_OPTION_TYPE_SCRUB,
3604df
         GF_BITROT_OPTION_TYPE_EXPIRY_TIME,
3604df
         GF_BITROT_CMD_SCRUB_STATUS,
3604df
+        GF_BITROT_CMD_SCRUB_ONDEMAND,
3604df
         GF_BITROT_OPTION_TYPE_MAX
3604df
 };
3604df
 
3604df
diff --git a/rpc/xdr/src/glusterfs-fops.x b/rpc/xdr/src/glusterfs-fops.x
3604df
index 8462dcc..3b6b649 100644
3604df
--- a/rpc/xdr/src/glusterfs-fops.x
3604df
+++ b/rpc/xdr/src/glusterfs-fops.x
3604df
@@ -84,6 +84,7 @@ enum glusterfs_event_t {
3604df
         GF_EVENT_UPCALL,
3604df
         GF_EVENT_SCRUB_STATUS,
3604df
         GF_EVENT_SOME_CHILD_DOWN,
3604df
+        GF_EVENT_SCRUB_ONDEMAND,
3604df
         GF_EVENT_MAXVAL
3604df
 };
3604df
 
3604df
diff --git a/tests/bitrot/bug-1207627-bitrot-scrub-status.t b/tests/bitrot/bug-1207627-bitrot-scrub-status.t
3604df
index bca3919..a361986 100644
3604df
--- a/tests/bitrot/bug-1207627-bitrot-scrub-status.t
3604df
+++ b/tests/bitrot/bug-1207627-bitrot-scrub-status.t
3604df
@@ -12,7 +12,7 @@ TEST glusterd;
3604df
 TEST pidof glusterd;
3604df
 
3604df
 ## Lets create and start the volume
3604df
-TEST $CLI volume create $V0 $H0:$B0/${V0}{1..2}
3604df
+TEST $CLI volume create $V0 $H0:$B0/${V0}1
3604df
 TEST $CLI volume start $V0
3604df
 
3604df
 ## Enable bitrot for volume $V0
3604df
@@ -26,11 +26,27 @@ TEST $CLI volume bitrot $V0 scrub-frequency hourly
3604df
 ## Setting scrubber throttle value lazy
3604df
 TEST $CLI volume bitrot $V0 scrub-throttle lazy
3604df
 
3604df
-
3604df
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Active' scrub_status $V0 'State of scrub'
3604df
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'lazy'   scrub_status $V0 'Scrub impact'
3604df
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'hourly' scrub_status $V0 'Scrub frequency'
3604df
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT '/var/log/glusterfs/bitd.log' scrub_status $V0 'Bitrot error log location'
3604df
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT '/var/log/glusterfs/scrub.log' scrub_status $V0 'Scrubber error log location'
3604df
 
3604df
+## Set expiry-timeout to 1 sec
3604df
+TEST $CLI volume set $V0 features.expiry-time 1
3604df
+
3604df
+##Mount $V0
3604df
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
3604df
+
3604df
+#Create sample file
3604df
+TEST `echo "1234" > $M0/FILE1`
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.bit-rot.signature' check_for_xattr 'trusted.bit-rot.signature' "/$B0/${V0}1/FILE1"
3604df
+
3604df
+##Corrupt the file
3604df
+TEST `echo "corrupt" >> /$B0/${V0}1/FILE1`
3604df
+
3604df
+## Ondemand scrub
3604df
+TEST $CLI volume bitrot $V0 scrub ondemand
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.bit-rot.bad-file' check_for_xattr 'trusted.bit-rot.bad-file' "/$B0/${V0}1/FILE1"
3604df
+
3604df
 cleanup;
3604df
diff --git a/tests/volume.rc b/tests/volume.rc
3604df
index 5ea75a5..989538d 100644
3604df
--- a/tests/volume.rc
3604df
+++ b/tests/volume.rc
3604df
@@ -579,6 +579,12 @@ else
3604df
 fi
3604df
 }
3604df
 
3604df
+function check_for_xattr {
3604df
+        local xattr=$1
3604df
+        local filepath=$2
3604df
+        getfattr -n $xattr $filepath 2>/dev/null | grep "$xattr" | cut -f1 -d'='
3604df
+}
3604df
+
3604df
 function get_bitd_count {
3604df
         ps auxww | grep glusterfs | grep bitd.pid | grep -v grep | wc -l
3604df
 }
3604df
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c
3604df
index d50f40a..601dea9 100644
3604df
--- a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c
3604df
+++ b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c
3604df
@@ -860,6 +860,7 @@ br_fsscan_calculate_delta (uint32_t times)
3604df
         return times;
3604df
 }
3604df
 
3604df
+#define BR_SCRUB_ONDEMAND   (1)
3604df
 #define BR_SCRUB_MINUTE     (60)
3604df
 #define BR_SCRUB_HOURLY     (60 * 60)
3604df
 #define BR_SCRUB_DAILY      (1 * 24 * 60 * 60)
3604df
@@ -1037,6 +1038,53 @@ br_fsscan_reschedule (xlator_t *this)
3604df
         return 0;
3604df
 }
3604df
 
3604df
+int32_t
3604df
+br_fsscan_ondemand (xlator_t *this)
3604df
+{
3604df
+        int32_t             ret     = 0;
3604df
+        uint32_t            timo    = 0;
3604df
+        char timestr[1024]          = {0,};
3604df
+        struct timeval      now     = {0,};
3604df
+        br_private_t       *priv    = NULL;
3604df
+        struct br_scrubber *fsscrub = NULL;
3604df
+        struct br_monitor  *scrub_monitor = NULL;
3604df
+
3604df
+        priv = this->private;
3604df
+        fsscrub = &priv->fsscrub;
3604df
+        scrub_monitor = &priv->scrub_monitor;
3604df
+
3604df
+        if (!fsscrub->frequency_reconf)
3604df
+                return 0;
3604df
+
3604df
+        (void) gettimeofday (&now, NULL);
3604df
+
3604df
+        timo = BR_SCRUB_ONDEMAND;
3604df
+
3604df
+        gf_time_fmt (timestr, sizeof (timestr),
3604df
+                     (now.tv_sec + timo), gf_timefmt_FT);
3604df
+
3604df
+        pthread_mutex_lock (&scrub_monitor->donelock);
3604df
+        {
3604df
+                scrub_monitor->done = _gf_false;
3604df
+        }
3604df
+        pthread_mutex_unlock (&scrub_monitor->donelock);
3604df
+
3604df
+        ret = gf_tw_mod_timer_pending (priv->timer_wheel, scrub_monitor->timer,
3604df
+                                       timo);
3604df
+        if (ret == 0)
3604df
+                gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO,
3604df
+                        "Scrubber is currently running and would be "
3604df
+                        "rescheduled after completion");
3604df
+        else {
3604df
+                _br_monitor_set_scrub_state (scrub_monitor,
3604df
+                                             BR_SCRUB_STATE_PENDING);
3604df
+                gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO,
3604df
+                        "Ondemand Scrubbing scheduled to run at %s", timestr);
3604df
+        }
3604df
+
3604df
+        return 0;
3604df
+}
3604df
+
3604df
 #define BR_SCRUB_THREAD_SCALE_LAZY       0
3604df
 #define BR_SCRUB_THREAD_SCALE_NORMAL     0.4
3604df
 #define BR_SCRUB_THREAD_SCALE_AGGRESSIVE 1.0
3604df
@@ -1864,7 +1912,7 @@ br_monitor_thread (void *arg)
3604df
         /* this needs to be serialized with reconfigure() */
3604df
         pthread_mutex_lock (&priv->lock);
3604df
         {
3604df
-                ret = br_scrub_state_machine (this);
3604df
+                ret = br_scrub_state_machine (this, _gf_false);
3604df
         }
3604df
         pthread_mutex_unlock (&priv->lock);
3604df
         if (ret) {
3604df
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.h b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.h
3604df
index 6316906..8cc88ec 100644
3604df
--- a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.h
3604df
+++ b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.h
3604df
@@ -20,6 +20,7 @@ int32_t br_fsscan_schedule (xlator_t *);
3604df
 int32_t br_fsscan_reschedule (xlator_t *);
3604df
 int32_t br_fsscan_activate (xlator_t *);
3604df
 int32_t br_fsscan_deactivate (xlator_t *);
3604df
+int32_t br_fsscan_ondemand (xlator_t *);
3604df
 
3604df
 int32_t br_scrubber_handle_options (xlator_t *, br_private_t *, dict_t *);
3604df
 
3604df
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot-ssm.c b/xlators/features/bit-rot/src/bitd/bit-rot-ssm.c
3604df
index d304fc8..af887a1 100644
3604df
--- a/xlators/features/bit-rot/src/bitd/bit-rot-ssm.c
3604df
+++ b/xlators/features/bit-rot/src/bitd/bit-rot-ssm.c
3604df
@@ -84,16 +84,22 @@ br_scrub_ssm_state_stall (xlator_t *this)
3604df
 
3604df
 static br_scrub_ssm_call *
3604df
 br_scrub_ssm[BR_SCRUB_MAXSTATES][BR_SCRUB_MAXEVENTS] = {
3604df
-        {br_fsscan_schedule, br_scrub_ssm_state_ipause},    /* INACTIVE */
3604df
-        {br_fsscan_reschedule, br_fsscan_deactivate},       /* PENDING  */
3604df
-        {br_scrub_ssm_noop, br_scrub_ssm_state_stall},      /* ACTIVE   */
3604df
-        {br_fsscan_activate, br_scrub_ssm_noop},            /* PAUSED   */
3604df
-        {br_fsscan_schedule, br_scrub_ssm_noop},            /* IPAUSED  */
3604df
-        {br_scrub_ssm_state_active, br_scrub_ssm_noop},     /* STALLED  */
3604df
+        /* INACTIVE */
3604df
+        {br_fsscan_schedule, br_scrub_ssm_state_ipause, br_scrub_ssm_noop},
3604df
+        /* PENDING  */
3604df
+        {br_fsscan_reschedule, br_fsscan_deactivate, br_fsscan_ondemand},
3604df
+        /* ACTIVE   */
3604df
+        {br_scrub_ssm_noop, br_scrub_ssm_state_stall, br_scrub_ssm_noop},
3604df
+        /* PAUSED   */
3604df
+        {br_fsscan_activate, br_scrub_ssm_noop, br_scrub_ssm_noop},
3604df
+        /* IPAUSED  */
3604df
+        {br_fsscan_schedule, br_scrub_ssm_noop, br_scrub_ssm_noop},
3604df
+        /* STALLED  */
3604df
+        {br_scrub_ssm_state_active, br_scrub_ssm_noop, br_scrub_ssm_noop},
3604df
 };
3604df
 
3604df
 int32_t
3604df
-br_scrub_state_machine (xlator_t *this)
3604df
+br_scrub_state_machine (xlator_t *this, gf_boolean_t scrub_ondemand)
3604df
 {
3604df
         br_private_t       *priv      = NULL;
3604df
         br_scrub_ssm_call  *call      = NULL;
3604df
@@ -107,7 +113,10 @@ br_scrub_state_machine (xlator_t *this)
3604df
         scrub_monitor = &priv->scrub_monitor;
3604df
 
3604df
         currstate = scrub_monitor->state;
3604df
-        event = _br_child_get_scrub_event (fsscrub);
3604df
+        if (scrub_ondemand)
3604df
+                event = BR_SCRUB_EVENT_ONDEMAND;
3604df
+        else
3604df
+                event = _br_child_get_scrub_event (fsscrub);
3604df
 
3604df
         call = br_scrub_ssm[currstate][event];
3604df
         return call (this);
3604df
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot-ssm.h b/xlators/features/bit-rot/src/bitd/bit-rot-ssm.h
3604df
index 936ee4d..8609477 100644
3604df
--- a/xlators/features/bit-rot/src/bitd/bit-rot-ssm.h
3604df
+++ b/xlators/features/bit-rot/src/bitd/bit-rot-ssm.h
3604df
@@ -26,11 +26,12 @@ typedef enum br_scrub_state {
3604df
 typedef enum br_scrub_event {
3604df
         BR_SCRUB_EVENT_SCHEDULE = 0,
3604df
         BR_SCRUB_EVENT_PAUSE,
3604df
+        BR_SCRUB_EVENT_ONDEMAND,
3604df
         BR_SCRUB_MAXEVENTS,
3604df
 } br_scrub_event_t;
3604df
 
3604df
 struct br_monitor;
3604df
 
3604df
-int32_t br_scrub_state_machine (xlator_t *);
3604df
+int32_t br_scrub_state_machine (xlator_t *, gf_boolean_t);
3604df
 
3604df
 #endif /* __BIT_ROT_SSM_H__ */
3604df
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot.c b/xlators/features/bit-rot/src/bitd/bit-rot.c
3604df
index 174af2b..ab32925 100644
3604df
--- a/xlators/features/bit-rot/src/bitd/bit-rot.c
3604df
+++ b/xlators/features/bit-rot/src/bitd/bit-rot.c
3604df
@@ -1534,7 +1534,6 @@ _br_qchild_event (xlator_t *this, br_child_t *child, br_child_handler *call)
3604df
 int
3604df
 br_scrubber_status_get (xlator_t *this, dict_t **dict)
3604df
 {
3604df
-
3604df
         int                    ret          = -1;
3604df
         br_private_t          *priv         = NULL;
3604df
         struct br_scrub_stats *scrub_stats  = NULL;
3604df
@@ -1600,9 +1599,11 @@ notify (xlator_t *this, int32_t event, void *data, ...)
3604df
         br_private_t *priv   = NULL;
3604df
         dict_t       *output = NULL;
3604df
         va_list       ap;
3604df
+        struct br_monitor  *scrub_monitor = NULL;
3604df
 
3604df
         subvol = (xlator_t *)data;
3604df
         priv = this->private;
3604df
+        scrub_monitor = &priv->scrub_monitor;
3604df
 
3604df
         gf_msg_trace (this->name, 0, "Notification received: %d", event);
3604df
 
3604df
@@ -1676,6 +1677,30 @@ notify (xlator_t *this, int32_t event, void *data, ...)
3604df
                 ret = br_scrubber_status_get (this, &output);
3604df
                 gf_msg_debug (this->name, 0, "returning %d", ret);
3604df
                 break;
3604df
+
3604df
+        case GF_EVENT_SCRUB_ONDEMAND:
3604df
+                gf_log (this->name, GF_LOG_INFO, "BitRot scrub ondemand "
3604df
+                              "called");
3604df
+
3604df
+                if (scrub_monitor->state != BR_SCRUB_STATE_PENDING)
3604df
+                        return -2;
3604df
+
3604df
+                /* Needs synchronization with reconfigure thread */
3604df
+                pthread_mutex_lock (&priv->lock);
3604df
+                {
3604df
+                        ret = br_scrub_state_machine (this, _gf_true);
3604df
+                }
3604df
+                pthread_mutex_unlock (&priv->lock);
3604df
+
3604df
+                if (ret) {
3604df
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
3604df
+                                BRB_MSG_RESCHEDULE_SCRUBBER_FAILED,
3604df
+                                "Could not schedule ondemand scrubbing. "
3604df
+                                "Scrubbing will continue according to "
3604df
+                                "old frequency.");
3604df
+                }
3604df
+                gf_msg_debug (this->name, 0, "returning %d", ret);
3604df
+                break;
3604df
         default:
3604df
                 default_notify (this, event, data);
3604df
         }
3604df
@@ -2027,7 +2052,7 @@ br_reconfigure_monitor (xlator_t *this)
3604df
 {
3604df
         int32_t ret = 0;
3604df
 
3604df
-        ret = br_scrub_state_machine (this);
3604df
+        ret = br_scrub_state_machine (this, _gf_false);
3604df
         if (ret) {
3604df
                 gf_msg (this->name, GF_LOG_ERROR, 0,
3604df
                         BRB_MSG_RESCHEDULE_SCRUBBER_FAILED,
3604df
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot.h b/xlators/features/bit-rot/src/bitd/bit-rot.h
3604df
index 8e92670..a729f81 100644
3604df
--- a/xlators/features/bit-rot/src/bitd/bit-rot.h
3604df
+++ b/xlators/features/bit-rot/src/bitd/bit-rot.h
3604df
@@ -297,7 +297,7 @@ static inline br_scrub_event_t
3604df
 _br_child_get_scrub_event (struct br_scrubber *fsscrub)
3604df
 {
3604df
         return (fsscrub->frequency == BR_FSSCRUB_FREQ_STALLED)
3604df
-                ? BR_SCRUB_EVENT_PAUSE : BR_SCRUB_EVENT_SCHEDULE;
3604df
+             ? BR_SCRUB_EVENT_PAUSE : BR_SCRUB_EVENT_SCHEDULE;
3604df
 }
3604df
 
3604df
 int32_t
3604df
diff --git a/xlators/mgmt/glusterd/src/glusterd-bitrot.c b/xlators/mgmt/glusterd/src/glusterd-bitrot.c
3604df
index 6e91106..8c5ddfd 100644
3604df
--- a/xlators/mgmt/glusterd/src/glusterd-bitrot.c
3604df
+++ b/xlators/mgmt/glusterd/src/glusterd-bitrot.c
3604df
@@ -138,6 +138,34 @@ __glusterd_handle_bitrot (rpcsvc_request_t *req)
3604df
                 }
3604df
         }
3604df
 
3604df
+        if (type == GF_BITROT_CMD_SCRUB_ONDEMAND) {
3604df
+                /* Backward compatibility handling for scrub status command*/
3604df
+                if (conf->op_version < GD_OP_VERSION_3_9_0) {
3604df
+                        snprintf (msg, sizeof (msg), "Cannot execute command. "
3604df
+                                  "The cluster is operating at version %d. "
3604df
+                                  "Bitrot scrub ondemand command unavailable in "
3604df
+                                  "this version", conf->op_version);
3604df
+                        ret = -1;
3604df
+                        goto out;
3604df
+                }
3604df
+
3604df
+                ret = dict_get_str (dict, "scrub-value", &scrub);
3604df
+                if (ret) {
3604df
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
3604df
+                                GD_MSG_DICT_GET_FAILED,
3604df
+                                "Failed to get scrub value.");
3604df
+                        ret = -1;
3604df
+                        goto out;
3604df
+                }
3604df
+
3604df
+                if (!strncmp (scrub, "ondemand", strlen ("ondemand"))) {
3604df
+                        ret = glusterd_op_begin_synctask (req,
3604df
+                                                          GD_OP_SCRUB_ONDEMAND,
3604df
+                                                          dict);
3604df
+                        goto out;
3604df
+                }
3604df
+        }
3604df
+
3604df
         ret = glusterd_op_begin_synctask (req, GD_OP_BITROT, dict);
3604df
 
3604df
 out:
3604df
@@ -572,6 +600,7 @@ glusterd_op_bitrot (dict_t *dict, char **op_errstr, dict_t *rsp_dict)
3604df
                 if (ret)
3604df
                         goto out;
3604df
         case GF_BITROT_CMD_SCRUB_STATUS:
3604df
+        case GF_BITROT_CMD_SCRUB_ONDEMAND:
3604df
                 break;
3604df
 
3604df
         default:
3604df
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
3604df
index 9194077..409a205 100644
3604df
--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c
3604df
+++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
3604df
@@ -714,6 +714,7 @@ glusterd_node_op_build_payload (glusterd_op_t op, gd1_mgmt_brick_op_req **req,
3604df
                 break;
3604df
 
3604df
         case GD_OP_SCRUB_STATUS:
3604df
+        case GD_OP_SCRUB_ONDEMAND:
3604df
                 brick_req = GF_CALLOC (1, sizeof(*brick_req),
3604df
                                        gf_gld_mt_mop_brick_req_t);
3604df
                 if (!brick_req)
3604df
@@ -4113,6 +4114,7 @@ glusterd_op_build_payload (dict_t **req, char **op_errstr, dict_t *op_ctx)
3604df
                 case GD_OP_BARRIER:
3604df
                 case GD_OP_BITROT:
3604df
                 case GD_OP_SCRUB_STATUS:
3604df
+                case GD_OP_SCRUB_ONDEMAND:
3604df
                         {
3604df
                                 do_common = _gf_true;
3604df
                         }
3604df
@@ -4707,6 +4709,7 @@ glusterd_op_modify_op_ctx (glusterd_op_t op, void *ctx)
3604df
          */
3604df
         case GD_OP_DEFRAG_BRICK_VOLUME:
3604df
         case GD_OP_SCRUB_STATUS:
3604df
+        case GD_OP_SCRUB_ONDEMAND:
3604df
                 ret = dict_get_int32 (op_ctx, "count", &count);
3604df
                 if (ret) {
3604df
                         gf_msg_debug (this->name, 0,
3604df
@@ -4754,10 +4757,11 @@ glusterd_op_modify_op_ctx (glusterd_op_t op, void *ctx)
3604df
                                 GD_MSG_CONVERSION_FAILED,
3604df
                                 "Failed uuid to hostname conversion");
3604df
 
3604df
-                /* Since Both rebalance and bitrot scrub status are going to
3604df
-                 * use same code path till here, we should break in case
3604df
-                 * of scrub status */
3604df
-                if (op == GD_OP_SCRUB_STATUS) {
3604df
+                /* Since Both rebalance and bitrot scrub status/ondemand
3604df
+                 * are going to use same code path till here, we should
3604df
+                 * break in case of scrub status.
3604df
+                 */
3604df
+                if (op == GD_OP_SCRUB_STATUS || op == GD_OP_SCRUB_ONDEMAND) {
3604df
                         break;
3604df
                 }
3604df
 
3604df
@@ -5424,6 +5428,7 @@ glusterd_need_brick_op (glusterd_op_t op)
3604df
         case GD_OP_DEFRAG_BRICK_VOLUME:
3604df
         case GD_OP_HEAL_VOLUME:
3604df
         case GD_OP_SCRUB_STATUS:
3604df
+        case GD_OP_SCRUB_ONDEMAND:
3604df
                 ret = _gf_true;
3604df
                 break;
3604df
         default:
3604df
@@ -5695,6 +5700,7 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr,
3604df
 
3604df
                 case GD_OP_BITROT:
3604df
                 case GD_OP_SCRUB_STATUS:
3604df
+                case GD_OP_SCRUB_ONDEMAND:
3604df
                         ret = glusterd_op_stage_bitrot (dict, op_errstr,
3604df
                                                         rsp_dict);
3604df
                         break;
3604df
@@ -5820,6 +5826,7 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr,
3604df
 
3604df
                 case GD_OP_BITROT:
3604df
                 case GD_OP_SCRUB_STATUS:
3604df
+                case GD_OP_SCRUB_ONDEMAND:
3604df
                         ret = glusterd_op_bitrot (dict, op_errstr, rsp_dict);
3604df
                         break;
3604df
 
3604df
@@ -7270,6 +7277,7 @@ glusterd_op_bricks_select (glusterd_op_t op, dict_t *dict, char **op_errstr,
3604df
                 ret = glusterd_bricks_select_snap (dict, op_errstr, selected);
3604df
                 break;
3604df
         case GD_OP_SCRUB_STATUS:
3604df
+        case GD_OP_SCRUB_ONDEMAND:
3604df
                 ret = glusterd_bricks_select_scrub (dict, op_errstr, selected);
3604df
                 break;
3604df
         default:
3604df
diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c
3604df
index d37a8f2..c87a6da 100644
3604df
--- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c
3604df
+++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c
3604df
@@ -143,6 +143,7 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret,
3604df
         case GD_OP_BARRIER:
3604df
         case GD_OP_BITROT:
3604df
         case GD_OP_SCRUB_STATUS:
3604df
+        case GD_OP_SCRUB_ONDEMAND:
3604df
         {
3604df
                 /*nothing specific to be done*/
3604df
                 break;
3604df
diff --git a/xlators/mgmt/glusterd/src/glusterd-syncop.c b/xlators/mgmt/glusterd/src/glusterd-syncop.c
3604df
index a233f34..64a0aeb 100644
3604df
--- a/xlators/mgmt/glusterd/src/glusterd-syncop.c
3604df
+++ b/xlators/mgmt/glusterd/src/glusterd-syncop.c
3604df
@@ -309,6 +309,10 @@ glusterd_syncop_aggr_rsp_dict (glusterd_op_t op, dict_t *aggr, dict_t *rsp)
3604df
         case GD_OP_SCRUB_STATUS:
3604df
                 ret = glusterd_volume_bitrot_scrub_use_rsp_dict (aggr, rsp);
3604df
         break;
3604df
+
3604df
+        case GD_OP_SCRUB_ONDEMAND:
3604df
+        break;
3604df
+
3604df
         default:
3604df
         break;
3604df
         }
3604df
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
3604df
index eec1adf..3aaedbc 100644
3604df
--- a/xlators/mgmt/glusterd/src/glusterd.h
3604df
+++ b/xlators/mgmt/glusterd/src/glusterd.h
3604df
@@ -116,6 +116,7 @@ typedef enum glusterd_op_ {
3604df
         GD_OP_DETACH_TIER,
3604df
         GD_OP_TIER_MIGRATE,
3604df
         GD_OP_SCRUB_STATUS,
3604df
+        GD_OP_SCRUB_ONDEMAND,
3604df
         GD_OP_MAX,
3604df
 } glusterd_op_t;
3604df
 
3604df
-- 
3604df
1.7.1
3604df