Patchwork [BUG:1307] 'gluster volume rebalance' related fixes

login
register
Submitter Amar Tumballi
Date 2010-08-09 11:08:46
Message ID <20100809110846.GA10267@gluster.com>
Download mbox | patch
Permalink /patch/4025/
State Accepted
Delegated to: Anand Avati
Headers show

Comments

Amar Tumballi - 2010-08-09 11:08:46
Signed-off-by: Amar Tumballi <amar@gluster.com>
---
 cli/src/cli-cmd-volume.c                       |   54 +++-
 cli/src/cli.h                                  |    1 +
 cli/src/cli3_1-cops.c                          |   78 +++++--
 extras/glusterfs-defrag.in                     |    7 +-
 rpc/xdr/src/cli1-xdr.c                         |    8 +
 rpc/xdr/src/cli1-xdr.h                         |    4 +
 rpc/xdr/src/cli1.h                             |    4 +
 xlators/mgmt/glusterd/src/glusterd-handler.c   |  309 +++++++++++++++++++++---
 xlators/mgmt/glusterd/src/glusterd-mem-types.h |    1 +
 xlators/mgmt/glusterd/src/glusterd.h           |   37 +++
 xlators/mgmt/glusterd/src/glusterd3_1-mops.c   |    2 +-
 11 files changed, 440 insertions(+), 65 deletions(-)

Patch

diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
index 22844c5..63c1547 100644
--- a/cli/src/cli-cmd-volume.c
+++ b/cli/src/cli-cmd-volume.c
@@ -219,8 +219,7 @@  cli_cmd_volume_rename_cbk (struct cli_state *state, struct cli_cmd_word *word,
                 goto out;
 
         dict = dict_new ();
-
-        if (dict)
+        if (!dict)
                 goto out;
 
         GF_ASSERT (words[2]);
@@ -254,34 +253,57 @@  out:
         return ret;
 }
 
+void
+cli_cmd_volume_defrag_usage ()
+{
+        cli_out ("Usage: volume rebalance <volname> <start|stop|status>");
+}
 
 int
 cli_cmd_volume_defrag_cbk (struct cli_state *state, struct cli_cmd_word *word,
                            const char **words, int wordcount)
 {
-        int                     ret = -1;
-        rpc_clnt_procedure_t    *proc = NULL;
-        call_frame_t            *frame = NULL;
-        char                    *volname = NULL;
-
+        int                   ret     = -1;
+        rpc_clnt_procedure_t *proc    = NULL;
+        call_frame_t         *frame   = NULL;
+        dict_t               *dict = NULL;
 
         frame = create_frame (THIS, THIS->ctx->pool);
         if (!frame)
                 goto out;
 
+        dict = dict_new ();
+        if (!dict)
+                goto out;
+
+        GF_ASSERT (words[2]);
+
+        if (!(words[3])) {
+                cli_cmd_volume_defrag_usage();
+                goto out;
+        }
         //TODO: Build validation here
-        volname = (char *)words[2];
-        GF_ASSERT (volname);
+        ret = dict_set_str (dict, "volname", (char *)words[2]);
+        if (ret)
+                goto out;
+
+        ret = dict_set_str (dict, "command", (char *)words[3]);
+        if (ret)
+                goto out;
 
         proc = &cli_rpc_prog->proctable[GF1_CLI_DEFRAG_VOLUME];
 
         if (proc->fn) {
-                ret = proc->fn (frame, THIS, volname);
+                ret = proc->fn (frame, THIS, dict);
         }
 
 out:
-        if (!proc && ret)
-                cli_out ("Defrag of Volume %s failed", volname);
+        if (!proc && ret) {
+                if (dict)
+                        dict_destroy (dict);
+
+                cli_out ("Defrag of Volume %s failed", (char *)words[2]);
+        }
 
         return 0;
 }
@@ -438,7 +460,13 @@  struct cli_cmd volume_cmds[] = {
         { "volume remove-brick <VOLNAME> [(replica <COUNT>)|(stripe <COUNT>)] <BRICK> ...",
           cli_cmd_volume_remove_brick_cbk },
 
-        { "volume defrag <VOLNAME>",
+        { "volume rebalance <VOLNAME> start",
+          cli_cmd_volume_defrag_cbk },
+
+        { "volume rebalance <VOLNAME> stop",
+          cli_cmd_volume_defrag_cbk },
+
+        { "volume rebalance <VOLNAME> status",
           cli_cmd_volume_defrag_cbk },
 
         { "volume replace-brick <VOLNAME> (<BRICK> <NEW-BRICK>)|pause|abort|start|status",
diff --git a/cli/src/cli.h b/cli/src/cli.h
index 7b2de66..36ac721 100644
--- a/cli/src/cli.h
+++ b/cli/src/cli.h
@@ -123,6 +123,7 @@  struct cli_local {
 
                 struct {
                         char    *volname;
+                        int      cmd;
                 } defrag_vol;
 
                 struct {
diff --git a/cli/src/cli3_1-cops.c b/cli/src/cli3_1-cops.c
index 929f490..e6d609f 100644
--- a/cli/src/cli3_1-cops.c
+++ b/cli/src/cli3_1-cops.c
@@ -499,11 +499,12 @@  int
 gf_cli3_1_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov,
                              int count, void *myframe)
 {
-        gf1_cli_defrag_vol_rsp  rsp   = {0,};
-        int                     ret   = 0;
-        cli_local_t             *local = NULL;
-        char                    *volname = NULL;
-        call_frame_t            *frame = NULL;
+        gf1_cli_defrag_vol_rsp  rsp     = {0,};
+        cli_local_t            *local   = NULL;
+        char                   *volname = NULL;
+        call_frame_t           *frame   = NULL;
+        int                     cmd     = 0;
+        int                     ret     = 0;
 
         if (-1 == req->rpc_status) {
                 goto out;
@@ -520,12 +521,34 @@  gf_cli3_1_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov,
         if (frame)
                 local = frame->local;
 
-        if (local)
-                volname = local->u.start_vol.volname;
+        if (local) {
+                volname = local->u.defrag_vol.volname;
+                cmd = local->u.defrag_vol.cmd;
+        }
+        if (cmd == GF_DEFRAG_CMD_START) {
+                cli_out ("starting defrag on volume %s has been %s", volname,
+                         (rsp.op_ret) ? "unsuccessful": "successful");
+        }
+        if (cmd == GF_DEFRAG_CMD_STOP) {
+                if (rsp.op_ret == -1)
+                        cli_out ("'defrag volume %s stop' failed", volname);
+                else
+                        cli_out ("stopped defrag process of volume %s \n"
+                                 "(after rebalancing %"PRId64" files totaling "
+                                 "%"PRId64" bytes)", volname, rsp.files, rsp.size);
+        }
+        if (cmd == GF_DEFRAG_CMD_STATUS) {
+                if (rsp.op_ret == -1)
+                        cli_out ("failed to get the status of defrag process");
+                else {
+                        cli_out ("rebalanced %"PRId64" files of size %"PRId64
+                                 " (total files scanned %"PRId64")",
+                                 rsp.files, rsp.size, rsp.lookedup_files);
+                }
+        }
 
-        gf_log ("cli", GF_LOG_NORMAL, "Received resp to probe");
-        cli_out ("Defrag of volume %s has been %s", volname,
-                (rsp.op_ret) ? "unsuccessful": "successful");
+        if (volname)
+                GF_FREE (volname);
 
         ret = rsp.op_ret;
 
@@ -1073,23 +1096,48 @@  int32_t
 gf_cli3_1_defrag_volume (call_frame_t *frame, xlator_t *this,
                          void *data)
 {
-        gf1_cli_defrag_vol_req   req = {0,};
-        int                    ret = 0;
-        cli_local_t            *local = NULL;
+        gf1_cli_defrag_vol_req  req     = {0,};
+        int                     ret     = 0;
+        cli_local_t            *local   = NULL;
+        char                   *volname = NULL;
+        char                   *cmd_str = NULL;
+        dict_t                 *dict    = NULL;
 
         if (!frame || !this ||  !data) {
                 ret = -1;
                 goto out;
         }
 
+        dict = data;
+
+        ret = dict_get_str (dict, "volname", &volname);
+        if (ret)
+                gf_log ("", GF_LOG_DEBUG, "error");
+
+        ret = dict_get_str (dict, "command", &cmd_str);
+        if (ret) {
+                gf_log ("", GF_LOG_DEBUG, "error");
+                goto out;
+        }
+
+        if (strncasecmp (cmd_str, "start", 6) == 0) {
+                req.cmd = GF_DEFRAG_CMD_START;
+        } else if (strncasecmp (cmd_str, "stop", 5) == 0) {
+                req.cmd = GF_DEFRAG_CMD_STOP;
+        } else if (strncasecmp (cmd_str, "status", 7) == 0) {
+                req.cmd = GF_DEFRAG_CMD_STATUS;
+        }
+
+
         local = cli_local_get ();
 
         if (local) {
-                local->u.defrag_vol.volname = data;
+                local->u.defrag_vol.volname = gf_strdup (volname);
+                local->u.defrag_vol.cmd = req.cmd;
                 frame->local = local;
         }
 
-        req.volname = data;
+        req.volname = volname;
 
         ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
                               GD_MGMT_CLI_DEFRAG_VOLUME, NULL,
diff --git a/extras/glusterfs-defrag.in b/extras/glusterfs-defrag.in
index 8bdaf3d..68a393f 100644
--- a/extras/glusterfs-defrag.in
+++ b/extras/glusterfs-defrag.in
@@ -12,7 +12,10 @@ 
 
 set -e;
 
-added_bricks="node1:/gfs/export1"
+#
+#added_bricks="node1:/gfs/export1"
+#
+added_bricks=""
 
 CP="cp"
 MV="mv"
@@ -53,6 +56,8 @@  relocate_file()
         return;
     fi
 
+    size=$(stat -c '%s' "$path");
+
     # If there are some entries in added_bricks, then check
     # if the link file is present on those nodes, if not,
     # set flag=1, so full defrag happens
diff --git a/rpc/xdr/src/cli1-xdr.c b/rpc/xdr/src/cli1-xdr.c
index 32e42c2..3dddde1 100644
--- a/rpc/xdr/src/cli1-xdr.c
+++ b/rpc/xdr/src/cli1-xdr.c
@@ -301,6 +301,8 @@  bool_t
 xdr_gf1_cli_defrag_vol_req (XDR *xdrs, gf1_cli_defrag_vol_req *objp)
 {
 
+	 if (!xdr_int (xdrs, &objp->cmd))
+		 return FALSE;
 	 if (!xdr_string (xdrs, &objp->volname, ~0))
 		 return FALSE;
 	return TRUE;
@@ -316,6 +318,12 @@  xdr_gf1_cli_defrag_vol_rsp (XDR *xdrs, gf1_cli_defrag_vol_rsp *objp)
 		 return FALSE;
 	 if (!xdr_string (xdrs, &objp->volname, ~0))
 		 return FALSE;
+	 if (!xdr_u_quad_t (xdrs, &objp->files))
+		 return FALSE;
+	 if (!xdr_u_quad_t (xdrs, &objp->size))
+		 return FALSE;
+	 if (!xdr_u_quad_t (xdrs, &objp->lookedup_files))
+		 return FALSE;
 	return TRUE;
 }
 
diff --git a/rpc/xdr/src/cli1-xdr.h b/rpc/xdr/src/cli1-xdr.h
index 2f71df4..b8ac5ad 100644
--- a/rpc/xdr/src/cli1-xdr.h
+++ b/rpc/xdr/src/cli1-xdr.h
@@ -174,6 +174,7 @@  struct gf1_cli_rename_vol_rsp {
 typedef struct gf1_cli_rename_vol_rsp gf1_cli_rename_vol_rsp;
 
 struct gf1_cli_defrag_vol_req {
+        int   cmd;
 	char *volname;
 };
 typedef struct gf1_cli_defrag_vol_req gf1_cli_defrag_vol_req;
@@ -182,6 +183,9 @@  struct gf1_cli_defrag_vol_rsp {
 	int op_ret;
 	int op_errno;
 	char *volname;
+        u_quad_t files;
+        u_quad_t size;
+        u_quad_t lookedup_files;
 };
 typedef struct gf1_cli_defrag_vol_rsp gf1_cli_defrag_vol_rsp;
 
diff --git a/rpc/xdr/src/cli1.h b/rpc/xdr/src/cli1.h
index 73f9f8d..578b822 100644
--- a/rpc/xdr/src/cli1.h
+++ b/rpc/xdr/src/cli1.h
@@ -25,6 +25,10 @@ 
 
 #include "cli1-xdr.h"
 
+#define GF_DEFRAG_CMD_START   1
+#define GF_DEFRAG_CMD_STOP    2
+#define GF_DEFRAG_CMD_STATUS  3
+
 ssize_t
 gf_xdr_serialize_cli_probe_rsp (struct iovec outmsg, void *rsp);
 
diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c
index a8b334c..ce4c661 100644
--- a/xlators/mgmt/glusterd/src/glusterd-handler.c
+++ b/xlators/mgmt/glusterd/src/glusterd-handler.c
@@ -594,7 +594,203 @@  out:
         return ret;
 }
 
+int
+glusterd_check_and_rebalance (glusterd_volinfo_t *volinfo, char *dir)
+{
+        int                     ret                = -1;
+        int                     dst_fd             = -1;
+        int                     src_fd             = -1;
+        DIR                    *fd                 = NULL;
+        glusterd_defrag_info_t *defrag             = NULL;
+        struct dirent          *entry              = NULL;
+        struct stat             stbuf              = {0,};
+        struct stat             new_stbuf          = {0,};
+        char                    full_path[1024]    = {0,};
+        char                    tmp_filename[1024] = {0,};
+        char                    value[128]         = {0,};
+
+        defrag = volinfo->defrag;
+        if (!defrag)
+                goto out;
+
+        fd = opendir (dir);
+        if (!fd)
+                goto out;
+
+        do {
+                entry = readdir (fd);
+                if (!entry)
+                        break;
+
+                if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, ".."))
+                        continue;
+
+                snprintf (full_path, 1024, "%s/%s", dir, entry->d_name);
+
+                ret = stat (full_path, &stbuf);
+                if (ret == -1)
+                        continue;
+
+                if (S_ISDIR (stbuf.st_mode)) {
+                        //getfattr -n trusted.distribute.fix.layout "$path" ;
+                        getxattr (full_path, "trusted.distribute.fix.layout",
+                                  &value, 128);
+
+                        ret = glusterd_check_and_rebalance (volinfo, full_path);
+                }
+                if (S_ISREG (stbuf.st_mode) && ((stbuf.st_mode & 01000) == 01000)) {
+                        /* TODO: run the defrag */
+                        snprintf (tmp_filename, 1024, "%s/.%s.gfs%zu", dir,
+                                  entry->d_name, stbuf.st_size);
+
+                        dst_fd = creat (tmp_filename, (stbuf.st_mode & ~01000));
+                        if (dst_fd == -1)
+                                continue;
+
+                        src_fd = open (full_path, O_RDONLY);
+                        if (src_fd == -1) {
+                                close (dst_fd);
+                                continue;
+                        }
+
+                        while (1) {
+                                ret = read (src_fd, defrag->databuf, 131072);
+                                if (!ret || (ret < 0)) {
+                                        close (dst_fd);
+                                        close (src_fd);
+                                        break;
+                                }
+                                ret = write (dst_fd, defrag->databuf, ret);
+                                if (ret < 0) {
+                                        close (dst_fd);
+                                        close (src_fd);
+                                        break;
+                                }
+                        }
+
+                        ret = stat (full_path, &new_stbuf);
+                        if (ret < 0)
+                                continue;
+                        if (new_stbuf.st_mtime != stbuf.st_mtime)
+                                continue;
+
+                        ret = rename (tmp_filename, full_path);
+                        if (ret != -1) {
+                                LOCK (&defrag->lock);
+                                {
+                                        defrag->total_files += 1;
+                                        defrag->total_data += stbuf.st_size;
+                                }
+                                UNLOCK (&defrag->lock);
+                        }
+                }
+                ret = 0;
+
+                LOCK (&defrag->lock);
+                {
+                        if (S_ISREG (stbuf.st_mode))
+                                defrag->num_files_lookedup += 1;
+                        if (volinfo->defrag_status == GF_DEFRAG_STATUS_STOPED)
+                                ret = 1;
+                }
+                UNLOCK (&defrag->lock);
+                if (ret)
+                        break;
+
+                /* Write the full 'glusterfs-defrag' here */
+
+        } while (1);
+
+        closedir (fd);
+
+        if (!entry)
+                ret = 0;
+out:
+        return ret;
+}
+
+void *
+glusterd_defrag_start (void *data)
+{
+        glusterd_volinfo_t     *volinfo = data;
+        glusterd_defrag_info_t *defrag  = NULL;
+        char                    cmd_str[1024] = {0,};
+        int                     ret     = -1;
+
+        /* TODO: make it more generic.. */
+        defrag = volinfo->defrag;
+        if (!defrag)
+                goto out;
+
+        ret = glusterd_check_and_rebalance (volinfo, defrag->mount);
+
+        /* TODO: This should run in a thread, and finish the thread when
+           the task is complete. While defrag is running, keep updating
+           files */
+
+        volinfo->defrag_status   = GF_DEFRAG_STATUS_COMPLETE;
+        volinfo->rebalance_files = defrag->total_files;
+        volinfo->rebalance_data  = defrag->total_data;
+        volinfo->lookedup_files  = defrag->num_files_lookedup;
+out:
+        gf_log ("defrag", GF_LOG_NORMAL, "defrag on %s complete",
+                defrag->mount);
+
+        snprintf (cmd_str, 1024, "umount %s", defrag->mount);
+        system (cmd_str);
+        volinfo->defrag = NULL;
+        LOCK_DESTROY (&defrag->lock);
+        GF_FREE (defrag);
+
+        return NULL;
+}
+
+int
+glusterd_defrag_stop (glusterd_volinfo_t *volinfo,
+                      gf1_cli_defrag_vol_rsp *rsp)
+{
+        /* TODO: set a variaeble 'stop_defrag' here, it should be checked
+           in defrag loop */
+        if (!volinfo || !volinfo->defrag)
+                goto out;
+
+        LOCK (&volinfo->defrag->lock);
+        {
+                volinfo->defrag_status = GF_DEFRAG_STATUS_STOPED;
+                rsp->files = volinfo->defrag->total_files;
+                rsp->size = volinfo->defrag->total_data;
+        }
+        UNLOCK (&volinfo->defrag->lock);
 
+        rsp->op_ret = 0;
+out:
+        return 0;
+}
+
+int
+glusterd_defrag_status_get (glusterd_volinfo_t *volinfo,
+                            gf1_cli_defrag_vol_rsp *rsp)
+{
+        if (!volinfo)
+                goto out;
+
+        if (volinfo->defrag) {
+                LOCK (&volinfo->defrag->lock);
+                {
+                        rsp->files = volinfo->defrag->total_files;
+                        rsp->size = volinfo->defrag->total_data;
+                        rsp->lookedup_files = volinfo->defrag->num_files_lookedup;
+                }
+                UNLOCK (&volinfo->defrag->lock);
+        } else {
+                rsp->files = volinfo->rebalance_files;
+                rsp->size  = volinfo->rebalance_data;
+                rsp->lookedup_files = volinfo->lookedup_files;
+        }
+        rsp->op_ret = 0;
+out:
+        return 0;
+}
 
 int
 glusterd_handle_defrag_volume (rpcsvc_request_t *req)
@@ -603,7 +799,9 @@  glusterd_handle_defrag_volume (rpcsvc_request_t *req)
         gf1_cli_defrag_vol_req cli_req       = {0,};
         glusterd_conf_t         *priv = NULL;
         char                   cmd_str[4096] = {0,};
-	 glusterd_volinfo_t      *tmp_volinfo = NULL;
+        glusterd_volinfo_t      *volinfo = NULL;
+        glusterd_defrag_info_t *defrag =  NULL;
+        gf1_cli_defrag_vol_rsp rsp = {0,};
 
         GF_ASSERT (req);
 
@@ -617,46 +815,87 @@  glusterd_handle_defrag_volume (rpcsvc_request_t *req)
         gf_log ("glusterd", GF_LOG_NORMAL, "Received defrag volume on %s",
                 cli_req.volname);
 
-	 if (glusterd_volinfo_find(cli_req.volname, &tmp_volinfo)) {
-		 gf_log ("glusterd", GF_LOG_NORMAL, "Received defrag on invalid"
-			 " volname %s", cli_req.volname);
-		 goto out;
-	 }
- 
-        glusterd_op_set_op (GD_OP_DEFRAG_VOLUME);
+        rsp.volname = cli_req.volname;
+        rsp.op_ret = -1;
+        if (glusterd_volinfo_find(cli_req.volname, &volinfo)) {
+                gf_log ("glusterd", GF_LOG_NORMAL, "Received defrag on invalid"
+                        " volname %s", cli_req.volname);
+                goto out;
+        }
 
-        glusterd_op_set_ctx (GD_OP_DEFRAG_VOLUME, cli_req.volname);
+        if (volinfo->status != GLUSTERD_STATUS_STARTED) {
+                gf_log ("glusterd", GF_LOG_NORMAL, "Received defrag on stopped"
+                        " volname %s", cli_req.volname);
+                goto out;
+        }
 
-        /* TODO: make it more generic.. */
-        /* Create a directory, mount glusterfs over it, start glusterfs-defrag */
-        snprintf (cmd_str, 4096, "mkdir -p %s/mount/%s",
-                  priv->workdir, cli_req.volname);
-        ret = system (cmd_str);
-
-	 if (ret) {
-		   gf_log("glusterd", GF_LOG_DEBUG, "command: %s failed", cmd_str);
-		   goto out;
-	 }
-
-        snprintf (cmd_str, 4096, "glusterfs -f %s/vols/%s/%s-tcp.vol "
-                  "--xlator-option dht0.unhashed-sticky-bit=yes "
-                  "--xlator-option dht0.lookup-unhashed=on %s/mount/%s",
-                  priv->workdir, cli_req.volname, cli_req.volname,
-                  priv->workdir, cli_req.volname);
-        ret = system (cmd_str);
+        switch (cli_req.cmd) {
+        case GF_DEFRAG_CMD_START:
+        {
+                if (volinfo->defrag) {
+                        gf_log ("glusterd", GF_LOG_DEBUG,
+                                "defrag on volume %s already started",
+                                cli_req.volname);
+                        goto out;
+                }
 
-        if (ret) {
-                  gf_log("glusterd", GF_LOG_DEBUG, "command: %s failed", cmd_str);
-                  goto out;
-        }
+                volinfo->defrag = GF_CALLOC (1, sizeof (glusterd_defrag_info_t),
+                                             gf_gld_mt_defrag_info);
+                if (!volinfo->defrag)
+                        goto out;
+
+                defrag = volinfo->defrag;
+
+                LOCK_INIT (&defrag->lock);
+                snprintf (defrag->mount, 1024, "%s/mount/%s",
+                          priv->workdir, cli_req.volname);
+                /* Create a directory, mount glusterfs over it, start glusterfs-defrag */
+                snprintf (cmd_str, 4096, "mkdir -p %s", defrag->mount);
+                ret = system (cmd_str);
+
+                if (ret) {
+                        gf_log("glusterd", GF_LOG_DEBUG, "command: %s failed", cmd_str);
+                        goto out;
+                }
 
-        snprintf (cmd_str, 4096, "glusterfs-defrag %s/mount/%s",
-                  priv->workdir, cli_req.volname);
-        ret = system (cmd_str);
+                snprintf (cmd_str, 4096, "glusterfs -f %s/vols/%s/%s-tcp.vol "
+                          "--xlator-option dht0.unhashed-sticky-bit=yes "
+                          "--xlator-option dht0.lookup-unhashed=yes "
+                          "--volume-name quickread %s",
+                          priv->workdir, cli_req.volname, cli_req.volname,
+                          defrag->mount);
+                ret = system (cmd_str);
 
-	 if (ret)
-		   gf_log("glusterd", GF_LOG_DEBUG, "command: %s failed",cmd_str);
+                if (ret) {
+                        gf_log("glusterd", GF_LOG_DEBUG, "command: %s failed", cmd_str);
+                        goto out;
+                }
+                rsp.op_ret = 0;
+                ret = pthread_create (&defrag->th, NULL, glusterd_defrag_start,
+                                      volinfo);
+                if (ret) {
+                        snprintf (cmd_str, 1024, "umount -l %s", defrag->mount);
+                        ret = system (cmd_str);
+                        rsp.op_ret = -1;
+                }
+                break;
+        }
+        case GF_DEFRAG_CMD_STOP:
+                ret = glusterd_defrag_stop (volinfo, &rsp);
+                break;
+        case GF_DEFRAG_CMD_STATUS:
+                ret = glusterd_defrag_status_get (volinfo, &rsp);
+                break;
+        default:
+                break;
+        }
+        if (ret)
+                gf_log("glusterd", GF_LOG_DEBUG, "command: %s failed",cmd_str);
 out:
+
+        ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL,
+                                     gf_xdr_serialize_cli_defrag_vol_rsp);
+
         return ret;
 }
 
diff --git a/xlators/mgmt/glusterd/src/glusterd-mem-types.h b/xlators/mgmt/glusterd/src/glusterd-mem-types.h
index 8df9416..a5d7c4f 100644
--- a/xlators/mgmt/glusterd/src/glusterd-mem-types.h
+++ b/xlators/mgmt/glusterd/src/glusterd-mem-types.h
@@ -54,6 +54,7 @@  enum gf_gld_mem_types_ {
         gf_gld_mt_ifreq,
         gf_gld_mt_store_handle_t,
         gf_gld_mt_store_iter_t,
+        gf_gld_mt_defrag_info,
         gf_gld_mt_end
 };
 #endif
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
index 368c0a6..dce3275 100644
--- a/xlators/mgmt/glusterd/src/glusterd.h
+++ b/xlators/mgmt/glusterd/src/glusterd.h
@@ -25,7 +25,10 @@ 
 #include "config.h"
 #endif
 
+#include <sys/types.h>
+#include <dirent.h>
 #include <pthread.h>
+
 #include "uuid.h"
 
 #include "rpc-clnt.h"
@@ -84,6 +87,33 @@  struct glusterd_brickinfo {
 
 typedef struct glusterd_brickinfo glusterd_brickinfo_t;
 
+struct gf_defrag_brickinfo_ {
+        char *name;
+        int   files;
+        int   size;
+};
+
+typedef enum gf_defrag_status_ {
+        GF_DEFRAG_STATUS_NOT_STARTED,
+        GF_DEFRAG_STATUS_STARTED,
+        GF_DEFRAG_STATUS_STOPED,
+        GF_DEFRAG_STATUS_COMPLETE,
+} gf_defrag_status_t;
+
+struct glusterd_defrag_info_ {
+        uint64_t                     total_files;
+        uint64_t                     total_data;
+        uint64_t                     num_files_lookedup;
+        gf_lock_t                    lock;
+        pthread_t                    th;
+        char                         mount[1024];
+        char                         databuf[131072];
+        struct gf_defrag_brickinfo_ *bricks; /* volinfo->brick_count */
+};
+
+
+typedef struct glusterd_defrag_info_ glusterd_defrag_info_t;
+
 struct glusterd_volinfo_ {
         char                    volname[GLUSTERD_MAX_VOLUME_NAME];
         int                     type;
@@ -94,6 +124,13 @@  struct glusterd_volinfo_ {
         int                     sub_count;
         int                     port;
         glusterd_store_handle_t *shandle;
+
+        /* Defrag/rebalance related */
+        gf_defrag_status_t      defrag_status;
+        uint64_t                rebalance_files;
+        uint64_t                rebalance_data;
+        uint64_t                lookedup_files;
+        glusterd_defrag_info_t  *defrag;
 };
 
 typedef struct glusterd_volinfo_ glusterd_volinfo_t;
diff --git a/xlators/mgmt/glusterd/src/glusterd3_1-mops.c b/xlators/mgmt/glusterd/src/glusterd3_1-mops.c
index 86d0919..59933e8 100644
--- a/xlators/mgmt/glusterd/src/glusterd3_1-mops.c
+++ b/xlators/mgmt/glusterd/src/glusterd3_1-mops.c
@@ -1199,7 +1199,7 @@  rpcsvc_actor_t glusterd1_mgmt_actors[] = {
         [GD_MGMT_COMMIT_OP] = { "COMMIT_OP", GD_MGMT_COMMIT_OP, glusterd_handle_rpc_msg, NULL, NULL},
         [GD_MGMT_CLI_PROBE] = { "CLI_PROBE", GD_MGMT_CLI_PROBE, glusterd_handle_rpc_msg, NULL, NULL},
         [GD_MGMT_CLI_CREATE_VOLUME] = { "CLI_CREATE_VOLUME", GD_MGMT_CLI_CREATE_VOLUME, glusterd_handle_rpc_msg, NULL,NULL},
-        [GD_MGMT_CLI_DEFRAG_VOLUME] = { "CLI_DEFRAG_VOLUME", GD_MGMT_CLI_DEFRAG_VOLUME, glusterd_handle_rpc_msg, NULL,NULL},
+        [GD_MGMT_CLI_DEFRAG_VOLUME] = { "CLI_DEFRAG_VOLUME", GD_MGMT_CLI_DEFRAG_VOLUME, glusterd_handle_defrag_volume, NULL,NULL},
         [GD_MGMT_CLI_DEPROBE] = { "FRIEND_REMOVE", GD_MGMT_CLI_DEPROBE, glusterd_handle_rpc_msg, NULL, NULL},
         [GD_MGMT_CLI_LIST_FRIENDS] = { "LIST_FRIENDS", GD_MGMT_CLI_LIST_FRIENDS, glusterd_handle_rpc_msg, NULL, NULL},
         [GD_MGMT_CLI_START_VOLUME] = { "START_VOLUME", GD_MGMT_CLI_START_VOLUME, glusterd_handle_rpc_msg, NULL, NULL},