A minimal user-mode application to Create / Remove / Resize OSD objects from a device, for use with the osdblk.ko block device driver. See inside patch for Usage instructions. Signed-off-by: Boaz Harrosh <bharrosh@xxxxxxxxxxx> --- usr/Makefile | 12 ++- usr/osdblk.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 347 insertions(+), 1 deletions(-) create mode 100644 usr/osdblk.c diff --git a/usr/Makefile b/usr/Makefile index 2021d9b..534fba7 100755 --- a/usr/Makefile +++ b/usr/Makefile @@ -36,7 +36,7 @@ CFLAGS = -fPIC $(CWARN) $(INCLUDES) $(DEFINES) OSD_LIBS=-L../lib -losd -ALL = osd_test mkfs.exofs +ALL = osd_test mkfs.exofs osdblk all: $(DEPEND) $(ALL) clean: $(ALL:=_clean) @@ -78,6 +78,16 @@ mkfs.exofs_clean: $(DEPEND): $(mkfs_COMMON_OBJ:.o=.c) $(mkfs_OBJ:.o=.c) +# =============== osdblk ====================================================== +osdblk_OBJ=osdblk.o + +osdblk: $(osdblk_OBJ) + $(CC) -o $@ $^ $(OSD_LIBS) + +osdblk_clean: + +$(DEPEND): $(osdblk_OBJ:.o=.c) + # =============== common rules ================================================= # every thing should compile if Makefile changed %.o: %.c Makefile diff --git a/usr/osdblk.c b/usr/osdblk.c new file mode 100644 index 0000000..f7df257 --- /dev/null +++ b/usr/osdblk.c @@ -0,0 +1,336 @@ +/* + * osdblk.c - A user-mode program that calls into the osd ULD + * + * Copyright (C) 2009 Panasas Inc. All rights reserved. + * + * Authors: + * Boaz Harrosh <bharrosh@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Panasas company nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <open-osd/libosd.h> + +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> + +#define OSDBLK_ERR(fmt, a...) fprintf(stderr, "osdblk: " fmt, ##a) +#define OSDBLK_INFO(fmt, a...) printf("osdblk: " fmt, ##a) + +#ifdef CONFIG_OSDBLK_DEBUG +#define OSDBLK_DBGMSG(fmt, a...) \ + printf("osdblk @%s:%d: " fmt, __func__, __LINE__, ##a) +#else +#define EXOFS_DBGMSG(fmt, a...) \ + if (0) printf(fmt, ##a); +#endif + +static void usage(void) +{ + static char msg[] = { + "usage: osdblk COMMAND --pid=pid_no --obj=obj_no --length=ob_size /dev/osdX\n" + "\n" + "COMMAND is one of: --create | --remove | --resize\n" + "--create | -c\n" + " Create a new object. If object exist returns error\n" + " --length can be used to denote an initial size\n" + "\n" + "--remove\n" + " remove an existing object. If does not exist does nothing\n" + " --length is ignored\n" + "\n" + "--resize | -s\n" + " Resize an existing object. If does not exist errors\n" + " If --length=0 then does nothing (Only check for existance)\n" + "\n" + "--pid=pid_no | -p pid_no\n" + " pid_no is the partition 64bit number of the object in question\n" + " Both 0xabc hex or decimal anotation can be used\n" + "\n" + "--obj=obj_no | -o obj_no\n" + " obj_no is the object 64bit number of the object in question\n" + " Both 0xabc hex or decimal anotation can be used\n" + "\n" + "--length=size | -l size\n" + " \"size\" is the new size of the object to be set\n" + " 0xhex or decimal can be used. G, M, K can be appended to the\n" + " number to denote base-two Giga Mega or Kilo\n" + "\n" + "/dev/osdX is the osd LUN (char-dev) to use containing the object\n" + "\n" + "Description: Create Remove or Resize an OSD object on an OSD LUN\n" + " The object can later be used, for example, by the\n" + " osdblk device driver\n" + }; + + printf(msg); +} + +#define _LLU(x) ((unsigned long long)x) + +static u64 ullwithGMK(char *optarg) +{ + char *pGMK; + u64 mul; + u64 val = strtoll(optarg, &pGMK, 0); + + switch (*pGMK) { + case 'K': + case 'k': + mul = 1024LLU; + break; + case 'M': + mul = 1024LLU * 1024LLU; + break; + case 'G': + mul = 1024LLU * 1024LLU * 1024LLU; + break; + default: + mul = 1; + } + + return val * mul; +} + +static void osdblk_make_credential(u8 *creds, struct osd_obj_id *obj, + bool is_v1) +{ + osd_sec_init_nosec_doall_caps(creds, obj, false, is_v1); +} + +static int osdblk_exec(struct osd_request *or, u8 *cred) +{ + struct osd_sense_info osi; + int ret; + + ret = osd_finalize_request(or, 0, cred, NULL); + if (ret) { + OSDBLK_ERR("Error: Faild to osd_finalize_request() => %d\n", + ret); + return ret; + } + + osd_execute_request(or); + ret = osd_req_decode_sense(or, &osi); + + if (ret) { /* translate to Linux codes */ + if (osi.additional_code == scsi_invalid_field_in_cdb) { + if (osi.cdb_field_offset == OSD_CFO_STARTING_BYTE) + ret = 0; /*this is OK*/ + if (osi.cdb_field_offset == OSD_CFO_OBJECT_ID) + ret = -ENOENT; + else + ret = -EINVAL; + } else if (osi.additional_code == osd_quota_error) + ret = -ENOSPC; + else + ret = -EIO; + } + + return ret; +} + +static int do_resize(struct osd_dev *od, struct osd_obj_id *obj, u64 size) +{ + struct osd_request *or = osd_start_request(od, GFP_KERNEL); + __be64 be_size = cpu_to_be64(size); + u8 creds[OSD_CAP_LEN]; + struct osd_attr attr_logical_length = ATTR_SET( + OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, + sizeof(be_size), &be_size); + int ret; + + if (unlikely(!or)) + return -ENOMEM; + + osdblk_make_credential(creds, obj, osd_req_is_ver1(or)); + + osd_req_set_attributes(or, obj); + osd_req_add_set_attr_list(or, &attr_logical_length, 1); + + ret = osdblk_exec(or, creds); + osd_end_request(or); + + if (ret) + return ret; + + OSDBLK_INFO("Resized: pid=0x%llx oid=0x%llx length=0x%llx\n", + _LLU(obj->partition), _LLU(obj->id), + _LLU(size)); + + return 0; +} + +static int do_create(struct osd_dev *od, struct osd_obj_id *obj, u64 size) +{ + struct osd_request *or = osd_start_request(od, GFP_KERNEL); + u8 creds[OSD_CAP_LEN]; + int ret; + + if (unlikely(!or)) + return -ENOMEM; + + osdblk_make_credential(creds, obj, osd_req_is_ver1(or)); + osd_req_create_object(or, obj); + ret = osdblk_exec(or, creds); + osd_end_request(or); + + if (ret) + return ret; + + OSDBLK_INFO("Created: pid=0x%llx oid=0x%llx\n", + _LLU(obj->partition), _LLU(obj->id)); + + return do_resize(od, obj, size); +} + +static int do_remove(struct osd_dev *od, struct osd_obj_id *obj) +{ + struct osd_request *or = osd_start_request(od, GFP_KERNEL); + u8 creds[OSD_CAP_LEN]; + int ret; + + if (unlikely(!or)) + return -ENOMEM; + + osdblk_make_credential(creds, obj, osd_req_is_ver1(or)); + osd_req_remove_object(or, obj); + ret = osdblk_exec(or, creds); + osd_end_request(or); + + if (ret) + return ret; + + OSDBLK_INFO("Removed: pid=0x%llx oid=0x%llx\n", + _LLU(obj->partition), _LLU(obj->id)); + + return 0; +} + +enum osd_todo { + osd_none = 0, + osd_create, + osd_remove, + osd_resize, +}; + +static int _do(char *path, struct osd_obj_id *obj, u64 size, + enum osd_todo todo) +{ + struct osd_dev *od; + int ret; + + ret = osd_open(path, &od); + if (ret) + return ret; + + switch (todo) { + case osd_create: + ret = do_create(od, obj, size); + break; + case osd_remove: + ret = do_remove(od, obj); + break; + case osd_resize: + ret = do_resize(od, obj, size); + break; + default: + usage(); + return 1; + } + + osd_close(od); + + /* osd lib has Kernel API which return negative errors */ + return -ret; +} + +int main(int argc, char *argv[]) +{ + struct option opt[] = { + {.name = "create", .has_arg = 0, .flag = NULL, .val = 'c'} , + {.name = "remove", .has_arg = 0, .flag = NULL, .val = 'r'} , + {.name = "resize", .has_arg = 0, .flag = NULL, .val = 's'} , + {.name = "pid", .has_arg = 1, .flag = NULL, .val = 'p'} , + {.name = "oid", .has_arg = 1, .flag = NULL, .val = 'o'} , + {.name = "size", .has_arg = 1, .flag = NULL, .val = 'l'} , + + {.name = 0, .has_arg = 0, .flag = 0, .val = 0} , + }; + struct osd_obj_id obj = {.id = 0}; + enum osd_todo todo = osd_none; + u64 size = 0; + char op; + int err; + + while ((op = getopt_long(argc, argv, "csp:o:l:", opt, NULL)) != -1) { + switch (op) { + case 'c': + todo = osd_create; + break; + case 'r': + todo = osd_remove; + break; + case 's': + todo = osd_resize; + break; + + case 'p': + obj.partition = strtoll(optarg, NULL, 0); + break; + case 'o': + obj.id = strtoll(optarg, NULL, 0); + break; + + case 'l': + size = ullwithGMK(optarg); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc <= 0) { + usage(); + return 1; + } + + if ((todo == osd_none) || !obj.partition || !obj.id) { + usage(); + return 1; + } + + err = _do(argv[0], &obj, size, todo); + if (err) + OSDBLK_ERR("Error: %s\n", strerror(err)); + + return err; +} -- 1.6.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html