diff --git a/.gitignore b/.gitignore index 7d6760e..a343e08 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,6 @@ Module.symvers .tmp_versions/ modules.order -srb.mod.c +*.mod.c linux/ linux-clones/ diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000..47aff43 --- /dev/null +++ b/Kbuild @@ -0,0 +1 @@ +obj-y := srb/ diff --git a/Makefile b/Makefile index 129ec92..62fceea 100644 --- a/Makefile +++ b/Makefile @@ -1,34 +1,23 @@ -## -## Copyright (C) 2014 SCALITY SA - http://www.scality.com -## -## This file is part of ScalityRestBlock. -## -## ScalityRestBlock is free software: you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation, either version 3 of the License, or -## (at your option) any later version. -## -## ScalityRestBlock is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with ScalityRestBlock. If not, see . -## -## +# Copyright (C) 2014, 2015 Scality SA - http://www.scality.com +# +# This file is part of ScalityRestBlock. +# +# ScalityRestBlock is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ScalityRestBlock is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ScalityRestBlock. If not, see . -TARGET := srb +KDIR ?= /lib/modules/$(shell uname -r)/build -srb-objs := srb_driver.o srb_sysfs.o srb_cdmi.o srb_http.o jsmn/jsmn.o -obj-m := $(TARGET).o -KDIR := /lib/modules/$(shell uname -r)/build -PWD := $(shell pwd) +default: modules -ccflags-y += -g3 -O2 -Wall -Wextra -Wno-unused-parameter -Werror -Warray-bounds -D_REENTRANT -DJSMN_PARENT_LINKS - -all: - $(MAKE) -C $(KDIR) M=$(PWD) modules - -clean: - $(MAKE) -C $(KDIR) M=$(PWD) clean +modules modules_install clean help: + $(MAKE) -C $(KDIR) M=$$PWD $@ diff --git a/README.centos b/README.centos deleted file mode 100644 index 830817f..0000000 --- a/README.centos +++ /dev/null @@ -1,52 +0,0 @@ - README file for CentOS Installation - - -INTRODUCTION -============ - -This Linux Kernel Driver can be installed on CentOS v7 and greater releases -with Linux Kernel v3.10 and greater. - - -Installing the driver with a service ------------------------------------- -CentOS system uses 'systemd' as system management daemon which has been -designed for Linux as a replacement of the init system inherited from -UNIX System V. -'systemd' Project: http://www.freedesktop.org/wiki/Software/systemd/ - -In order to install the driver as a service, you can install the 'systemd' -script in order to configure and use the driver to access your CDMI Rest API. - -In order to install the system script, please use the following command: - - # cp systemd/srb.service /etc/systemd/system/ - # cp systemd/srb.conf /etc/ - -NB: Update your srb.conf according to your CDMI condiguration: ---- - set KMOD_PATH with the path where you have built the driver - - set URLS with your server(s) URL(S) - - -Using the driver as a service ------------------------------ -'systemd' provides a command named 'systemctl' that allows to interact with any -service. - -In order to start / stop the service use the following command: - - # systemctl start srb.service - # systemctl stop srb.service - -In order to enable / disable the service at boot time, use the following command: - - # systemctl enable srb.service - # systemctl disable srb.service - - -Listing device used by ScalityRestBlock service: - # systemctl list-units | grep -E '(rest|srb)' - UNIT LOAD ACTIVE SUB DESCRIPTION - sys-devices-virtual-block-srba-srba1.device loaded active plugged /sys/devices/virtual/block/srba/srba1 - sys-devices-virtual-block-srba.device loaded active plugged /sys/devices/virtual/block/srba - srb.service loaded active exited Scality RestBlock driver diff --git a/README.md b/README.md index 1ff0816..0e617b7 100644 --- a/README.md +++ b/README.md @@ -66,12 +66,6 @@ the servers: * add\_urls: allows adding one or more server urls to the driver * remove\_urls: allows removing one or more server urls from the driver -Then, the following management files are available: - * create: allows creating a volume file on the storage - * extend: allows extending a volume (increasing size), whether it is attached - or not - * destroy: deletes the volume file from the storage - The way those files work is described in the following sections, each dedicated to one management (/sys) file. Please mind that each one of theses files can be displayed (using cat on them) to show a simple usage text. @@ -138,69 +132,6 @@ Note also that when unloading the module, the devices are detached automatically before the module can actually be unloaded. -Creating a new volume ---------------------- - -To create a volume, just give the name of the file to create to the driver, -accompanied by a byte size, such as in the following example: - - # echo "filename human\_readable\_size" > /sys/class/srb/create - -The volume will be created on the storage with the requested size. -But beware: - * The human readable size formats understood by the LKM are the following: - * [integer number]: size in bytes - * [integer number]k: size in Kilobytes - * [integer number]M: size in Megabytes - * [integer number]G: size in Gigabytes - * At least one server url must exist and be valid for the volume to be -created - * Created volume are not automatically attached as a device on the system. - -Before you can use the volume, you have to attach it through the attach /sys -file (see below). - -Extending a volume ------------------- - -Sometimes, a volume might look to be provisionned too small for the actual -need. For this reason, you can actually extend it through the extend /sys -control file. This command follows the same usage as the create command, thus -using it is simple: - - # echo "volumename human\_readable\_size" > /sys/class/srb/extend - -Be aware that this command can only extend a volume, meaning the size you give -must be higher than the current size. Also, this is a supported operation -on an attached volume, though any file-system formatted onto the volume should -be extended to the new volume's size manually since most of the filesystems -don't support flexible partition or volume extension (unless you are using LVM -underneath). - -Once the operation is complete, the new size will be properly reported to the -system without any additional administrative task. For instance, displaying the -contents of the file /proc/partitions will show you the updated size of the -volume. - -Note that the human readable size format of the extend command follows the -same rules as that of the create command. - -Destruction of an existing volume ---------------------------------- - -Destroying a volume means that it volume will no longer be accessible after -a successful operation. To destroy a volume, give the driver the name of the -file to remove from the storage as the following example shows: - - # echo filename > /sys/class/srb/destroy - -The volume is then removed from storage and is no longer accessible. -But beware: - * The destroyed volume must exist beforehand - * Destroying a volume used by other drivers on other machines srb -can lead to errors and unexpected behaviors; this is untested. - - Attaching and Detaching devices =============================== @@ -219,26 +150,6 @@ the three following management files are available: They are described in detail in the following sections. -Listing the volumes -------------------- - -Since you might not know from memory which volumes exist on your servers, -you might want a way to list those, to attach them easily. One of the ways -provided is to read the content of the volumes /sys file: - -``` - # cat /sys/class/srb/volumes - Volume1 - Foo - Bar - Baz - Qux -``` - -This way, you can know that you have five volumes available on your servers, -and know their names, which will allow you to either attach, extend or destroy -them. - Attaching a device ------------------ diff --git a/README.ubuntu b/README.ubuntu deleted file mode 100644 index 7325728..0000000 --- a/README.ubuntu +++ /dev/null @@ -1,42 +0,0 @@ - README file for Ubuntu Installation - - -INTRODUCTION -============ - -This Linux Kernel Driver can be installed on Ubuntu 14 LTS and greater releases -with Linux Kernel v3.10 and greater. - - -Installing the driver with a service ------------------------------------- -Ubuntu system uses 'UNIX System V' as system management daemon. - - -In order to install the driver as a service, you have to install the 'systemd' -script in order to configure and use the driver to access your CDMI Rest API. - -In order to install the system script, please use the following command: - - # cp system-v_init/srb-ubuntu.init /etc/init.d/srb - # cp system-v_init/srb.conf /etc/ - -NB: Update your srb.conf according to your CDMI condiguration: ---- - set KMOD_PATH with the path where you have built the driver - - set URLS with your server URL(S) - - -Using the driver as a service ------------------------------ -Ubuntu systems provide a command named 'update-rc.d' that allows to interact with -any service. - -In order to start / stop the service use the following command: - - # /etc/init.d/srb start - # /etc/init.d/srb stop - -In order to enable / disable the service at boot time, use the following command: - - # update-rc.d srb defaults - # update-rc.d -f srb remove diff --git a/bin/srb b/bin/srb new file mode 100755 index 0000000..295332c --- /dev/null +++ b/bin/srb @@ -0,0 +1,155 @@ +#!/usr/bin/env python + +# srb - A simple CDMI volume operations client +# Copyright (C) 2015 Scality SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import sys +import argparse +import subprocess + +import requests + +MODULE_NAME = 'srb' +DEFAULT_HEADERS = { + 'User-Agent': 'srb/0.0.1', +} + +def call_silent(cmd): + with open('/dev/null', 'w') as fd: + return subprocess.call(cmd, stdout=fd, stderr=fd) + +def stdout(msg, *args): + sys.stdout.writelines([msg % args, '\n']) + +def stderr(msg, *args): + sys.stderr.writelines([msg % args, '\n']) + +def handle_module_load(args): + rc = call_silent(['modinfo', '-n', MODULE_NAME]) + + if rc != 0: + raise EnvironmentError('Module \'%s\' not found' % MODULE_NAME) + + rc = call_silent(['modprobe', MODULE_NAME]) + if rc == 0: + stdout('Module \'%s\' loaded successfully', MODULE_NAME) + else: + stderr('Failed to load module \'%s\'', MODULE_NAME) + +def make_headers(extra=None): + result = DEFAULT_HEADERS.copy() + if extra: + result.update(extra) + + return result + +def handle_volume_list(args): + headers = make_headers({ + 'X-CDMI-Specification-Version': '1.0.1', + }) + + response = requests.get(args.url, headers=headers) + response.raise_for_status() + + for child in response.json()['children']: + print child + +def handle_volume_create(args): + headers = make_headers({ + 'If-None-Match': '*', + }) + + response = requests.put(args.url, headers=headers) + response.raise_for_status() + + headers = make_headers({ + 'X-Scal-Truncate': args.size, + }) + + response = requests.put(args.url, headers=headers) + response.raise_for_status() + +def handle_volume_delete(args): + headers = make_headers() + + response = requests.delete(args.url, headers=headers) + response.raise_for_status() + +def handle_volume_extend(args): + headers = make_headers() + params = { + 'metadata': 1, + } + + response = requests.get(args.url, params=params) + response.raise_for_status() + + current_size = response.json()['metadata']['cdmi_size'] + + if current_size > args.size: + raise ValueError('Can\'t shrink volumes') + + headers == make_headers({ + 'X-Scal-Truncate': args.size, + }) + + response = requests.put(args.url, headers=headers) + response.raise_for_status() + +def main(args): + parser = argparse.ArgumentParser( + description='SRB utilities', + epilog='Note: For some commands root permissions are required') + + subparser = parser.add_subparsers(title='subcommands') + + parser_module_load = subparser.add_parser('module-load') + parser_module_load.set_defaults(func=handle_module_load) + + parser_volume_list = subparser.add_parser('volume-list') + parser_volume_list.set_defaults(func=handle_volume_list) + parser_volume_list.add_argument('url', metavar='URL', type=str, + help='CDMI container URL') + + parser_volume_create = subparser.add_parser('volume-create') + parser_volume_create.set_defaults(func=handle_volume_create) + parser_volume_create.add_argument('url', metavar='URL', type=str, + help='CDMI object URL') + parser_volume_create.add_argument('size', metavar='SIZE', type=int, + help='Object size (in bytes)') + + parser_volume_delete = subparser.add_parser('volume-delete') + parser_volume_delete.set_defaults(func=handle_volume_delete) + parser_volume_delete.add_argument('url', metavar='URL', type=str, + help='CDMI object URL') + + parser_volume_extend = subparser.add_parser('volume-extend') + parser_volume_extend.set_defaults(func=handle_volume_extend) + parser_volume_extend.add_argument('url', metavar='URL', type=str, + help='CDMI object URL') + parser_volume_extend.add_argument('size', metavar='SIZE', type=int, + help='Object size (in bytes)') + + args = parser.parse_args(args) + + try: + args.func(args) + except Exception as exc: + stderr(str(exc)) + sys.exit(1) + +if __name__ == '__main__': + main(None) diff --git a/include/srb/srb-cdmi.h b/include/srb/srb-cdmi.h new file mode 100644 index 0000000..10234ba --- /dev/null +++ b/include/srb/srb-cdmi.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Scality SA - http://www.scality.com + * + * This file is part of ScalityRestBlock. + * + * ScalityRestBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ScalityRestBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see . + * + */ + +#ifndef __SRB_CDMI_H__ +#define __SRB_CDMI_H__ + +#include + +#include +#include + +#define SRB_CDMI_URL_SIZE (256) +#define SRB_CDMI_HTTP_HEADER_SIZE (1024) + +#define SRB_CDMI_XMIT_BUFFER_SIZE (SRB_CDMI_HTTP_HEADER_SIZE + SRB_DEV_SECTORSIZE) + +struct srb_cdmi_desc { + /* For /sys/block/srb?/srb_url */ + char url[SRB_CDMI_URL_SIZE + 1]; + uint8_t state; + char ip_addr[16]; + uint16_t port; + char filename[SRB_CDMI_URL_SIZE + 1]; + char xmit_buff[SRB_CDMI_XMIT_BUFFER_SIZE]; + uint64_t nb_requests; /* Number of HTTP + * requests already sent + * through this socket */ + struct scatterlist sgl[SRB_DEV_NB_PHYS_SEGS]; + int sgl_size; + struct socket *socket; + struct sockaddr_in sockaddr; + struct timeval timeout; +}; + +int srb_cdmi_init(srb_debug_t *dbg, struct srb_cdmi_desc *desc, + const char *url); +int srb_cdmi_connect(srb_debug_t *dbg, struct srb_cdmi_desc *desc); +int srb_cdmi_disconnect(srb_debug_t *dbg, struct srb_cdmi_desc *desc); + +int srb_cdmi_getsize(srb_debug_t *dbg, struct srb_cdmi_desc *desc, + uint64_t *size); + +int srb_cdmi_getrange(srb_debug_t *dbg, struct srb_cdmi_desc *desc, + uint64_t offset, int size); + +int srb_cdmi_putrange(srb_debug_t *dbg, struct srb_cdmi_desc *desc, + uint64_t offset, int size); +#endif diff --git a/include/srb/srb-http.h b/include/srb/srb-http.h new file mode 100644 index 0000000..65bf3ca --- /dev/null +++ b/include/srb/srb-http.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2015 Scality SA - http://www.scality.com + * + * This file is part of ScalityRestBlock. + * + * ScalityRestBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ScalityRestBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see . + * + */ + +#ifndef __SRB_HTTP_H__ +#define __SRB_HTTP_H__ + +#include + +/* + * Status Ranges extracted from RFC 2616 + */ +enum srb_http_statusrange +{ + SRB_HTTP_STATUSRANGE_INFORMATIONAL = 1, // 1.. + SRB_HTTP_STATUSRANGE_SUCCESS = 2, // 2.. + SRB_HTTP_STATUSRANGE_REDIRECTION = 3, // 3.. + SRB_HTTP_STATUSRANGE_CLIENTERROR = 4, // 4.. + SRB_HTTP_STATUSRANGE_SERVERERROR = 5, // 5.. + SRB_HTTP_STATUSRANGE_EXTENDED = 0 +}; + +/* + * Codes extracted from RFC 2616 + */ +enum srb_http_statuscode +{ + SRB_HTTP_STATUS_CONTINUE = 100, // "100" ; Section 10.1.1: Continue + SRB_HTTP_STATUS_SWITCHPROTO = 101, // "101" ; Section 10.1.2: Switching Protocols + SRB_HTTP_STATUS_OK = 200, // "200" ; Section 10.2.1: OK + SRB_HTTP_STATUS_CREATED = 201, // "201" ; Section 10.2.2: Created + SRB_HTTP_STATUS_ACCEPTED = 202, // "202" ; Section 10.2.3: Accepted + SRB_HTTP_STATUS_NONAUTH_INFO = 203, // "203" ; Section 10.2.4: Non-Authoritative Information + SRB_HTTP_STATUS_NOCONTENT = 204, // "204" ; Section 10.2.5: No Content + SRB_HTTP_STATUS_RESETCONTENT = 205, // "205" ; Section 10.2.6: Reset Content + SRB_HTTP_STATUS_PARTIAL = 206, // "206" ; Section 10.2.7: Partial Content + SRB_HTTP_STATUS_MULTIPLE_CHOICES = 300, // "300" ; Section 10.3.1: Multiple Choices + SRB_HTTP_STATUS_MOVED = 301, // "301" ; Section 10.3.2: Moved Permanently + SRB_HTTP_STATUS_FOUND = 302, // "302" ; Section 10.3.3: Found + SRB_HTTP_STATUS_SEEOTHER = 303, // "303" ; Section 10.3.4: See Other + SRB_HTTP_STATUS_NOTMODIF = 304, // "304" ; Section 10.3.5: Not Modified + SRB_HTTP_STATUS_USE_PROXY = 305, // "305" ; Section 10.3.6: Use Proxy + SRB_HTTP_STATUS_TEMP_REDIR = 307, // "307" ; Section 10.3.8: Temporary Redirect + SRB_HTTP_STATUS_BADREQ = 400, // "400" ; Section 10.4.1: Bad Request + SRB_HTTP_STATUS_UNAUTH = 401, // "401" ; Section 10.4.2: Unauthorized + SRB_HTTP_STATUS_PAYMENT_REQ = 402, // "402" ; Section 10.4.3: Payment Required + SRB_HTTP_STATUS_FORBIDDEN = 403, // "403" ; Section 10.4.4: Forbidden + SRB_HTTP_STATUS_NOT_FOUND = 404, // "404" ; Section 10.4.5: Not Found + SRB_HTTP_STATUS_NOT_ALLOWED = 405, // "405" ; Section 10.4.6: Method Not Allowed + SRB_HTTP_STATUS_NOT_ACCEPTABLE = 406, // "406" ; Section 10.4.7: Not Acceptable + SRB_HTTP_STATUS_PROXYAUTH_REQ = 407, // "407" ; Section 10.4.8: Proxy Authentication Required + SRB_HTTP_STATUS_REQTIMEOUT = 408, // "408" ; Section 10.4.9: Request Time-out + SRB_HTTP_STATUS_CONFLICT = 409, // "409" ; Section 10.4.10: Conflict + SRB_HTTP_STATUS_GONE = 410, // "410" ; Section 10.4.11: Gone + SRB_HTTP_STATUS_LENGTH_REQ = 410, // "411" ; Section 10.4.12: Length Required + SRB_HTTP_STATUS_PRECOND_FAILED = 412, // "412" ; Section 10.4.13: Precondition Failed + SRB_HTTP_STATUS_ENTITY_TOOLARGE = 413, // "413" ; Section 10.4.14: Request Entity Too Large + SRB_HTTP_STATUS_URI_TOOLARGE = 414, // "414" ; Section 10.4.15: Request-URI Too Large + SRB_HTTP_STATUS_UNSUP_MEDIA = 415, // "415" ; Section 10.4.16: Unsupported Media Type + SRB_HTTP_STATUS_BADRANGE = 416, // "416" ; Section 10.4.17: Requested range not satisfiable + SRB_HTTP_STATUS_EXPECT_FAILED = 417, // "417" ; Section 10.4.18: Expectation Failed + SRB_HTTP_STATUS_INTERNAL_ERROR = 500, // "500" ; Section 10.5.1: Internal Server Error + SRB_HTTP_STATUS_NOTIMPL = 501, // "501" ; Section 10.5.2: Not Implemented + SRB_HTTP_STATUS_BAD_GW = 502, // "502" ; Section 10.5.3: Bad Gateway + SRB_HTTP_STATUS_SERVICE_UNAVAIL = 503, // "503" ; Section 10.5.4: Service Unavailable + SRB_HTTP_STATUS_GW_TIMEOUT = 504, // "504" ; Section 10.5.5: Gateway Time-out + SRB_HTTP_STATUS_VERSION_NOTSUPP = 505, // "505" ; Section 10.5.6: HTTP Version not supported + SRB_HTTP_STATUS_EXTENSION = 0 // ; extension-code +}; + +int srb_http_check_response_complete(char *buff, int len); +int srb_http_mkrange(char *cmd, char *buff, int len, char *host, char *page, + uint64_t start, uint64_t end); + +int srb_http_header_get_uint64(char *buff, int len, char *key, + uint64_t *value); +int srb_http_skipheader(char **buff, int *len); +int srb_http_mkmetadata(char *buff, int len, char *host, char *page); + +int srb_http_get_status(char *buf, int len, enum srb_http_statuscode *code); +enum srb_http_statusrange srb_http_get_status_range(enum srb_http_statuscode status); + +#endif diff --git a/srb_log.h b/include/srb/srb-log.h similarity index 75% rename from srb_log.h rename to include/srb/srb-log.h index 34e7b6e..00e88ce 100644 --- a/srb_log.h +++ b/include/srb/srb-log.h @@ -18,8 +18,13 @@ * */ -#ifndef __SRBLOCK_LOG_H__ -# define __SRBLOCK_LOG_H__ +#ifndef __SRB_LOG_H__ +#define __SRB_LOG_H__ + +typedef struct srb_debug_s { + const char *name; + int level; +} srb_debug_t; /* * Standard Kernel value for log level @@ -53,7 +58,7 @@ #define SRB_LOGFMT_LVL(lvl) "[" SRB_LVLSTR_##lvl "]" #define SRB_LOGFMT_NAME DEV_NAME ": " #define SRB_LOGFMT_DEVICE "device %i: " -#define SRB_LOGARG_DEVICE(dev) (dev)->major +#define SRB_LOGARG_DEVICE(dev) srb_device_get_major(dev) #define SRB_LOGFMT_MODULE "%s: " #define SRB_LOGARG_MODULE(dbg) dbg ? (dbg)->name : NULL #define SRB_LOGFMT_DBG "@%s(l.%i): " @@ -128,22 +133,56 @@ if (level >= SRB_EMERG) SRB_INTERNAL_DBG(EMERG, fmt, ##args) #define SRBDEV_LOG_DEBUG(dev, fmt, a...) \ - if ((dev)->debug.level >= SRB_DEBUG) SRBDEV_INTERNAL_DBG(DEBUG, dev, &((dev)->debug), fmt, ##a) + do { \ + const srb_debug_t *debug = srb_device_get_debug(dev); \ + if (debug->level >= SRB_DEBUG) SRBDEV_INTERNAL_DBG(DEBUG, dev, debug, fmt, ##a); \ + } while(0) #define SRBDEV_LOG_INFO(dev, fmt, a...) \ - if ((dev)->debug.level >= SRB_INFO) SRBDEV_INTERNAL_DBG(INFO, dev, &((dev)->debug), fmt, ##a) + do { \ + const srb_debug_t *debug = srb_device_get_debug(dev); \ + if (debug->level >= SRB_INFO) SRBDEV_INTERNAL_DBG(INFO, dev, debug, fmt, ##a) \ + } while(0) #define SRBDEV_LOG_NOTICE(dev, fmt, a...) \ - if ((dev)->debug.level >= SRB_NOTICE) SRBDEV_INTERNAL_DBG(NOTICE, dev, &((dev)->debug), fmt, ##a) + do { \ + const srb_debug_t *debug = srb_device_get_debug(dev); \ + if (debug->level >= SRB_NOTICE) SRBDEV_INTERNAL_DBG(NOTICE, dev, debug, fmt, ##a) \ + } while(0) #define SRBDEV_LOG_WARN(dev, fmt, a...) \ - if ((dev)->debug.level >= SRB_WARNING) SRBDEV_INTERNAL_DBG(WARNING, dev, &((dev)->debug), fmt, ##a) + do { \ + const srb_debug_t *debug = srb_device_get_debug(dev); \ + if (debug->level >= SRB_WARNING) SRBDEV_INTERNAL_DBG(WARNING, dev, debug, fmt, ##a) \ + } while(0) #define SRBDEV_LOG_ERR(dev, fmt, a...) \ - if ((dev)->debug.level >= SRB_ERR) SRBDEV_INTERNAL_DBG(ERR, dev, &((dev)->debug), fmt, ##a) + do { \ + const srb_debug_t *debug = srb_device_get_debug(dev); \ + if (debug->level >= SRB_ERR) SRBDEV_INTERNAL_DBG(ERR, dev, debug, fmt, ##a) \ + } while(0) #define SRBDEV_LOG_CRIT(dev, fmt, a...) \ - if ((dev)->debug.level >= SRB_CRIT) SRBDEV_INTERNAL_DBG(CRIT, dev, &((dev)->debug), fmt, ##a) + do { \ + const srb_debug_t *debug = srb_device_get_debug(dev); \ + if (debug->level >= SRB_CRIT) SRBDEV_INTERNAL_DBG(CRIT, dev, debug, fmt, ##a) \ + } while(0) #define SRBDEV_LOG_ALERT(dev, fmt, a...) \ - if ((dev)->debug.level >= SRB_ALERT) SRBDEV_INTERNAL_DBG(ALERT, dev, &((dev)->debug), fmt, ##a) + do { \ + const srb_debug_t *debug = srb_device_get_debug(dev); \ + if (debug->level >= SRB_ALERT) SRBDEV_INTERNAL_DBG(ALERT, dev, debug, fmt, ##a) \ + } while(0) #define SRBDEV_LOG_EMERG(dev, fmt, a...) \ - if ((dev)->debug.level >= SRB_EMERG) SRBDEV_INTERNAL_DBG(EMERG, dev, &((dev)->debug), fmt, ##a) + do { \ + const srb_debug_t *debug = srb_device_get_debug(dev); \ + if (debug->level >= SRB_EMERG) SRBDEV_INTERNAL_DBG(EMERG, dev, debug, fmt, ##a) \ + } while(0) +#if 0 +#define SRBDEV_LOG_DEBUG(dev, fmt, a...) +#define SRBDEV_LOG_INFO(dev, fmt, a...) +#define SRBDEV_LOG_NOTICE(dev, fmt, a...) +#define SRBDEV_LOG_WARN(dev, fmt, a...) +#define SRBDEV_LOG_ERR(dev, fmt, a...) +#define SRBDEV_LOG_CRIT(dev, fmt, a...) +#define SRBDEV_LOG_ALERT(dev, fmt, a...) +#define SRBDEV_LOG_EMERG(dev, fmt, a...) +#endif /* #define SRB_INFO(fmt, a...) \ @@ -153,4 +192,4 @@ printk(KERN_ERR "srb: " fmt "\n" , ##a) */ -#endif /* ! __SRBLOCK_LOG_H__ */ +#endif /* ! __SRB_LOG_H__ */ diff --git a/include/srb/srb-trace.h b/include/srb/srb-trace.h new file mode 100644 index 0000000..f09179c --- /dev/null +++ b/include/srb/srb-trace.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 Scality SA - http://www.scality.com + * + * This file is part of ScalityRestBlock. + * + * ScalityRestBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ScalityRestBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ScalityRestBlock. If not, see . + * + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM srb + +#if !defined(_SRB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _SRB_TRACE_H + +#include + +#endif /* _SRB_TRACE_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH srb/ +#define TRACE_INCLUDE_FILE srb-trace +#include diff --git a/include/srb/srb.h b/include/srb/srb.h new file mode 100644 index 0000000..30a3d61 --- /dev/null +++ b/include/srb/srb.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 Scality SA - http://www.scality.com + * + * This file is part of ScalityRestBlock. + * + * ScalityRestBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ScalityRestBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see . + * + */ + +#ifndef __SRB_H__ +#define __SRB_H__ + +#define SRB_DEV_SECTORSIZE (1 * 1024 * 1024) +/* This defines the max_hw_sectors_kb value + * Unit is a sector (512B) + */ +#define SRB_DEV_NB_PHYS_SEGS (512 * 4 * 32) + +#endif diff --git a/jsmn/.hg/00changelog.i b/jsmn/.hg/00changelog.i deleted file mode 100644 index d3a8311..0000000 Binary files a/jsmn/.hg/00changelog.i and /dev/null differ diff --git a/jsmn/.hg/branch b/jsmn/.hg/branch deleted file mode 100644 index 4ad96d5..0000000 --- a/jsmn/.hg/branch +++ /dev/null @@ -1 +0,0 @@ -default diff --git a/jsmn/.hg/cache/branchheads b/jsmn/.hg/cache/branchheads deleted file mode 100644 index 8215aaa..0000000 --- a/jsmn/.hg/cache/branchheads +++ /dev/null @@ -1,4 +0,0 @@ -54f042505d20c8bbee2aba9c656eb083ad219254 78 -54f042505d20c8bbee2aba9c656eb083ad219254 default -531a30361bd2fce5b2180f0e0028bb74faf71129 markdown -3db7fc681e7a4cbaaba03edb51bbf0c875c5ed21 clean diff --git a/jsmn/.hg/cache/tags b/jsmn/.hg/cache/tags deleted file mode 100644 index 6cd9dae..0000000 --- a/jsmn/.hg/cache/tags +++ /dev/null @@ -1,4 +0,0 @@ -78 54f042505d20c8bbee2aba9c656eb083ad219254 -63 531a30361bd2fce5b2180f0e0028bb74faf71129 -60 3db7fc681e7a4cbaaba03edb51bbf0c875c5ed21 - diff --git a/jsmn/.hg/dirstate b/jsmn/.hg/dirstate deleted file mode 100644 index 904dae2..0000000 Binary files a/jsmn/.hg/dirstate and /dev/null differ diff --git a/jsmn/.hg/hgrc b/jsmn/.hg/hgrc deleted file mode 100644 index 2290de1..0000000 --- a/jsmn/.hg/hgrc +++ /dev/null @@ -1,2 +0,0 @@ -[paths] -default = https://bitbucket.org/zserge/jsmn diff --git a/jsmn/.hg/requires b/jsmn/.hg/requires deleted file mode 100644 index c1674f2..0000000 --- a/jsmn/.hg/requires +++ /dev/null @@ -1,4 +0,0 @@ -revlogv1 -fncache -store -dotencode diff --git a/jsmn/.hg/store/00changelog.i b/jsmn/.hg/store/00changelog.i deleted file mode 100644 index 88c2935..0000000 Binary files a/jsmn/.hg/store/00changelog.i and /dev/null differ diff --git a/jsmn/.hg/store/00manifest.i b/jsmn/.hg/store/00manifest.i deleted file mode 100644 index 88753ba..0000000 Binary files a/jsmn/.hg/store/00manifest.i and /dev/null differ diff --git a/jsmn/.hg/store/data/_l_i_c_e_n_s_e.i b/jsmn/.hg/store/data/_l_i_c_e_n_s_e.i deleted file mode 100644 index fba581b..0000000 Binary files a/jsmn/.hg/store/data/_l_i_c_e_n_s_e.i and /dev/null differ diff --git a/jsmn/.hg/store/data/_makefile.i b/jsmn/.hg/store/data/_makefile.i deleted file mode 100644 index 722280c..0000000 Binary files a/jsmn/.hg/store/data/_makefile.i and /dev/null differ diff --git a/jsmn/.hg/store/data/_r_e_a_d_m_e.i b/jsmn/.hg/store/data/_r_e_a_d_m_e.i deleted file mode 100644 index 0433f55..0000000 Binary files a/jsmn/.hg/store/data/_r_e_a_d_m_e.i and /dev/null differ diff --git a/jsmn/.hg/store/data/_r_e_a_d_m_e.md.i b/jsmn/.hg/store/data/_r_e_a_d_m_e.md.i deleted file mode 100644 index c4f7753..0000000 Binary files a/jsmn/.hg/store/data/_r_e_a_d_m_e.md.i and /dev/null differ diff --git a/jsmn/.hg/store/data/demo.c.i b/jsmn/.hg/store/data/demo.c.i deleted file mode 100644 index 0165bea..0000000 Binary files a/jsmn/.hg/store/data/demo.c.i and /dev/null differ diff --git a/jsmn/.hg/store/data/jsmn.c.i b/jsmn/.hg/store/data/jsmn.c.i deleted file mode 100644 index 77ee228..0000000 Binary files a/jsmn/.hg/store/data/jsmn.c.i and /dev/null differ diff --git a/jsmn/.hg/store/data/jsmn.h.i b/jsmn/.hg/store/data/jsmn.h.i deleted file mode 100644 index 0bcc56c..0000000 Binary files a/jsmn/.hg/store/data/jsmn.h.i and /dev/null differ diff --git a/jsmn/.hg/store/data/jsmn__test.c.i b/jsmn/.hg/store/data/jsmn__test.c.i deleted file mode 100644 index e07c7ab..0000000 Binary files a/jsmn/.hg/store/data/jsmn__test.c.i and /dev/null differ diff --git a/jsmn/.hg/store/data/test.sh.i b/jsmn/.hg/store/data/test.sh.i deleted file mode 100644 index 7b9031c..0000000 Binary files a/jsmn/.hg/store/data/test.sh.i and /dev/null differ diff --git a/jsmn/.hg/store/fncache b/jsmn/.hg/store/fncache deleted file mode 100644 index d6b8427..0000000 --- a/jsmn/.hg/store/fncache +++ /dev/null @@ -1,9 +0,0 @@ -data/jsmn_test.c.i -data/test.sh.i -data/jsmn.h.i -data/README.i -data/demo.c.i -data/jsmn.c.i -data/LICENSE.i -data/Makefile.i -data/README.md.i diff --git a/jsmn/.hg/store/undo b/jsmn/.hg/store/undo deleted file mode 100644 index d83144c..0000000 Binary files a/jsmn/.hg/store/undo and /dev/null differ diff --git a/jsmn/.hg/undo.bookmarks b/jsmn/.hg/undo.bookmarks deleted file mode 100644 index e69de29..0000000 diff --git a/jsmn/.hg/undo.branch b/jsmn/.hg/undo.branch deleted file mode 100644 index 331d858..0000000 --- a/jsmn/.hg/undo.branch +++ /dev/null @@ -1 +0,0 @@ -default \ No newline at end of file diff --git a/jsmn/.hg/undo.desc b/jsmn/.hg/undo.desc deleted file mode 100644 index 561861e..0000000 --- a/jsmn/.hg/undo.desc +++ /dev/null @@ -1,3 +0,0 @@ -0 -pull -https://bitbucket.org/zserge/jsmn diff --git a/jsmn/.hg/undo.dirstate b/jsmn/.hg/undo.dirstate deleted file mode 100644 index e69de29..0000000 diff --git a/jsmn/LICENSE b/jsmn/LICENSE deleted file mode 100644 index c84fb2e..0000000 --- a/jsmn/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2010 Serge A. Zaitsev - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/jsmn/Makefile b/jsmn/Makefile deleted file mode 100644 index ac947a3..0000000 --- a/jsmn/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# You can put your build options here --include config.mk - -all: libjsmn.a - -libjsmn.a: jsmn.o - $(AR) rc $@ $^ - -%.o: %.c jsmn.h - $(CC) -c $(CFLAGS) $< -o $@ - -test: jsmn_test - ./jsmn_test - -jsmn_test: jsmn_test.o - $(CC) -L. -ljsmn $< -o $@ - -jsmn_test.o: jsmn_test.c libjsmn.a - -clean: - rm -f jsmn.o jsmn_test.o - rm -f jsmn_test - rm -f jsmn_test.exe - rm -f libjsmn.a - -.PHONY: all clean test - diff --git a/jsmn/README.md b/jsmn/README.md deleted file mode 100644 index a282407..0000000 --- a/jsmn/README.md +++ /dev/null @@ -1,165 +0,0 @@ - -JSMN -==== - -jsmn (pronounced like 'jasmine') is a minimalistic JSON parser in C. It can be -easily integrated into resource-limited or embedded projects. - -You can find more information about JSON format at [json.org][1] - -Library sources are available at [bitbucket.org/zserge/jsmn][2] - -The web page with some information about jsmn can be found at -[http://zserge.com/jsmn.html][3] - -Philosophy ----------- - -Most JSON parsers offer you a bunch of functions to load JSON data, parse it -and extract any value by its name. jsmn proves that checking the correctness of -every JSON packet or allocating temporary objects to store parsed JSON fields -often is an overkill. - -JSON format itself is extremely simple, so why should we complicate it? - -jsmn is designed to be **robust** (it should work fine even with erroneous -data), **fast** (it should parse data on the fly), **portable** (no superfluous -dependencies or non-standard C extensions). An of course, **simplicity** is a -key feature - simple code style, simple algorithm, simple integration into -other projects. - -Features --------- - -* compatible with C89 -* no dependencies (even libc!) -* highly portable (tested on x86/amd64, ARM, AVR) -* about 200 lines of code -* extremely small code footprint -* API contains only 2 functions -* no dynamic memory allocation -* incremental single-pass parsing -* library code is covered with unit-tests - -Design ------- - -The rudimentary jsmn object is a **token**. Let's consider a JSON string: - - '{ "name" : "Jack", "age" : 27 }' - -It holds the following tokens: - -* Object: `{ "name" : "Jack", "age" : 27}` (the whole object) -* Strings: `"name"`, `"Jack"`, `"age"` (keys and some values) -* Number: `27` - -In jsmn, tokens do not hold any data, but point to token boundaries in JSON -string instead. In the example above jsmn will create tokens like: Object -[0..31], String [3..7], String [12..16], String [20..23], Number [27..29]. - -Every jsmn token has a type, which indicates the type of corresponding JSON -token. jsmn supports the following token types: - -* Object - a container of key-value pairs, e.g.: - `{ "foo":"bar", "x":0.3 }` -* Array - a sequence of values, e.g.: - `[ 1, 2, 3 ]` -* String - a quoted sequence of chars, e.g.: `"foo"` -* Primitive - a number, a boolean (`true`, `false`) or `null` - -Besides start/end positions, jsmn tokens for complex types (like arrays -or objects) also contain a number of child items, so you can easily follow -object hierarchy. - -This approach provides enough information for parsing any JSON data and makes -it possible to use zero-copy techniques. - -Install -------- - -To clone the repository you should have mercurial installed. Just run: - - $ hg clone http://bitbucket.org/zserge/jsmn jsmn - -Repository layout is simple: jsmn.c and jsmn.h are library files, tests are in -the jsmn\_test.c, you will also find README, LICENSE and Makefile files inside. - -To build the library, run `make`. It is also recommended to run `make test`. -Let me know, if some tests fail. - -If build was successful, you should get a `libjsmn.a` library. -The header file you should include is called `"jsmn.h"`. - -API ---- - -Token types are described by `jsmntype_t`: - - typedef enum { - JSMN_PRIMITIVE = 0, - JSMN_OBJECT = 1, - JSMN_ARRAY = 2, - JSMN_STRING = 3 - } jsmntype_t; - -**Note:** Unlike JSON data types, primitive tokens are not divided into -numbers, booleans and null, because one can easily tell the type using the -first character: - -* 't', 'f' - boolean -* 'n' - null -* '-', '0'..'9' - number - -Token is an object of `jsmntok_t` type: - - typedef struct { - jsmntype_t type; // Token type - int start; // Token start position - int end; // Token end position - int size; // Number of child (nested) tokens - } jsmntok_t; - -**Note:** string tokens point to the first character after -the opening quote and the previous symbol before final quote. This was made -to simplify string extraction from JSON data. - -All job is done by `jsmn_parser` object. You can initialize a new parser using: - - struct jsmn_parser parser; - jsmntok_t tokens[10]; - - // js - pointer to JSON string - // tokens - an array of tokens available - // 10 - number of tokens available - jsmn_init_parser(&parser, js, tokens, 10); - -This will create a parser, that can parse up to 10 JSON tokens from `js` string. - -Later, you can use `jsmn_parse(&parser)` function to process JSON string with the parser. - -A non-negative value is the number of tokens actually used by the parser. -Passing NULL instead of the tokens array would not store parsing results, but -instead the function will return the value of tokens needed to parse the given -string. This can be useful if you don't know yet how many tokens to allocate. - -If something goes wrong, you will get an error. Error will be one of these: - -* `JSMN_ERROR_INVAL` - bad token, JSON string is corrupted -* `JSMN_ERROR_NOMEM` - not enough tokens, JSON string is too large -* `JSMN_ERROR_PART` - JSON string is too short, expecting more JSON data - -If you get `JSON_ERROR_NOMEM`, you can re-allocate more tokens and call -`jsmn_parse` once more. If you read json data from the stream, you can -periodically call `jsmn_parse` and check if return value is `JSON_ERROR_PART`. -You will get this error until you reach the end of JSON data. - -Other info ----------- - -This software is distributed under [MIT license](http://www.opensource.org/licenses/mit-license.php), - so feel free to integrate it in your commercial products. - -[1]: http://www.json.org/ -[2]: https://bitbucket.org/zserge/jsmn/wiki/Home -[3]: http://zserge.com/jsmn.html diff --git a/jsmn/jsmn.c b/jsmn/jsmn.c deleted file mode 100644 index c10d40c..0000000 --- a/jsmn/jsmn.c +++ /dev/null @@ -1,282 +0,0 @@ -#include - -#include "jsmn.h" - -/** - * Allocates a fresh unused token from the token pull. - */ -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, - jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *tok; - if (parser->toknext >= num_tokens) { - return NULL; - } - tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; - tok->size = 0; -#ifdef JSMN_PARENT_LINKS - tok->parent = -1; -#endif - return tok; -} - -/** - * Fills token type and boundaries. - */ -static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, - int start, int end) { - token->type = type; - token->start = start; - token->end = end; - token->size = 0; -} - -/** - * Fills next available token with JSON primitive. - */ -static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, - size_t len, jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *token; - int start; - - start = parser->pos; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - switch (js[parser->pos]) { -#ifndef JSMN_STRICT - /* In strict mode primitive must be followed by "," or "}" or "]" */ - case ':': -#endif - case '\t' : case '\r' : case '\n' : case ' ' : - case ',' : case ']' : case '}' : - goto found; - } - if (js[parser->pos] < 32 || js[parser->pos] >= 127) { - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } -#ifdef JSMN_STRICT - /* In strict mode primitive must be followed by a comma/object/array */ - parser->pos = start; - return JSMN_ERROR_PART; -#endif - -found: - if (tokens == NULL) { - parser->pos--; - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - parser->pos--; - return 0; -} - -/** - * Filsl next token with JSON string. - */ -static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, - size_t len, jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *token; - - int start = parser->pos; - int i = 0; - - parser->pos++; - - /* Skip starting quote */ - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c = js[parser->pos]; - - /* Quote: end of string */ - if (c == '\"') { - if (tokens == NULL) { - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - return 0; - } - - /* Backslash: Quoted symbol expected */ - if (c == '\\') { - parser->pos++; - switch (js[parser->pos]) { - /* Allowed escaped symbols */ - case '\"': case '/' : case '\\' : case 'b' : - case 'f' : case 'r' : case 'n' : case 't' : - break; - /* Allows escaped symbol \uXXXX */ - case 'u': - parser->pos++; - for(; i < 4 && js[parser->pos] != '\0'; i++) { - /* If it isn't a hex character we have an error */ - if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ - parser->pos = start; - return JSMN_ERROR_INVAL; - } - parser->pos++; - } - parser->pos--; - break; - /* Unexpected symbol */ - default: - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } - } - parser->pos = start; - return JSMN_ERROR_PART; -} - -/** - * Parse JSON string and fill tokens. - */ -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, - jsmntok_t *tokens, unsigned int num_tokens) { - jsmnerr_t r; - int i; - jsmntok_t *token; - int count = 0; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c; - jsmntype_t type; - - c = js[parser->pos]; - switch (c) { - case '{': case '[': - count++; - if (tokens == NULL) { - break; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) - return JSMN_ERROR_NOMEM; - if (parser->toksuper != -1) { - tokens[parser->toksuper].size++; -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - } - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); - token->start = parser->pos; - parser->toksuper = parser->toknext - 1; - break; - case '}': case ']': - if (tokens == NULL) - break; - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); -#ifdef JSMN_PARENT_LINKS - if (parser->toknext < 1) { - return JSMN_ERROR_INVAL; - } - token = &tokens[parser->toknext - 1]; - for (;;) { - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - token->end = parser->pos + 1; - parser->toksuper = token->parent; - break; - } - if (token->parent == -1) { - break; - } - token = &tokens[token->parent]; - } -#else - for (i = parser->toknext - 1; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - parser->toksuper = -1; - token->end = parser->pos + 1; - break; - } - } - /* Error if unmatched closing bracket */ - if (i == -1) return JSMN_ERROR_INVAL; - for (; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - parser->toksuper = i; - break; - } - } -#endif - break; - case '\"': - r = jsmn_parse_string(parser, js, len, tokens, num_tokens); - if (r < 0) return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; - case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': - break; -#ifdef JSMN_STRICT - /* In strict mode primitives are: numbers and booleans */ - case '-': case '0': case '1' : case '2': case '3' : case '4': - case '5': case '6': case '7' : case '8': case '9': - case 't': case 'f': case 'n' : -#else - /* In non-strict mode every unquoted value is a primitive */ - default: -#endif - r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); - if (r < 0) return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; - -#ifdef JSMN_STRICT - /* Unexpected char in strict mode */ - default: - return JSMN_ERROR_INVAL; -#endif - } - } - - for (i = parser->toknext - 1; i >= 0; i--) { - /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) { - return JSMN_ERROR_PART; - } - } - - return count; -} - -/** - * Creates a new parser based over a given buffer with an array of tokens - * available. - */ -void jsmn_init(jsmn_parser *parser) { - parser->pos = 0; - parser->toknext = 0; - parser->toksuper = -1; -} - diff --git a/jsmn/jsmn.h b/jsmn/jsmn.h deleted file mode 100644 index c8f388c..0000000 --- a/jsmn/jsmn.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef __JSMN_H_ -#define __JSMN_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * JSON type identifier. Basic types are: - * o Object - * o Array - * o String - * o Other primitive: number, boolean (true/false) or null - */ -typedef enum { - JSMN_PRIMITIVE = 0, - JSMN_OBJECT = 1, - JSMN_ARRAY = 2, - JSMN_STRING = 3 -} jsmntype_t; - -typedef enum { - /* Not enough tokens were provided */ - JSMN_ERROR_NOMEM = -1, - /* Invalid character inside JSON string */ - JSMN_ERROR_INVAL = -2, - /* The string is not a full JSON packet, more bytes expected */ - JSMN_ERROR_PART = -3, -} jsmnerr_t; - -/** - * JSON token description. - * @param type type (object, array, string etc.) - * @param start start position in JSON data string - * @param end end position in JSON data string - */ -typedef struct { - jsmntype_t type; - int start; - int end; - int size; -#ifdef JSMN_PARENT_LINKS - int parent; -#endif -} jsmntok_t; - -/** - * JSON parser. Contains an array of token blocks available. Also stores - * the string being parsed now and current position in that string - */ -typedef struct { - unsigned int pos; /* offset in the JSON string */ - unsigned int toknext; /* next token to allocate */ - int toksuper; /* superior token node, e.g parent object or array */ -} jsmn_parser; - -/** - * Create JSON parser over an array of tokens - */ -void jsmn_init(jsmn_parser *parser); - -/** - * Run JSON parser. It parses a JSON data string into and array of tokens, each describing - * a single JSON object. - */ -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, - jsmntok_t *tokens, unsigned int num_tokens); - -#ifdef __cplusplus -} -#endif - -#endif /* __JSMN_H_ */ diff --git a/jsmn/jsmn_test.c b/jsmn/jsmn_test.c deleted file mode 100644 index c5bfc03..0000000 --- a/jsmn/jsmn_test.c +++ /dev/null @@ -1,556 +0,0 @@ -#include -#include -#include - -static int test_passed = 0; -static int test_failed = 0; - -/* Terminate current test with error */ -#define fail() return __LINE__ - -/* Successfull end of the test case */ -#define done() return 0 - -/* Check single condition */ -#define check(cond) do { if (!(cond)) fail(); } while (0) - -/* Test runner */ -static void test(int (*func)(void), const char *name) { - int r = func(); - if (r == 0) { - test_passed++; - } else { - test_failed++; - printf("FAILED: %s (at line %d)\n", name, r); - } -} - -#define TOKEN_EQ(t, tok_start, tok_end, tok_type) \ - ((t).start == tok_start \ - && (t).end == tok_end \ - && (t).type == (tok_type)) - -#define TOKEN_STRING(js, t, s) \ - (strncmp(js+(t).start, s, (t).end - (t).start) == 0 \ - && strlen(s) == (t).end - (t).start) - -#define TOKEN_PRINT(t) \ - printf("start: %d, end: %d, type: %d, size: %d\n", \ - (t).start, (t).end, (t).type, (t).size) - -#define JSMN_STRICT -#include "jsmn.c" - -int test_empty() { - const char *js; - int r; - jsmn_parser p; - jsmntok_t t[10]; - - js = "{}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), t, 10); - check(r >= 0); - check(t[0].type == JSMN_OBJECT); - check(t[0].start == 0 && t[0].end == 2); - - js = "[]"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), t, 10); - check(r >= 0); - check(t[0].type == JSMN_ARRAY); - check(t[0].start == 0 && t[0].end == 2); - - js = "{\"a\":[]}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), t, 10); - check(r >= 0); - check(t[0].type == JSMN_OBJECT && t[0].start == 0 && t[0].end == 8); - check(t[1].type == JSMN_STRING && t[1].start == 2 && t[1].end == 3); - check(t[2].type == JSMN_ARRAY && t[2].start == 5 && t[2].end == 7); - - js = "[{},{}]"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), t, 10); - check(r >= 0); - check(t[0].type == JSMN_ARRAY && t[0].start == 0 && t[0].end == 7); - check(t[1].type == JSMN_OBJECT && t[1].start == 1 && t[1].end == 3); - check(t[2].type == JSMN_OBJECT && t[2].start == 4 && t[2].end == 6); - return 0; -} - -int test_simple() { - const char *js; - int r; - jsmn_parser p; - jsmntok_t tokens[10]; - - js = "{\"a\": 0}"; - - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r >= 0); - check(TOKEN_EQ(tokens[0], 0, 8, JSMN_OBJECT)); - check(TOKEN_EQ(tokens[1], 2, 3, JSMN_STRING)); - check(TOKEN_EQ(tokens[2], 6, 7, JSMN_PRIMITIVE)); - - check(TOKEN_STRING(js, tokens[0], js)); - check(TOKEN_STRING(js, tokens[1], "a")); - check(TOKEN_STRING(js, tokens[2], "0")); - - jsmn_init(&p); - js = "[\"a\":{},\"b\":{}]"; - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r >= 0); - - jsmn_init(&p); - js = "{\n \"Day\": 26,\n \"Month\": 9,\n \"Year\": 12\n }"; - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r >= 0); - - return 0; -} - -int test_primitive() { - int r; - jsmn_parser p; - jsmntok_t tok[10]; - const char *js; -#ifndef JSMN_STRICT - js = "\"boolVar\" : true"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_PRIMITIVE); - check(TOKEN_STRING(js, tok[0], "boolVar")); - check(TOKEN_STRING(js, tok[1], "true")); - - js = "\"boolVar\" : false"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_PRIMITIVE); - check(TOKEN_STRING(js, tok[0], "boolVar")); - check(TOKEN_STRING(js, tok[1], "false")); - - js = "\"intVar\" : 12345"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_PRIMITIVE); - check(TOKEN_STRING(js, tok[0], "intVar")); - check(TOKEN_STRING(js, tok[1], "12345")); - - js = "\"floatVar\" : 12.345"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_PRIMITIVE); - check(TOKEN_STRING(js, tok[0], "floatVar")); - check(TOKEN_STRING(js, tok[1], "12.345")); - - js = "\"nullVar\" : null"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_PRIMITIVE); - check(TOKEN_STRING(js, tok[0], "nullVar")); - check(TOKEN_STRING(js, tok[1], "null")); -#endif - return 0; -} - -int test_string() { - int r; - jsmn_parser p; - jsmntok_t tok[10]; - const char *js; - - js = "\"strVar\" : \"hello world\""; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_STRING); - check(TOKEN_STRING(js, tok[0], "strVar")); - check(TOKEN_STRING(js, tok[1], "hello world")); - - js = "\"strVar\" : \"escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\\""; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_STRING); - check(TOKEN_STRING(js, tok[0], "strVar")); - check(TOKEN_STRING(js, tok[1], "escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\")); - - js = "\"strVar\" : \"\""; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_STRING); - check(TOKEN_STRING(js, tok[0], "strVar")); - check(TOKEN_STRING(js, tok[1], "")); - - return 0; -} - -int test_partial_string() { - int r; - jsmn_parser p; - jsmntok_t tok[10]; - const char *js; - - jsmn_init(&p); - js = "\"x\": \"va"; - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r == JSMN_ERROR_PART && tok[0].type == JSMN_STRING); - check(TOKEN_STRING(js, tok[0], "x")); - check(p.toknext == 1); - - js = "\"x\": \"valu"; - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r == JSMN_ERROR_PART && tok[0].type == JSMN_STRING); - check(TOKEN_STRING(js, tok[0], "x")); - check(p.toknext == 1); - - js = "\"x\": \"value\""; - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_STRING); - check(TOKEN_STRING(js, tok[0], "x")); - check(TOKEN_STRING(js, tok[1], "value")); - - js = "\"x\": \"value\", \"y\": \"value y\""; - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_STRING - && tok[1].type == JSMN_STRING && tok[2].type == JSMN_STRING - && tok[3].type == JSMN_STRING); - check(TOKEN_STRING(js, tok[0], "x")); - check(TOKEN_STRING(js, tok[1], "value")); - check(TOKEN_STRING(js, tok[2], "y")); - check(TOKEN_STRING(js, tok[3], "value y")); - - return 0; -} - -int test_unquoted_keys() { -#ifndef JSMN_STRICT - int r; - jsmn_parser p; - jsmntok_t tok[10]; - const char *js; - - jsmn_init(&p); - js = "key1: \"value\"\nkey2 : 123"; - - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_PRIMITIVE - && tok[1].type == JSMN_STRING && tok[2].type == JSMN_PRIMITIVE - && tok[3].type == JSMN_PRIMITIVE); - check(TOKEN_STRING(js, tok[0], "key1")); - check(TOKEN_STRING(js, tok[1], "value")); - check(TOKEN_STRING(js, tok[2], "key2")); - check(TOKEN_STRING(js, tok[3], "123")); -#endif - return 0; -} - -int test_partial_array() { - int r; - jsmn_parser p; - jsmntok_t tok[10]; - const char *js; - - jsmn_init(&p); - js = " [ 1, true, "; - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY - && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE); - - js = " [ 1, true, [123, \"hello"; - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY - && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE - && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE); - - js = " [ 1, true, [123, \"hello\"]"; - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY - && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE - && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE - && tok[5].type == JSMN_STRING); - /* check child nodes of the 2nd array */ - check(tok[3].size == 2); - - js = " [ 1, true, [123, \"hello\"]]"; - r = jsmn_parse(&p, js, strlen(js), tok, 10); - check(r >= 0 && tok[0].type == JSMN_ARRAY - && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE - && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE - && tok[5].type == JSMN_STRING); - check(tok[3].size == 2); - check(tok[0].size == 3); - return 0; -} - -int test_array_nomem() { - int i; - int r; - jsmn_parser p; - jsmntok_t toksmall[10], toklarge[10]; - const char *js; - - js = " [ 1, true, [123, \"hello\"]]"; - - for (i = 0; i < 6; i++) { - jsmn_init(&p); - memset(toksmall, 0, sizeof(toksmall)); - memset(toklarge, 0, sizeof(toklarge)); - r = jsmn_parse(&p, js, strlen(js), toksmall, i); - check(r == JSMN_ERROR_NOMEM); - - memcpy(toklarge, toksmall, sizeof(toksmall)); - - r = jsmn_parse(&p, js, strlen(js), toklarge, 10); - check(r >= 0); - - check(toklarge[0].type == JSMN_ARRAY && toklarge[0].size == 3); - check(toklarge[3].type == JSMN_ARRAY && toklarge[3].size == 2); - } - return 0; -} - -int test_objects_arrays() { - int i; - int r; - jsmn_parser p; - jsmntok_t tokens[10]; - const char *js; - - js = "[10}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r == JSMN_ERROR_INVAL); - - js = "[10]"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r >= 0); - - js = "{\"a\": 1]"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r == JSMN_ERROR_INVAL); - - js = "{\"a\": 1}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r >= 0); - - return 0; -} - -int test_issue_22() { - int i; - int r; - jsmn_parser p; - jsmntok_t tokens[128]; - const char *js; - - js = "{ \"height\":10, \"layers\":[ { \"data\":[6,6], \"height\":10, " - "\"name\":\"Calque de Tile 1\", \"opacity\":1, \"type\":\"tilelayer\", " - "\"visible\":true, \"width\":10, \"x\":0, \"y\":0 }], " - "\"orientation\":\"orthogonal\", \"properties\": { }, \"tileheight\":32, " - "\"tilesets\":[ { \"firstgid\":1, \"image\":\"..\\/images\\/tiles.png\", " - "\"imageheight\":64, \"imagewidth\":160, \"margin\":0, \"name\":\"Tiles\", " - "\"properties\":{}, \"spacing\":0, \"tileheight\":32, \"tilewidth\":32 }], " - "\"tilewidth\":32, \"version\":1, \"width\":10 }"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 128); - check(r >= 0); -#if 0 - for (i = 1; tokens[i].end < tokens[0].end; i++) { - if (tokens[i].type == JSMN_STRING || tokens[i].type == JSMN_PRIMITIVE) { - printf("%.*s\n", tokens[i].end - tokens[i].start, js + tokens[i].start); - } else if (tokens[i].type == JSMN_ARRAY) { - printf("[%d elems]\n", tokens[i].size); - } else if (tokens[i].type == JSMN_OBJECT) { - printf("{%d elems}\n", tokens[i].size); - } else { - TOKEN_PRINT(tokens[i]); - } - } -#endif - return 0; -} - -int test_unicode_characters() { - jsmn_parser p; - jsmntok_t tokens[10]; - const char *js; - - int r; - js = "{\"a\":\"\\uAbcD\"}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r >= 0); - - js = "{\"a\":\"str\\u0000\"}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r >= 0); - - js = "{\"a\":\"\\uFFFFstr\"}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r >= 0); - - js = "{\"a\":\"str\\uFFGFstr\"}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r == JSMN_ERROR_INVAL); - - js = "{\"a\":\"str\\u@FfF\"}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r == JSMN_ERROR_INVAL); - - js = "{\"a\":[\"\\u028\"]}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r == JSMN_ERROR_INVAL); - - js = "{\"a\":[\"\\u0280\"]}"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r >= 0); - - return 0; -} - -int test_input_length() { - const char *js; - int r; - jsmn_parser p; - jsmntok_t tokens[10]; - - js = "{\"a\": 0}garbage"; - - jsmn_init(&p); - r = jsmn_parse(&p, js, 8, tokens, 10); - check(r == 3); - check(TOKEN_STRING(js, tokens[0], "{\"a\": 0}")); - check(TOKEN_STRING(js, tokens[1], "a")); - check(TOKEN_STRING(js, tokens[2], "0")); - - return 0; -} - -int test_count() { - jsmn_parser p; - const char *js; - - js = "{}"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 1); - - js = "[]"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 1); - - js = "[[]]"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 2); - - js = "[[], []]"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 3); - - js = "[[], []]"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 3); - - js = "[[], [[]], [[], []]]"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 7); - - js = "[\"a\", [[], []]]"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 5); - - js = "[[], \"[], [[]]\", [[]]]"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 5); - - js = "[1, 2, 3]"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 4); - - js = "[1, 2, [3, \"a\"], null]"; - jsmn_init(&p); - check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 7); - - return 0; -} - -/** A huge redefinition of everything to include jsmn in non-script mode */ -#define jsmn_init jsmn_init_nonstrict -#define jsmn_parse jsmn_parse_nonstrict -#define jsmn_parser jsmn_parser_nonstrict -#define jsmn_alloc_token jsmn_alloc_token_nonstrict -#define jsmn_fill_token jsmn_fill_token_nonstrict -#define jsmn_parse_primitive jsmn_parse_primitive_nonstrict -#define jsmn_parse_string jsmn_parse_string_nonstrict -#define jsmntype_t jsmntype_nonstrict_t -#define jsmnerr_t jsmnerr_nonstrict_t -#define jsmntok_t jsmntok_nonstrict_t -#define JSMN_PRIMITIVE JSMN_PRIMITIVE_NONSTRICT -#define JSMN_OBJECT JSMN_OBJECT_NONSTRICT -#define JSMN_ARRAY JSMN_ARRAY_NONSTRICT -#define JSMN_STRING JSMN_STRING_NONSTRICT -#define JSMN_ERROR_NOMEM JSMN_ERROR_NOMEM_NONSTRICT -#define JSMN_ERROR_INVAL JSMN_ERROR_INVAL_NONSTRICT -#define JSMN_ERROR_PART JSMN_ERROR_PART_NONSTRICT -#undef __JSMN_H_ -#undef JSMN_STRICT -#include "jsmn.c" - -int test_nonstrict() { - const char *js; - int r; - jsmn_parser p; - jsmntok_t tokens[10]; - - js = "a: 0garbage"; - - jsmn_init(&p); - r = jsmn_parse(&p, js, 4, tokens, 10); - check(r == 2); - check(TOKEN_STRING(js, tokens[0], "a")); - check(TOKEN_STRING(js, tokens[1], "0")); - - js = "Day : 26\nMonth : Sep\n\nYear: 12"; - jsmn_init(&p); - r = jsmn_parse(&p, js, strlen(js), tokens, 10); - check(r == 6); - return 0; -} - -int main() { - test(test_empty, "general test for a empty JSON objects/arrays"); - test(test_simple, "general test for a simple JSON string"); - test(test_primitive, "test primitive JSON data types"); - test(test_string, "test string JSON data types"); - test(test_partial_string, "test partial JSON string parsing"); - test(test_partial_array, "test partial array reading"); - test(test_array_nomem, "test array reading with a smaller number of tokens"); - test(test_unquoted_keys, "test unquoted keys (like in JavaScript)"); - test(test_objects_arrays, "test objects and arrays"); - test(test_unicode_characters, "test unicode characters"); - test(test_input_length, "test strings that are not null-terminated"); - test(test_issue_22, "test issue #22"); - test(test_count, "test tokens count estimation"); - test(test_nonstrict, "test for non-strict mode"); - printf("\nPASSED: %d\nFAILED: %d\n", test_passed, test_failed); - return 0; -} - diff --git a/playground/.gitignore b/playground/.gitignore index 0d20b64..5714b6a 100644 --- a/playground/.gitignore +++ b/playground/.gitignore @@ -1 +1,2 @@ *.pyc +playground_data/ diff --git a/playground/server.py b/playground/server.py index d5b4ef3..dd31e05 100644 --- a/playground/server.py +++ b/playground/server.py @@ -350,11 +350,16 @@ def _list_dir(self, response, path, do_json): else: data = "Listing of the volumes" data += "
  • " - for entry in entries: + for entry in entries[:-1]: if do_json: data += "\"%s\"," % (str(entry)) else: data += "
      %s
    " % (str(entry)) + if do_json: + data += "\"%s\"" % (str(entries[-1])) + else: + data += "
      %s
    " % (str(entry)) + if do_json: data += """], "childrenrange": "" diff --git a/srb.h b/srb.h deleted file mode 100644 index af47373..0000000 --- a/srb.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (C) 2014 SCALITY SA - http://www.scality.com - * - * This file is part of ScalityRestBlock. - * - * ScalityRestBlock is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ScalityRestBlock is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see . - * - */ - -#ifndef __SRBLOCK_H__ -# define __SRBLOCK_H__ - -#include -#include -#include // for in_aton() -#include -#include -#include -#include -#include - -/* Constants */ -#define kB 1024 -#define MB (1024 * kB) -#define GB (1024 * MB) - -/* Unix device constants */ -#define DEV_NAME "srb" -#define DEV_REL_VERSION "0.6.1" // Set version of srb LKM -#define DEV_MINORS 256 -#define DEV_DEFAULT_DISKSIZE (50 * MB) -#define DEV_MAX 64 -#define DEV_SECTORSIZE 1 * MB -#define DEV_NB_PHYS_SEGS 512 - -/* Device state (reduce spinlock section and avoid multiple operation on same device) */ -#define DEV_IN_USE 1 -#define DEV_UNUSED 0 - -/* Dewpoint server related constants */ -#define SRB_HTTP_HEADER_SIZE 1024 -#define SRB_URL_SIZE 256 -#define SRB_REUSE_LIMIT 100 /* Max number of requests sent to - * a single HTTP connection before - * restarting a new one. - */ - -/* - * Linux Kernel Module (LKM) parameters - */ -extern unsigned short srb_log; -extern unsigned short req_timeout; -extern unsigned short nb_req_retries; -extern unsigned short server_conn_timeout; -extern unsigned int thread_pool_size; - -/* - * Default values for ScalityRestBlock LKM parameters - */ -#define SRB_REQ_TIMEOUT_DFLT 30 -#define SRB_NB_REQ_RETRIES_DFLT 3 -#define SRB_CONN_TIMEOUT_DFLT 30 -#define SRB_LOG_LEVEL_DFLT SRB_INFO -#define SRB_THREAD_POOL_SIZE_DFLT 8 - -#define SRB_DEBUG_LEVEL 0 /* We do not want to be polluted - * by default */ - -#define SRB_XMIT_BUFFER_SIZE (SRB_HTTP_HEADER_SIZE + DEV_SECTORSIZE) - -#define SRB_MIN(x, y) ((x) < (y) ? (x) : (y)) -#define SRB_N_JSON_TOKENS 128 - -/* - * Status Ranges extracted from RFC 2616 - */ -enum srb_http_statusrange -{ - SRB_HTTP_STATUSRANGE_INFORMATIONAL = 1, // 1.. - SRB_HTTP_STATUSRANGE_SUCCESS = 2, // 2.. - SRB_HTTP_STATUSRANGE_REDIRECTION = 3, // 3.. - SRB_HTTP_STATUSRANGE_CLIENTERROR = 4, // 4.. - SRB_HTTP_STATUSRANGE_SERVERERROR = 5, // 5.. - SRB_HTTP_STATUSRANGE_EXTENDED = 0 -}; - -/* - * Codes extracted from RFC 2616 - */ -enum srb_http_statuscode -{ - SRB_HTTP_STATUS_CONTINUE = 100, // "100" ; Section 10.1.1: Continue - SRB_HTTP_STATUS_SWITCHPROTO = 101, // "101" ; Section 10.1.2: Switching Protocols - SRB_HTTP_STATUS_OK = 200, // "200" ; Section 10.2.1: OK - SRB_HTTP_STATUS_CREATED = 201, // "201" ; Section 10.2.2: Created - SRB_HTTP_STATUS_ACCEPTED = 202, // "202" ; Section 10.2.3: Accepted - SRB_HTTP_STATUS_NONAUTH_INFO = 203, // "203" ; Section 10.2.4: Non-Authoritative Information - SRB_HTTP_STATUS_NOCONTENT = 204, // "204" ; Section 10.2.5: No Content - SRB_HTTP_STATUS_RESETCONTENT = 205, // "205" ; Section 10.2.6: Reset Content - SRB_HTTP_STATUS_PARTIAL = 206, // "206" ; Section 10.2.7: Partial Content - SRB_HTTP_STATUS_MULTIPLE_CHOICES = 300, // "300" ; Section 10.3.1: Multiple Choices - SRB_HTTP_STATUS_MOVED = 301, // "301" ; Section 10.3.2: Moved Permanently - SRB_HTTP_STATUS_FOUND = 302, // "302" ; Section 10.3.3: Found - SRB_HTTP_STATUS_SEEOTHER = 303, // "303" ; Section 10.3.4: See Other - SRB_HTTP_STATUS_NOTMODIF = 304, // "304" ; Section 10.3.5: Not Modified - SRB_HTTP_STATUS_USE_PROXY = 305, // "305" ; Section 10.3.6: Use Proxy - SRB_HTTP_STATUS_TEMP_REDIR = 307, // "307" ; Section 10.3.8: Temporary Redirect - SRB_HTTP_STATUS_BADREQ = 400, // "400" ; Section 10.4.1: Bad Request - SRB_HTTP_STATUS_UNAUTH = 401, // "401" ; Section 10.4.2: Unauthorized - SRB_HTTP_STATUS_PAYMENT_REQ = 402, // "402" ; Section 10.4.3: Payment Required - SRB_HTTP_STATUS_FORBIDDEN = 403, // "403" ; Section 10.4.4: Forbidden - SRB_HTTP_STATUS_NOT_FOUND = 404, // "404" ; Section 10.4.5: Not Found - SRB_HTTP_STATUS_NOT_ALLOWED = 405, // "405" ; Section 10.4.6: Method Not Allowed - SRB_HTTP_STATUS_NOT_ACCEPTABLE = 406, // "406" ; Section 10.4.7: Not Acceptable - SRB_HTTP_STATUS_PROXYAUTH_REQ = 407, // "407" ; Section 10.4.8: Proxy Authentication Required - SRB_HTTP_STATUS_REQTIMEOUT = 408, // "408" ; Section 10.4.9: Request Time-out - SRB_HTTP_STATUS_CONFLICT = 409, // "409" ; Section 10.4.10: Conflict - SRB_HTTP_STATUS_GONE = 410, // "410" ; Section 10.4.11: Gone - SRB_HTTP_STATUS_LENGTH_REQ = 410, // "411" ; Section 10.4.12: Length Required - SRB_HTTP_STATUS_PRECOND_FAILED = 412, // "412" ; Section 10.4.13: Precondition Failed - SRB_HTTP_STATUS_ENTITY_TOOLARGE = 413, // "413" ; Section 10.4.14: Request Entity Too Large - SRB_HTTP_STATUS_URI_TOOLARGE = 414, // "414" ; Section 10.4.15: Request-URI Too Large - SRB_HTTP_STATUS_UNSUP_MEDIA = 415, // "415" ; Section 10.4.16: Unsupported Media Type - SRB_HTTP_STATUS_BADRANGE = 416, // "416" ; Section 10.4.17: Requested range not satisfiable - SRB_HTTP_STATUS_EXPECT_FAILED = 417, // "417" ; Section 10.4.18: Expectation Failed - SRB_HTTP_STATUS_INTERNAL_ERROR = 500, // "500" ; Section 10.5.1: Internal Server Error - SRB_HTTP_STATUS_NOTIMPL = 501, // "501" ; Section 10.5.2: Not Implemented - SRB_HTTP_STATUS_BAD_GW = 502, // "502" ; Section 10.5.3: Bad Gateway - SRB_HTTP_STATUS_SERVICE_UNAVAIL = 503, // "503" ; Section 10.5.4: Service Unavailable - SRB_HTTP_STATUS_GW_TIMEOUT = 504, // "504" ; Section 10.5.5: Gateway Time-out - SRB_HTTP_STATUS_VERSION_NOTSUPP = 505, // "505" ; Section 10.5.6: HTTP Version not supported - SRB_HTTP_STATUS_EXTENSION = 0 // ; extension-code -}; - -/* srb_cdmi.c */ -struct srb_cdmi_desc_s { - /* For /sys/block/srb?/srb_url */ - char url[SRB_URL_SIZE + 1]; - uint8_t state; - char ip_addr[16]; - uint16_t port; - char filename[SRB_URL_SIZE + 1]; - char xmit_buff[SRB_XMIT_BUFFER_SIZE]; - uint64_t nb_requests; /* Number of HTTP - * requests already sent - * through this socket */ - struct scatterlist sgl[DEV_NB_PHYS_SEGS]; - int sgl_size; - struct socket *socket; - struct sockaddr_in sockaddr; - struct timeval timeout; -}; - -/* srb device definition */ -typedef struct srb_debug_s { - const char *name; - int level; -} srb_debug_t; - -typedef struct srb_device_s { - /* Device subsystem related data */ - int id; /* device ID */ - int major; /* blkdev assigned major */ - - /* NOTE: use const from ./linux/genhd.h */ - char name[DISK_NAME_LEN]; /* blkdev name, e.g. srba */ - struct gendisk *disk; - uint64_t disk_size; /* Size in bytes */ - int users; /* Number of users who - * opened dev */ - int state; /* for create extend attach detach destroy purpose */ - - struct request_queue *q; - spinlock_t rq_lock; /* request queue lock */ - - struct task_struct **thread; /* allow dynamic allocation during device creation */ - int nb_threads; - - /* Dewpoint specific data */ - struct srb_cdmi_desc_s **thread_cdmi_desc; /* allow dynamic allocation during device creation*/ - - /* - ** List of requests received by the drivers, but still to be - ** processed. This due to network latency. - */ - spinlock_t waiting_lock; /* wait_queue lock */ - wait_queue_head_t waiting_wq; - struct list_head waiting_queue; /* Requests to be sent */ - - /* Debug traces */ - srb_debug_t debug; -} srb_device_t; - -typedef struct srb_server_s { - struct srb_server_s *next; - struct srb_cdmi_desc_s cdmi_desc; -} srb_server_t; - - -#include "srb_log.h" - -/* srb.c */ -int srb_device_create(const char *filename, unsigned long long size); -int srb_device_extend(const char *filename, unsigned long long size); -int srb_device_destroy(const char *filename); - -int srb_device_attach(const char *filename, const char *devname); -int srb_device_detach(const char *devname); - -int srb_server_add(const char *url); -int srb_server_remove(const char *url); -ssize_t srb_servers_dump(char *buf, ssize_t max_size); -int srb_volumes_dump(char *buf, size_t max_size); - -/* srb_sysfs.c*/ -int srb_sysfs_init(void); -void srb_sysfs_device_init(srb_device_t *dev); -void srb_sysfs_cleanup(void); - -/* srb_cdmi.c */ -int srb_cdmi_init(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, - const char *url); -int srb_cdmi_connect(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc); -int srb_cdmi_disconnect(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc); - -int srb_cdmi_getsize(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, - uint64_t *size); - -int srb_cdmi_getrange(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, - uint64_t offset, int size); - -int srb_cdmi_putrange(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, - uint64_t offset, int size); - -int srb_cdmi_flush(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, - unsigned long flush_size); - -int srb_cdmi_truncate(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, - unsigned long trunc_size); - -int srb_cdmi_create(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, - unsigned long long trunc_size); -int srb_cdmi_extend(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, - unsigned long long trunc_size); -int srb_cdmi_delete(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc); - -typedef int (*srb_cdmi_list_cb)(void * data, const char *); -int srb_cdmi_list(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, - srb_cdmi_list_cb cb, void *cb_data); - -/* srb_http.c */ -int srb_http_check_response_complete(char *buff, int len); -int srb_http_mklist(char *buff, int len, char *host, char *page); -int srb_http_mkhead(char *buff, int len, char *host, char *page); -int srb_http_mkrange(char *cmd, char *buff, int len, char *host, char *page, - uint64_t start, uint64_t end); - -int srb_http_mkcreate(char *buff, int len, char *host, char *page); -int srb_http_mktruncate(char *buff, int len, char *host, char *page, - unsigned long long size); -int srb_http_mkdelete(char *buff, int len, char *host, char *page); -int srb_http_header_get_uint64(char *buff, int len, char *key, - uint64_t *value); -int srb_http_skipheader(char **buff, int *len); -int srb_http_mkmetadata(char *buff, int len, char *host, char *page); - -int srb_http_get_status(char *buf, int len, enum srb_http_statuscode *code); -enum srb_http_statusrange srb_http_get_status_range(enum srb_http_statuscode status); - -#endif diff --git a/srb/Kbuild b/srb/Kbuild new file mode 100644 index 0000000..3141c98 --- /dev/null +++ b/srb/Kbuild @@ -0,0 +1,9 @@ +obj-m := srb.o + +srb-y := srb-driver.o srb-sysfs.o srb-cdmi.o srb-http.o srb-trace.o + +EXTRA_CFLAGS := -ggdb3 -Wall -Wextra -Werror -Wno-unused-parameter -I$(src)/../include + +ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1) +EXTRA_CFLAGS += -Wno-unknown-attributes -Wno-error=sign-compare -Wno-error=unused-function +endif diff --git a/srb_cdmi.c b/srb/srb-cdmi.c similarity index 62% rename from srb_cdmi.c rename to srb/srb-cdmi.c index 0f239ee..445a32a 100644 --- a/srb_cdmi.c +++ b/srb/srb-cdmi.c @@ -20,16 +20,21 @@ * */ -#include // included for all kernel modules -#include // included for KERN_INFO -#include // for uintx_t -#include +#include +#include #include -#include #include +#include + #include "srb.h" -#include "jsmn/jsmn.h" +#include +#include + +#define SRB_REUSE_LIMIT 100 /* Max number of requests sent to + * a single HTTP connection before + * restarting a new one. + */ /* TODO: add username and password support */ #define CDMI_DISCONNECTED 0 @@ -103,7 +108,7 @@ static int get_port(const char *url, int *port) * */ int srb_cdmi_init(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, + struct srb_cdmi_desc *desc, const char *url) { /* 1 1 */ @@ -116,9 +121,9 @@ int srb_cdmi_init(srb_debug_t *dbg, desc->filename[0] = 0; *ip = 0; - strncpy(desc->url, url, SRB_URL_SIZE); + strncpy(desc->url, url, SRB_CDMI_URL_SIZE); - desc->url[SRB_URL_SIZE] = 0; + desc->url[SRB_CDMI_URL_SIZE] = 0; /* Only 'http://' supported for the moment */ if (strncmp(url, PROTO_HTTP, strlen(PROTO_HTTP))) return -EINVAL; @@ -163,7 +168,7 @@ int srb_cdmi_init(srb_debug_t *dbg, * Returns 0 if successfull or a negative value depending the error. */ int srb_cdmi_connect(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc) + struct srb_cdmi_desc *desc) { int ret; int arg = 1; @@ -239,7 +244,7 @@ int srb_cdmi_connect(srb_debug_t *dbg, * */ int srb_cdmi_disconnect(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc) + struct srb_cdmi_desc *desc) { if (!desc) return -EINVAL; @@ -259,7 +264,7 @@ int srb_cdmi_disconnect(srb_debug_t *dbg, * Send or receive packet. */ static int sock_xmit(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, + struct srb_cdmi_desc *desc, int send, void *buf, int size, int strict_receive) @@ -334,7 +339,7 @@ static int sock_xmit(srb_debug_t *dbg, } static int sock_send_receive(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, + struct srb_cdmi_desc *desc, int send_size, int rcv_size) { char *buff = desc->xmit_buff; @@ -346,7 +351,7 @@ static int sock_send_receive(srb_debug_t *dbg, if (rcv_size == 0) { strict_rcv = 0; - rcv_size = SRB_XMIT_BUFFER_SIZE; + rcv_size = SRB_CDMI_XMIT_BUFFER_SIZE; } rcvbuf = vmalloc(rcv_size); if (rcvbuf == NULL) { @@ -432,7 +437,7 @@ static int sock_send_receive(srb_debug_t *dbg, } static int sock_send_sglist_receive(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, + struct srb_cdmi_desc *desc, int send_size, int rcv_size) { char *buff = desc->xmit_buff; @@ -445,7 +450,7 @@ static int sock_send_sglist_receive(srb_debug_t *dbg, if (rcv_size == 0) { strict_rcv = 0; - rcv_size = SRB_XMIT_BUFFER_SIZE; + rcv_size = SRB_CDMI_XMIT_BUFFER_SIZE; } rcvbuf = vmalloc(rcv_size); if (rcvbuf == NULL) { @@ -558,7 +563,7 @@ static int sock_send_sglist_receive(srb_debug_t *dbg, } static int retried_send_receive(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, + struct srb_cdmi_desc *desc, int send_size, int rcv_size, int do_sglist, int attempts) { @@ -593,381 +598,6 @@ static int retried_send_receive(srb_debug_t *dbg, return ret; } -int srb_cdmi_list(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, - int (*volume_cb)(void * data, const char *), - void *cb_data) -{ - jsmn_parser json_parser; - jsmntok_t *json_tokens = NULL, *json_tokens2 = NULL; - unsigned int n_tokens = 0; - jsmnerr_t json_err = JSMN_ERROR_NOMEM; - - char filename[SRB_URL_SIZE+1]; - char *buff = desc->xmit_buff; - - enum srb_http_statuscode code; - char *content = NULL; - uint64_t contentlen; - - int len; - int ret; - int array, obj, found; - int cb_errcount = 0; - - if (!desc->socket) - return 0; - - // Construct HTTTP GET (for listing container) - len = srb_http_mklist(buff, SRB_XMIT_BUFFER_SIZE, - desc->ip_addr, desc->filename); - if (len <= 0) return len; - - len = sock_send_receive(dbg, desc, len, 0); - if (len < 0) return len; - - // Check response status - ret = srb_http_get_status(buff, len, &code); - if (ret == -1) - { - SRB_LOG_ERR(dbg->level, "[list] Cannot retrieve response status"); - ret = -EIO; - goto err; - } - if (code != SRB_HTTP_STATUS_OK) - { - SRB_LOG_ERR(dbg->level, "[list] Server listing yielded " - "response status %i", code); - ret = -EIO; - goto err; - } - - // Get content length - ret = srb_http_header_get_uint64(buff, len, - "Content-Length", &contentlen); - if (ret) - { - SRB_LOG_ERR(dbg->level, "[list] Could not find content length in " - "response headers."); - ret = -EIO; - goto err; - } - - content = vmalloc(contentlen); - if (content == NULL) - { - SRB_LOG_ERR(dbg->level, "[list] Cannot allocate enough memory to" - " read volume repository."); - ret = -ENOMEM; - goto err; - } - memset(content, 0, contentlen); - - // Skip header - ret = srb_http_skipheader(&buff, &len); - if (ret) { - SRB_LOG_ERR(dbg->level, "[list] skipheader failed: %d", ret); - ret = -EIO; - goto err; - } - if (len > contentlen) - { - SRB_LOG_ERR(dbg->level, "[list] More data left than expected:" - " len=%i > contentlen=%llu", len, contentlen); - ret = -EIO; - goto err; - } - - // Get body - // First, copy leftovers from buff - memcpy(content, buff, len); - if (len != contentlen) { - SRB_LOG_ERR(dbg->level, "[list] Cannot read whole listing: " - "len: %d contentlen:%llu", len, contentlen); - ret = -EIO; - goto err; - } - - // Now retrieve the list of objects... -#define SRB_N_JSON_TOKENS 128 - jsmn_init(&json_parser); - n_tokens = SRB_N_JSON_TOKENS; - do - { - n_tokens *= 2; - json_tokens2 = json_tokens; - json_tokens = krealloc(json_tokens2, - n_tokens * sizeof(*json_tokens), - GFP_KERNEL); - if (json_tokens != NULL) - { - json_err = jsmn_parse(&json_parser, content, contentlen, - json_tokens, n_tokens); - } else { - /* krealloc doesn't free the original */ - kfree(json_tokens2); - } - - } while (json_tokens != NULL - && json_err < 0 && json_err == JSMN_ERROR_NOMEM); - - if (json_err < 0) - { - if (json_tokens == NULL) - { - SRB_LOG_ERR(dbg->level, "Could not allocate enough memory to " - "parse JSON volume list."); - ret = -ENOMEM; - } - else - { - SRB_LOG_ERR(dbg->level, "Could not parse Json: error %i", json_err); - ret = -EIO; - } - goto err; - } - - // Find the "children" object within json root object - // for each sub-loop, ret (aka tmp iterator) is intialized to 1 - // in order to start after the object/array token it iterates within. - found = 0; - for (ret = 0; ret < json_err; ret ++) - { - jsmntok_t *objtok = &json_tokens[ret]; - // Dive into root object - if (objtok->parent == -1 && objtok->type == JSMN_OBJECT) - { - obj = ret; - for (ret = 1; obj+ret < json_err; ret += 2) - { - jsmntok_t *artok = &json_tokens[obj+ret]; - // Dive into key 'children' (should contain an array) - if (artok->type == JSMN_STRING - && strncmp("children", &content[artok->start], - artok->end - artok->start) == 0 - && obj+ret < json_err - && json_tokens[obj+ret+1].type == JSMN_ARRAY) - { - array = obj + ret + 1; - SRB_LOG_DEBUG(dbg->level, "Found children list:"); - // List children of the array we found. - for (ret = 1; - array + ret < json_err - && json_tokens[array+ret].parent == array - && ret < DEV_MAX; - ++ret) - { - len = json_tokens[array+ret].end - - json_tokens[array+ret].start; - SRB_LOG_DEBUG(dbg->level, "Volume %i: %.*s", ret, len, - &content[json_tokens[array+ret].start]); - strncpy(filename, - &content[json_tokens[array+ret].start], - SRB_MIN(SRB_URL_SIZE, len)); - filename[SRB_MIN(SRB_URL_SIZE, len)] = 0; - - if (volume_cb(cb_data, filename) != 0) { - cb_errcount += 1; - } - } - found = 1; - break ; - } - } - if (found) - break ; - } - } - - ret = 0; - if (cb_errcount != 0) - ret = -EIO; - -err: - if (json_tokens) - kfree(json_tokens); - if (content) - vfree(content); - - return ret; -} - -int srb_cdmi_flush(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, - unsigned long flush_size) -{ - char *buff = desc->xmit_buff; - uint64_t size; - int len; - int ret; - enum srb_http_statuscode code; - - if (!desc->socket) - return 0; - - /* Construct HTTP truncate */ - len = srb_http_mktruncate(buff, SRB_XMIT_BUFFER_SIZE, - desc->ip_addr, desc->filename, flush_size); - if (len <= 0) return len; - - len = sock_send_receive(dbg, desc, len, 0); - if (len < 0) return len; - - ret = srb_http_get_status(buff, len, &code); - if (ret != 0) - { - SRB_LOG_ERR(dbg->level, "Cannot get http response status."); - return -EIO; - } - if (srb_http_get_status_range(code) != SRB_HTTP_STATUSRANGE_SUCCESS) - { - SRB_LOG_ERR(dbg->level, "Http server responded with bad status: %i", code); - if (code == SRB_HTTP_STATUS_NOT_FOUND) - return -ENODEV; - return -EIO; - } - - buff[len] = 0; - ret = srb_http_header_get_uint64(buff, len, "Content-Length", &size); - if (ret) - return -EIO; - - return 0; -} - -int srb_cdmi_extend(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, - unsigned long long trunc_size) -{ - char *buff = desc->xmit_buff; - unsigned long long cur_size = 0; - int len; - int ret; - enum srb_http_statuscode code; - - if (!desc || !desc->socket) - return -EINVAL; - - ret = srb_cdmi_getsize(dbg, desc, &cur_size); - if (ret != 0) { - SRB_LOG_ERR(dbg->level, "[extend] Could not get size of existing volume."); - return ret; - } - - if (cur_size >= trunc_size) { - SRB_LOG_ERR(dbg->level, "[extend] Cannot shrink a volume."); - return -EINVAL; - } - - /* Construct/send HTTP truncate */ - len = srb_http_mktruncate(buff, SRB_XMIT_BUFFER_SIZE, - desc->ip_addr, desc->filename, trunc_size); - if (len <= 0) return len; - - len = sock_send_receive(dbg, desc, len, 0); - if (len < 0) return len; - - ret = srb_http_get_status(buff, len, &code); - if (ret == -1) { - SRB_LOG_ERR(dbg->level, "[extend] Cannot retrieve response status"); - return -EIO; - } - - if (srb_http_get_status_range(code) != SRB_HTTP_STATUSRANGE_SUCCESS) { - SRB_LOG_ERR(dbg->level, "[extend] Status of extend operation = %i.", code); - return -EIO; - } - - return 0; -} - -int srb_cdmi_create(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, - unsigned long long trunc_size) -{ - char *buff = desc->xmit_buff; - int len; - int ret; - enum srb_http_statuscode code; - - if (!desc || !desc->socket) - return -EINVAL; - - /* Construct/send HTTP create */ - len = srb_http_mkcreate(buff, SRB_XMIT_BUFFER_SIZE, - desc->ip_addr, desc->filename); - if (len <= 0) return len; - - len = sock_send_receive(dbg, desc, len, 0); - if (len < 0) return len; - - ret = srb_http_get_status(buff, len, &code); - if (ret == -1) { - SRB_LOG_ERR(dbg->level, "[create] Cannot retrieve response status from %.*s", 32, buff); - return -EIO; - } - - if (srb_http_get_status_range(code) != SRB_HTTP_STATUSRANGE_SUCCESS) { - SRB_LOG_ERR(dbg->level, "[create] Status of create operation = %i.", code); - return -EIO; - } - - /* Construct/send HTTP truncate */ - len = srb_http_mktruncate(buff, SRB_XMIT_BUFFER_SIZE, - desc->ip_addr, desc->filename, trunc_size); - if (len <= 0) return len; - - len = sock_send_receive(dbg, desc, len, 0); - if (len < 0) return len; - - ret = srb_http_get_status(buff, len, &code); - if (ret == -1) { - SRB_LOG_ERR(dbg->level, "[create-trunc] Cannot retrieve response status"); - return -EIO; - } - - if (srb_http_get_status_range(code) != SRB_HTTP_STATUSRANGE_SUCCESS) { - SRB_LOG_ERR(dbg->level, "[create-trunc] Status of create operation = %i.", code); - return -EIO; - } - - return 0; -} - -int srb_cdmi_delete(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc) -{ - char *buff = desc->xmit_buff; - int len; - int ret; - enum srb_http_statuscode code; - - if (!desc || !desc->socket) - return -EINVAL; - - /* Construct HTTP delete */ - len = srb_http_mkdelete(buff, SRB_XMIT_BUFFER_SIZE, - desc->ip_addr, desc->filename); - if (len <= 0) return len; - - len = sock_send_receive(dbg, desc, len, 0); - if (len < 0) return len; - - ret = srb_http_get_status(buff, len, &code); - if (ret == -1) { - SRB_LOG_ERR(dbg->level, "[destroy] Cannot retrieve response status"); - return -EIO; - } - - if (srb_http_get_status_range(code) != SRB_HTTP_STATUSRANGE_SUCCESS) { - SRB_LOG_ERR(dbg->level, "[destroy] Status of delete operation = %i.", code); - if (code == SRB_HTTP_STATUS_NOT_FOUND) - return -ENOENT; - return -EIO; - } - - return 0; -} - /* HACK: due to a bug in HTTP HEAD from scality,using metadata instead */ #if 0 int srb_cdmi_getsize(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, @@ -994,7 +624,7 @@ int srb_cdmi_getsize(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, } #endif -int srb_cdmi_getsize(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, +int srb_cdmi_getsize(srb_debug_t *dbg, struct srb_cdmi_desc *desc, uint64_t *size) { char *buff = desc->xmit_buff; @@ -1003,7 +633,7 @@ int srb_cdmi_getsize(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, int ret, len; /* Construct a GET (?metadata) command */ - len = srb_http_mkmetadata(buff, SRB_XMIT_BUFFER_SIZE, + len = srb_http_mkmetadata(buff, SRB_CDMI_XMIT_BUFFER_SIZE, desc->ip_addr, desc->filename); if (len <= 0) return len; @@ -1037,7 +667,7 @@ int srb_cdmi_getsize(srb_debug_t *dbg, struct srb_cdmi_desc_s *desc, * at specified "offset" writing "size" bytes from "buff". */ int srb_cdmi_putrange(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, + struct srb_cdmi_desc *desc, uint64_t offset, int size) { char *xmit_buff = desc->xmit_buff; @@ -1051,7 +681,7 @@ int srb_cdmi_putrange(srb_debug_t *dbg, end = offset + size - 1; /* Construct a PUT request with range info */ - ret = srb_http_mkrange("PUT", xmit_buff, SRB_XMIT_BUFFER_SIZE, + ret = srb_http_mkrange("PUT", xmit_buff, SRB_CDMI_XMIT_BUFFER_SIZE, desc->ip_addr, desc->filename, start, end); if (ret <= 0) return ret; @@ -1082,7 +712,7 @@ int srb_cdmi_putrange(srb_debug_t *dbg, * at specified "offset" reading "size" bytes from "buff". */ int srb_cdmi_getrange(srb_debug_t *dbg, - struct srb_cdmi_desc_s *desc, + struct srb_cdmi_desc *desc, uint64_t offset, int size) { char *xmit_buff = desc->xmit_buff; @@ -1096,7 +726,7 @@ int srb_cdmi_getrange(srb_debug_t *dbg, end = offset + size - 1; /* Construct a PUT request with range info */ - len = srb_http_mkrange("GET", xmit_buff, SRB_XMIT_BUFFER_SIZE, + len = srb_http_mkrange("GET", xmit_buff, SRB_CDMI_XMIT_BUFFER_SIZE, desc->ip_addr, desc->filename, start, end); if (len <= 0) diff --git a/srb_driver.c b/srb/srb-driver.c similarity index 77% rename from srb_driver.c rename to srb/srb-driver.c index 67e50f8..9820ba7 100644 --- a/srb_driver.c +++ b/srb/srb-driver.c @@ -21,24 +21,27 @@ // Linux Kernel/LKM headers: module.h is needed by all modules and // kernel.h is needed for KERN_INFO. -#include // included for all kernel modules -#include // included for KERN_INFO -#include // included for LKM parameters -#include // included for __init and __exit macros -#include -#include -#include -#include -#include #include -#include -#include // for vmalloc() #include +#include #include -#include + +#include +#include #include "srb.h" +#define DEV_MAX 64 +#define DEV_MINORS 256 + +/* + * Default values for ScalityRestBlock LKM parameters + */ +#define SRB_REQ_TIMEOUT_DFLT 30 +#define SRB_NB_REQ_RETRIES_DFLT 3 +#define SRB_CONN_TIMEOUT_DFLT 30 +#define SRB_LOG_LEVEL_DFLT SRB_INFO +#define SRB_THREAD_POOL_SIZE_DFLT 8 // LKM information MODULE_AUTHOR("Laurent Meyer "); @@ -47,6 +50,78 @@ MODULE_DESCRIPTION("Block Device Driver for REST-based storage"); MODULE_LICENSE("GPL"); MODULE_VERSION(DEV_REL_VERSION); +typedef struct srb_server_s { + struct srb_server_s *next; + struct srb_cdmi_desc cdmi_desc; +} srb_server_t; + +/* Device state (reduce spinlock section and avoid multiple operation on same device) */ +enum device_state { + DEV_IN_USE, + DEV_UNUSED, +}; + +struct srb_device { + /* Device subsystem related data */ + int id; /* device ID */ + int major; /* blkdev assigned major */ + + /* NOTE: use const from ./linux/genhd.h */ + char name[DISK_NAME_LEN]; /* blkdev name, e.g. srba */ + struct gendisk *disk; + uint64_t disk_size; /* Size in bytes */ + atomic_t users; /* Number of users who + * opened dev */ + enum device_state state; /* for create extend attach detach destroy purpose */ + + struct request_queue *q; + spinlock_t rq_lock; /* request queue lock */ + + struct task_struct **thread; /* allow dynamic allocation during device creation */ + int nb_threads; + + /* Dewpoint specific data */ + struct srb_cdmi_desc **thread_cdmi_desc; /* allow dynamic allocation during device creation*/ + + /* + ** List of requests received by the drivers, but still to be + ** processed. This due to network latency. + */ + spinlock_t waiting_lock; /* wait_queue lock */ + wait_queue_head_t waiting_wq; + struct list_head waiting_queue; /* Requests to be sent */ + + /* Debug traces */ + srb_debug_t debug; +}; + +const srb_debug_t * srb_device_get_debug(const struct srb_device *dev) { + return &dev->debug; +} + +int srb_device_get_major(const struct srb_device *dev) { + return dev->major; +} + +const char * srb_device_get_name(const struct srb_device *dev) { + return dev->name; +} + +int srb_device_get_debug_level(const struct srb_device *dev) { + return dev->debug.level; +} +void srb_device_set_debug_level(struct srb_device *dev, int level) { + dev->debug.level = level; +} + +struct srb_cdmi_desc * srb_device_get_thread_cdmi_desc(const struct srb_device *dev, int idx) { + return dev->thread_cdmi_desc[idx]; +} + +struct gendisk * srb_device_get_disk(const struct srb_device *dev) { + return dev->disk; +} + static srb_device_t devtab[DEV_MAX]; static srb_server_t *servers = NULL; static DEFINE_SPINLOCK(devtab_lock); @@ -256,8 +331,8 @@ static int req_flags_to_str(int flags, char *buff) /* * Handle an I/O request. */ -static int srb_xfer_scl(struct srb_device_s *dev, - struct srb_cdmi_desc_s *desc, +static int srb_xfer_scl(struct srb_device *dev, + struct srb_cdmi_desc *desc, struct request *req) { int ret = 0; @@ -302,7 +377,7 @@ static int srb_xfer_scl(struct srb_device_s *dev, /* * Free internal disk */ -static int srb_free_disk(struct srb_device_s *dev) +static int srb_free_disk(struct srb_device *dev) { struct gendisk *disk = NULL; @@ -330,7 +405,7 @@ static int srb_free_disk(struct srb_device_s *dev) */ static int srb_thread(void *data) { - struct srb_device_s *dev; + struct srb_device *dev; struct request *req; unsigned long flags; int th_id; @@ -342,9 +417,9 @@ static int srb_thread(void *data) #else struct bio_vec bvec; #endif - struct srb_cdmi_desc_s *cdmi_desc; + struct srb_cdmi_desc *cdmi_desc; - SRBDEV_LOG_DEBUG(((struct srb_device_s *)data), "Thread started with device %p", data); + SRBDEV_LOG_DEBUG(((struct srb_device *)data), "Thread started with device %p", data); dev = data; @@ -401,8 +476,8 @@ static int srb_thread(void *data) } /* Create scatterlist */ - cdmi_desc = dev->thread_cdmi_desc[th_id]; - sg_init_table(dev->thread_cdmi_desc[th_id]->sgl, DEV_NB_PHYS_SEGS); + cdmi_desc = srb_device_get_thread_cdmi_desc(dev, th_id); + sg_init_table(cdmi_desc->sgl, DEV_NB_PHYS_SEGS); dev->thread_cdmi_desc[th_id]->sgl_size = blk_rq_map_sg(dev->q, req, dev->thread_cdmi_desc[th_id]->sgl); SRBDEV_LOG_DEBUG(dev, "scatter_list size %d [nb_seg = %d," @@ -428,7 +503,7 @@ static int srb_thread(void *data) static void srb_rq_fn(struct request_queue *q) { - struct srb_device_s *dev = q->queuedata; + struct srb_device *dev = q->queuedata; struct request *req; unsigned long flags; @@ -465,7 +540,7 @@ static int srb_open(struct block_device *bdev, fmode_t mode) goto out; } - dev->users++; + atomic_inc(&dev->users); out: spin_unlock(&devtab_lock); return ret; @@ -482,7 +557,7 @@ static void srb_release(struct gendisk *disk, fmode_t mode) dev = disk->private_data; SRBDEV_LOG_INFO(dev, "Releasing device (%s)", disk->disk_name); spin_lock(&devtab_lock); - dev->users--; + atomic_dec(&dev->users); spin_unlock(&devtab_lock); } @@ -493,11 +568,11 @@ static const struct block_device_operations srb_fops = .release = srb_release, }; -static int srb_init_disk(struct srb_device_s *dev) +static int srb_init_disk(struct srb_device *dev) { struct gendisk *disk = NULL; struct request_queue *q; - int i; + unsigned int i; int ret = 0; SRB_LOG_INFO(srb_log, "srb_init_disk: initializing disk for device: %s", dev->name); @@ -594,7 +669,7 @@ static int srb_init_disk(struct srb_device_s *dev) static int srb_device_new(const char *devname, srb_device_t *dev) { int ret = -EINVAL; - int i; + unsigned int i; SRB_LOG_INFO(srb_log, "srb_device_new: creating new device %s" " with %d threads", devname, thread_pool_size); @@ -617,7 +692,7 @@ static int srb_device_new(const char *devname, srb_device_t *dev) */ dev->debug.name = &dev->name[0]; dev->debug.level = srb_log; - dev->users = 0; + atomic_set(&dev->users, 0); strncpy(dev->name, devname, strlen(devname)); /* XXX: dynamic allocation of thread pool and cdmi connection pool @@ -632,7 +707,7 @@ static int srb_device_new(const char *devname, srb_device_t *dev) goto err_mem; } for (i = 0; i < thread_pool_size; i++) { - dev->thread_cdmi_desc[i] = vmalloc(sizeof(struct srb_cdmi_desc_s)); + dev->thread_cdmi_desc[i] = vmalloc(sizeof(struct srb_cdmi_desc)); if (dev->thread_cdmi_desc[i] == NULL) { SRB_LOG_CRIT(srb_log, "srb_device_new: Unable to allocate memory for CDMI struct, step %d", i); ret = -ENOMEM; @@ -674,7 +749,7 @@ static void __srb_device_free(srb_device_t *dev) static void srb_device_free(srb_device_t *dev) { - int i = 0; + unsigned int i = 0; SRB_LOG_INFO(srb_log, "srb_device_free: freeing device: %s", dev->name); @@ -712,16 +787,16 @@ static int _srb_reconstruct_url(char *url, char *name, if (seplen) { - urllen = snprintf(url, SRB_URL_SIZE, "%s/%s", baseurl, filename); - namelen = snprintf(name, SRB_URL_SIZE, "%s/%s", basepath, filename); + urllen = snprintf(url, SRB_CDMI_URL_SIZE, "%s/%s", baseurl, filename); + namelen = snprintf(name, SRB_CDMI_URL_SIZE, "%s/%s", basepath, filename); } else { - urllen = snprintf(url, SRB_URL_SIZE, "%s%s", baseurl, filename); - namelen = snprintf(name, SRB_URL_SIZE, "%s%s", basepath, filename); + urllen = snprintf(url, SRB_CDMI_URL_SIZE, "%s%s", baseurl, filename); + namelen = snprintf(name, SRB_CDMI_URL_SIZE, "%s%s", basepath, filename); } - if (urllen >= SRB_URL_SIZE || namelen >= SRB_URL_SIZE) + if (urllen >= SRB_CDMI_URL_SIZE || namelen >= SRB_CDMI_URL_SIZE) return -EINVAL; return 0; @@ -729,7 +804,7 @@ static int _srb_reconstruct_url(char *url, char *name, static int __srb_device_detach(srb_device_t *dev) { - int i; + unsigned int i, users = 0; int ret = 0; SRB_LOG_DEBUG(srb_log, "detaching device (%p)", dev); @@ -741,8 +816,9 @@ static int __srb_device_detach(srb_device_t *dev) SRBDEV_LOG_DEBUG(dev, "Detaching device (%s)", dev->name); - if (dev->users > 0) { - SRBDEV_LOG_ERR(dev, "Unable to remove, device still opened (#users: %d)", dev->users); + users = atomic_read(&dev->users); + if (users > 0) { + SRBDEV_LOG_ERR(dev, "Unable to remove, device still opened (#users: %d)", users); return -EBUSY; } @@ -878,10 +954,10 @@ static int _srb_server_new(srb_debug_t *dbg, const char *url, srb_server_t **ser * XXX NOTE XXX: #13 This function picks only one server that has enough free * space in the URL buffer to append the filename. */ -static int _srb_server_pick(const char *filename, struct srb_cdmi_desc_s *pick) +static int _srb_server_pick(const char *filename, struct srb_cdmi_desc *pick) { - char url[SRB_URL_SIZE]; - char name[SRB_URL_SIZE]; + char url[SRB_CDMI_URL_SIZE]; + char name[SRB_CDMI_URL_SIZE]; int ret; int found = 0; srb_server_t *server = NULL; @@ -898,9 +974,9 @@ static int _srb_server_pick(const char *filename, struct srb_cdmi_desc_s *pick) filename); SRB_LOG_INFO(srb_log, "Dewb reconstruct url yielded %s, %i", url, ret); if (ret == 0) { - memcpy(pick, &server->cdmi_desc, sizeof(struct srb_cdmi_desc_s)); - strncpy(pick->url, url, SRB_URL_SIZE); - strncpy(pick->filename, name, SRB_URL_SIZE); + memcpy(pick, &server->cdmi_desc, sizeof(struct srb_cdmi_desc)); + strncpy(pick->url, url, SRB_CDMI_URL_SIZE); + strncpy(pick->filename, name, SRB_CDMI_URL_SIZE); SRB_LOG_INFO(srb_log, "Copied into pick: url=%s, name=%s", pick->url, pick->filename); found = 1; break ; @@ -941,7 +1017,7 @@ int srb_server_add(const char *url) debug.name = ""; debug.level = srb_log; - if (strlen(url) >= SRB_URL_SIZE) { + if (strlen(url) >= SRB_CDMI_URL_SIZE) { SRB_LOG_ERR(srb_log, "Url too big: '%s'", url); ret = -EINVAL; goto err_out_dev; @@ -1039,7 +1115,7 @@ int srb_server_remove(const char *url) SRB_LOG_INFO(srb_log, "srb_server_remove: removing server %s", url); - if (strlen(url) >= SRB_URL_SIZE) { + if (strlen(url) >= SRB_CDMI_URL_SIZE) { SRB_LOG_ERR(srb_log, "Url too big: '%s'", url); ret = -EINVAL; goto end; @@ -1097,98 +1173,12 @@ ssize_t srb_servers_dump(char *buf, ssize_t max_size) return ret < 0 ? ret : printed; } -struct cdmi_volume_list_data { - char *buf; - size_t max_size; - size_t printed; -}; -static int _srb_volume_dump(struct cdmi_volume_list_data *cb_data, const char *volname) -{ - int ret; - int len; - - SRB_LOG_DEBUG(srb_log, "Adding volume %s to listing", volname); - if (cb_data->printed + strlen(volname) + 1 < cb_data->max_size) - { - len = snprintf(cb_data->buf + cb_data->printed, - cb_data->max_size - cb_data->printed, - "%s\n", volname); - if (len == -1 - || len > cb_data->max_size - cb_data->printed) { - SRB_LOG_ERR(srb_log, "Not enough space to print" - " volume list in buffer."); - ret = -ENOMEM; - goto end; - } - cb_data->printed += len; - } - - ret = 0; - -end: - return ret; -} - -int srb_volumes_dump(char *buf, size_t max_size) -{ - int ret = 0; - int connected = 0; - struct srb_cdmi_desc_s *cdmi_desc; - struct cdmi_volume_list_data cb_data = { buf, max_size, 0}; - srb_debug_t debug; - - SRB_LOG_INFO(srb_log, "srb_volumes_dump: dumping volumes: buf: %p, max_size: %ld", buf, max_size); - - cdmi_desc = vmalloc(sizeof(*cdmi_desc)); - if (cdmi_desc == NULL) { - ret = -ENOMEM; - goto cleanup; - } - - /* Find server for directory (filename must be empty, not NULL) */ - ret = _srb_server_pick("", cdmi_desc); - if (ret != 0) { - SRB_LOG_ERR(srb_log, "Unable to get server: %i", ret); - goto cleanup; - } - SRB_LOG_INFO(srb_log, "Dumping volumes: Picked server " - "[ip=%s port=%d fullpath=%s]", - cdmi_desc->ip_addr, cdmi_desc->port, - cdmi_desc->filename); - - /* Inherit log level from srb LKM */ - debug.name = ""; - debug.level = srb_log; - - ret = srb_cdmi_connect(&debug, cdmi_desc); - if (ret != 0) - goto cleanup; - connected = 1; - - ret = srb_cdmi_list(&debug, cdmi_desc, - (srb_cdmi_list_cb)_srb_volume_dump, (void*)&cb_data); - if (ret != 0) - goto cleanup; - - ret = 0; - -cleanup: - if (NULL != cdmi_desc) - { - if (connected) - srb_cdmi_disconnect(&debug, cdmi_desc); - vfree(cdmi_desc); - } - - return ret < 0 ? ret : cb_data.printed; -} - int srb_device_detach(const char *devname) { int ret = 0; int i; int found = 0; - struct srb_device_s *dev = NULL; + struct srb_device *dev = NULL; SRB_LOG_INFO(srb_log, "srb_device_detach: detaching device name %s", devname); @@ -1200,7 +1190,7 @@ int srb_device_detach(const char *devname) if (strcmp(devname, devtab[i].name) == 0) { found = 1; dev = &devtab[i]; - if (devtab[i].users > 0) + if (atomic_read(&devtab[i].users) > 0) ret = -EBUSY; else if (devtab[i].state == DEV_IN_USE) { ret = -EBUSY; @@ -1246,9 +1236,9 @@ int srb_device_attach(const char *filename, const char *devname) { srb_device_t *dev = NULL; int rc = 0; - int i; + unsigned int i; int do_unregister = 0; - struct srb_cdmi_desc_s *cdmi_desc = NULL; + struct srb_cdmi_desc *cdmi_desc = NULL; int found = 0; const char *fname; @@ -1298,7 +1288,7 @@ int srb_device_attach(const char *filename, const char *devname) SRB_LOG_INFO(srb_log, "Volume %s not attached yet, using device slot %d", filename, dev->id); - cdmi_desc = vmalloc(sizeof(struct srb_cdmi_desc_s)); + cdmi_desc = vmalloc(sizeof(struct srb_cdmi_desc)); if (cdmi_desc == NULL) { SRB_LOG_ERR(srb_log, "Unable to allocate memory for cdmi struct"); rc = -ENOMEM; @@ -1338,7 +1328,7 @@ int srb_device_attach(const char *filename, const char *devname) for (i = 0; i < thread_pool_size; i++) { memcpy(dev->thread_cdmi_desc[i], cdmi_desc, - sizeof(struct srb_cdmi_desc_s)); + sizeof(struct srb_cdmi_desc)); } rc = register_blkdev(0, DEV_NAME); if (rc < 0) { @@ -1390,216 +1380,6 @@ int srb_device_attach(const char *filename, const char *devname) return rc; } -int srb_device_create(const char *filename, unsigned long long size) -{ - srb_debug_t debug; - struct srb_cdmi_desc_s *cdmi_desc; - int rc; - - SRB_LOG_INFO(srb_log, "srb_device_create: creating volume %s of size %llu", filename, size); - - debug.name = NULL; - debug.level = srb_log; - - cdmi_desc = vmalloc(sizeof(struct srb_cdmi_desc_s)); - if (cdmi_desc == NULL) { - rc = -ENOMEM; - goto err_out_mod; - } - - /* Now, setup a cdmi connection then Truncate(create) the file. */ - rc = _srb_server_pick(filename, cdmi_desc); - if (rc != 0) - goto err_out_alloc; - - rc = srb_cdmi_connect(&debug, cdmi_desc); - if (rc != 0) - goto err_out_alloc; - - rc = srb_cdmi_create(&debug, cdmi_desc, size); - if (rc != 0) - goto err_out_cdmi; - - srb_cdmi_disconnect(&debug, cdmi_desc); - - SRB_LOG_INFO(srb_log, "Created volume with filename %s", filename); - - if (cdmi_desc) - vfree(cdmi_desc); - - return rc; - -err_out_cdmi: - srb_cdmi_disconnect(&debug, cdmi_desc); -err_out_alloc: - if (cdmi_desc) - vfree(cdmi_desc); -err_out_mod: - SRB_LOG_ERR(srb_log, "Error creating volume %s", filename); - - return rc; -} - -int srb_device_extend(const char *filename, unsigned long long size) -{ - srb_debug_t debug; - struct srb_cdmi_desc_s *cdmi_desc = NULL; - int i; - int rc = 0; - struct srb_device_s *dev = NULL; - - SRB_LOG_INFO(srb_log, "srb_device_extend: extending volume %s to %llu size", filename, size); - - debug.name = NULL; - debug.level = srb_log; - - /* check if volume is already attached, otherwise use the first empty slot */ - spin_lock(&devtab_lock); - for (i = 0; i < DEV_MAX; ++i) { - if (!device_free_slot(&devtab[i])) { - const char *fname = kbasename(devtab[i].thread_cdmi_desc[0]->filename); - if (strlen(fname) == strlen(filename) && strncmp(fname, filename, strlen(filename)) == 0) { - dev = &devtab[i]; - if (dev->state == DEV_IN_USE) - rc = -EBUSY; - else - dev->state = DEV_IN_USE; - break; - } - } - } - spin_unlock(&devtab_lock); - if (0 != rc) { - SRBDEV_LOG_ERR(dev, "Cannot extend volume %s: attached on device in use (%s)", filename, dev->name); - dev = NULL; - return rc; - } - - cdmi_desc = vmalloc(sizeof(struct srb_cdmi_desc_s)); - if (cdmi_desc == NULL) { - rc = -ENOMEM; - goto err_out_mod; - } - memset(cdmi_desc, 0, sizeof(struct srb_cdmi_desc_s)); - - /* Now, setup a cdmi connection then Truncate(create) the file. */ - rc = _srb_server_pick(filename, cdmi_desc); - if (rc != 0) - goto err_out_alloc; - - rc = srb_cdmi_connect(&debug, cdmi_desc); - if (rc != 0) - goto err_out_alloc; - - rc = srb_cdmi_extend(&debug, cdmi_desc, size); - if (rc != 0) - goto err_out_cdmi; - - rc = srb_cdmi_disconnect(&debug, cdmi_desc); - if (rc != 0) - goto err_out_cdmi; - - if (cdmi_desc) - vfree(cdmi_desc); - - // Find device (normally only 1) associated to filename and update their size - spin_lock(&devtab_lock); - if (dev) { - devtab[i].disk_size = size; - set_capacity(devtab[i].disk, devtab[i].disk_size / 512ULL); - revalidate_disk(devtab[i].disk); - dev->state = DEV_UNUSED; - } - spin_unlock(&devtab_lock); - - SRB_LOG_INFO(srb_log, "Extended filename %s", filename); - - return rc; - -err_out_cdmi: - srb_cdmi_disconnect(&debug, cdmi_desc); -err_out_alloc: - if (cdmi_desc) - vfree(cdmi_desc); -err_out_mod: - SRB_LOG_ERR(srb_log, "Error extending device %s", filename); - - return rc; -} - -int srb_device_destroy(const char *filename) -{ - srb_debug_t debug; - struct srb_cdmi_desc_s *cdmi_desc = NULL; - int rc = -EIO; - int i; - int found = 0; - - SRB_LOG_INFO(srb_log, "srb_device_destroy: destroying volume: %s", filename); - - debug.name = NULL; - debug.level = srb_log; - - // Check that there is no device associated to filename - spin_lock(&devtab_lock); - for (i = 0; i < DEV_MAX; ++i) { - if (!device_free_slot(&devtab[i])) { - const char *fname = kbasename( - devtab[i].thread_cdmi_desc[0]->filename); - if (strlen(fname) == strlen(filename) && strncmp(fname, filename, strlen(fname)) == 0) { - found = 1; - break; - } - } - } - spin_unlock(&devtab_lock); - - if (found) { - SRB_LOG_ERR(srb_log, "Found a device associated to volume %s", filename); - rc = -EBUSY; - goto err_out_mod; - } - - cdmi_desc = vmalloc(sizeof(struct srb_cdmi_desc_s)); - if (cdmi_desc == NULL) { - SRB_LOG_ERR(srb_log, "Unable to allocate memory for temporary CDMI"); - rc = -ENOMEM; - goto err_out_mod; - } - - /* First, setup a cdmi connection then Delete the file. */ - rc = _srb_server_pick(filename, cdmi_desc); - if (rc != 0) - goto err_out_alloc; - - rc = srb_cdmi_connect(&debug, cdmi_desc); - if (rc != 0) - goto err_out_alloc; - - rc = srb_cdmi_delete(&debug, cdmi_desc); - if (rc != 0) - goto err_out_cdmi; - - srb_cdmi_disconnect(&debug, cdmi_desc); - - if (cdmi_desc) - vfree(cdmi_desc); - - SRB_LOG_INFO(srb_log, "Destroyed volume %s", filename); - - return rc; - -err_out_cdmi: - srb_cdmi_disconnect(&debug, cdmi_desc); -err_out_alloc: - if (cdmi_desc) - vfree(cdmi_desc); -err_out_mod: - SRB_LOG_ERR(srb_log, "Error destroying volume %s", filename); - - return rc; -} - static int __init srb_init(void) { int rc; diff --git a/srb_http.c b/srb/srb-http.c similarity index 63% rename from srb_http.c rename to srb/srb-http.c index a949290..2ff4f52 100644 --- a/srb_http.c +++ b/srb/srb-http.c @@ -18,9 +18,8 @@ * */ -#include -#include - +#include +#include #include "srb.h" #define HTTP_VER "HTTP/1.1" @@ -108,6 +107,7 @@ int srb_http_get_status(char *buf, int len, enum srb_http_statuscode *code) return -1; } +EXPORT_SYMBOL(srb_http_get_status); enum srb_http_statusrange srb_http_get_status_range(enum srb_http_statuscode status) @@ -127,6 +127,7 @@ enum srb_http_statusrange srb_http_get_status_range(enum srb_http_statuscode sta return range; } +EXPORT_SYMBOL(srb_http_get_status_range); #if 0 // Add a \0 at the end of the buffer @@ -176,193 +177,7 @@ int srb_http_check_response_complete(char *buff, int len) return hdr_end + contentlen <= len; } - -int srb_http_mkhead(char *buff, int len, char *host, char *page) -{ - char *bufp = buff; - int mylen = len; - int ret; - - *buff = 0; - ret = add_buffer(&bufp, &mylen, "HEAD "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, page); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, " " HTTP_VER CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_KEEPALIVE CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_USER_AGENT CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, "Host: "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, host); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, CRLF CRLF); - if (ret) - return -ENOMEM; - - return (len - mylen); -} - -int srb_http_mkcreate(char *buff, int len, char *host, char *page) -{ - char *bufp = buff; - int mylen = len; - int ret; - - *buff = 0; - ret = add_buffer(&bufp, &mylen, "PUT "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, page); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, " " HTTP_VER CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_KEEPALIVE CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_USER_AGENT CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, "Host: "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, host); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, "If-None-Match: *"); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, CRLF CRLF); - if (ret) - return -ENOMEM; - - return (len - mylen); -} - -int srb_http_mktruncate(char *buff, int len, char *host, char *page, unsigned long long size) -{ - char *bufp = buff; - int mylen = len; - char buf[64]; - int ret; - - *buff = 0; - ret = add_buffer(&bufp, &mylen, "PUT "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, page); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, " " HTTP_VER CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_KEEPALIVE CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_USER_AGENT CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, "Host: "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, host); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, CRLF); - if (ret) - return -ENOMEM; - - sprintf(buf, "%s: %llu", HTTP_TRUNCATE, size); - - ret = add_buffer(&bufp, &mylen, buf); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, CRLF CRLF); - if (ret) - return -ENOMEM; - - return (len - mylen); -} - -int srb_http_mkdelete(char *buff, int len, char *host, char *page) -{ - char *bufp = buff; - int mylen = len; - int ret; - - *buff = 0; - ret = add_buffer(&bufp, &mylen, "DELETE "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, page); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, " " HTTP_VER CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_KEEPALIVE CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_USER_AGENT CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, "Host: "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, host); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, CRLF CRLF); - if (ret) - return -ENOMEM; - - return (len - mylen); -} +EXPORT_SYMBOL(srb_http_check_response_complete); int srb_http_mkmetadata(char *buff, int len, char *host, char *page) { @@ -405,6 +220,7 @@ int srb_http_mkmetadata(char *buff, int len, char *host, char *page) return (len - mylen); } +EXPORT_SYMBOL(srb_http_mkmetadata); int srb_http_mkrange(char *cmd, char *buff, int len, char *host, char *page, uint64_t start, uint64_t end) @@ -478,67 +294,7 @@ int srb_http_mkrange(char *cmd, char *buff, int len, char *host, char *page, return (len - mylen); } - -int srb_http_mklist(char *buff, int len, char *host, char *page) -{ - char *bufp = buff; - int mylen = len; - int ret; - - *buff = 0; - ret = add_buffer(&bufp, &mylen, "GET "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, " "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, page); - if (ret) - return -ENOMEM; - - if (page[strlen(page) - 1] != '/') - { - ret = add_buffer(&bufp, &mylen, "/"); - if (ret) - return -ENOMEM; - } - - ret = add_buffer(&bufp, &mylen, " " HTTP_VER CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_KEEPALIVE CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_USER_AGENT CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, "Host: "); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, host); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, HTTP_CDMI_VERS CRLF); - if (ret) - return -ENOMEM; - - ret = add_buffer(&bufp, &mylen, CRLF); - if (ret) - return -ENOMEM; - - return (len - mylen); -} +EXPORT_SYMBOL(srb_http_mkrange); int srb_http_header_get_uint64(char *buff, int len, char *key, uint64_t *value) { @@ -594,6 +350,7 @@ int srb_http_header_get_uint64(char *buff, int len, char *key, uint64_t *value) return 0; } +EXPORT_SYMBOL(srb_http_header_get_uint64); int srb_http_skipheader(char **buff, int *len) { @@ -615,3 +372,4 @@ int srb_http_skipheader(char **buff, int *len) return -1; } +EXPORT_SYMBOL(srb_http_skipheader); diff --git a/srb_sysfs.c b/srb/srb-sysfs.c similarity index 56% rename from srb_sysfs.c rename to srb/srb-sysfs.c index a9b23cf..d38b70c 100644 --- a/srb_sysfs.c +++ b/srb/srb-sysfs.c @@ -18,11 +18,7 @@ * */ -#include // included for all kernel modules -#include // included for KERN_INFO -#include -#include -#include +#include #include "srb.h" @@ -54,57 +50,18 @@ static int parse_params(char *params, const char *delim, char **param_tbl, int p return j; } -static int human_to_bytes(char *size_str, unsigned long long *size) -{ - char h; - unsigned long long coef; - int ret; - - //printk(KERN_DEBUG "DEBUG: human_to_bytes: buff: %s\n", size_str); - - coef = 1; - h = size_str[strlen(size_str) - 1]; - /* get human format if any and set coeff */ - switch (h) { - case 'G': - coef = GB; - size_str[strlen(size_str) - 1] = '\0'; - break; - case 'M': - coef = MB; - size_str[strlen(size_str) - 1] = '\0'; - break; - case 'k': - coef = kB; - size_str[strlen(size_str) - 1] = '\0'; - break; - default: - coef = 1; - } - /* calculate size */ - ret = kstrtoull(size_str, 10, size); - if (ret != 0) { - SRB_LOG_ERR(srb_log, "Invalid volume size %s (%llu) (ret: %d)", size_str, *size, ret); - return -EINVAL; - } - *size = *size * coef; - - return 0; -} - /******************************************************************** * /sys/block/srb?/ * srb_debug Sets verbosity * srb_urls Gets device CDMI url * srb_name Gets device's on-storage filename - * srb_size Gets device size *******************************************************************/ static ssize_t attr_debug_store(struct device *dv, struct device_attribute *attr, const char *buff, size_t count) { struct gendisk *disk = dev_to_disk(dv); - struct srb_device_s *dev = disk->private_data; + struct srb_device *dev = disk->private_data; long int val; int ret; @@ -116,12 +73,12 @@ static ssize_t attr_debug_store(struct device *dv, if ((int)val < 0 || (int)val > 7) { SRBDEV_LOG_WARN(dev, "Invalid debug value (%d) for device %s in sysfs", - (int)val, dev->name); + (int)val, srb_device_get_name(dev)); return -EINVAL; } - dev->debug.level = (int)val; - SRBDEV_LOG_DEBUG(dev, "Setting Log level to %d for device %s", (int)val, dev->name); + srb_device_set_debug_level(dev, (int)val); + SRBDEV_LOG_DEBUG(dev, "Setting Log level to %d for device %s", (int)val, srb_device_get_name(dev)); return count; } @@ -130,9 +87,9 @@ static ssize_t attr_debug_show(struct device *dv, struct device_attribute *attr, char *buff) { struct gendisk *disk = dev_to_disk(dv); - struct srb_device_s *dev = disk->private_data; + struct srb_device *dev = disk->private_data; - return scnprintf(buff, PAGE_SIZE, "%d\n", dev->debug.level); + return scnprintf(buff, PAGE_SIZE, "%d\n", srb_device_get_debug_level(dev)); } @@ -140,36 +97,25 @@ static ssize_t attr_urls_show(struct device *dv, struct device_attribute *attr, char *buff) { struct gendisk *disk = dev_to_disk(dv); - struct srb_device_s *dev = disk->private_data; + struct srb_device *dev = disk->private_data; //snprintf(buff, PAGE_SIZE, "%s\n", dev->thread_cdmi_desc[0].url); - return scnprintf(buff, PAGE_SIZE, "%s\n", dev->thread_cdmi_desc[0]->url); + return scnprintf(buff, PAGE_SIZE, "%s\n", srb_device_get_thread_cdmi_desc(dev, 0)->url); } static ssize_t attr_disk_name_show(struct device *dv, struct device_attribute *attr, char *buff) { struct gendisk *disk = dev_to_disk(dv); - struct srb_device_s *dev = disk->private_data; + struct srb_device *dev = disk->private_data; //snprintf(buff, PAGE_SIZE, "%s\n", kbasename(dev->thread_cdmi_desc[0].url)); - return scnprintf(buff, PAGE_SIZE, "%s\n", kbasename(dev->thread_cdmi_desc[0]->url)); -} - -static ssize_t attr_disk_size_show(struct device *dv, - struct device_attribute *attr, char *buff) -{ - struct gendisk *disk = dev_to_disk(dv); - struct srb_device_s *dev = disk->private_data; - - return scnprintf(buff, PAGE_SIZE, "%llu\n", dev->disk_size); + return scnprintf(buff, PAGE_SIZE, "%s\n", kbasename(srb_device_get_thread_cdmi_desc(dev, 0)->url)); } static DEVICE_ATTR(srb_debug, S_IWUSR | S_IRUGO, &attr_debug_show, &attr_debug_store); static DEVICE_ATTR(srb_urls, S_IRUGO, &attr_urls_show, NULL); static DEVICE_ATTR(srb_name, S_IRUGO, &attr_disk_name_show, NULL); -static DEVICE_ATTR(srb_size, S_IRUGO, &attr_disk_size_show, NULL); - /************************************************************************ * /sys/class/srb/ @@ -189,202 +135,6 @@ static void class_srb_release(struct class *cls) kfree(cls); } -static ssize_t class_srb_create_show(struct class *c, struct class_attribute *attr, - char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "# Usage: echo 'VolumeName size(bytes)' > create\n"); -} - -static ssize_t class_srb_create_store(struct class *c, - struct class_attribute *attr, - const char *buf, size_t count) -{ - ssize_t ret = 0; - unsigned long long size = 0; - size_t len = 0; - char *size_str = NULL; - char *params[2]; - const char *delim = " "; - char *tmp_buf; - - SRB_LOG_INFO(srb_log, "Creating volume with params: %s (%lu)", buf, count); - - /* TODO: split the buff into two string array with a thread-safe function strtok_r - * - use a temporary buffer - * - properly end string - */ - tmp_buf = NULL; - if (count >= 256) { - SRB_LOG_ERR(srb_log, "Invalid parameter (too long: %lu)", count); - ret = -EINVAL; - goto out; - } - - tmp_buf = kmalloc(count + 1, GFP_KERNEL); - if (NULL == tmp_buf) { - SRB_LOG_ERR(srb_log, "Unable to allocate memory for parameters"); - ret = -ENOMEM; - goto out; - } - memset(tmp_buf, 0, count + 1); - memcpy(tmp_buf, buf, count); - - /* remove CR or LF if any and end string */ - if (tmp_buf[count - 1] == '\n' || tmp_buf[count - 1] == '\r') - tmp_buf[count - 1] = 0; - else - tmp_buf[count] = 0; - - parse_params(tmp_buf, delim, params, 2, count); - /* sanity check */ - len = strlen(params[0]); - if (len >= SRB_URL_SIZE) { - SRB_LOG_ERR(srb_log, "Invalid volume name (too long: %lu)", len); - ret = -EINVAL; - goto out; - } - ret = human_to_bytes(params[1], &size); - if (ret != 0) { - SRB_LOG_ERR(srb_log, "Invalid volume size: %s", params[1]); - goto out; - } - - SRB_LOG_INFO(srb_log, "Creating volume %s of size %llu (bytes)", params[0], size); - - ret = srb_device_create(params[0], size); - if (ret != 0) { - SRB_LOG_ERR(srb_log, "Failed to create device: %lu", ret); - goto out; - } - - ret = count; - -out: - if (size_str != NULL) - kfree(size_str); - if (tmp_buf != NULL) - kfree(tmp_buf); - - return ret; -} - -static ssize_t class_srb_extend_show(struct class *c, struct class_attribute *attr, - char *buf) -{ - return scnprintf(buf, PAGE_SIZE, - "The new size must be greater than the current size.\n" - "# Usage: echo 'VolumeName size(bytes)' > extend\n"); -} - -static ssize_t class_srb_extend_store(struct class *c, - struct class_attribute *attr, - const char *buf, size_t count) -{ - ssize_t ret = 0; - //char filename[SRB_URL_SIZE + 1]; - //const char *tmp = buf; - unsigned long long size = 0; - size_t len = 0; - char *size_str = NULL; - char *params[2]; - const char *delim = " "; - char *tmp_buf; - - SRB_LOG_INFO(srb_log, "Extending volume with params: %s (%lu)", buf, count); - - tmp_buf = NULL; - if (count >= 256) { - SRB_LOG_ERR(srb_log, "Invalid parameter (too long: %lu)", count); - ret = -EINVAL; - goto out; - } - - tmp_buf = kmalloc(count, GFP_KERNEL); - if (NULL == tmp_buf) { - SRB_LOG_ERR(srb_log, "Unable to allocate memory for parameters"); - ret = -ENOMEM; - goto out; - } - memset(tmp_buf, 0, count); - memcpy(tmp_buf, buf, count); - - /* remove CR or LF if any and end string */ - if (tmp_buf[count - 1] == '\n' || tmp_buf[count - 1] == '\r') - tmp_buf[count - 1] = 0; - else - tmp_buf[count] = 0; - - parse_params(tmp_buf, delim, params, 2, count); - /* sanity check */ - len = strlen(params[0]); - if (len >= SRB_URL_SIZE) { - SRB_LOG_ERR(srb_log, "Invalid volume name (too long: %lu)", len); - ret = -EINVAL; - goto out; - } - ret = human_to_bytes(params[1], &size); - if (ret != 0) { - SRB_LOG_ERR(srb_log, "Invalid volume size: %s", params[1]); - goto out; - } - - SRB_LOG_INFO(srb_log, "Extending volume %s of size %llu (bytes)", params[0], size); - - ret = srb_device_extend(params[0], size); - if (ret != 0) { - goto out; - } - - ret = count; - -out: - if (size_str != NULL) - kfree(size_str); - if (tmp_buf != NULL) - kfree(tmp_buf); - - return ret; -} - -static ssize_t class_srb_destroy_show(struct class *c, struct class_attribute *attr, - char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "# Usage: echo VolumeName > destroy\n"); -} - -static ssize_t class_srb_destroy_store(struct class *c, - struct class_attribute *attr, - const char *buf, size_t count) -{ - ssize_t ret = 0; - char filename[SRB_URL_SIZE + 1]; - - /* Sanity check URL size */ - if ((count == 0) || (count >= SRB_URL_SIZE)) { - SRB_LOG_ERR(srb_log, "Invalid parameter (too long: %lu)", count); - ret = -EINVAL; - goto out; - } - - memset(filename, 0, count); - memcpy(filename, buf, count); - if (filename[count - 1] == '\n' || filename[count - 1] == '\r') - filename[count - 1] = 0; - else - filename[count] = 0; - - SRB_LOG_INFO(srb_log, "Destroying volume '%s'", filename); - ret = srb_device_destroy(filename); - if (ret != 0) { - goto out; - } - - ret = count; - -out: - return ret; -} - static ssize_t class_srb_attach_show(struct class *c, struct class_attribute *attr, char *buf) { @@ -427,7 +177,7 @@ static ssize_t class_srb_attach_store(struct class *c, } /* Sanity check params sizes */ - if (NULL == *filename || strlen(*filename) > SRB_URL_SIZE) { + if (NULL == *filename || strlen(*filename) > SRB_CDMI_URL_SIZE) { SRB_LOG_ERR(srb_log, "Invalid parameter #1: " "'%s'(%lu characters)", *filename, strlen(*filename)); @@ -503,7 +253,7 @@ static ssize_t class_srb_addurl_store(struct class *c, size_t count) { ssize_t ret = 0; - char url[SRB_URL_SIZE+1]; + char url[SRB_CDMI_URL_SIZE+1]; const char *tmp = buf; const char *tmpend = tmp; int errcount = 0; @@ -523,7 +273,7 @@ static ssize_t class_srb_addurl_store(struct class *c, while (*tmpend && *tmpend != '\n') tmpend++; - if ((tmpend - tmp) > SRB_URL_SIZE) { + if ((tmpend - tmp) > SRB_CDMI_URL_SIZE) { SRB_LOG_ERR(srb_log, "Url too big: '%s'", tmp); ret = -EINVAL; goto end; @@ -532,7 +282,7 @@ static ssize_t class_srb_addurl_store(struct class *c, url[(tmpend - tmp)] = 0; tmpend = NULL; } - url[SRB_URL_SIZE] = 0; + url[SRB_CDMI_URL_SIZE] = 0; ret = srb_server_add(url); if (ret < 0) @@ -563,7 +313,7 @@ static ssize_t class_srb_removeurl_store(struct class *c, size_t count) { ssize_t ret = 0; - char url[SRB_URL_SIZE]; + char url[SRB_CDMI_URL_SIZE]; const char *tmp = buf; const char *tmpend = tmp; @@ -585,7 +335,7 @@ static ssize_t class_srb_removeurl_store(struct class *c, while (*tmpend && *tmpend != '\n') tmpend++; - if ((tmpend - tmp) > SRB_URL_SIZE) + if ((tmpend - tmp) > SRB_CDMI_URL_SIZE) { SRB_LOG_ERR(srb_log, "Url too big: '%s'", tmp); ret = -EINVAL; @@ -622,35 +372,21 @@ static ssize_t class_srb_urls_show(struct class *c, struct class_attribute *attr return ret; } -static ssize_t class_srb_volumes_show(struct class *c, struct class_attribute *attr, - char *buf) +void srb_sysfs_device_init(struct srb_device *dev) { - ssize_t ret = 0; - - ret = srb_volumes_dump(buf, PAGE_SIZE); - - return ret; -} + struct gendisk *disk = srb_device_get_disk(dev); - -void srb_sysfs_device_init(srb_device_t *dev) -{ - device_create_file(disk_to_dev(dev->disk), &dev_attr_srb_debug); - device_create_file(disk_to_dev(dev->disk), &dev_attr_srb_urls); - device_create_file(disk_to_dev(dev->disk), &dev_attr_srb_name); - device_create_file(disk_to_dev(dev->disk), &dev_attr_srb_size); + device_create_file(disk_to_dev(disk), &dev_attr_srb_debug); + device_create_file(disk_to_dev(disk), &dev_attr_srb_urls); + device_create_file(disk_to_dev(disk), &dev_attr_srb_name); } static struct class_attribute class_srb_attrs[] = { __ATTR(attach, 0600, class_srb_attach_show, class_srb_attach_store), __ATTR(detach, 0600, class_srb_detach_show, class_srb_detach_store), - __ATTR(create, 0600, class_srb_create_show, class_srb_create_store), - __ATTR(extend, 0600, class_srb_extend_show, class_srb_extend_store), - __ATTR(destroy, 0600, class_srb_destroy_show, class_srb_destroy_store), __ATTR(add_urls, 0600, class_srb_addurl_show, class_srb_addurl_store), __ATTR(remove_urls, 0600, class_srb_removeurl_show, class_srb_removeurl_store), __ATTR(urls, 0400, class_srb_urls_show, NULL), - __ATTR(volumes, 0400, class_srb_volumes_show, NULL), __ATTR_NULL }; diff --git a/srb/srb-trace.c b/srb/srb-trace.c new file mode 100644 index 0000000..885bd33 --- /dev/null +++ b/srb/srb-trace.c @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2015 Scality SA - http://www.scality.com + * + * This file is part of ScalityRestBlock. + * + * ScalityRestBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ScalityRestBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ScalityRestBlock. If not, see . + * + */ + +#define CREATE_TRACE_POINTS +#include diff --git a/srb/srb.h b/srb/srb.h new file mode 100644 index 0000000..54ac1aa --- /dev/null +++ b/srb/srb.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 SCALITY SA - http://www.scality.com + * + * This file is part of ScalityRestBlock. + * + * ScalityRestBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ScalityRestBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see . + * + */ + +#ifndef __SRBLOCK_H__ +# define __SRBLOCK_H__ + +#include +#include + +#include +#include +#include + +/* Unix device constants */ +#define DEV_NAME "srb" +#define DEV_REL_VERSION "0.6.1" // Set version of srb LKM +#define DEV_SECTORSIZE SRB_DEV_SECTORSIZE +#define DEV_NB_PHYS_SEGS SRB_DEV_NB_PHYS_SEGS + +/* + * Linux Kernel Module (LKM) parameters + */ +extern unsigned short srb_log; +extern unsigned short nb_req_retries; + +/* srb.c */ +int srb_device_attach(const char *filename, const char *devname); +int srb_device_detach(const char *devname); + +int srb_server_add(const char *url); +int srb_server_remove(const char *url); +ssize_t srb_servers_dump(char *buf, ssize_t max_size); + +struct srb_device; +typedef struct srb_device srb_device_t; +const srb_debug_t * srb_device_get_debug(const struct srb_device *dev); +int srb_device_get_debug_level(const struct srb_device *dev); +int srb_device_get_major(const struct srb_device *dev); +const char * srb_device_get_name(const struct srb_device *dev); +void srb_device_set_debug_level(struct srb_device *dev, int level); +struct srb_cdmi_desc * srb_device_get_thread_cdmi_desc(const struct srb_device *dev, int idx); +struct gendisk * srb_device_get_disk(const struct srb_device *dev); + +/* srb_sysfs.c*/ +int srb_sysfs_init(void); +void srb_sysfs_device_init(srb_device_t *dev); +void srb_sysfs_cleanup(void); +#endif diff --git a/system-v_init/srb-ubuntu.init b/system-v_init/srb-ubuntu.init deleted file mode 100755 index 927cc85..0000000 --- a/system-v_init/srb-ubuntu.init +++ /dev/null @@ -1,140 +0,0 @@ -#! /bin/sh -### BEGIN INIT INFO -# Provides: srb -# Required-Start: $syslog -# Required-Stop: $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Scality RestBlock Driver -# Description: This service loads Scality RestBlock Driver -# and configures the servers from /etc/srb.conf. -### END INIT INFO - -# Author: Frederic Donnat -# - -# Do NOT "set -e" - -# PATH should only include /usr/* if it runs after the mountnfs.sh script -PATH=/sbin:/usr/sbin:/bin:/usr/bin -DESC="Scality RestBlock driver" -NAME=srb -SCRIPTNAME=/etc/init.d/$NAME -VERBOSE=yes -KMOD_NAME=srb - -# Exit if the package is not installed -#[ -x "$DAEMON" ] || exit 0 - -# Read configuration variable file if it is present -[ -r /etc/${NAME}.conf ] && . /etc/${NAME}.conf - -# Load the VERBOSE setting and other rcS variables -#. /lib/init/vars.sh - -# Define LSB log_* functions. -# Depend on lsb-base (>= 3.2-14) to ensure that this file is present -# and status_of_proc is working. -. /lib/lsb/init-functions - -# -# Parsing config -# -if [ -z $KMOD_PATH ]; then KMOD_PATH="/lib/modules/$(uname -r)/kernel/drivers/srb/"; fi - -# -# Function that loads the ScalityRestBlock -# -do_load_drv() { - # Load the driver - insmod $KMOD_PATH/${KMOD_NAME}.ko > /dev/null || return 2 -} - -# -# Function that unload the ScalityRestBlock -# -do_unload_drv() { - # Unload the driver - rmmod $KMOD_NAME > /dev/null || return 2 -} - -# -# Function that configures the servers -# -do_config_servers() { - echo "$URLS" > /sys/class/srb/add_urls || return 2 -} - -# -# Function that unconfigures the servers -# -do_deconfig_servers() { - echo "$URLS" > /sys/class/srb/remove_urls || return 2 -} - -# -# Function that checks status -# -do_check_drv_status() { - lsmod | grep $KMOD_NAME > /dev/null || return 2 -} -do_check_servers_status() { - nb_urls=$(cat /sys/class/srb/urls | wc -l) - [ $nb_urls -ne 0 ] && return 0 || return 2 -} - -case "$1" in - start) - #log_begin_msg "Starting $DESC" "$NAME" - [ "$VERBOSE" != no ] && log_action_begin_msg "Loading ${KMOD_NAME} driver" - do_load_drv - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_action_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_action_end_msg 1 ;; - esac - [ "$VERBOSE" != no ] && log_action_begin_msg "Adding ${NAME} servers" - do_config_servers - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_action_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_action_end_msg 1 ; return 2 ;; - esac - #log_end_msg $? - ;; - stop) - #log_begin_msg "Stopping $DESC" "$NAME" - [ "$VERBOSE" != no ] && log_action_begin_msg "Removing ${NAME} servers" - do_deconfig_servers - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_action_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_action_end_msg 1 ; return 2 ;; - esac - [ "$VERBOSE" != no ] && log_action_begin_msg "Unloading ${KMOD_NAME} driver" - do_unload_drv - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_action_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_action_end_msg 1 ; return 2 ;; - esac - #log_end_msg $? - ;; - status) - [ "$VERBOSE" != no ] && do_check_drv_status - if [ $? -eq 0 ]; then - [ "$VERBOSE" != no ] && log_success_msg "${KMOD_NAME} driver loaded" - else - [ "$VERBOSE" != no ] && log_failure_msg "${KMOD_NAME} driver *NOT* loaded" - return 2 - fi - [ "$VERBOSE" != no ] && do_check_servers_status - if [ $? -eq 0 ]; then - [ "$VERBOSE" != no ] && log_success_msg "${NAME} servers configured" - else - [ "$VERBOSE" != no ] && log_failure_msg "${NAME} *NO* servers configured" - return 2 - fi - return 0 - ;; - *) - echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 - exit 3 - ;; -esac diff --git a/system-v_init/srb.conf b/system-v_init/srb.conf deleted file mode 100644 index 66a16a0..0000000 --- a/system-v_init/srb.conf +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (C) 2014 SCALITY SA - http://www.scality.com -# -# This file is part of ScalityRestBlock. -# -# ScalityRestBlock is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# ScalityRestBlock is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with ScalityRestBlock. If not, see . -# - -# -# ScalityRestBlock configuration -# - -# -# Kernel module path (if not default) -# -KMOD_PATH="/media/data/scality/ScalityRestBlock" - -# -# Servers list: List of server urls comma separated -# Example: URLS="http://First_Server/Server_Path,http://Second_Server/Server_Path" -URLS="http://192.168.40.134/fdt_test" - -# Module Default configuration - diff --git a/systemd/srb.conf b/systemd/srb.conf deleted file mode 100644 index dc5cc6b..0000000 --- a/systemd/srb.conf +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (C) 2014 SCALITY SA - http://www.scality.com -# -# This file is part of ScalityRestBlock. -# -# ScalityRestBlock is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# ScalityRestBlock is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with ScalityRestBlock. If not, see . -# - -# -# ScalityRestBlock configuration -# - -# -# Kernel module path (if not default) -# -KMOD_PATH=/opt/scality/ScalityRestBlock -KMOD_NAME=srb - -# -# Servers list: List of server urls comma separated -# Example: URLS="http://First_Server/Server_Path,http://Second_Server/Server_Path" -URLS=http://192.168.40.134/fdt_test - -# Module Default configuration diff --git a/systemd/srb.service b/systemd/srb.service deleted file mode 100644 index 97838b4..0000000 --- a/systemd/srb.service +++ /dev/null @@ -1,33 +0,0 @@ -[Unit] -Description=Scality RestBlock Driver -After=syslog.target network.target - -# Check if configuration file exists -ConditionFileNotEmpty=/etc/srb.conf - - -[Service] -Type=oneshot -RemainAfterExit=yes -EnvironmentFile=/etc/srb.conf - -# -# Start -# -ExecStart=/usr/sbin/insmod ${KMOD_PATH}/${KMOD_NAME}.ko -ExecStart=/usr/bin/cp /sys/class/srb/add_urls /tmp/add_urls -ExecStart=/usr/bin/sed -r -e "s,.*,${URLS}," -i /tmp/add_urls -ExecStart=/usr/bin/cp /tmp/add_urls /sys/class/srb/add_urls -ExecStart=/usr/bin/rm -f /tmp/add_urls - -# -# Stop -# -ExecStop=/usr/bin/touch /tmp/add_urls -ExecStop=/usr/bin/cp /tmp/add_urls /sys/class/srb/add_urls -ExecStop=/usr/sbin/rmmod $KMOD_NAME -ExecStop=/usr/bin/rm -f /tmp/add_urls - - -[Install] -WantedBy=multi-user.target