Blob Blame History Raw
From 922a57492cd16e6c2a1105b91ff3c53f50dfde09 Mon Sep 17 00:00:00 2001
From: Kotresh HR <khiremat@redhat.com>
Date: Fri, 5 Aug 2016 09:03:22 +0530
Subject: [PATCH 27/86] feature/bitrot: Ondemand scrub option for bitrot

The bitrot scrubber takes 'hourly/daily/biweekly/monthly'
as the values for 'scrub-frequency'. There is no way
to schedule the scrubbing when the admin wants it.

Ondemand scrubbing brings in the new option 'ondemand'
with which the admin can start scrubbing ondemand.
It starts the scrubbing immediately.

Ondemand scrubbing is successful only if the scrubber
is in 'Active (Idle)' (waiting for it's next frequency
cycle to start scrubbing). It is not entertained when
the scrubber is in 'Paused' or already running.

Here is the command line syntax.

gluster volume bitrot <vol name> scrub ondemand

>Change-Id: I84c28904367eed827a7dae8d6a535c14b28e9f4d
>BUG: 1366195
>Signed-off-by: Kotresh HR <khiremat@redhat.com>
>Reviewed-on: http://review.gluster.org/15111
>Smoke: Gluster Build System <jenkins@build.gluster.org>
>NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
>CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
>Reviewed-by: Venky Shankar <vshankar@redhat.com>

Change-Id: I84c28904367eed827a7dae8d6a535c14b28e9f4d
BUG: 1359588
Signed-off-by: Kotresh HR <khiremat@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/84665
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
Tested-by: Atin Mukherjee <amukherj@redhat.com>
---
 cli/src/cli-cmd-parser.c                          |    5 ++-
 cli/src/cli-cmd-volume.c                          |    2 +-
 doc/gluster.8                                     |    6 +--
 glusterfsd/src/glusterfsd-messages.h              |    4 +-
 glusterfsd/src/glusterfsd-mgmt.c                  |   24 +++++++++-
 libglusterfs/src/globals.h                        |    4 +-
 rpc/xdr/src/cli1-xdr.x                            |    1 +
 rpc/xdr/src/glusterfs-fops.x                      |    1 +
 tests/bitrot/bug-1207627-bitrot-scrub-status.t    |   20 +++++++-
 tests/volume.rc                                   |    6 +++
 xlators/features/bit-rot/src/bitd/bit-rot-scrub.c |   50 ++++++++++++++++++++-
 xlators/features/bit-rot/src/bitd/bit-rot-scrub.h |    1 +
 xlators/features/bit-rot/src/bitd/bit-rot-ssm.c   |   25 +++++++---
 xlators/features/bit-rot/src/bitd/bit-rot-ssm.h   |    3 +-
 xlators/features/bit-rot/src/bitd/bit-rot.c       |   29 +++++++++++-
 xlators/features/bit-rot/src/bitd/bit-rot.h       |    2 +-
 xlators/mgmt/glusterd/src/glusterd-bitrot.c       |   29 ++++++++++++
 xlators/mgmt/glusterd/src/glusterd-op-sm.c        |   16 +++++--
 xlators/mgmt/glusterd/src/glusterd-rpc-ops.c      |    1 +
 xlators/mgmt/glusterd/src/glusterd-syncop.c       |    4 ++
 xlators/mgmt/glusterd/src/glusterd.h              |    1 +
 21 files changed, 205 insertions(+), 29 deletions(-)

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