diff options
| author | M. Mohan Kumar <mohan@in.ibm.com> | 2012-11-29 21:46:07 +0530 | 
|---|---|---|
| committer | Vijay Bellur <vbellur@redhat.com> | 2012-11-29 09:40:14 -0800 | 
| commit | 983d290f7b36fea580ed9337bdc15e8f0f6f5bb3 (patch) | |
| tree | 7437660f9427ca9fb1bbf5432b38dc35f7351389 | |
| parent | 3c72850e8d00f0cf35ae054136be076a394e08e9 (diff) | |
BD Backend: CLI to create a full/linked clone of a image
A new CLI command added to support cloning/snapshotting of a LV device
Syntax is:
$ gluster bd clone <volname>:<vg>/<lv> <newlv>
$ gluster bd snapshot <volname>:<vg>/<lv> <snap_lv> <size>
BUG: 805138
Change-Id: Idc2ac14525a3998329c742bf85a06326cac8cd54
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Reviewed-on: http://review.gluster.org/3719
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
| -rw-r--r-- | cli/src/cli-cmd-parser.c | 2 | ||||
| -rw-r--r-- | cli/src/cli-cmd-volume-bdevice.c | 47 | ||||
| -rw-r--r-- | cli/src/cli-rpc-ops.c | 6 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/protocol-common.h | 2 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volume-ops.c | 19 | ||||
| -rw-r--r-- | xlators/storage/bd_map/src/bd_map.c | 106 | 
6 files changed, 170 insertions, 12 deletions
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index f7ee29a10c7..ae754b97c05 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -369,7 +369,7 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options                  cli_err ("Block Device backend volume does not support multiple"                           " bricks");                  gf_log ("", GF_LOG_ERROR, -                          "Block Device backend volumer does not support multiple" +                         "Block Device backend volume does not support multiple"                          " bricks");                  ret = -1;                  goto out; diff --git a/cli/src/cli-cmd-volume-bdevice.c b/cli/src/cli-cmd-volume-bdevice.c index ea7edab6502..19325754fb9 100644 --- a/cli/src/cli-cmd-volume-bdevice.c +++ b/cli/src/cli-cmd-volume-bdevice.c @@ -41,6 +41,8 @@ cli_cmd_bd_parse (dict_t *dict, const char **words)          char          *size     = NULL;          char          *eptr     = NULL;          gf_xl_bd_op_t  bd_op    = GF_BD_OP_INVALID; +        char          *dest_lv  = NULL; +          /* volname:/path */          if (!strchr (words[2], ':') || !strchr (words[2], '/')) { @@ -64,6 +66,10 @@ cli_cmd_bd_parse (dict_t *dict, const char **words)                  bd_op = GF_BD_OP_NEW_BD;          else if (!strcasecmp (words[1], "delete"))                  bd_op = GF_BD_OP_DELETE_BD; +        else if (!strcasecmp (words[1], "clone")) +                bd_op = GF_BD_OP_CLONE_BD; +        else if (!strcasecmp (words[1], "snapshot")) +                bd_op = GF_BD_OP_SNAPSHOT_BD;          else                  return -1; @@ -83,6 +89,30 @@ cli_cmd_bd_parse (dict_t *dict, const char **words)                  ret = dict_set_dynstr (dict, "size", size);                  if (ret)                          goto out; +        } else if (bd_op == GF_BD_OP_SNAPSHOT_BD || +                   bd_op == GF_BD_OP_CLONE_BD) { +                /* +                 * dest_lv should be just dest_lv, we don't support +                 * cloning/snapshotting to a different volume or vg +                 */ +                if (strchr (words[3], ':') || strchr (words[3], '/')) { +                        cli_err ("invalid parameter %s, volname/vg not needed", +                                 words[3]); +                        ret = -1; +                        goto out; +                } +                dest_lv = gf_strdup (words[3]); +                ret = dict_set_dynstr (dict, "dest_lv", dest_lv); +                if (ret) +                        goto out; + +                /* clone needs size as parameter */ +                if (bd_op == GF_BD_OP_SNAPSHOT_BD) { +                        ret = dict_set_dynstr (dict, "size", +                                               gf_strdup (words[4])); +                        if (ret) +                                goto out; +                }          }          ret = 0; @@ -94,13 +124,15 @@ out:  /*   * bd create <volname>:/path <size>   * bd delete <volname>:/path + * bd clone <volname>:/path <newbd> + * bd snapshot <volname>:/<path> <newbd> <size>   */  int32_t  cli_cmd_bd_validate (const char **words, int wordcount, dict_t **options)  {          dict_t  *dict = NULL;          int     ret   = -1; -        char    *op[] = { "create", "delete", NULL }; +        char    *op[] = { "create", "delete", "clone", "snapshot", NULL };          int     index = 0;          for (index = 0; op[index]; index++) @@ -120,6 +152,12 @@ cli_cmd_bd_validate (const char **words, int wordcount, dict_t **options)          } else if (!strcasecmp (words[1], "delete")) {                  if (wordcount != 3)                          goto out; +        } else if (!strcasecmp (words[1], "clone")) { +                if (wordcount != 4) +                        goto out; +        } else if (!strcasecmp (words[1], "snapshot")) { +                if (wordcount != 5) +                        goto out;          } else {                  ret = -1;                  goto out; @@ -193,6 +231,13 @@ struct cli_cmd cli_bd_cmds[] = {          { "bd delete <volname>:<bd>",            cli_cmd_bd_cbk,            "Delete a block device"}, +        { "bd clone <volname>:<bd> <newbd>", +          cli_cmd_bd_cbk, +          "clone device"}, +        { "bd snapshot <volname>:<bd> <newbd> <size>", +          cli_cmd_bd_cbk, +          "\n\tsnapshot device where size can be " +          "suffixed with KB, MB etc. Default size is in MB"},          { NULL, NULL, NULL }  }; diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 9e4e03d0754..da239b51ec3 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -2647,6 +2647,12 @@ gf_cli_bd_op_cbk (struct rpc_req *req, struct iovec *iov,          case GF_BD_OP_DELETE_BD:                  operation = gf_strdup ("delete");                  break; +        case GF_BD_OP_CLONE_BD: +                operation = gf_strdup ("clone"); +                break; +        case GF_BD_OP_SNAPSHOT_BD: +                operation = gf_strdup ("snapshot"); +                break;          default:                  break;          } diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 38528bd5f97..97017e5fe3c 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -211,6 +211,8 @@ typedef enum {          GF_BD_OP_INVALID,          GF_BD_OP_NEW_BD,          GF_BD_OP_DELETE_BD, +        GF_BD_OP_CLONE_BD, +        GF_BD_OP_SNAPSHOT_BD,  } gf_xl_bd_op_t ;  #define GLUSTER_HNDSK_PROGRAM    14398633 /* Completely random */ diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c index b74bbec7c59..db143d5f07a 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c @@ -1295,6 +1295,24 @@ glusterd_op_stage_bd (dict_t *dict, char **op_errstr)                          ret = -1;                          goto out;                  } +        } else if (bd_op == GF_BD_OP_SNAPSHOT_BD) { +                ret = dict_get_str (dict, "size", &size); +                if (ret) { +                        snprintf (msg, sizeof(msg), "Failed to get size"); +                        gf_log ("", GF_LOG_ERROR, "%s", msg); +                        *op_errstr = gf_strdup (msg); +                        goto out; +                } + +                if (gf_string2bytesize (size, &bytes) < 0) { +                        ret = -1; +                        snprintf (msg, sizeof(msg), +                                "Invalid size %s, suffix with KB, MB etc", +                                size); +                        gf_log ("", GF_LOG_ERROR, "%s", msg); +                        *op_errstr = gf_strdup (msg); +                        goto out; +                }          }          ret = glusterd_volinfo_find (volname, &volinfo); @@ -1324,7 +1342,6 @@ out:          gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);          return ret;  } -  #endif  int diff --git a/xlators/storage/bd_map/src/bd_map.c b/xlators/storage/bd_map/src/bd_map.c index a84ee29fba2..9c8f69c6488 100644 --- a/xlators/storage/bd_map/src/bd_map.c +++ b/xlators/storage/bd_map/src/bd_map.c @@ -371,10 +371,6 @@ int bd_clone_lv (bd_priv_t *priv, bd_entry_t *p_entry, dict_t *output,          ret = 0;          gf_log (THIS->name, GF_LOG_INFO, "Clone completed");  out: -        for (i = 0; i < IOV_NR; i++) { -                if (vec[i].iov_base) -                        GF_FREE (vec[i].iov_base); -        }          if (vg)                  lvm_vg_close (vg);          if (fd1 != -1) @@ -387,7 +383,7 @@ out:  }  int bd_snapshot_lv (bd_priv_t *priv, bd_entry_t *p_entry, dict_t *output, -                    const char *lv_name, const char *dest_lv, uint64_t size, +                    const char *lv_name, const char *dest_lv, char *size,                      struct iatt *stbuf)  {          int32_t         ret      = -1; @@ -408,7 +404,7 @@ int bd_snapshot_lv (bd_priv_t *priv, bd_entry_t *p_entry, dict_t *output,          runner_argprintf (&runner, "/dev/%s/%s", p_entry->name, lv_name);          runner_add_args  (&runner, "--name", NULL);          runner_argprintf (&runner, "%s", dest_lv); -        runner_argprintf (&runner, "-L%ld", size); +        runner_argprintf (&runner, "-L%s", size);          runner_start (&runner);          runner_end (&runner); @@ -534,7 +530,7 @@ bd_symlink (call_frame_t *frame, xlator_t *this,          memcpy (&preparent, lventry->parent->attr, sizeof(preparent));          if (bd_snapshot_lv (priv, lventry->parent, NULL, lventry->name, -                            name, 1, &stbuf) < 0) { +                            name, "1", &stbuf) < 0) {                  op_errno = EAGAIN;                  goto out;          } @@ -2232,6 +2228,94 @@ out:          return ret;  } +int bd_xl_op_clone(bd_priv_t *priv, int subop, dict_t *input, dict_t *output) +{ +        bd_entry_t      *p_entry = NULL; +        bd_entry_t      *lventry = NULL; +        int             ret      = -1; +        char            *error   = NULL; +        int             retval   = -1; +        char            *vg      = NULL; +        char            *lv      = NULL; +        char            *dest_lv = NULL; +        char            *size    = NULL; +        char            *buff    = NULL; +        char            *buffp   = NULL; +        char            *path    = NULL; +        char            *save    = NULL; +        char            *npath   = NULL; + +        ret = dict_get_str (input, "path", &path); +        ret = dict_get_str (input, "dest_lv", &dest_lv); +        ret = dict_get_str (input, "size", &size); + +        if (!path || !dest_lv) { +                gf_asprintf (&error, "invalid arguments"); +                ret = -1; +                goto out; +        } + +        buff = buffp = gf_strdup (path); + +        vg = strtok_r (buff, "/", &save); +        lv = strtok_r (NULL, "/", &save); +        if (!lv) { +                gf_asprintf (&error, "lv not given %s", path); +                ret = -1; +                goto out; +        } + +        BD_ENTRY (priv, p_entry, vg); +        if (!p_entry) { +                gf_asprintf (&error, "%s does not exist", vg); +                retval = dict_set_str (output, "error", error); +                goto out; +        } + +        BD_ENTRY (priv, lventry, path); +        if (!lventry) { +                gf_asprintf (&error, "%s does not exist", path); +                ret = -1; +                goto out; +        } +        BD_PUT_ENTRY (priv, lventry); +        lventry = NULL; +        gf_asprintf (&npath, "/%s/%s", vg, dest_lv); +        BD_ENTRY (priv, lventry, npath); +        if (lventry) { +                gf_asprintf (&error, "%s already exists", dest_lv); +                BD_PUT_ENTRY (priv, lventry); +                ret = -1; +                goto out; +        } + +        if (subop == GF_BD_OP_SNAPSHOT_BD) { +                if (!size) { +                        gf_asprintf (&error, "size not given"); +                        ret = -1; +                        goto out; +                } +                ret = bd_snapshot_lv (priv, p_entry, output, lv, dest_lv, +                                  size, NULL); +        } else +                ret = bd_clone_lv (priv, p_entry, output, vg, lv, dest_lv, +                                  NULL); + +        if (ret) +                goto out; +        ret = 0; +out: +        if (error) +                retval = dict_set_dynstr (output, "error", error); +        if (p_entry) +                BD_PUT_ENTRY (priv, p_entry); +        if (npath) +                GF_FREE (npath); +        if (buffp) +                GF_FREE (buffp); +        return ret; +} +  int32_t  bd_notify (xlator_t *this, dict_t *input, dict_t *output)  { @@ -2246,7 +2330,7 @@ bd_notify (xlator_t *this, dict_t *input, dict_t *output)          ret = dict_get_int32 (input, "bd-op", (int32_t *)&bdop);          if (ret) { -                asprintf (&error, "no sub-op specified"); +                gf_asprintf (&error, "no sub-op specified");                  goto out;          } @@ -2258,6 +2342,10 @@ bd_notify (xlator_t *this, dict_t *input, dict_t *output)          case GF_BD_OP_DELETE_BD:                  ret = bd_xl_op_delete (priv, input, output);                  break; +        case GF_BD_OP_CLONE_BD: +        case GF_BD_OP_SNAPSHOT_BD: +                ret = bd_xl_op_clone (priv, bdop, input, output); +                break;          default:                  gf_asprintf (&error, "invalid bd-op %d specified", bdop);                  retval = dict_set_dynstr (output, "error", error); @@ -2278,7 +2366,7 @@ notify (xlator_t *this,          ...)  {          va_list ap; -        int     ret    = -1; +        int     ret    = 0;          void    *data2 = NULL;          dict_t  *input = NULL;          dict_t  *output = NULL;  | 
