From 9b7364d2450c7b51043bd39a0f586cf1c6041f4d Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 27 Dec 2013 19:40:59 +0200 Subject: [PATCH] rbd: expose options available to rbd map Add a -o / --options option, which would allow users to specify rbd-specific and generic ceph client and osd options available at mapping time in a comma separated list (similar to mount(8) mount options). Exposed options are: - fsid=%s - ip=%s - share - noshare - crc - nocrc - osdkeepalive=%d - osd_idle_ttl=%d - rw - ro (equivalent to existing --read-only flag) The rw/ro < 3.7 kernels compatibility kludge added in commit fb0f1986449b is preserved. Signed-off-by: Ilya Dryomov --- doc/man/8/rbd.rst | 39 +++++++++++- man/rbd.8 | 41 +++++++++++- src/rbd.cc | 135 +++++++++++++++++++++++++++++++++++++--- src/test/cli/rbd/help.t | 1 + 4 files changed, 203 insertions(+), 13 deletions(-) diff --git a/doc/man/8/rbd.rst b/doc/man/8/rbd.rst index 8370d4d2de37a..215aa9204e695 100644 --- a/doc/man/8/rbd.rst +++ b/doc/man/8/rbd.rst @@ -113,9 +113,15 @@ Parameters Make json or xml formatted output more human-readable. +.. option:: -o map-options, --options map-options + + Specifies which options to use when mapping an image. map-options is + a comma-separated string of options (similar to mount(8) mount options). + See map options section below for more details. + .. option:: --read-only - Set device readonly when mapping image. + Map the image read-only. Equivalent to -o ro. Commands @@ -235,7 +241,7 @@ Commands This requires image format 2. -:command:`map` [*image-name*] +:command:`map` [*image-name*] [-o | --options *map-options* ] [--read-only] Maps the specified image to a block device via the rbd kernel module. :command:`unmap` [*device-path*] @@ -306,6 +312,35 @@ By default, [*stripe_unit*] is the same as the object size and [*stripe_count*] used. +Map options +=========== + +Most of these options are useful mainly for debugging and benchmarking. The +default values are set in the kernel and may therefore depend on the version of +the running kernel. + +* fsid=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee - FSID that should be assumed by + the client. + +* ip=a.b.c.d[:p] - IP and, optionally, port the client should use. + +* share - Enable sharing of client instances with other mappings (default). + +* noshare - Disable sharing of client instances with other mappings. + +* crc - Enable CRC32C checksumming for data writes (default). + +* nocrc - Disable CRC32C checksumming for data writes. + +* osdkeepalive=x - OSD keepalive timeout (default is 5 seconds). + +* osd_idle_ttl=x - OSD idle TTL (default is 60 seconds). + +* rw - Map the image read-write (default). + +* ro - Map the image read-only. Equivalent to --read-only. + + Examples ======== diff --git a/man/rbd.8 b/man/rbd.8 index 59fbf52ca2fb7..910f19cf52bff 100644 --- a/man/rbd.8 +++ b/man/rbd.8 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "RBD" "8" "December 09, 2013" "dev" "Ceph" +.TH "RBD" "8" "December 27, 2013" "dev" "Ceph" .SH NAME rbd \- manage rados block device (RBD) images . @@ -177,8 +177,15 @@ Make json or xml formatted output more human\-readable. .UNINDENT .INDENT 0.0 .TP +.B \-o map\-options, \-\-options map\-options +Specifies which options to use when mapping an image. map\-options is +a comma\-separated string of options (similar to mount(8) mount options). +See map options section below for more details. +.UNINDENT +.INDENT 0.0 +.TP .B \-\-read\-only -Set device readonly when mapping image. +Map the image read\-only. Equivalent to \-o ro. .UNINDENT .SH COMMANDS .INDENT 0.0 @@ -295,7 +302,7 @@ in different pools than the parent snapshot.) .sp This requires image format 2. .TP -.B \fBmap\fP [\fIimage\-name\fP] +.B \fBmap\fP [\fIimage\-name\fP] [\-o | \-\-options \fImap\-options\fP ] [\-\-read\-only] Maps the specified image to a block device via the rbd kernel module. .TP .B \fBunmap\fP [\fIdevice\-path\fP] @@ -381,6 +388,34 @@ The striping is controlled by three parameters: By default, [\fIstripe_unit\fP] is the same as the object size and [\fIstripe_count\fP] is 1. Specifying a different [\fIstripe_unit\fP] requires that the STRIPINGV2 feature be supported (added in Ceph v0.53) and format 2 images be used. +.SH MAP OPTIONS +.sp +Most of these options are useful mainly for debugging and benchmarking. The +default values are set in the kernel and may therefore depend on the version of +the running kernel. +.INDENT 0.0 +.IP \(bu 2 +fsid=aaaaaaaa\-bbbb\-cccc\-dddd\-eeeeeeeeeeee \- FSID that should be assumed by +the client. +.IP \(bu 2 +ip=a.b.c.d[:p] \- IP and, optionally, port the client should use. +.IP \(bu 2 +share \- Enable sharing of client instances with other mappings (default). +.IP \(bu 2 +noshare \- Disable sharing of client instances with other mappings. +.IP \(bu 2 +crc \- Enable CRC32C checksumming for data writes (default). +.IP \(bu 2 +nocrc \- Disable CRC32C checksumming for data writes. +.IP \(bu 2 +osdkeepalive=x \- OSD keepalive timeout (default is 5 seconds). +.IP \(bu 2 +osd_idle_ttl=x \- OSD idle TTL (default is 60 seconds). +.IP \(bu 2 +rw \- Map the image read\-write (default). +.IP \(bu 2 +ro \- Map the image read\-only. Equivalent to \-\-read\-only. +.UNINDENT .SH EXAMPLES .sp To create a new rbd image that is 100 GB: diff --git a/src/rbd.cc b/src/rbd.cc index 6a8e6029a262d..2e87b62664d85 100644 --- a/src/rbd.cc +++ b/src/rbd.cc @@ -70,7 +70,8 @@ static string dir_info_oid = RBD_INFO; bool udevadm_settle = true; bool progress = true; bool resize_allow_shrink = false; -bool read_only = false; + +map map_options; // -o / --options map #define dout_subsys ceph_subsys_rbd @@ -154,6 +155,7 @@ void usage() " --pretty-format make json or xml output more readable\n" " --no-settle do not wait for udevadm to settle on map/unmap\n" " --no-progress do not show progress for long-running commands\n" +" -o, --options options to use when mapping an image\n" " --read-only set device readonly when mapping image\n" " --allow-shrink allow shrinking of an image when resizing\n"; } @@ -1649,13 +1651,8 @@ static int do_kernel_add(const char *poolname, const char *imgname, oss << ","; } - if (read_only) - oss << " ro,"; - else - oss << " "; - const char *user = g_conf->name.get_id().c_str(); - oss << "name=" << user; + oss << " name=" << user; char key_name[strlen(user) + strlen("client.") + 1]; snprintf(key_name, sizeof(key_name), "client.%s", user); @@ -1691,6 +1688,18 @@ static int do_kernel_add(const char *poolname, const char *imgname, oss << ",key=" << key_name; } + for (map::const_iterator it = map_options.begin(); + it != map_options.end(); + ++it) { + // for compatibility with < 3.7 kernels, assume that rw is on by + // default and omit it even if it was specified by the user + // (see ceph.git commit fb0f1986449b) + if (it->first == "rw" && it->second == "rw") + continue; + + oss << "," << it->second; + } + oss << " " << poolname << " " << imgname; if (snapname) { @@ -2056,6 +2065,109 @@ static int do_kernel_rm(const char *dev) return r; } +static string map_option_uuid_cb(const char *value_char) +{ + uuid_d u; + if (!u.parse(value_char)) + return ""; + + ostringstream oss; + oss << u; + return oss.str(); +} + +static string map_option_ip_cb(const char *value_char) +{ + entity_addr_t a; + const char *endptr; + if (!a.parse(value_char, &endptr) || + endptr != value_char + strlen(value_char)) { + return ""; + } + + ostringstream oss; + oss << a.addr; + return oss.str(); +} + +static string map_option_int_cb(const char *value_char) +{ + string err; + int d = strict_strtol(value_char, 10, &err); + if (!err.empty() || d < 0) + return ""; + + ostringstream oss; + oss << d; + return oss.str(); +} + +static void put_map_option(const string key, string val) +{ + map::const_iterator it = map_options.find(key); + if (it != map_options.end()) { + cerr << "rbd: warning: redefining map option " << key << ": '" + << it->second << "' -> '" << val << "'" << std::endl; + } + map_options[key] = val; +} + +static int put_map_option_value(const string opt, const char *value_char, + string (*parse_cb)(const char *)) +{ + if (!value_char || *value_char == '\0') { + cerr << "rbd: " << opt << " option requires a value" << std::endl; + return 1; + } + + string value = parse_cb(value_char); + if (value.empty()) { + cerr << "rbd: invalid " << opt << " value '" << value_char << "'" + << std::endl; + return 1; + } + + put_map_option(opt, opt + "=" + value); + return 0; +} + +static int parse_map_options(char *options) +{ + for (char *this_char = strtok(options, ", "); + this_char != NULL; + this_char = strtok(NULL, ",")) { + char *value_char; + + if ((value_char = strchr(this_char, '=')) != NULL) + *value_char++ = '\0'; + + if (!strcmp(this_char, "fsid")) { + if (put_map_option_value("fsid", value_char, map_option_uuid_cb)) + return 1; + } else if (!strcmp(this_char, "ip")) { + if (put_map_option_value("ip", value_char, map_option_ip_cb)) + return 1; + } else if (!strcmp(this_char, "share") || !strcmp(this_char, "noshare")) { + put_map_option("share", this_char); + } else if (!strcmp(this_char, "crc") || !strcmp(this_char, "nocrc")) { + put_map_option("crc", this_char); + } else if (!strcmp(this_char, "osdkeepalive")) { + if (put_map_option_value("osdkeepalive", value_char, map_option_int_cb)) + return 1; + } else if (!strcmp(this_char, "osd_idle_ttl")) { + if (put_map_option_value("osd_idle_ttl", value_char, map_option_int_cb)) + return 1; + } else if (!strcmp(this_char, "rw") || !strcmp(this_char, "ro")) { + put_map_option("rw", this_char); + } else { + cerr << "rbd: unknown map option '" << this_char << "'" << std::endl; + return 1; + } + } + + return 0; +} + enum { OPT_NO_CMD = 0, OPT_LIST, @@ -2291,8 +2403,15 @@ int main(int argc, const char **argv) lock_tag = strdup(val.c_str()); } else if (ceph_argparse_flag(args, i, "--no-settle", (char *)NULL)) { udevadm_settle = false; + } else if (ceph_argparse_witharg(args, i, &val, "-o", "--options", (char*)NULL)) { + char *map_options = strdup(val.c_str()); + if (parse_map_options(map_options)) { + cerr << "rbd: couldn't parse map options" << std::endl; + return EXIT_FAILURE; + } } else if (ceph_argparse_flag(args, i, "--read-only", (char *)NULL)) { - read_only = true; + // --read-only is equivalent to -o ro + put_map_option("rw", "ro"); } else if (ceph_argparse_flag(args, i, "--no-progress", (char *)NULL)) { progress = false; } else if (ceph_argparse_flag(args, i , "--allow-shrink", (char *)NULL)) { diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index 754e11f935706..5723bef8417b9 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -76,5 +76,6 @@ --pretty-format make json or xml output more readable --no-settle do not wait for udevadm to settle on map/unmap --no-progress do not show progress for long-running commands + -o, --options options to use when mapping an image --read-only set device readonly when mapping image --allow-shrink allow shrinking of an image when resizing -- 2.39.5