mirror of
https://github.com/ceph/ceph
synced 2024-12-19 09:57:05 +00:00
Merge pull request #19666 from trociny/wip-nbd-unmap-by-image
rbd-nbd: allow to unmap by image or snap spec Reviewed-by: Jason Dillaman <dillaman@redhat.com>
This commit is contained in:
commit
e4b8ae348b
@ -65,6 +65,7 @@ function cleanup()
|
||||
sleep $s
|
||||
rbd -p ${POOL} status ${IMAGE} | grep 'Watchers: none' && break
|
||||
done
|
||||
rbd -p ${POOL} snap purge ${IMAGE}
|
||||
rbd -p ${POOL} remove ${IMAGE}
|
||||
fi
|
||||
}
|
||||
@ -170,6 +171,31 @@ _sudo dd if=${DATA} of=${DEV} bs=1M oflag=direct
|
||||
expect_false timeout 10 \
|
||||
rbd bench ${IMAGE} --io-type write --io-size=1024 --io-total=1024
|
||||
_sudo rbd-nbd unmap ${DEV}
|
||||
DEV=
|
||||
rbd bench ${IMAGE} --io-type write --io-size=1024 --io-total=1024
|
||||
|
||||
# unmap by image name test
|
||||
DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}`
|
||||
PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \
|
||||
'$2 == pool && $3 == img && $5 == dev {print $1}')
|
||||
test -n "${PID}"
|
||||
ps -p ${PID} -o cmd | grep rbd-nbd
|
||||
_sudo rbd-nbd unmap "${IMAGE}"
|
||||
rbd-nbd list-mapped | expect_false grep "${DEV} $"
|
||||
DEV=
|
||||
ps -p ${PID} -o cmd | expect_false grep rbd-nbd
|
||||
|
||||
# map/unmap snap test
|
||||
rbd snap create ${POOL}/${IMAGE}@snap
|
||||
DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}@snap`
|
||||
PID=$(rbd-nbd list-mapped |
|
||||
awk -v pool=${POOL} -v img=${IMAGE} -v snap=snap -v dev=${DEV} \
|
||||
'$2 == pool && $3 == img && $4 == snap && $5 == dev {print $1}')
|
||||
test -n "${PID}"
|
||||
_sudo rbd-nbd unmap "${IMAGE}@snap"
|
||||
rbd-nbd list-mapped | expect_false grep "${DEV} $"
|
||||
DEV=
|
||||
ps -p ${PID} -o cmd | expect_false grep rbd-nbd
|
||||
|
||||
# auto unmap test
|
||||
DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}`
|
||||
@ -184,7 +210,4 @@ for i in `seq 10`; do
|
||||
done
|
||||
rbd-nbd list-mapped | expect_false grep "^${PID} *${POOL} *${IMAGE}"
|
||||
|
||||
DEV=
|
||||
rbd bench ${IMAGE} --io-type write --io-size=1024 --io-total=1024
|
||||
|
||||
echo OK
|
||||
|
@ -1169,13 +1169,20 @@ Skip test on FreeBSD as it generates different output there.
|
||||
--timeout arg set nbd request timeout (seconds)
|
||||
|
||||
rbd help nbd unmap
|
||||
usage: rbd nbd unmap
|
||||
<device-spec>
|
||||
usage: rbd nbd unmap [--pool <pool>] [--image <image>] [--snap <snap>]
|
||||
<image-or-snap-or-device-spec>
|
||||
|
||||
Unmap a nbd device.
|
||||
|
||||
Positional arguments
|
||||
<device-spec> specify nbd device
|
||||
<image-or-snap-or-device-spec> image, snapshot, or device specification
|
||||
[<pool-name>/]<image-name>[@<snapshot-name>]
|
||||
or <device-path>
|
||||
|
||||
Optional arguments
|
||||
-p [ --pool ] arg pool name
|
||||
--image arg image name
|
||||
--snap arg snapshot name
|
||||
|
||||
rbd help object-map check
|
||||
usage: rbd object-map check [--pool <pool>] [--image <image>] [--snap <snap>]
|
||||
|
@ -80,6 +80,30 @@ static int call_nbd_cmd(const po::variables_map &vm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_image_or_snap_spec(const po::variables_map &vm, std::string *spec) {
|
||||
size_t arg_index = 0;
|
||||
std::string pool_name;
|
||||
std::string image_name;
|
||||
std::string snap_name;
|
||||
int r = utils::get_pool_image_snapshot_names(
|
||||
vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
|
||||
&snap_name, utils::SNAPSHOT_PRESENCE_PERMITTED,
|
||||
utils::SPEC_VALIDATION_NONE);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
spec->append(pool_name);
|
||||
spec->append("/");
|
||||
spec->append(image_name);
|
||||
if (!snap_name.empty()) {
|
||||
spec->append("@");
|
||||
spec->append(snap_name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void get_show_arguments(po::options_description *positional,
|
||||
po::options_description *options)
|
||||
{ }
|
||||
@ -109,28 +133,13 @@ void get_map_arguments(po::options_description *positional,
|
||||
|
||||
int execute_map(const po::variables_map &vm)
|
||||
{
|
||||
size_t arg_index = 0;
|
||||
std::string pool_name;
|
||||
std::string image_name;
|
||||
std::string snap_name;
|
||||
int r = utils::get_pool_image_snapshot_names(
|
||||
vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
|
||||
&snap_name, utils::SNAPSHOT_PRESENCE_PERMITTED,
|
||||
utils::SPEC_VALIDATION_NONE);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
std::vector<const char*> args;
|
||||
|
||||
args.push_back("map");
|
||||
std::string img;
|
||||
img.append(pool_name);
|
||||
img.append("/");
|
||||
img.append(image_name);
|
||||
if (!snap_name.empty()) {
|
||||
img.append("@");
|
||||
img.append(snap_name);
|
||||
int r = get_image_or_snap_spec(vm, &img);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
args.push_back(img.c_str());
|
||||
|
||||
@ -164,7 +173,12 @@ void get_unmap_arguments(po::options_description *positional,
|
||||
po::options_description *options)
|
||||
{
|
||||
positional->add_options()
|
||||
("device-spec", "specify nbd device");
|
||||
("image-or-snap-or-device-spec",
|
||||
"image, snapshot, or device specification\n"
|
||||
"[<pool-name>/]<image-name>[@<snapshot-name>] or <device-path>");
|
||||
at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE);
|
||||
at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE);
|
||||
at::add_snap_option(options, at::ARGUMENT_MODIFIER_NONE);
|
||||
}
|
||||
|
||||
int execute_unmap(const po::variables_map &vm)
|
||||
@ -174,15 +188,25 @@ int execute_unmap(const po::variables_map &vm)
|
||||
device_name.clear();
|
||||
}
|
||||
|
||||
std::string image_name;
|
||||
if (device_name.empty()) {
|
||||
std::cerr << "rbd: nbd unmap requires device path" << std::endl;
|
||||
int r = get_image_or_snap_spec(vm, &image_name);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (device_name.empty() && image_name.empty()) {
|
||||
std::cerr << "rbd: unmap requires either image name or device path"
|
||||
<< std::endl;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
std::vector<const char*> args;
|
||||
|
||||
args.push_back("unmap");
|
||||
args.push_back(device_name.c_str());
|
||||
args.push_back(device_name.empty() ? image_name.c_str() :
|
||||
device_name.c_str());
|
||||
|
||||
return call_nbd_cmd(vm, args);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#include "mon/MonClient.h"
|
||||
#include "common/config.h"
|
||||
@ -78,7 +79,7 @@ struct Config {
|
||||
static void usage()
|
||||
{
|
||||
std::cout << "Usage: rbd-nbd [options] map <image-or-snap-spec> Map an image to nbd device\n"
|
||||
<< " unmap <device path> Unmap nbd device\n"
|
||||
<< " unmap <device|image-or-snap-spec> Unmap nbd device\n"
|
||||
<< " list-mapped List mapped nbd devices\n"
|
||||
<< "Options:\n"
|
||||
<< " --device <device path> Specify nbd device path\n"
|
||||
@ -93,12 +94,14 @@ static void usage()
|
||||
|
||||
static int nbd = -1;
|
||||
|
||||
static enum {
|
||||
enum Command {
|
||||
None,
|
||||
Connect,
|
||||
Disconnect,
|
||||
List
|
||||
} cmd = None;
|
||||
};
|
||||
|
||||
static Command cmd = None;
|
||||
|
||||
#define RBD_NBD_BLKSIZE 512UL
|
||||
|
||||
@ -114,7 +117,8 @@ static enum {
|
||||
#endif
|
||||
#define htonll(a) ntohll(a)
|
||||
|
||||
static int parse_args(vector<const char*>& args, std::ostream *err_msg, Config *cfg);
|
||||
static int parse_args(vector<const char*>& args, std::ostream *err_msg,
|
||||
Command *command, Config *cfg);
|
||||
|
||||
static void handle_signal(int signum)
|
||||
{
|
||||
@ -491,11 +495,84 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class NBDListIterator {
|
||||
public:
|
||||
bool get(int *pid, Config *cfg) {
|
||||
while (true) {
|
||||
std::string nbd_path = "/sys/block/nbd" + stringify(m_index);
|
||||
if(access(nbd_path.c_str(), F_OK) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*cfg = Config();
|
||||
cfg->devpath = "/dev/nbd" + stringify(m_index++);
|
||||
|
||||
std::ifstream ifs;
|
||||
ifs.open(nbd_path + "/pid", std::ifstream::in);
|
||||
if (!ifs.is_open()) {
|
||||
continue;
|
||||
}
|
||||
ifs >> *pid;
|
||||
|
||||
int r = get_mapped_info(*pid, cfg);
|
||||
if (r < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int m_index = 0;
|
||||
|
||||
int get_mapped_info(int pid, Config *cfg) {
|
||||
int r;
|
||||
std::string path = "/proc/" + stringify(pid) + "/cmdline";
|
||||
std::ifstream ifs;
|
||||
std::string cmdline;
|
||||
std::vector<const char*> args;
|
||||
|
||||
ifs.open(path.c_str(), std::ifstream::in);
|
||||
if (!ifs.is_open())
|
||||
return -1;
|
||||
ifs >> cmdline;
|
||||
|
||||
for (unsigned i = 0; i < cmdline.size(); i++) {
|
||||
const char *arg = &cmdline[i];
|
||||
if (i == 0) {
|
||||
if (strcmp(basename(arg) , "rbd-nbd") != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
args.push_back(arg);
|
||||
}
|
||||
|
||||
while (cmdline[i] != '\0') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream err_msg;
|
||||
Command command;
|
||||
r = parse_args(args, &err_msg, &command, cfg);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (command != Connect) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
static int open_device(const char* path, Config *cfg = nullptr, bool try_load_module = false)
|
||||
{
|
||||
int nbd = open(path, O_RDWR);
|
||||
bool loaded_module = false;
|
||||
|
||||
|
||||
if (nbd < 0 && try_load_module && access("/sys/module/nbd", F_OK) != 0) {
|
||||
ostringstream param;
|
||||
int r;
|
||||
@ -520,7 +597,7 @@ static int open_device(const char* path, Config *cfg = nullptr, bool try_load_mo
|
||||
cerr << "rbd-nbd: ignoring kernel module parameter options: nbd module already loaded"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
return nbd;
|
||||
}
|
||||
|
||||
@ -777,14 +854,14 @@ static int do_map(int argc, const char *argv[], Config *cfg)
|
||||
NBDServer server(fd[1], image);
|
||||
|
||||
server.start();
|
||||
|
||||
|
||||
init_async_signal_handler();
|
||||
register_async_signal_handler(SIGHUP, sighup_handler);
|
||||
register_async_signal_handler_oneshot(SIGINT, handle_signal);
|
||||
register_async_signal_handler_oneshot(SIGTERM, handle_signal);
|
||||
|
||||
ioctl(nbd, NBD_DO_IT);
|
||||
|
||||
|
||||
unregister_async_signal_handler(SIGHUP, sighup_handler);
|
||||
unregister_async_signal_handler(SIGINT, handle_signal);
|
||||
unregister_async_signal_handler(SIGTERM, handle_signal);
|
||||
@ -834,12 +911,12 @@ static int do_unmap(const std::string &devpath)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int parse_imgpath(const std::string &imgpath, Config *cfg)
|
||||
{
|
||||
static int parse_imgpath(const std::string &imgpath, Config *cfg,
|
||||
std::ostream *err_msg) {
|
||||
boost::regex pattern("^(?:([^/@]+)/)?([^/@]+)(?:@([^/@]+))?$");
|
||||
boost::smatch match;
|
||||
if (!boost::regex_match(imgpath, match, pattern)) {
|
||||
std::cerr << "rbd-nbd: invalid spec '" << imgpath << "'" << std::endl;
|
||||
*err_msg << "rbd-nbd: invalid spec '" << imgpath << "'";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -855,60 +932,9 @@ static int parse_imgpath(const std::string &imgpath, Config *cfg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_mapped_info(int pid, Config *cfg)
|
||||
{
|
||||
int r;
|
||||
std::string path = "/proc/" + stringify(pid) + "/cmdline";
|
||||
std::ifstream ifs;
|
||||
std::string cmdline;
|
||||
std::vector<const char*> args;
|
||||
|
||||
ifs.open(path.c_str(), std::ifstream::in);
|
||||
if (!ifs.is_open())
|
||||
return -1;
|
||||
ifs >> cmdline;
|
||||
|
||||
for (unsigned i = 0; i < cmdline.size(); i++) {
|
||||
const char *arg = &cmdline[i];
|
||||
if (i == 0) {
|
||||
if (strcmp(basename(arg) , "rbd-nbd") != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
args.push_back(arg);
|
||||
}
|
||||
|
||||
while (cmdline[i] != '\0') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream err_msg;
|
||||
r = parse_args(args, &err_msg, cfg);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int get_map_pid(const std::string& pid_path)
|
||||
{
|
||||
int pid = 0;
|
||||
std::ifstream ifs;
|
||||
ifs.open(pid_path.c_str(), std::ifstream::in);
|
||||
if (!ifs.is_open()) {
|
||||
return 0;
|
||||
}
|
||||
ifs >> pid;
|
||||
return pid;
|
||||
}
|
||||
|
||||
static int do_list_mapped_devices()
|
||||
{
|
||||
int r;
|
||||
bool should_print = false;
|
||||
int index = 0;
|
||||
int pid = 0;
|
||||
|
||||
std::string default_pool_name;
|
||||
|
||||
TextTable tbl;
|
||||
|
||||
tbl.define_column("pid", TextTable::LEFT, TextTable::LEFT);
|
||||
@ -916,31 +942,17 @@ static int do_list_mapped_devices()
|
||||
tbl.define_column("image", TextTable::LEFT, TextTable::LEFT);
|
||||
tbl.define_column("snap", TextTable::LEFT, TextTable::LEFT);
|
||||
tbl.define_column("device", TextTable::LEFT, TextTable::LEFT);
|
||||
|
||||
while (true) {
|
||||
std::string nbd_path = "/sys/block/nbd" + stringify(index);
|
||||
if(access(nbd_path.c_str(), F_OK) != 0) {
|
||||
break;
|
||||
}
|
||||
std::string pid_path = nbd_path + "/pid";
|
||||
pid = get_map_pid(pid_path);
|
||||
|
||||
if(pid > 0) {
|
||||
Config cfg;
|
||||
r = get_mapped_info(pid, &cfg);
|
||||
if (r < 0) {
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
should_print = true;
|
||||
if (cfg.snapname.empty()) {
|
||||
cfg.snapname = "-";
|
||||
}
|
||||
tbl << pid << cfg.poolname << cfg.imgname << cfg.snapname
|
||||
<< "/dev/nbd" + stringify(index) << TextTable::endrow;
|
||||
int pid;
|
||||
Config cfg;
|
||||
NBDListIterator it;
|
||||
while (it.get(&pid, &cfg)) {
|
||||
should_print = true;
|
||||
if (cfg.snapname.empty()) {
|
||||
cfg.snapname = "-";
|
||||
}
|
||||
|
||||
index++;
|
||||
tbl << pid << cfg.poolname << cfg.imgname << cfg.snapname << cfg.devpath
|
||||
<< TextTable::endrow;
|
||||
}
|
||||
|
||||
if (should_print) {
|
||||
@ -949,8 +961,23 @@ static int do_list_mapped_devices()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_args(vector<const char*>& args, std::ostream *err_msg, Config *cfg)
|
||||
{
|
||||
static bool find_mapped_dev_by_spec(Config *cfg) {
|
||||
int pid;
|
||||
Config c;
|
||||
NBDListIterator it;
|
||||
while (it.get(&pid, &c)) {
|
||||
if (c.poolname == cfg->poolname && c.imgname == cfg->imgname &&
|
||||
c.snapname == cfg->snapname) {
|
||||
*cfg = c;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int parse_args(vector<const char*>& args, std::ostream *err_msg,
|
||||
Command *command, Config *cfg) {
|
||||
std::string conf_file_list;
|
||||
std::string cluster;
|
||||
CephInitParameters iparams = ceph_argparse_early_args(
|
||||
@ -1016,6 +1043,7 @@ static int parse_args(vector<const char*>& args, std::ostream *err_msg, Config *
|
||||
}
|
||||
}
|
||||
|
||||
Command cmd = None;
|
||||
if (args.begin() != args.end()) {
|
||||
if (strcmp(*args.begin(), "map") == 0) {
|
||||
cmd = Connect;
|
||||
@ -1041,16 +1069,27 @@ static int parse_args(vector<const char*>& args, std::ostream *err_msg, Config *
|
||||
*err_msg << "rbd-nbd: must specify image-or-snap-spec";
|
||||
return -EINVAL;
|
||||
}
|
||||
if (parse_imgpath(string(*args.begin()), cfg) < 0)
|
||||
if (parse_imgpath(*args.begin(), cfg, err_msg) < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
args.erase(args.begin());
|
||||
break;
|
||||
case Disconnect:
|
||||
if (args.begin() == args.end()) {
|
||||
*err_msg << "rbd-nbd: must specify nbd device path";
|
||||
*err_msg << "rbd-nbd: must specify nbd device or image-or-snap-spec";
|
||||
return -EINVAL;
|
||||
}
|
||||
cfg->devpath = *args.begin();
|
||||
if (boost::starts_with(*args.begin(), "/dev/")) {
|
||||
cfg->devpath = *args.begin();
|
||||
} else {
|
||||
if (parse_imgpath(*args.begin(), cfg, err_msg) < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!find_mapped_dev_by_spec(cfg)) {
|
||||
*err_msg << "rbd-nbd: " << *args.begin() << " is not mapped";
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
args.erase(args.begin());
|
||||
break;
|
||||
default:
|
||||
@ -1063,6 +1102,7 @@ static int parse_args(vector<const char*>& args, std::ostream *err_msg, Config *
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*command = cmd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1074,7 +1114,7 @@ static int rbd_nbd(int argc, const char *argv[])
|
||||
argv_to_vec(argc, argv, args);
|
||||
|
||||
std::ostringstream err_msg;
|
||||
r = parse_args(args, &err_msg, &cfg);
|
||||
r = parse_args(args, &err_msg, &cmd, &cfg);
|
||||
if (r == HELP_INFO) {
|
||||
usage();
|
||||
ceph_abort();
|
||||
|
Loading…
Reference in New Issue
Block a user