Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 00 of 13 v6] blktap3: Introduce a small subset of blktap3 files
blktap3 is a disk back-end driver. It is based on blktap2 but does not require the blktap/blkback kernel modules as it allows tapdisk to talk directly to blkfront. This primarily simplifies maintenance, and _may_ lead to performance improvements. blktap3 is based on a blktap2 fork maintained mostly by Citrix (it lives in github), so these changes are also imported, apart from the blktap3 ones. I''ve organised my upstream effort as follows: 1. Upstream the smallest possible subset of blktap3 that will allow guest VMs to use RAW images backed by blktap3. This will enable early testing on the bits introduced by blktap3. 2. Upstream the remaining of blktap3, most notably back-end drivers, e.g. VHD etc. 3. Import bug fixes from blktap2 living in github. 4. Import new features and optimisations from blktap2 living in github, e.g. the mirroring plug-in. blktap3 is broken into patches that can be found here: https://bitbucket.org/tmakatos/blktap3-patches blktap3 is made of the following components: 1. blkfront (not a blktap3 component and already upstream): a virtual block device driver in the guest VM that receives block I/O requests and forwards them to tapdisk via the shared ring. 2. tapdisk: a user space process that receives block I/O requests from blkfront, translates them to whatever the current backing file format is (i.e. RAW, VHD, qcow etc.), and performs the actual I/O. Apart from block I/O requests, the tapdisk also allows basic management of each virtual block device, e.g. a device may be temporarily paused. tapdisk listens to a loopback socket for such commands. The tap-ctl utility (explained later) can be used for managing the tapdisk. 3. tapback (formerly known as xenio): a user space daemon that acts as the back-end of each virtual block device: it monitors XenStore for the block front-end''s state changes, creates/destroys the shared ring, spawns the tapdisk if necessary, and instructs the tapdisk to connect to/disconnect from the shared ring. It also communicates to the block front-end required parameters (e.g. block device size in sectors) via XenStore. The tapback daemon is only involved during the set up/tear down of the connection between the two ends, it does not participate in the data path. There is one tapback daemon per back-end driver domain, though we could have a tapback daemon per guest VM or per VBD. 5. libblktapctl: a user space library where the tapdisk management functions are implemented, used by libxl and the tapback daemon. 6. tap-ctl: a user space utility that allows management of the tapdisk, uses libblktapctl. This patch series introduces a small subset of files required by tapback (the tapback daemon is introduced by the next patch series): - basic blktap3 header files - a rudimentary implementation of libblktapctl. Only the bits required by tapback to manage the tapdisk are introduced, the rest of this library will be introduced by later patches. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v1: * In all patches the patch message has been improved. * Patches 1, 5, and 6 use GPLv2. * Patch 0: Basic explanation of blktap3''s fundamental components. * Patch 9: Improved tools/blktap3/control/Makefile by moving hard coded paths to config/StdGNU.mk. Changed since v2: * Updated tapback daemon description. Changed since v3: * Update description of blktap3 architecture. * Introduced additional tap-ctl-* files as a result of the architectural change. Changed since v4: * Remove tap-ctl-attach/detach.
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 01 of 13 v6] blktap3: Introduce blktap3 headers
This patch introduces basic blktap3 header files. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v2: * Use GPL license instead of LGPL in compiler.h. * Removed ARRAY_SIZE macro. * Use libxl_internal.h''s definition of containerof macro. Changed since v4: * Introduce path to tapback''s control socket. diff --git a/tools/blktap3/include/blktap3.h b/tools/blktap3/include/blktap3.h new file mode 100644 --- /dev/null +++ b/tools/blktap3/include/blktap3.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 Citrix Ltd. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * Commonly used headers and definitions. + */ + +#ifndef __BLKTAP_3_H__ +#define __BLKTAP_3_H__ + +#include "compiler.h" + +/* TODO remove from other files */ +#include <xen-external/bsd-sys-queue.h> + +#define BLKTAP3_CONTROL_NAME "blktap-control" +#define BLKTAP3_CONTROL_DIR "/var/run/"BLKTAP3_CONTROL_NAME +#define BLKTAP3_CONTROL_SOCKET "ctl" + +#define BLKTAP3_ENOSPC_SIGNAL_FILE "/var/run/tapdisk3-enospc" + +#define TAPBACK_CTL_SOCK_PATH "/var/run/tapback.sock" + +/* + * TODO They may have to change due to macro namespacing. + */ +#define TAILQ_MOVE_HEAD(node, src, dst, entry) \ + TAILQ_REMOVE(src, node, entry); \ + TAILQ_INSERT_HEAD(dst, node, entry); + +#define TAILQ_MOVE_TAIL(node, src, dst, entry) \ + TAILQ_REMOVE(src, node, entry); \ + TAILQ_INSERT_TAIL(dst, node, entry); + +#endif /* __BLKTAP_3_H__ */ diff --git a/tools/blktap3/include/compiler.h b/tools/blktap3/include/compiler.h new file mode 100644 --- /dev/null +++ b/tools/blktap3/include/compiler.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Citrix Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __COMPILER_H__ +#define __COMPILER_H__ + +#define likely(_cond) __builtin_expect(!!(_cond), 1) +#define unlikely(_cond) __builtin_expect(!!(_cond), 0) + +#define containerof(inner_ptr, outer, member_name) \ + ({ \ + typeof(outer) *container_of_; \ + container_of_ = (void*)((char*)(inner_ptr) - \ + offsetof(typeof(outer), member_name)); \ + (void)(&container_of_->member_name == \ + (typeof(inner_ptr))0) /* type check */; \ + container_of_; \ + }) + +#define __printf(a, b) __attribute__((format(printf, a, b))) +#define __scanf(_f, _a) __attribute__((format (scanf, _f, _a))) + +#define UNUSED_PARAMETER(x) \ + (void)(x); + +#endif /* __COMPILER_H__ */
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 02 of 13 v6] blktap3/libblktapctl: Introduce tapdisk message types and structures
This patch introduces function prototypes and structures that are implemented by libblktapctl (the library that allows libxl, tap-ctl, and the tapback daemon to manage a running tapdisk process). This file is based on the existing blktap2 file, with some changes coming from blktap2.5 (the STATS message, support for mirroring). tapdisk_message_name is now neater and uses a look up table instead of a big switch. blktap3 introduces the following messages: - DISK_INFO: used by the tapback daemon to communicate to blkfront via XenStore the number of sectors and the sector size so that it can create the virtual block device. - XENBLKIF_CONNECT/DISCONNECT: used by the tapback daemon to instruct a running tapdisk process to connect to the ring. The tapdisk_message_blkif structure is used to convey such messages. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v2: * Include TAPDISK_MESSAGE_MAX in the enum. * Updated comment regarding the proto member in struct tapdisk_message blkif. * Rearranged enum tapdisk_message_id in such a way that messages requiring a response belong to a "group". Introduce self-explanatory function tapdisk_message_is_rsp_paired. Changed since v3: * Use the correct name for the back-end daemon in the description of this patch (tapback instead of the obsolete xenio). * Removed erroneous statement in the patch description stating that attach/detach is obsolete. Changed since v4: * Remove the minor numbers from struct tapdisk_message_params and tapdisk_message_list. * Add the VDI type:/path/to/file into struct tapdisk_message_blkif as this is what uniquely identifies a VBD now that the minor number has been removed. * Remove the cookie from struct tapdisk_message as it was used for storing the minor number, which has been removed. * Remove attach/detach messages. diff --git a/tools/blktap2/include/tapdisk-message.h b/tools/blktap3/include/tapdisk-message.h copy from tools/blktap2/include/tapdisk-message.h copy to tools/blktap3/include/tapdisk-message.h --- a/tools/blktap2/include/tapdisk-message.h +++ b/tools/blktap3/include/tapdisk-message.h @@ -36,29 +36,33 @@ #define TAPDISK_MESSAGE_MAX_MINORS \ ((TAPDISK_MESSAGE_MAX_PATH_LENGTH / sizeof(int)) - 1) -#define TAPDISK_MESSAGE_FLAG_SHARED 0x01 -#define TAPDISK_MESSAGE_FLAG_RDONLY 0x02 -#define TAPDISK_MESSAGE_FLAG_ADD_CACHE 0x04 -#define TAPDISK_MESSAGE_FLAG_VHD_INDEX 0x08 -#define TAPDISK_MESSAGE_FLAG_LOG_DIRTY 0x10 +#define TAPDISK_MESSAGE_FLAG_SHARED 0x001 +#define TAPDISK_MESSAGE_FLAG_RDONLY 0x002 +#define TAPDISK_MESSAGE_FLAG_ADD_CACHE 0x004 +#define TAPDISK_MESSAGE_FLAG_VHD_INDEX 0x008 +#define TAPDISK_MESSAGE_FLAG_LOG_DIRTY 0x010 +#define TAPDISK_MESSAGE_FLAG_ADD_LCACHE 0x020 +#define TAPDISK_MESSAGE_FLAG_REUSE_PRT 0x040 +#define TAPDISK_MESSAGE_FLAG_SECONDARY 0x080 +#define TAPDISK_MESSAGE_FLAG_STANDBY 0x100 typedef struct tapdisk_message tapdisk_message_t; -typedef uint8_t tapdisk_message_flag_t; +typedef uint32_t tapdisk_message_flag_t; typedef struct tapdisk_message_image tapdisk_message_image_t; typedef struct tapdisk_message_params tapdisk_message_params_t; typedef struct tapdisk_message_string tapdisk_message_string_t; typedef struct tapdisk_message_response tapdisk_message_response_t; typedef struct tapdisk_message_minors tapdisk_message_minors_t; typedef struct tapdisk_message_list tapdisk_message_list_t; +typedef struct tapdisk_message_stat tapdisk_message_stat_t; +typedef struct tapdisk_message_blkif tapdisk_message_blkif_t; struct tapdisk_message_params { tapdisk_message_flag_t flags; - - uint8_t storage; - uint32_t devnum; uint32_t domid; - uint16_t path_len; char path[TAPDISK_MESSAGE_MAX_PATH_LENGTH]; + char prt_path[TAPDISK_MESSAGE_MAX_PATH_LENGTH]; + char secondary[TAPDISK_MESSAGE_MAX_PATH_LENGTH]; }; struct tapdisk_message_image { @@ -83,14 +87,69 @@ struct tapdisk_message_minors { struct tapdisk_message_list { int count; - int minor; int state; char path[TAPDISK_MESSAGE_MAX_PATH_LENGTH]; }; +struct tapdisk_message_stat { + uint16_t type; + uint16_t cookie; + size_t length; +}; + +/** + * Tapdisk message containing all the necessary information required for the + * tapdisk to connect to a guest''s blkfront. + */ +struct tapdisk_message_blkif { + /** + * The domain ID of the guest to connect to. + */ + uint32_t domid; + + /** + * The device ID of the virtual block device. + */ + uint32_t devid; + + /** + * Grant references for the shared ring. + * TODO Why 8 specifically? + */ + uint32_t gref[8]; + + /** + * Number of pages in the ring, expressed as a page order. + */ + uint32_t order; + + /** + * Protocol to use: native, 32 bit, or 64 bit. Used for supporting a + * 32-bit domU talking to a 64-bit dom0/domU and vice versa. + */ + uint32_t proto; + + /** + * TODO Page pool? Can be NULL. + */ + char pool[TAPDISK_MESSAGE_STRING_LENGTH]; + + /** + * The event channel port. + */ + uint32_t port; + + /** + * type:/path/to/file + */ + char params[TAPDISK_MESSAGE_MAX_PATH_LENGTH]; +}; + struct tapdisk_message { + /** + * TAPDISK_MESSAGE_??? + */ uint16_t type; - uint16_t cookie; union { pid_t tapdisk_pid; @@ -100,16 +159,31 @@ struct tapdisk_message { tapdisk_message_minors_t minors; tapdisk_message_response_t response; tapdisk_message_list_t list; + tapdisk_message_stat_t info; + tapdisk_message_blkif_t blkif; } u; }; -enum tapdisk_message_id { +/** + * Messages that are paired with a response (e.g. TAPDISK_MESSAGE_FOO goes + * hand in hand with message TAPDISK_MESSAGE_FOO_RSP) should be placed within + * a contiguous range in the enum in order to be able to easily identify + * whether a given message requires a response. Also, a message''s response + * must follow the message in the enum so that their values differ by 1. + */ +typedef enum tapdisk_message_id { + /* + * TODO Why start from 1 and not from 0? + */ TAPDISK_MESSAGE_ERROR = 1, TAPDISK_MESSAGE_RUNTIME_ERROR, - TAPDISK_MESSAGE_PID, + + /* + * Begin of messages paired with a response. + */ + TAPDISK_MESSAGE_REQS_RSP_START, /* not an actual message */ + TAPDISK_MESSAGE_PID = TAPDISK_MESSAGE_REQS_RSP_START, TAPDISK_MESSAGE_PID_RSP, - TAPDISK_MESSAGE_ATTACH, - TAPDISK_MESSAGE_ATTACH_RSP, TAPDISK_MESSAGE_OPEN, TAPDISK_MESSAGE_OPEN_RSP, TAPDISK_MESSAGE_PAUSE, @@ -118,86 +192,90 @@ enum tapdisk_message_id { TAPDISK_MESSAGE_RESUME_RSP, TAPDISK_MESSAGE_CLOSE, TAPDISK_MESSAGE_CLOSE_RSP, - TAPDISK_MESSAGE_DETACH, - TAPDISK_MESSAGE_DETACH_RSP, - TAPDISK_MESSAGE_LIST_MINORS, - TAPDISK_MESSAGE_LIST_MINORS_RSP, + TAPDISK_MESSAGE_LIST_MINORS, /* TODO still valid? */ + TAPDISK_MESSAGE_LIST_MINORS_RSP, /* TODO still valid? */ TAPDISK_MESSAGE_LIST, TAPDISK_MESSAGE_LIST_RSP, + TAPDISK_MESSAGE_STATS, + TAPDISK_MESSAGE_STATS_RSP, + TAPDISK_MESSAGE_DISK_INFO, + TAPDISK_MESSAGE_DISK_INFO_RSP, + TAPDISK_MESSAGE_XENBLKIF_CONNECT, + TAPDISK_MESSAGE_XENBLKIF_CONNECT_RSP, + TAPDISK_MESSAGE_XENBLKIF_DISCONNECT, + TAPDISK_MESSAGE_XENBLKIF_DISCONNECT_RSP, + TAPDISK_MESSAGE_REQS_RSP_END = TAPDISK_MESSAGE_XENBLKIF_DISCONNECT_RSP, + /* + * End of messages requiring a response. + */ + TAPDISK_MESSAGE_FORCE_SHUTDOWN, TAPDISK_MESSAGE_EXIT, -}; + TAPDISK_MESSAGE_MAX +} td_msg_id_t; -static inline char * -tapdisk_message_name(enum tapdisk_message_id id) -{ - switch (id) { - case TAPDISK_MESSAGE_ERROR: - return "error"; +/** + * Tells whether a request message is paired with a reply message or vice + * versa. + * + * @param id the message ID + * @returns 1 if the request message is paired with a response (or vice versa), + * 0 otherwise + */ +static inline int tapdisk_message_is_rsp_paired(const td_msg_id_t id) { + return id >= TAPDISK_MESSAGE_REQS_RSP_START + && id <= TAPDISK_MESSAGE_REQS_RSP_END; +} - case TAPDISK_MESSAGE_PID: - return "pid"; +/** + * Retrieves a message''s human-readable representation. + * + * @param id the message ID to translate + * @return the name of the message + * + * @note If the message type is unknown the function simply returns ''unknown'', + * so the information regarding the erroneous message type is lost. We could + * include the number of the message in the returned string but we would then + * have to allocate it, forcing the user to release each string this function + * would return, something that users of this function would probably forget + * to do. + */ +static inline char const * +tapdisk_message_name(const td_msg_id_t id) { + static char const *msg_names[TAPDISK_MESSAGE_MAX] = { + [TAPDISK_MESSAGE_ERROR] = "error", + [TAPDISK_MESSAGE_RUNTIME_ERROR] = "runtime error", + [TAPDISK_MESSAGE_PID] = "pid", + [TAPDISK_MESSAGE_PID_RSP] = "pid response", + [TAPDISK_MESSAGE_OPEN] = "open", + [TAPDISK_MESSAGE_OPEN_RSP] = "open response", + [TAPDISK_MESSAGE_PAUSE] = "pause", + [TAPDISK_MESSAGE_PAUSE_RSP] = "pause response", + [TAPDISK_MESSAGE_RESUME] = "resume", + [TAPDISK_MESSAGE_RESUME_RSP] = "resume response", + [TAPDISK_MESSAGE_CLOSE] = "close", + [TAPDISK_MESSAGE_FORCE_SHUTDOWN] = "force shutdown", + [TAPDISK_MESSAGE_CLOSE_RSP] = "close response", + [TAPDISK_MESSAGE_LIST_MINORS] = "list minors", + [TAPDISK_MESSAGE_LIST_MINORS_RSP] = "list minors response", + [TAPDISK_MESSAGE_LIST] = "list", + [TAPDISK_MESSAGE_LIST_RSP] = "list response", + [TAPDISK_MESSAGE_STATS] = "stats", + [TAPDISK_MESSAGE_STATS_RSP] = "stats response", + [TAPDISK_MESSAGE_DISK_INFO] = "disk info", + [TAPDISK_MESSAGE_DISK_INFO_RSP] = "disk info response", + [TAPDISK_MESSAGE_XENBLKIF_CONNECT] = "blkif connect", + [TAPDISK_MESSAGE_XENBLKIF_CONNECT_RSP] = "blkif connect response", + [TAPDISK_MESSAGE_XENBLKIF_DISCONNECT] = "blkif disconnect", + [TAPDISK_MESSAGE_XENBLKIF_DISCONNECT_RSP] + = "blkif disconnect response", + [TAPDISK_MESSAGE_EXIT] = "exit" + }; - case TAPDISK_MESSAGE_PID_RSP: - return "pid response"; - - case TAPDISK_MESSAGE_OPEN: - return "open"; - - case TAPDISK_MESSAGE_OPEN_RSP: - return "open response"; - - case TAPDISK_MESSAGE_PAUSE: - return "pause"; - - case TAPDISK_MESSAGE_PAUSE_RSP: - return "pause response"; - - case TAPDISK_MESSAGE_RESUME: - return "resume"; - - case TAPDISK_MESSAGE_RESUME_RSP: - return "resume response"; - - case TAPDISK_MESSAGE_CLOSE: - return "close"; - - case TAPDISK_MESSAGE_FORCE_SHUTDOWN: - return "force shutdown"; - - case TAPDISK_MESSAGE_CLOSE_RSP: - return "close response"; - - case TAPDISK_MESSAGE_ATTACH: - return "attach"; - - case TAPDISK_MESSAGE_ATTACH_RSP: - return "attach response"; - - case TAPDISK_MESSAGE_DETACH: - return "detach"; - - case TAPDISK_MESSAGE_DETACH_RSP: - return "detach response"; - - case TAPDISK_MESSAGE_LIST_MINORS: - return "list minors"; - - case TAPDISK_MESSAGE_LIST_MINORS_RSP: - return "list minors response"; - - case TAPDISK_MESSAGE_LIST: - return "list"; - - case TAPDISK_MESSAGE_LIST_RSP: - return "list response"; - - case TAPDISK_MESSAGE_EXIT: - return "exit"; - - default: + if (id < 1 || id >= TAPDISK_MESSAGE_MAX) { return "unknown"; } + return msg_names[id]; } -#endif +#endif /* _TAPDISK_MESSAGE_H_ */
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 03 of 13 v6] blktap3/libblktapctl: Introduce the tapdisk control header
This patch introduces the header file where tapdisk control-related structures and functions are declared. This file is based on the existing blktap2, with most changes coming from blktap2.5. Linux lists are replaced by BSD tail queues. Few functions are partly documented, most of them are not documented at all, this will be addressed by a future patch. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v3: * Include file name and line number on log messages instead of function name. * Updated documentation for tap_ctl_create, tap_ctl_spawn. Changed since v4: * Removed the minor number from struct tap_list. * Replaced the minor number with the /path/to/file or type:/path/to/file in all function declarations. * Moved here declarations of functions tap_ctl_connect_xenblkif and tap_ctl_disconnect_xenblkif. * Made function parse_params a public function. Changed since v5: * Minor documentation improvements. diff --git a/tools/blktap2/control/tap-ctl.h b/tools/blktap3/control/tap-ctl.h copy from tools/blktap2/control/tap-ctl.h copy to tools/blktap3/control/tap-ctl.h --- a/tools/blktap2/control/tap-ctl.h +++ b/tools/blktap3/control/tap-ctl.h @@ -30,72 +30,261 @@ #include <syslog.h> #include <errno.h> +#include <sys/time.h> + +#include <inttypes.h> +#include <xen/xen.h> +#include <xen/grant_table.h> +#include <xen/event_channel.h> + #include <tapdisk-message.h> +#include "blktap3.h" +/* + * TODO These are private, move to an internal header. + */ extern int tap_ctl_debug; #ifdef TAPCTL -#define DBG(_f, _a...) \ - do { \ +#define DBG(_f, _a...) \ + do { \ if (tap_ctl_debug) \ printf(_f, ##_a); \ } while (0) #define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a) -#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a) -#define PERROR(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f ": %s", __func__, ##_a, \ - strerror(errno)) +#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s:%d " _f, __FILE__, \ + __LINE__, ##_a) +#define PERROR(_f, _a...) syslog(LOG_ERR, "tap-err:%s:%d " _f ": %s", \ + __FILE__, __LINE__, ##_a, strerror(errno)) #endif -void tap_ctl_version(int *major, int *minor); -int tap_ctl_kernel_version(int *major, int *minor); +/** + * Contains information about a tapdisk process. + * TODO Or a VBD? If so, make it a union. + */ +typedef struct tap_list { -int tap_ctl_check_blktap(const char **message); -int tap_ctl_check_version(const char **message); -int tap_ctl_check(const char **message); + /** + * The process ID. + */ + pid_t pid; + /** + * State of the VBD, specified in drivers/tapdisk-vbd.h. + */ + int state; + + /** + * TODO + */ + char *type; + + /** + * /path/to/file + */ + char *path; + + /** + * for linked lists + */ + TAILQ_ENTRY(tap_list) entry; +} tap_list_t; + +TAILQ_HEAD(tqh_tap_list, tap_list); + +/** + * Iterate over a list of struct tap_list elements. + */ +#define tap_list_for_each_entry(_pos, _head) \ + TAILQ_FOREACH(_pos, _head, entry) + +/** + * Iterate over a list of struct tap_list elements allowing deletions without + * having to restart the iteration. + */ +#define tap_list_for_each_entry_safe(_pos, _n, _head) \ + TAILQ_FOREACH_SAFE(_pos, _head, entry, _n) + +/** + * Connects to a tapdisk. + * + * @param /path/to/file of the control socket (e.g. + * /var/run/blktap-control/ctl/<pid> + * @param socket output parameter that receives the connection + * @returns 0 on success, an error code otherwise + */ int tap_ctl_connect(const char *path, int *socket); -int tap_ctl_connect_id(int id, int *socket); -int tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout); -int tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout); -int tap_ctl_send_and_receive(int fd, tapdisk_message_t *message, int timeout); -int tap_ctl_connect_send_and_receive(int id, - tapdisk_message_t *message, int timeout); + +/** + * Connects to a tapdisk. + * + * @param id the process ID of the tapdisk to connect to + * @param socket output parameter that receives the connection + * @returns 0 on success, an error code otherwise + */ +int tap_ctl_connect_id(const int id, int *socket); + +/** + * Reads from the tapdisk connection to the buffer. + * + * @param fd the file descriptor of the socket to read from + * @param buf buffer that receives the output + * @param sz size, in bytes, of the buffer + * @param timeout (optional) specifies the maximum time to wait for reading + * @returns 0 on success, an error code otherwise + */ +int tap_ctl_read_raw(const int fd, void *buf, const size_t sz, + struct timeval *timeout); + +int tap_ctl_read_message(int fd, tapdisk_message_t * message, + struct timeval *timeout); + +int tap_ctl_write_message(int fd, tapdisk_message_t * message, + struct timeval *timeout); + +int tap_ctl_send_and_receive(int fd, tapdisk_message_t * message, + struct timeval *timeout); + +int tap_ctl_connect_send_and_receive(int id, tapdisk_message_t * message, + struct timeval *timeout); + char *tap_ctl_socket_name(int id); -typedef struct { - int id; - pid_t pid; - int minor; - int state; - char *type; - char *path; -} tap_list_t; +int tap_ctl_list_pid(pid_t pid, struct tqh_tap_list *list); -int tap_ctl_get_driver_id(const char *handle); +/** + * Retrieves a list of all tapdisks. + * + * @param list output parameter that receives the list of tapdisks + * @returns 0 on success, an error code otherwise + */ +int tap_ctl_list(struct tqh_tap_list *list); -int tap_ctl_list(tap_list_t ***list); -void tap_ctl_free_list(tap_list_t **list); -int tap_ctl_find(const char *type, const char *path, tap_list_t *tap); +/** + * Deallocates a list of struct tap_list. + * + * @param list the tapdisk information structure to deallocate. + */ +void tap_ctl_list_free(struct tqh_tap_list *list); -int tap_ctl_allocate(int *minor, char **devname); -int tap_ctl_free(const int minor); +/** + * Creates a tapdisk process. + * + * TODO document parameters + * @param params type:/path/to/file + * @param flags + * @param prt_path parent /path/to/file (optional) + * @param secondary + * @returns 0 on success, an negative error code otherwise + */ +int tap_ctl_create(const char *params, int flags, const char * prt_path, + char *secondary); -int tap_ctl_create(const char *params, char **devname); -int tap_ctl_destroy(const int id, const int minor); - +/* + * TODO The following functions are not currently used by anything else + * other than the tapdisk itself. Move to a private header? + * + * @returns A positive integer on success, which the process ID of the tapdisk. + * Otherwise, a negative error code. + */ int tap_ctl_spawn(void); pid_t tap_ctl_get_pid(const int id); -int tap_ctl_attach(const int id, const int minor); -int tap_ctl_detach(const int id, const int minor); +/** + * @param pid the process ID of the tapdisk + * @param params type:/path/to/file + * @param prt_path parent /path/to/file (optional) + * @returns 0 on success, a (positive) error code otherwise + */ +int tap_ctl_open(const int pid, const char *params, + int flags, const char * prt_path, const char *secondary); -int tap_ctl_open(const int id, const int minor, const char *params); -int tap_ctl_close(const int id, const int minor, const int force); +/** + * Closes the image. + * + * @param id the tapdisk process ID + * @param type:/path/to/file + */ +int tap_ctl_close(const int id, const char *params, const int force, + struct timeval *timeout); +int tap_ctl_destroy(const int id, const char *params, int force, + struct timeval *timeout); -int tap_ctl_pause(const int id, const int minor); -int tap_ctl_unpause(const int id, const int minor, const char *params); +/** + * Pauses the VBD. + */ +int tap_ctl_pause(const int id, const char * params, struct timeval + *timeout); +/** + * Unpauses the VBD + */ +int tap_ctl_unpause(const int id, const char * params); -int tap_ctl_blk_major(void); +ssize_t tap_ctl_stats(pid_t pid, const char * params, char *buf, size_t size); +int tap_ctl_stats_fwrite(pid_t pid, const char * params, FILE * out); -#endif +/** + * Retrieves virtual disk information from a tapdisk. + * + * @pid the process ID of the tapdisk process + * @params type:/path/to/file + * @sectors output parameter that receives the number of sectors + * @sector_size output parameter that receives the size of the sector + * @info TODO ? + * + */ +int tap_ctl_info(pid_t pid, const char *params, unsigned long long *sectors, + unsigned int *sector_size, unsigned int *info); + +/** + * Instructs a tapdisk to connect to the shared ring. + * + * @param pid the process ID of the tapdisk that should connect to the shared + * ring + * @param path /path/to/vdi + * @param domid the domain ID of the guest VM + * @param devid the device ID + * @param grefs the grant references + * @param order number of grant references, expressed as a 2''s order + * @param port event channel port + * @param proto the protocol: native (XENIO_BLKIF_PROTO_NATIVE), + * x86 (XENIO_BLKIF_PROTO_X86_32), or x64 (XENIO_BLKIF_PROTO_X86_64) + * @param pool a string used as an identifier to group two or more VBDs + * beloning to the same tapdisk process. For VBDs with the same pool name, a + * single event channel is used. + * @returns 0 on success, a negative error code otherwise + */ +int +tap_ctl_connect_xenblkif(const pid_t pid, const char *path, + const domid_t domid, const int devid, const grant_ref_t * grefs, + const int order, const evtchn_port_t port, int proto, + const char *pool); + +/** + * Instructs a tapdisk to disconnect from the shared ring. + * + * @param pid process ID of the tapdisk + * @param domid the ID of the guest VM + * @param devid the device ID of the virtual block device + * @param timeout timeout to wait, if NULL the function will wait indefinitely + * @returns 0 on success, a negative error code otherwise + */ +int +tap_ctl_disconnect_xenblkif(const pid_t pid, const domid_t domid, + const int devid, struct timeval *timeout); + +/** + * Parses a type:/path/to/file string, storing the type and path to the output + * parameters. Upon successful completion the caller must free @type and @path, + * otherwise their values are undefined. + * + * @param params type:/path/to/file to parse + * @param type output parameter the receives the type + * @param path output paramter that receives the path + * @returns 0 on success + */ +int +parse_params(const char *params, char **type, char **path); + +#endif /* __TAP_CTL_H__ */
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 04 of 13 v6] blktap3/libblktapctl: Introduce listing running tapdisks functionality
This patch introduces tap-ctl-list.c, the file where listing tapdisks functionality is implemented. It is based on the existing blktap2 file with most changes coming from blktap2.5. I have not examined the changes in detail but it seems they are minor. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v4: * Removed minor number. * Removed the message cookie from function _tap_ctl_find_tapdisks. * Removed the three-way merge between tapdisks, VBDs, and minor numbers from function _tap_ctl_find_tapdisks. diff --git a/tools/blktap3/control/tap-ctl-list.c b/tools/blktap3/control/tap-ctl-list.c new file mode 100644 --- /dev/null +++ b/tools/blktap3/control/tap-ctl-list.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <glob.h> + +#include "tap-ctl.h" +#include "blktap3.h" + +/** + * Allocates and initializes a tap_list_t. + */ +static tap_list_t * +_tap_list_alloc(void) +{ + const size_t sz = sizeof(tap_list_t); + tap_list_t *tl; + + tl = malloc(sz); + if (!tl) + return NULL; + + tl->pid = -1; + tl->state = -1; + tl->type = NULL; + tl->path = NULL; + + return tl; +} + +static void +_tap_list_free(tap_list_t * tl, struct tqh_tap_list *list) +{ + if (tl->type) { + free(tl->type); + tl->type = NULL; + } + + if (tl->path) { + free(tl->path); + tl->path = NULL; + } + + if (list) + TAILQ_REMOVE(list, tl, entry); + + free(tl); +} + +int +parse_params(const char *params, char **type, char **path) +{ + char *ptr; + size_t len; + + ptr = strchr(params, '':''); + if (!ptr) + return -EINVAL; + + len = ptr - params; + + *type = strndup(params, len); + *path = strdup(params + len + 1); + + if (!*type || !*path) { + free(*type); + *type = NULL; + + free(*path); + *path = NULL; + + return -errno; + } + + return 0; +} + +void +tap_ctl_list_free(struct tqh_tap_list *list) +{ + tap_list_t *tl, *n; + + tap_list_for_each_entry_safe(tl, n, list) + _tap_list_free(tl, list); +} + +/** + * Returns a list running tapdisks. tapdisks are searched for by looking for + * their control socket. + */ +static int +_tap_ctl_find_tapdisks(struct tqh_tap_list *list) +{ + glob_t glbuf = { 0 }; + const char *pattern, *format; + int err, i, n_taps = 0; + + pattern = BLKTAP3_CONTROL_DIR "/" BLKTAP3_CONTROL_SOCKET "*"; + format = BLKTAP3_CONTROL_DIR "/" BLKTAP3_CONTROL_SOCKET "%d"; + + TAILQ_INIT(list); + + err = glob(pattern, 0, NULL, &glbuf); + switch (err) { + case GLOB_NOMATCH: + goto done; + + case GLOB_ABORTED: + case GLOB_NOSPACE: + err = -errno; + EPRINTF("%s: glob failed: %s", pattern, strerror(err)); + goto fail; + } + + for (i = 0; i < glbuf.gl_pathc; ++i) { + tap_list_t *tl; + int n; + + tl = _tap_list_alloc(); + if (!tl) { + err = -ENOMEM; + goto fail; + } + + n = sscanf(glbuf.gl_pathv[i], format, &tl->pid); + if (n != 1) + goto skip; + + tl->pid = tap_ctl_get_pid(tl->pid); + if (tl->pid < 0) + goto skip; + + TAILQ_INSERT_TAIL(list, tl, entry); + n_taps++; + continue; + +skip: + _tap_list_free(tl, NULL); + } + +done: + err = 0; +out: + if (glbuf.gl_pathv) + globfree(&glbuf); + + return err ? : n_taps; + +fail: + tap_ctl_list_free(list); + goto out; +} + +/** + * Retrieves all the VBDs a tapdisk is serving. + * + * @param pid the process ID of the tapdisk whose VBDs should be retrieved + * @param list output parameter that receives the list of VBD + * @returns 0 on success, an error code otherwise + */ +static int +_tap_ctl_list_tapdisk(pid_t pid, struct tqh_tap_list *list) +{ + struct timeval timeout = {.tv_sec = 10,.tv_usec = 0 }; + tapdisk_message_t message; + tap_list_t *tl; + int err, sfd; + + err = tap_ctl_connect_id(pid, &sfd); + if (err) + return err; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_LIST; + + err = tap_ctl_write_message(sfd, &message, &timeout); + if (err) + return err; + + TAILQ_INIT(list); + + do { + err = tap_ctl_read_message(sfd, &message, &timeout); + if (err) { + err = -EPROTO; + goto fail; + } + + if (message.u.list.count == 0) + break; + + tl = _tap_list_alloc(); + if (!tl) { + err = -ENOMEM; + goto fail; + } + + tl->pid = pid; + tl->state = message.u.list.state; + + if (message.u.list.path[0] != 0) { + err = parse_params(message.u.list.path, &tl->type, &tl->path); + if (err) { + _tap_list_free(tl, NULL); + goto fail; + } + } + + TAILQ_INSERT_HEAD(list, tl, entry); + } while (1); + + err = 0; +out: + close(sfd); + return 0; + +fail: + tap_ctl_list_free(list); + goto out; +} + +int +tap_ctl_list(struct tqh_tap_list *list) +{ + struct tqh_tap_list tapdisks; + tap_list_t *tapdisk, *next_t; + int err; + + TAILQ_INIT(list); + + err = _tap_ctl_find_tapdisks(&tapdisks); + if (err < 0) { + EPRINTF("error finding tapdisks: %s\n", strerror(-err)); + goto out; + } + + tap_list_for_each_entry_safe(tapdisk, next_t, &tapdisks) { + struct tqh_tap_list vbds; + + err = _tap_ctl_list_tapdisk(tapdisk->pid, &vbds); + + if (!err) { + TAILQ_CONCAT(list, &vbds, entry); + } else { + EPRINTF("failed to get VBDs for tapdisk %d: %s\n", tapdisk->pid, + strerror(-err)); + /* TODO Return the error or just continue? */ + } + + _tap_list_free(tapdisk, &tapdisks); + } + +out: + tap_ctl_list_free(&tapdisks); + if (err) + tap_ctl_list_free(list); + return err; +} + +int +tap_ctl_list_pid(pid_t pid, struct tqh_tap_list *list) +{ + tap_list_t *t; + int err; + + t = _tap_list_alloc(); + if (!t) + return -ENOMEM; + + t->pid = tap_ctl_get_pid(pid); + if (t->pid < 0) { + _tap_list_free(t, NULL); + return 0; + } + + err = _tap_ctl_list_tapdisk(t->pid, list); + + if (err || TAILQ_EMPTY(list)) + TAILQ_INSERT_TAIL(list, t, entry); + + return 0; +}
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 05 of 13 v6] blktap3/libblktapctl: Introduce functionality used by tapback to instruct tapdisk to connect to the sring
This patch introduces functions tap_ctl_connect_xenblkif and tap_ctl_disconnect_xenblkif, that are used by the tapback daemon to instruct a running tapdisk process to connect to/disconnect from the shared ring. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v2: * Simplified error-checking after calling tap_ctl_connect_send_and_receive. Changed since v3: * Removed trailing whitespace in license. * Updated documentation regarding the pool parameter in tap_ctl_connect_xenblkif. * Use more const in the arguments of tap_ctl_connect_xenblkif and of tap_ctl_disconnect_xenblkif. Changed since v4: * Move definitions of functions tap_ctl_connect_xenblkif and tap_ctl_disconnect_xenblkif to tap-ctl.h. * Remove the minor number from tap_ctl_connect_xenblkif and tap_ctl_disconnect_xenblkif. diff --git a/tools/blktap3/control/tap-ctl-xen.c b/tools/blktap3/control/tap-ctl-xen.c new file mode 100644 --- /dev/null +++ b/tools/blktap3/control/tap-ctl-xen.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2012 Citrix Ltd. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include <stdio.h> +#include <string.h> + +#include "tap-ctl.h" + +int +tap_ctl_connect_xenblkif(const pid_t pid, const char *params, + const domid_t domid, const int devid, const grant_ref_t * grefs, + const int order, const evtchn_port_t port, int proto, const char *pool) +{ + tapdisk_message_t message; + int i, err; + + if (!params) + return -EINVAL; + if (strnlen(params, TAPDISK_MESSAGE_STRING_LENGTH) + >= TAPDISK_MESSAGE_STRING_LENGTH) + return -ENAMETOOLONG; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_XENBLKIF_CONNECT; + strcpy(message.u.blkif.params, params); + + message.u.blkif.domid = domid; + message.u.blkif.devid = devid; + for (i = 0; i < 1 << order; i++) + message.u.blkif.gref[i] = grefs[i]; + message.u.blkif.order = order; + message.u.blkif.port = port; + message.u.blkif.proto = proto; + if (pool) + strncpy(message.u.blkif.pool, pool, sizeof(message.u.blkif.pool)); + else + message.u.blkif.pool[0] = 0; + + err = tap_ctl_connect_send_and_receive(pid, &message, NULL); + if (err) + /* + * TODO include more info + */ + EPRINTF("failed to connect tapdisk %d to the ring: %s\n", pid, + strerror(-err)); + return err; +} + +int +tap_ctl_disconnect_xenblkif(const pid_t pid, const domid_t domid, + const int devid, struct timeval *timeout) +{ + tapdisk_message_t message; + int err; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_XENBLKIF_DISCONNECT; + message.u.blkif.domid = domid; + message.u.blkif.devid = devid; + + err = tap_ctl_connect_send_and_receive(pid, &message, timeout); + if (err) + /* + * TODO include more info + */ + EPRINTF("failed to disconnect tapdisk %d from the ring: %s\n", pid, + strerror(-err)); + + return err; +}
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 06 of 13 v6] blktap3/libblktapctl: Introduce block device control information retrieval functionality
This patch introduces function tap_ctl_info. It is used by the tapback daemon to retrieve the size of the block device, as well as the sector size, in order to communicate it to blkfront so that it can create the virtual block device. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v2: * Simplified error checking after calling tap_ctl_connect_send_and_receive. Changed since v4: * Remove the minor number and replace it with type:/path/to/file. * Remove tap-ctl-info.h and move the definitions into tap-ctl.h. diff --git a/tools/blktap3/control/tap-ctl-info.c b/tools/blktap3/control/tap-ctl-info.c new file mode 100644 --- /dev/null +++ b/tools/blktap3/control/tap-ctl-info.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 Citrix Ltd. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "tap-ctl.h" + +int tap_ctl_info(pid_t pid, const char *path, unsigned long long *sectors, + unsigned int *sector_size, unsigned int *info) +{ + tapdisk_message_t message; + int err; + + assert(sectors); + assert(sector_size); + assert(info); + + if (!path) + return EINVAL; + if (strnlen(path, TAPDISK_MESSAGE_STRING_LENGTH) + >= TAPDISK_MESSAGE_STRING_LENGTH) + return ENAMETOOLONG; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_DISK_INFO; + strcpy(message.u.string.text, path); + + err = tap_ctl_connect_send_and_receive(pid, &message, NULL); + if (err) { + EPRINTF("failed to get info from tapdisk %d: %s\n", pid, + strerror(err)); + return err; + } + + if (TAPDISK_MESSAGE_DISK_INFO_RSP == message.type) { + *sectors = message.u.image.sectors; + *sector_size = message.u.image.sector_size; + *info = message.u.image.info; + return 0; + } else if (TAPDISK_MESSAGE_ERROR == message.type) { + return message.u.response.error; + } else { + EPRINTF("unexpected reply %d\n", message.type); + return -EINVAL; + } +}
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 07 of 13 v6] blktap3/libblktapctl: Introduce tapdisk message exchange functionality
This patch introduces file conrol/tap-ctl-ipc.c, where the functionality of talking to a tapdisk process is implemented. This file is imported from the existing blktap2 implementation, with most changes coming from blktap2.5. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v2: * Check for unexpected response in tap_ctl_send_and_receive. * If the message has been served but an error occurred, the error in the message is returned by the function in order to simplify error checking/handling by the caller. Changed since v3: * Removed wrong way of checking for errors in order to provide more verbose logging, as not all messages contain an error field. Changed since v4: * Removed printing the message cookie in debug messages. diff --git a/tools/blktap2/control/tap-ctl-ipc.c b/tools/blktap3/control/tap-ctl-ipc.c copy from tools/blktap2/control/tap-ctl-ipc.c copy to tools/blktap3/control/tap-ctl-ipc.c --- a/tools/blktap2/control/tap-ctl-ipc.c +++ b/tools/blktap3/control/tap-ctl-ipc.c @@ -30,47 +30,37 @@ #include <unistd.h> #include <stdlib.h> #include <string.h> +#include <fcntl.h> #include <sys/un.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/socket.h> +#include <assert.h> #include "tap-ctl.h" -#include "blktap2.h" +#include "blktap3.h" int tap_ctl_debug = 0; int -tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout) +tap_ctl_read_raw(int fd, void *buf, size_t size, struct timeval *timeout) { fd_set readfds; - int ret, len, offset; - struct timeval tv, *t; + size_t offset = 0; + int ret; - t = NULL; - offset = 0; - len = sizeof(tapdisk_message_t); - - if (timeout) { - tv.tv_sec = timeout; - tv.tv_usec = 0; - t = &tv; - } - - memset(message, 0, sizeof(tapdisk_message_t)); - - while (offset < len) { + while (offset < size) { FD_ZERO(&readfds); FD_SET(fd, &readfds); - ret = select(fd + 1, &readfds, NULL, NULL, t); + ret = select(fd + 1, &readfds, NULL, NULL, timeout); if (ret == -1) { if (errno == EINTR) continue; break; } else if (FD_ISSET(fd, &readfds)) { - ret = read(fd, message + offset, len - offset); + ret = read(fd, buf + offset, size - offset); if (ret <= 0) { if (errno == EINTR) continue; @@ -81,36 +71,26 @@ tap_ctl_read_message(int fd, tapdisk_mes break; } - if (offset != len) { - EPRINTF("failure reading message\n"); + if (offset != size) { + EPRINTF("failure reading data %zd/%zd\n", offset, size); return -EIO; } - DBG("received ''%s'' message (uuid = %u)\n", - tapdisk_message_name(message->type), message->cookie); - return 0; } int -tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout) +tap_ctl_write_message(int fd, tapdisk_message_t * message, + struct timeval *timeout) { fd_set writefds; int ret, len, offset; - struct timeval tv, *t; - t = NULL; offset = 0; len = sizeof(tapdisk_message_t); - if (timeout) { - tv.tv_sec = timeout; - tv.tv_usec = 0; - t = &tv; - } - - DBG("sending ''%s'' message (uuid = %u)\n", - tapdisk_message_name(message->type), message->cookie); + DBG("sending ''%s'' message\n", + tapdisk_message_name(message->type)); while (offset < len) { FD_ZERO(&writefds); @@ -119,7 +99,7 @@ tap_ctl_write_message(int fd, tapdisk_me /* we don''t bother reinitializing tv. at worst, it will wait a * bit more time than expected. */ - ret = select(fd + 1, NULL, &writefds, NULL, t); + ret = select(fd + 1, NULL, &writefds, NULL, timeout); if (ret == -1) { if (errno == EINTR) continue; @@ -146,9 +126,15 @@ tap_ctl_write_message(int fd, tapdisk_me } int -tap_ctl_send_and_receive(int sfd, tapdisk_message_t *message, int timeout) +tap_ctl_send_and_receive(const int sfd, tapdisk_message_t * const message, + struct timeval *timeout) { int err; + td_msg_id_t msg_type; + + assert(message); + + msg_type = message->type; err = tap_ctl_write_message(sfd, message, timeout); if (err) { @@ -159,12 +145,27 @@ tap_ctl_send_and_receive(int sfd, tapdis err = tap_ctl_read_message(sfd, message, timeout); if (err) { + /* + * TODO If there are messages for which a response is not required + * and failure to receive a reply is expected, this print is bogus. + */ EPRINTF("failed to receive ''%s'' message\n", tapdisk_message_name(message->type)); return err; } - return 0; + if (tapdisk_message_is_rsp_paired(msg_type)) { + if (message->type - msg_type != 1) { + err = EINVAL; + EPRINTF("invalid response ''%s'' to message ''%s''\n", + tapdisk_message_name(message->type), + tapdisk_message_name(msg_type)); + } + else + err = 0; + } + + return err; } char * @@ -173,7 +174,7 @@ tap_ctl_socket_name(int id) char *name; if (asprintf(&name, "%s/%s%d", - BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, id) == -1) + BLKTAP3_CONTROL_DIR, BLKTAP3_CONTROL_SOCKET, id) == -1) return NULL; return name; @@ -234,7 +235,8 @@ tap_ctl_connect_id(int id, int *sfd) } int -tap_ctl_connect_send_and_receive(int id, tapdisk_message_t *message, int timeout) +tap_ctl_connect_send_and_receive(int id, tapdisk_message_t * message, + struct timeval *timeout) { int err, sfd; @@ -247,3 +249,19 @@ tap_ctl_connect_send_and_receive(int id, close(sfd); return err; } + +int +tap_ctl_read_message(int fd, tapdisk_message_t * message, + struct timeval *timeout) +{ + size_t size = sizeof(tapdisk_message_t); + int err; + + err = tap_ctl_read_raw(fd, message, size, timeout); + if (err) + return err; + + DBG("received ''%s'' message\n", tapdisk_message_name(message->type)); + + return 0; +}
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 08 of 13 v6] blktap3/libblktapctl: Introduce tapdisk spawn functionality
This patch imports file control/tap-ctl-spawn.c from the existing blktap2 implementation, with most changes coming from blktap2.5. Function tap-ctl-spawn is used for spawning a new tapdisk process in order to serve a new virtual block device. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v2: * Use "tapdisk3" instead of "tapdisk2" in getenv and printf''s. * Define tapdisk binary name and tapdisk binary location inside the source file as it doesn''t need to be configurable. Changed since v3: * Don''t specify the path to the tapdisk binary, just use whatever is available in $PATH. * Print error message instead of error code in tap_ctl_wait. Changed since v4: * Explicitly spawn tapdisk3 processes instead of tapdisk ones. diff --git a/tools/blktap2/control/tap-ctl-spawn.c b/tools/blktap3/control/tap-ctl-spawn.c copy from tools/blktap2/control/tap-ctl-spawn.c copy to tools/blktap3/control/tap-ctl-spawn.c --- a/tools/blktap2/control/tap-ctl-spawn.c +++ b/tools/blktap3/control/tap-ctl-spawn.c @@ -31,15 +31,18 @@ #include <unistd.h> #include <stdlib.h> #include <string.h> +#include <signal.h> #include <sys/wait.h> #include "tap-ctl.h" -#include "blktap2.h" +#include "blktap3.h" + +#define TAPDISK_EXEC "tapdisk3" static pid_t __tap_ctl_spawn(int *readfd) { - int err, child, channel[2]; + int child, channel[2]; char *tapdisk; if (pipe(channel)) { @@ -71,14 +74,17 @@ static pid_t close(channel[0]); close(channel[1]); - tapdisk = getenv("TAPDISK2"); + tapdisk = getenv("TAPDISK"); if (!tapdisk) - tapdisk = "tapdisk2"; + tapdisk = getenv("TAPDISK3"); - execlp(tapdisk, tapdisk, NULL); + if (tapdisk) { + execlp(tapdisk, tapdisk, NULL); + exit(errno); + } - EPRINTF("exec failed\n"); - exit(1); + execlp(TAPDISK_EXEC, TAPDISK_EXEC, NULL); + exit(errno); } pid_t @@ -90,7 +96,7 @@ tap_ctl_get_pid(const int id) memset(&message, 0, sizeof(message)); message.type = TAPDISK_MESSAGE_PID; - err = tap_ctl_connect_send_and_receive(id, &message, 2); + err = tap_ctl_connect_send_and_receive(id, &message, NULL); if (err) return err; @@ -105,24 +111,30 @@ tap_ctl_wait(pid_t child) pid = waitpid(child, &status, 0); if (pid < 0) { - EPRINTF("wait(%d) failed, err %d\n", child, errno); + EPRINTF("wait(%d) failed: %s\n", child, strerror(errno)); return -errno; } if (WIFEXITED(status)) { int code = WEXITSTATUS(status); if (code) - EPRINTF("tapdisk2[%d] failed, status %d\n", child, code); + EPRINTF("tapdisk3[%d] failed: %s\n", child, strerror(code)); return -code; } if (WIFSIGNALED(status)) { int signo = WTERMSIG(status); - EPRINTF("tapdisk2[%d] killed by signal %d\n", child, signo); + EPRINTF("tapdisk3[%d] killed by signal %d\n", child, signo); + if (signo == SIGUSR1) + /* NB. there''s a race between tapdisk''s + * sigaction init and xen-bugtool shooting + * debug signals. If killed by something as + * innocuous as USR1, then retry. */ + return -EAGAIN; return -EINTR; } - EPRINTF("tapdisk2[%d]: unexpected status %#x\n", child, status); + EPRINTF("tapdisk3[%d]: unexpected status %#x\n", child, status); return -EAGAIN; } @@ -139,8 +151,8 @@ tap_ctl_get_child_id(int readfd) } errno = 0; - if (fscanf(f, BLKTAP2_CONTROL_DIR"/" - BLKTAP2_CONTROL_SOCKET"%d", &id) != 1) { + if (fscanf(f, BLKTAP3_CONTROL_DIR "/" + BLKTAP3_CONTROL_SOCKET "%d", &id) != 1) { errno = (errno ? : EINVAL); EPRINTF("parsing id failed: %d\n", errno); id = -1; @@ -158,13 +170,17 @@ tap_ctl_spawn(void) readfd = -1; + again: child = __tap_ctl_spawn(&readfd); if (child < 0) return child; err = tap_ctl_wait(child); - if (err) + if (err) { + if (err == -EAGAIN) + goto again; return err; + } id = tap_ctl_get_child_id(readfd); if (id < 0)
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 09 of 13 v6] blktap3/libblktapctl: Introduce tap-ctl-open
The tapback daemon needs to tell the tapdisk which file to open. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v3: * Introduced patch in patch series. Changed since v4: * Use the type:/path/to/file instead of the minor number. diff --git a/tools/blktap3/control/tap-ctl-open.c b/tools/blktap3/control/tap-ctl-open.c new file mode 100644 --- /dev/null +++ b/tools/blktap3/control/tap-ctl-open.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <getopt.h> + +#include "tap-ctl.h" + +int +tap_ctl_open(const int pid, const char *params, int flags, + const char * prt_path, const char *secondary) +{ + int err; + tapdisk_message_t message; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_OPEN; + if (prt_path) { + if (strnlen(prt_path, TAPDISK_MESSAGE_OPEN) == TAPDISK_MESSAGE_OPEN) + return -ENAMETOOLONG; + strcpy(message.u.params.prt_path, prt_path); + } + + message.u.params.flags = flags; + + err = snprintf(message.u.params.path, + sizeof(message.u.params.path) - 1, "%s", params); + if (err >= sizeof(message.u.params.path)) { + EPRINTF("name too long\n"); + return -ENAMETOOLONG; + } + + if (secondary) { + err = snprintf(message.u.params.secondary, + sizeof(message.u.params.secondary) - 1, "%s", + secondary); + if (err >= sizeof(message.u.params.secondary)) { + EPRINTF("secondary image name too long\n"); + return -ENAMETOOLONG; + } + } + + err = tap_ctl_connect_send_and_receive(pid, &message, NULL); + if (err) + return err; + + switch (message.type) { + case TAPDISK_MESSAGE_OPEN_RSP: + break; + case TAPDISK_MESSAGE_ERROR: + err = -message.u.response.error; + EPRINTF("open failed: %s\n", strerror(err)); + break; + default: + EPRINTF("got unexpected result ''%s'' from %d\n", + tapdisk_message_name(message.type), pid); + err = -EINVAL; + } + + return err; +}
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 10 of 13 v6] blktap3/libblktapctl: Introduce tap-ctl-create
Function tap_ctl_create spawns, attaches, and opens the tapdisk in one go instead of having to call tap_ctl_spawn, tap_ctl_attach, and tap_ctl_open. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v3: * Introduced patch in patch series. Changed since v4: * Remove the minor number and replace it with type:/path/to/file. * Remove call to tap_ctl_detach in the error handling path. diff --git a/tools/blktap3/control/tap-ctl-create.c b/tools/blktap3/control/tap-ctl-create.c new file mode 100644 --- /dev/null +++ b/tools/blktap3/control/tap-ctl-create.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <getopt.h> +#include <string.h> + +#include "tap-ctl.h" +#include "blktap3.h" + +int +tap_ctl_create(const char *params, int flags, const char * prt_path, + char *secondary) +{ + int err, id; + + id = tap_ctl_spawn(); + if (id < 0) { + EPRINTF("error spawning tapdisk: %s", strerror(id)); + return id; + } + + err = tap_ctl_open(id, params, flags, prt_path, secondary); + if (err) { + EPRINTF("error opening tapdisk: %s", strerror(err)); + /* FIXME must kill tapdisk */ + } + + return err; +}
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 11 of 13 v6] blktap3/libblktapctl: Introduce tap-ctl-close
Sends a message to a tapdisk process to close the file used to back the VBD. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v3: * Introduced patch in patch series. Changed since v4: * Remove the minor number and replace it with the type:/path/to/file. * Return errors as negative numbers. diff --git a/tools/blktap3/control/tap-ctl-close.c b/tools/blktap3/control/tap-ctl-close.c new file mode 100644 --- /dev/null +++ b/tools/blktap3/control/tap-ctl-close.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <getopt.h> + +#include "tap-ctl.h" + +int +tap_ctl_close(const int id, const char *params, const int force, + struct timeval *timeout) +{ + int err; + tapdisk_message_t message; + + if (!params) + return -EINVAL; + if (strnlen(params, TAPDISK_MESSAGE_STRING_LENGTH) + >= TAPDISK_MESSAGE_STRING_LENGTH) + return -ENAMETOOLONG; + + memset(&message, 0, sizeof(message)); + message.type = TAPDISK_MESSAGE_CLOSE; + if (force) + message.type = TAPDISK_MESSAGE_FORCE_SHUTDOWN; + + strcpy(message.u.string.text, params); + + err = tap_ctl_connect_send_and_receive(id, &message, timeout); + if (err) + return err; + + if (message.type == TAPDISK_MESSAGE_CLOSE_RSP) { + err = message.u.response.error; + if (err) + EPRINTF("close failed: %s\n", strerror(err)); + } else { + EPRINTF("got unexpected result ''%s'' from %d\n", + tapdisk_message_name(message.type), id); + err = -EINVAL; + } + + return err; +}
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 12 of 13 v6] blktap3: Introduce tap-ctl-destroy
Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v4: * Remove call to tap_ctl_destroy. diff --git a/tools/blktap3/control/tap-ctl-destroy.c b/tools/blktap3/control/tap-ctl-destroy.c new file mode 100644 --- /dev/null +++ b/tools/blktap3/control/tap-ctl-destroy.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 Citrix Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2.1 only. with the special + * exception on linking described in file LICENSE. + * + * 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 Lesser General Public License for more details. + */ + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <getopt.h> +#include <string.h> + +#include "tap-ctl.h" +#include "blktap3.h" + +/* TODO Without VBD.detach, tap-ctl destroy is the same as tap-ctl close, + * merge them. */ +int +tap_ctl_destroy(const int id, const char *params, + int force __attribute__((unused)), struct timeval *timeout) +{ + int err; + + if (!params) + return -EINVAL; + + err = tap_ctl_close(id, params, 0, timeout); + if (err) { + EPRINTF("failed to close tapdisk pid=%d, path=%s: %s\n", id, params, + strerror(-err)); + return err; + } + + return 0; +}
Thanos Makatos
2013-Jul-15 11:37 UTC
[PATCH 13 of 13 v6] blktap3/libblktapctl: Introduce makefile that builds tapback-required libblktapctl functionality
This patch imports control/Makefile from the existing blktap2 implementation, building only the libblktapctl functionality required by the tapback daemon. The rest of the binaries/functionality will be introduced by a later patch. Signed-off-by: Thanos Makatos <thanos.makatos@citrix.com> --- Changed since v2: * Ignore auto-generated file _paths.h. * Remove TAPDISK_EXEC and TAPDISK_EXECDIR from the configuration system as they don''t have to be configurable. Changed since v3: * Compile tap_ctl_open, tap_ctl_close, tap_ctl_create, tap_ctl_destroy, tap_ctl_attach, and tap_ctl_detach into libblktapctl as they''re now needed by the tapback daemon. * No need to generate header files indicating where the tapdisk lives, since tap_ctl_spawn now relies on $PATH. Changed since v4: * Install libblktapctl under a different name to avoid conflicts with the blktap2 one. * Remove tap-ctl-attach/detach from the compilation. diff --git a/tools/blktap2/control/Makefile b/tools/blktap3/control/Makefile copy from tools/blktap2/control/Makefile copy to tools/blktap3/control/Makefile --- a/tools/blktap2/control/Makefile +++ b/tools/blktap3/control/Makefile @@ -1,77 +1,64 @@ XEN_ROOT := $(CURDIR)/../../../ include $(XEN_ROOT)/tools/Rules.mk -MAJOR = 1.0 +MAJOR = 3 MINOR = 0 LIBNAME = libblktapctl -LIBSONAME = $(LIBNAME).so.$(MAJOR) -IBIN = tap-ctl +override CFLAGS += \ + -I../include \ + -DTAPDISK_BUILDDIR=''"../drivers"'' \ + $(CFLAGS_xeninclude) \ + $(CFLAGS_libxenctrl) \ + -D_GNU_SOURCE \ + -DTAPCTL \ + -Wall \ + -Wextra \ + -Werror -CFLAGS += -Werror -CFLAGS += -Wno-unused -CFLAGS += -I../include -I../drivers -CFLAGS += $(CFLAGS_xeninclude) -CFLAGS += $(CFLAGS_libxenctrl) -CFLAGS += -D_GNU_SOURCE -CFLAGS += -DTAPCTL +# FIXME cause trouble +override CFLAGS += \ + -Wno-type-limits \ + -Wno-missing-field-initializers \ + -Wno-sign-compare -CTL_OBJS := tap-ctl-ipc.o CTL_OBJS += tap-ctl-list.o -CTL_OBJS += tap-ctl-allocate.o -CTL_OBJS += tap-ctl-free.o +CTL_OBJS += tap-ctl-info.o +CTL_OBJS += tap-ctl-xen.o +CTL_OBJS += tap-ctl-ipc.o +CTL_OBJS += tap-ctl-spawn.o +CTL_OBJS += tap-ctl-open.o +CTL_OBJS += tap-ctl-close.o CTL_OBJS += tap-ctl-create.o CTL_OBJS += tap-ctl-destroy.o -CTL_OBJS += tap-ctl-spawn.o -CTL_OBJS += tap-ctl-attach.o -CTL_OBJS += tap-ctl-detach.o -CTL_OBJS += tap-ctl-open.o -CTL_OBJS += tap-ctl-close.o -CTL_OBJS += tap-ctl-pause.o -CTL_OBJS += tap-ctl-unpause.o -CTL_OBJS += tap-ctl-major.o -CTL_OBJS += tap-ctl-check.o CTL_PICS = $(patsubst %.o,%.opic,$(CTL_OBJS)) -OBJS = $(CTL_OBJS) tap-ctl.o PICS = $(CTL_PICS) LIB_STATIC = $(LIBNAME).a -LIB_SHARED = $(LIBSONAME).$(MINOR) -IBIN = tap-ctl +LIB_SHARED = $(LIBNAME).so.$(MAJOR).$(MINOR) all: build build: $(IBIN) $(LIB_STATIC) $(LIB_SHARED) -$(LIBNAME).so: $(LIBSONAME) - ln -sf $< $@ - -$(LIBSONAME): $(LIB_SHARED) - ln -sf $< $@ - -tap-ctl: tap-ctl.o $(LIBNAME).so - $(CC) $(LDFLAGS) -o $@ $^ - $(LIB_STATIC): $(CTL_OBJS) $(AR) r $@ $^ $(LIB_SHARED): $(CTL_PICS) - $(CC) $(LDFLAGS) -fPIC -Wl,$(SONAME_LDFLAG) -Wl,$(LIBSONAME) $(SHLIB_LDFLAGS) -rdynamic $^ -o $@ + $(CC) $(LDFLAGS) -fPIC -Wl,$(SONAME_LDFLAG) -Wl,$(LIB_SHARED) \ + $(SHLIB_LDFLAGS) -rdynamic $^ -o $@ -install: $(IBIN) $(LIB_STATIC) $(LIB_SHARED) +install: $(LIB_STATIC) $(LIB_SHARED) $(INSTALL_DIR) -p $(DESTDIR)$(SBINDIR) - $(INSTALL_PROG) $(IBIN) $(DESTDIR)$(SBINDIR) - $(INSTALL_DATA) $(LIB_STATIC) $(DESTDIR)$(LIBDIR) + # TODO Why install the static version? + #$(INSTALL_DATA) $(LIB_STATIC) $(DESTDIR)$(LIBDIR) $(INSTALL_PROG) $(LIB_SHARED) $(DESTDIR)$(LIBDIR) - ln -sf $(LIBSONAME) $(DESTDIR)$(LIBDIR)/$(LIBNAME).so - ln -sf $(LIB_SHARED) $(DESTDIR)$(LIBDIR)/$(LIBSONAME) + ldconfig clean: - rm -f $(OBJS) $(PICS) $(DEPS) $(IBIN) $(LIB_STATIC) $(LIB_SHARED) - rm -f $(LIBNAME).so $(LIBSONAME) - rm -f *~ + rm -f $(CTL_OBJS) $(PICS) $(DEPS) $(LIB_STATIC) $(LIB_SHARED) .PHONY: all build clean install