├── VERSION ├── tests ├── __init__.py ├── units.py ├── env.sh ├── devcount-dmsetup ├── constants.py ├── storage.py ├── sanlk_lockr.c ├── conftest.py ├── killpath.c ├── Makefile ├── sanlk_rename.c ├── sanlk_client.c ├── devcountn ├── sanlk_testr.c ├── sanlk_events.c ├── sanlk_lvb.c ├── sanlk_string.c ├── clientn ├── direct_test.py ├── sanlk_path.c ├── sanlk_mixmsg.c ├── util.py └── test-recovery.sh ├── requirements.txt ├── .gitattributes ├── .vimrc ├── src ├── logrotate.sanlock ├── libsanlock_client.pc.in ├── libsanlock.pc.in ├── lockfile.h ├── env.h ├── task.h ├── monotime.h ├── mode_block.h ├── client_cmd.h ├── env.c ├── cmd.h ├── sanlock_sock.c ├── monotime.c ├── watchdog.h ├── helper.h ├── rindex.h ├── paxos_dblock.h ├── sanlock_direct.h ├── sanlock.conf ├── sizeflags.h ├── ondisk.h ├── diskio.h ├── sanlock_rv.h ├── lockfile.c ├── paxos_lease.h ├── resource.h ├── direct.h ├── delta_lease.h ├── sanlock_sock.h ├── lockspace.h ├── log.h ├── leader.h ├── task.c ├── rindex_disk.h ├── Makefile ├── direct_lib.c ├── crc32c.c ├── watchdog.c ├── timeouts.c ├── sanlock.h ├── helper.c └── ondisk.c ├── init.d ├── wdmd.service ├── sanlk-resetd.service ├── sanlock.service.native ├── wdmd.service.native ├── sanlock.service ├── fence_sanlockd.service ├── wdmd.sysconfig ├── sanlock.sysconfig ├── sanlock ├── wdmd └── fence_sanlockd ├── python ├── Makefile ├── setup.py └── example.py ├── .travis.yml ├── README.license ├── .gitignore ├── common.mk ├── wdmd ├── wdmd.h ├── wdmd_sock.c ├── wdmd_sock.h ├── wdmd_client.c ├── Makefile ├── client.c └── wdmd.8 ├── fence_sanlock ├── fence_sanlockd.8 └── Makefile ├── Makefile ├── reset ├── Makefile ├── sanlk_reset.h ├── sanlk-resetd.8 └── sanlk-reset.8 ├── tox.ini ├── README.dev └── sanlock.spec.in /VERSION: -------------------------------------------------------------------------------- 1 | 3.8.5 2 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | tox 2 | userstorage>=0.5.1 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | " Local vim configuration for sanlock 2 | set noexpandtab 3 | set shiftwidth=8 4 | set tabstop=8 5 | -------------------------------------------------------------------------------- /src/logrotate.sanlock: -------------------------------------------------------------------------------- 1 | /var/log/sanlock.log { 2 | rotate 3 3 | missingok 4 | copytruncate 5 | size 10M 6 | compress 7 | compresscmd /usr/bin/xz 8 | uncompresscmd /usr/bin/unxz 9 | compressext .xz 10 | } 11 | -------------------------------------------------------------------------------- /init.d/wdmd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Watchdog Multiplexing Daemon 3 | After=syslog.target 4 | 5 | [Service] 6 | Type=forking 7 | ExecStart=/lib/systemd/systemd-wdmd start 8 | ExecStop=/lib/systemd/systemd-wdmd stop 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | 13 | -------------------------------------------------------------------------------- /init.d/sanlk-resetd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=daemon for host reset 3 | After=wdmd.service sanlock.service 4 | Requires=wdmd.service sanlock.service 5 | 6 | [Service] 7 | Type=forking 8 | ExecStart=/usr/sbin/sanlk-resetd 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | 13 | -------------------------------------------------------------------------------- /init.d/sanlock.service.native: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Shared Storage Lease Manager 3 | After=syslog.target 4 | Wants=wdmd.service 5 | 6 | [Service] 7 | Type=forking 8 | ExecStart=/usr/sbin/sanlock daemon 9 | SendSIGKILL=no 10 | LimitNOFILE=2048 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | 15 | -------------------------------------------------------------------------------- /init.d/wdmd.service.native: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Watchdog Multiplexing Daemon 3 | After=syslog.target 4 | 5 | [Service] 6 | Type=forking 7 | ExecStartPre=/lib/systemd/systemd-wdmd watchdog-check 8 | ExecStart=/usr/sbin/wdmd 9 | SendSIGKILL=no 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | 14 | -------------------------------------------------------------------------------- /src/libsanlock_client.pc.in: -------------------------------------------------------------------------------- 1 | prefix=/usr 2 | exec_prefix=${prefix} 3 | includedir=${prefix}/include 4 | libdir=${exec_prefix}/lib64 5 | 6 | Name: libsanlock_client 7 | Description: The sanlock client library 8 | Version: @VERSION@ 9 | Cflags: -I${includedir} 10 | Libs: -L${libdir} -lsanlock_client 11 | 12 | -------------------------------------------------------------------------------- /init.d/sanlock.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Shared Storage Lease Manager 3 | After=syslog.target 4 | Wants=wdmd.service 5 | 6 | [Service] 7 | Type=forking 8 | ExecStart=/lib/systemd/systemd-sanlock start 9 | ExecStop=/lib/systemd/systemd-sanlock stop 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | 14 | -------------------------------------------------------------------------------- /src/libsanlock.pc.in: -------------------------------------------------------------------------------- 1 | prefix=/usr 2 | exec_prefix=${prefix} 3 | includedir=${prefix}/include 4 | libdir=${exec_prefix}/lib64 5 | 6 | Name: libsanlock 7 | Description: The sanlock library 8 | Version: @VERSION@ 9 | Cflags: -I${includedir} 10 | Libs: -L${libdir} -lpthread -lrt -laio -lblkid -luuid -lwdmd -lsanlock 11 | 12 | -------------------------------------------------------------------------------- /init.d/fence_sanlockd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=daemon for fence_sanlock agent 3 | After=syslog.target wdmd.service sanlock.service 4 | Before=corosync.service 5 | 6 | [Service] 7 | Type=forking 8 | ExecStart=/lib/systemd/systemd-fence_sanlockd start 9 | ExecStop=/lib/systemd/systemd-fence_sanlockd stop 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | 14 | -------------------------------------------------------------------------------- /init.d/wdmd.sysconfig: -------------------------------------------------------------------------------- 1 | # WDMDOPTS -- set the command line options for the wdmd daemon 2 | # See wdmd man page for full list of command line options. 3 | # 4 | # Include "-G sanlock" in the option string. 5 | # 6 | # To enable use of test scripts 7 | #WDMDOPTS="-G sanlock -S 1" 8 | # 9 | # To select a specific watchdog device 10 | #WDMDOPTS="-G sanlock -w /dev/watchdog1" 11 | 12 | -------------------------------------------------------------------------------- /python/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2010-2011 Red Hat, Inc. 2 | # 3 | # This copyrighted material is made available to anyone wishing to use, 4 | # modify, copy, or redistribute it subject to the terms and conditions 5 | # of the GNU General Public License v.2. 6 | 7 | PYTHON := python3 8 | 9 | all: 10 | $(PYTHON) setup.py build $(BUILDARGS) 11 | 12 | install: 13 | $(PYTHON) setup.py install --root=$(DESTDIR) 14 | 15 | clean: 16 | rm -rf build 17 | 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: bionic 2 | 3 | language: python 4 | 5 | python: 6 | - "3.6" 7 | - "3.7" 8 | - "3.8" 9 | - "3.9-dev" 10 | 11 | addons: 12 | apt: 13 | packages: 14 | - gcc 15 | - libaio-dev 16 | - libblkid-dev 17 | - make 18 | 19 | install: 20 | - pip install flake8 21 | 22 | script: 23 | - make BUILDARGS="--build-lib=." 24 | - source tests/env.sh 25 | - pytest 26 | - flake8 --statistics tests python 27 | -------------------------------------------------------------------------------- /src/lockfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __LOCKFILE_H__ 10 | #define __LOCKFILE_H__ 11 | 12 | int lockfile(const char *dir, const char *name, int uid, int gid); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /tests/units.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 Red Hat, Inc. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | """ 8 | Constants for file/disk sizes. 9 | """ 10 | 11 | KiB = 1024 12 | MiB = 1024**2 13 | GiB = 1024**3 14 | TiB = 1024**4 15 | PiB = 1024**5 16 | -------------------------------------------------------------------------------- /src/env.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __ENV_H__ 10 | #define __ENV_H__ 11 | 12 | const char *env_get(const char *key, const char *defval); 13 | int env_get_bool(const char *key, int defval); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/task.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __TASK_H__ 10 | #define __TASK_H__ 11 | 12 | void setup_task_aio(struct task *task, int use_aio, int cb_size); 13 | void close_task_aio(struct task *task); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/monotime.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __MONOTIME_H__ 10 | #define __MONOTIME_H__ 11 | 12 | uint64_t monotime(void); 13 | void ts_diff(struct timespec *begin, struct timespec *end, struct timespec *diff); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /README.license: -------------------------------------------------------------------------------- 1 | LGPLv2+ 2 | 3 | src/libsanlock_client.so 4 | src/sanlock.h 5 | src/sanlock_rv.h 6 | src/sanlock_admin.h 7 | src/sanlock_resource.h 8 | src/sanlock_sock.h 9 | src/sanlock_sock.c 10 | src/client.c 11 | wdmd/libwdmd.so 12 | wdmd/wdmd.h 13 | wdmd/wdmd_sock.h 14 | wdmd/wdmd_sock.c 15 | wdmd/client.c 16 | 17 | GPLv2 18 | 19 | src/list.h (copied from linux kernel) 20 | 21 | GPLv2+ 22 | 23 | src/crc32c.c (copied from btrfs-progs which copied from linux kernel) 24 | all other original files 25 | 26 | -------------------------------------------------------------------------------- /init.d/sanlock.sysconfig: -------------------------------------------------------------------------------- 1 | # SANLOCKOPTS -- set the command line options for the sanlock daemon 2 | # See sanlock man page for full list of command line options. 3 | # 4 | # Include "-U sanlock -G sanlock" in the option string unless 5 | # also changing the SANLOCKUSER above. 6 | # 7 | # To disable use of watchdog via wdmd 8 | #SANLOCKOPTS="-U sanlock -G sanlock -w 0" 9 | # 10 | # To disable use of watchdog via wdmd and disable high priority features 11 | #SANLOCKOPTS="-U sanlock -G sanlock -w 0 -h 0" 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.co 2 | *.swp 3 | *.tar.gz 4 | .tox/ 5 | .vimdir 6 | cscope.* 7 | python/*.so 8 | python/build/ 9 | python/usr/ 10 | reset/sanlk-reset 11 | reset/sanlk-resetd 12 | sanlock.spec 13 | src/libsanlock.pc 14 | src/libsanlock.so* 15 | src/libsanlock_client.pc 16 | src/libsanlock_client.so* 17 | src/sanlock 18 | tests/*.pyc 19 | tests/__pycache__/ 20 | tests/devcount 21 | tests/killpath 22 | tests/sanlk_client 23 | tests/sanlk_load 24 | tests/sanlk_path 25 | wdmd/libwdmd.so* 26 | wdmd/wdmd 27 | wdmd/wdmd_client 28 | -------------------------------------------------------------------------------- /tests/env.sh: -------------------------------------------------------------------------------- 1 | # Setup the environment for testing sanlock. 2 | 3 | # Use built libraries from source 4 | export LD_LIBRARY_PATH=$PWD/wdmd:$PWD/src 5 | 6 | # Disable privileged operations, allowing to run sanlock daemon as 7 | # non-privileged user. 8 | export SANLOCK_PRIVILEGED=0 9 | 10 | # Use temporary sanlock run dir, usable for non-privileged user. This 11 | # is used by sanlock daemon to create a lockfile and socket, and by 12 | # sanlock clients for communicating with the daemon. 13 | export SANLOCK_RUN_DIR=/tmp/sanlock 14 | 15 | # Import sanlock extension module from source. 16 | export PYTHONPATH=$PWD/python 17 | -------------------------------------------------------------------------------- /src/mode_block.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #ifndef __MODE_BLOCK_H__ 11 | #define __MODE_BLOCK_H__ 12 | 13 | #define MBLOCK_OFFSET 128 /* include paxos_dblock plus padding */ 14 | 15 | #define MBLOCK_SHARED 0x00000001 16 | 17 | struct mode_block { 18 | uint32_t flags; 19 | uint64_t generation; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /tests/devcount-dmsetup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -le 1 ]; then 4 | echo "num $#" 5 | echo "" 6 | echo "devcount-dmsetup save " 7 | echo "" 8 | echo "devcount-dmsetup error " 9 | echo "" 10 | echo "devcount-dmsetup linear " 11 | echo "" 12 | fi 13 | 14 | cmd=$1 15 | dev=$2 16 | 17 | if [ "$cmd" == "save" ]; then 18 | rm -f /tmp/table-linear.txt 19 | rm -f /tmp/table-error.txt 20 | dmsetup table $dev > /tmp/table-linear.txt 21 | sed "s/linear/error/" /tmp/table-linear.txt > /tmp/table-error.txt 22 | exit 0 23 | fi 24 | 25 | dmsetup suspend $dev 26 | dmsetup load $dev /tmp/table-$cmd.txt 27 | dmsetup resume $dev 28 | 29 | -------------------------------------------------------------------------------- /src/client_cmd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __CLIENT_CMD_H__ 10 | #define __CLIENT_CMD_H__ 11 | 12 | int sanlock_status(int debug, char sort_arg); 13 | int sanlock_host_status(int debug, char *lockspace_name); 14 | int sanlock_renewal(char *lockspace_name); 15 | int sanlock_log_dump(int max_size); 16 | int sanlock_shutdown(uint32_t force, int wait_result); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/env.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "env.h" 13 | 14 | const char *env_get(const char *key, const char *defval) 15 | { 16 | const char *val; 17 | 18 | val = getenv(key); 19 | if (val == NULL) 20 | return defval; 21 | 22 | return val; 23 | } 24 | 25 | int env_get_bool(const char *key, int defval) 26 | { 27 | const char *val; 28 | 29 | val = getenv(key); 30 | if (val == NULL) 31 | return defval; 32 | 33 | return strcmp(val, "1") ? 0 : 1; 34 | } 35 | -------------------------------------------------------------------------------- /common.mk: -------------------------------------------------------------------------------- 1 | export CC ?= cc 2 | 3 | check = $(shell echo "int main() { return 0; }" \ 4 | | $(CC) $(1) -xc - >&/dev/null && echo $(1) ||:) 5 | 6 | export CFLAGS += -D_GNU_SOURCE -O2 -ggdb \ 7 | -Wall \ 8 | -Wformat \ 9 | -Wformat-security \ 10 | -Wmissing-prototypes \ 11 | -Wnested-externs \ 12 | -Wpointer-arith \ 13 | -Wextra \ 14 | -Wshadow \ 15 | -Wcast-align \ 16 | -Wwrite-strings \ 17 | -Waggregate-return \ 18 | -Wstrict-prototypes \ 19 | -Winline \ 20 | -Wredundant-decls \ 21 | -Wno-sign-compare \ 22 | -Wno-unused-parameter \ 23 | -Wp,-D_FORTIFY_SOURCE=2 \ 24 | -Wno-strict-overflow \ 25 | -fexceptions \ 26 | -fasynchronous-unwind-tables \ 27 | -fdiagnostics-show-option \ 28 | -Wp,-D_GLIBCXX_ASSERTIONS \ 29 | -fstack-protector-strong \ 30 | $(check -fstack-clash-protection) \ 31 | -Wl,-z,now 32 | -------------------------------------------------------------------------------- /wdmd/wdmd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #ifndef __WDMD_H__ 11 | #define __WDMD_H__ 12 | 13 | #define WDMD_NAME_SIZE 128 14 | 15 | int wdmd_connect(void); 16 | int wdmd_open_watchdog(int con, int fire_timeout); 17 | int wdmd_register(int con, char *name); 18 | int wdmd_refcount_set(int con); 19 | int wdmd_refcount_clear(int con); 20 | int wdmd_test_live(int con, uint64_t renewal_time, uint64_t expire_time); 21 | int wdmd_status(int con, int *test_interval, int *fire_timeout, uint64_t *last_keepalive); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/cmd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __CMD_H__ 10 | #define __CMD_H__ 11 | 12 | struct cmd_args { 13 | struct list_head list; /* thread_pool data */ 14 | int ci_in; 15 | int ci_target; 16 | int cl_fd; 17 | int cl_pid; 18 | struct sm_header header; 19 | }; 20 | 21 | /* cmds processed by thread pool */ 22 | void call_cmd_thread(struct task *task, struct cmd_args *ca); 23 | 24 | /* cmds processed by main loop */ 25 | void call_cmd_daemon(int ci, struct sm_header *h_recv, int client_maxi); 26 | 27 | void daemon_shutdown_reply(void); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /tests/constants.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 Red Hat, Inc. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | """ 8 | Constants copied from sanlock source. 9 | """ 10 | 11 | # src/leader.h 12 | 13 | PAXOS_DISK_MAGIC = 0x06152010 14 | PAXOS_DISK_CLEAR = 0x11282016 15 | DELTA_DISK_MAGIC = 0x12212010 16 | 17 | # src/rindex_disk.h 18 | 19 | RINDEX_DISK_MAGIC = 0x01042018 20 | 21 | # src/rindex_disk.h 22 | # Copied from the docs module comment. 23 | 24 | RINDEX_ENTRY_SIZE = 64 25 | RINDEX_ENTRIES_SECTORS = 2000 26 | 27 | # src/sanlock_rv.h 28 | 29 | SANLK_LEADER_MAGIC = -223 30 | 31 | # src/sanlock.h 32 | 33 | SANLK_PATH_LEN = 1024 34 | -------------------------------------------------------------------------------- /wdmd/wdmd_sock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "wdmd.h" 19 | #include "wdmd_sock.h" 20 | 21 | int wdmd_socket_address(struct sockaddr_un *addr) 22 | { 23 | memset(addr, 0, sizeof(struct sockaddr_un)); 24 | addr->sun_family = AF_LOCAL; 25 | snprintf(addr->sun_path, sizeof(addr->sun_path) - 1, "%s/%s", 26 | WDMD_RUN_DIR, WDMD_SOCKET_NAME); 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2010-2019 Red Hat, Inc. 2 | # 3 | # This copyrighted material is made available to anyone wishing to use, 4 | # modify, copy, or redistribute it subject to the terms and conditions 5 | # of the GNU General Public License v.2. 6 | 7 | from setuptools import setup, Extension 8 | 9 | sanlocklib = ['sanlock'] 10 | sanlock = Extension(name='sanlock', 11 | sources=['sanlock.c'], 12 | include_dirs=['../src'], 13 | library_dirs=['../src'], 14 | extra_compile_args=["-std=c99"], 15 | libraries=sanlocklib) 16 | 17 | version = None 18 | with open('../VERSION') as f: 19 | version = f.readline() 20 | 21 | setup(name='sanlock-python', 22 | version=version, 23 | description='Python bindings for the sanlock library', 24 | ext_modules=[sanlock]) 25 | -------------------------------------------------------------------------------- /src/sanlock_sock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "sanlock.h" 19 | #include "sanlock_sock.h" 20 | 21 | int sanlock_socket_address(const char *dir, struct sockaddr_un *addr) 22 | { 23 | memset(addr, 0, sizeof(struct sockaddr_un)); 24 | addr->sun_family = AF_LOCAL; 25 | snprintf(addr->sun_path, sizeof(addr->sun_path) - 1, "%s/%s", 26 | dir, SANLK_SOCKET_NAME); 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /fence_sanlock/fence_sanlockd.8: -------------------------------------------------------------------------------- 1 | .TH FENCE_SANLOCKD 8 2012-09-26 2 | 3 | .SH NAME 4 | fence_sanlockd \- daemon for fence_sanlock agent 5 | 6 | .SH SYNOPSIS 7 | .B fence_sanlockd 8 | [OPTIONS] 9 | 10 | .SH DESCRIPTION 11 | The fence_sanlockd daemon is used by the fence_sanlock agent. 12 | See 13 | .BR fence_sanlock (8), 14 | for full description. 15 | 16 | .SH OPTIONS 17 | 18 | .B \-D 19 | Enable debugging to stderr and don't fork. 20 | 21 | .BI \-p " path" 22 | Path to shared storage with sanlock leases. 23 | 24 | .BI \-i " host_id" 25 | Local sanlock host_id (1-128). 26 | 27 | .B \-w 28 | Wait for fence_sanlockd -s to send options (p,i). 29 | 30 | .B \-s 31 | Send options (p,i) to waiting fence_sanlockd -w. 32 | 33 | .B \-1 34 | Send SIGUSR1 to running fence_sanlockd. 35 | 36 | 37 | .SH SEE ALSO 38 | .BR fence_sanlock (8), 39 | .BR sanlock (8), 40 | .BR wdmd (8), 41 | .BR fence_node (8), 42 | .BR fenced (8) 43 | 44 | -------------------------------------------------------------------------------- /src/monotime.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "monotime.h" 13 | 14 | uint64_t monotime(void) 15 | { 16 | struct timespec ts; 17 | 18 | clock_gettime(CLOCK_MONOTONIC, &ts); 19 | 20 | return ts.tv_sec; 21 | } 22 | 23 | void ts_diff(struct timespec *begin, struct timespec *end, struct timespec *diff) 24 | { 25 | if ((end->tv_nsec - begin->tv_nsec) < 0) { 26 | diff->tv_sec = end->tv_sec - begin->tv_sec - 1; 27 | diff->tv_nsec = end->tv_nsec - begin->tv_nsec + 1000000000; 28 | } else { 29 | diff->tv_sec = end->tv_sec - begin->tv_sec; 30 | diff->tv_nsec = end->tv_nsec - begin->tv_nsec; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/storage.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 Red Hat, Inc. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | """ 8 | storage - provide storage for sanlock tests. 9 | """ 10 | 11 | from userstorage import File, Mount, LoopDevice 12 | 13 | GiB = 1024**3 14 | 15 | BASE_DIR = "/var/tmp/sanlock-storage" 16 | 17 | BACKENDS = { 18 | 19 | "file": 20 | File( 21 | Mount( 22 | LoopDevice( 23 | base_dir=BASE_DIR, 24 | name="file", 25 | size=GiB, 26 | sector_size=4096))), 27 | 28 | "block": 29 | LoopDevice( 30 | base_dir=BASE_DIR, 31 | name="loop", 32 | size=GiB, 33 | sector_size=4096), 34 | 35 | } 36 | -------------------------------------------------------------------------------- /wdmd/wdmd_sock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #ifndef __WDMD_SOCK_H__ 11 | #define __WDMD_SOCK_H__ 12 | 13 | #define WDMD_RUN_DIR "/run/wdmd" 14 | #define WDMD_SOCKET_NAME "wdmd.sock" 15 | 16 | enum { 17 | CMD_REGISTER = 1, 18 | CMD_REFCOUNT_SET, 19 | CMD_REFCOUNT_CLEAR, 20 | CMD_TEST_LIVE, 21 | CMD_STATUS, 22 | CMD_DUMP_DEBUG, 23 | CMD_OPEN_WATCHDOG, 24 | }; 25 | 26 | struct wdmd_header { 27 | uint32_t magic; 28 | uint32_t cmd; 29 | uint32_t len; 30 | uint32_t flags; 31 | uint32_t test_interval; 32 | uint32_t fire_timeout; 33 | uint64_t last_keepalive; 34 | uint64_t renewal_time; 35 | uint64_t expire_time; 36 | char name[WDMD_NAME_SIZE]; 37 | }; 38 | 39 | int wdmd_socket_address(struct sockaddr_un *addr); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | version := $(shell cat VERSION) 2 | 3 | ifeq ($(shell git describe --exact-match 2>/dev/null),) 4 | # sanlock-3.7.0-5-g11fb098 -> 5.g11fb098 5 | release := $(shell git describe --tags | awk -F- '{print $$(NF-1) "." $$(NF)}') 6 | else 7 | release := 0 8 | endif 9 | 10 | distname := sanlock-$(version) 11 | tarball := $(distname).tar.gz 12 | 13 | SUBDIRS = wdmd src python reset 14 | 15 | .PHONY: all $(SUBDIRS) clean install 16 | 17 | all: $(SUBDIRS) 18 | 19 | $(SUBDIRS): 20 | $(MAKE) -C $@ 21 | 22 | src: wdmd 23 | 24 | python reset: src 25 | 26 | clean install: 27 | for dir in $(SUBDIRS); do \ 28 | $(MAKE) -C $$dir $@; \ 29 | done 30 | 31 | dist: spec 32 | rm -f $(tarball) 33 | git archive --prefix=$(distname)/ HEAD > $(distname).tar 34 | tar rf $(distname).tar --transform="s|^|$(distname)/&|" sanlock.spec 35 | gzip $(distname).tar 36 | 37 | srpm: dist 38 | rpmbuild -ts $(tarball) 39 | 40 | rpm: dist 41 | rpmbuild -ta $(tarball) 42 | 43 | spec: 44 | sed -e 's/@VERSION@/$(version)/g' \ 45 | -e 's/@RELEASE@/$(release)/g' \ 46 | sanlock.spec.in > sanlock.spec 47 | -------------------------------------------------------------------------------- /reset/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mk 2 | 3 | TARGET1 = sanlk-resetd 4 | TARGET2 = sanlk-reset 5 | 6 | SOURCE1 = sanlk_resetd.c 7 | SOURCE2 = sanlk_reset.c 8 | 9 | VER=$(shell cat ../VERSION) 10 | CFLAGS += -DVERSION=\"$(VER)\" -I../src -I../wdmd 11 | 12 | CFLAGS += -fPIE -DPIE 13 | 14 | LDFLAGS += -Wl,-z,relro -pie 15 | 16 | LDADD = -lsanlock -lwdmd 17 | 18 | all: $(TARGET1) $(TARGET2) 19 | 20 | $(TARGET1): $(SOURCE1) 21 | $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCE1) $(LDADD) -o $@ -L. -L../src -L../wdmd 22 | 23 | $(TARGET2): $(SOURCE2) 24 | $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCE2) $(LDADD) -o $@ -L. -L../src -L../wdmd 25 | 26 | clean: 27 | rm -f *.o *.so *.so.* $(TARGET1) $(TARGET2) 28 | 29 | INSTALL=$(shell which install) 30 | 31 | DESTDIR= 32 | BINDIR=/usr/sbin 33 | LIBDIR=/usr/lib64 34 | HEADIR=/usr/include 35 | MANDIR=/usr/share/man 36 | 37 | .PHONY: install 38 | install: all 39 | $(INSTALL) -d $(DESTDIR)/$(BINDIR) 40 | $(INSTALL) -c -m 755 $(TARGET1) $(TARGET2) $(DESTDIR)/$(BINDIR) 41 | $(INSTALL) -m 644 sanlk-reset.8 $(DESTDIR)/$(MANDIR)/man8/ 42 | $(INSTALL) -m 644 sanlk-resetd.8 $(DESTDIR)/$(MANDIR)/man8/ 43 | -------------------------------------------------------------------------------- /src/watchdog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __WATCHDOG_H__ 10 | #define __WATCHDOG_H__ 11 | 12 | /* open/close socket connection to wdmd daemon */ 13 | int connect_watchdog(struct space *sp); 14 | void disconnect_watchdog(struct space *sp); 15 | 16 | /* tell wdmd to open the watchdog device which arms it 17 | and wdmd begins keepalive loop, but the watchdog 18 | keepalive is not yet influenced by lockspace renewals. */ 19 | int open_watchdog(int con, int fire_timeout); 20 | 21 | /* associate per-lockspace renewals in sanlock with 22 | watchdog petting in wdmd */ 23 | int activate_watchdog(struct space *sp, uint64_t timestamp, 24 | int id_renewal_fail_seconds, int con); 25 | void deactivate_watchdog(struct space *sp); 26 | void update_watchdog(struct space *sp, uint64_t timestamp, 27 | int id_renewal_fail_seconds); 28 | #endif 29 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py{36,37,38,39,310},flake8 8 | skipsdist = True 9 | skip_missing_interpreters = True 10 | 11 | [testenv] 12 | passenv = * 13 | setenv = 14 | LD_LIBRARY_PATH={env:PWD}/wdmd:{env:PWD}/src 15 | SANLOCK_PRIVILEGED=0 16 | SANLOCK_RUN_DIR=/tmp/sanlock 17 | whitelist_externals = make 18 | deps = 19 | pytest 20 | userstorage>=0.5.1 21 | commands = 22 | py{36,37,38,39,310}: make BUILDARGS="--build-lib={envsitepackagesdir}" 23 | pytest {posargs} 24 | 25 | [testenv:flake8] 26 | deps = flake8 27 | commands = flake8 --statistics tests python 28 | 29 | [pytest] 30 | # Notes: 31 | # --basetemp: we must use /var/tmp as sanlock uses direct I/O. 32 | # -rxX show extra test summary: (x)failed, (X)passed, 33 | # --durations: show slowest test duration 34 | addopts = -rxX --basetemp=/var/tmp/sanlock --durations=10 35 | 36 | [flake8] 37 | show_source = True 38 | -------------------------------------------------------------------------------- /src/helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __HELPER_H__ 10 | #define __HELPER_H__ 11 | 12 | /* 13 | * helper process 14 | * recvs 512 byte helper_msg on in_fd 15 | * sends 4 byte helper_status on out_fd 16 | */ 17 | 18 | #define SANLK_HELPER_MSG_LEN 512 19 | 20 | #define HELPER_MSG_RUNPATH 1 21 | #define HELPER_MSG_KILLPID 2 22 | #define HELPER_MSG_WRITE_SYSFS 3 23 | 24 | struct helper_msg { 25 | uint8_t type; 26 | uint8_t pad1; 27 | uint16_t pad2; 28 | uint32_t flags; 29 | int pid; 30 | int sig; 31 | char path[SANLK_HELPER_PATH_LEN]; /* 128 */ 32 | char args[SANLK_HELPER_ARGS_LEN]; /* 128 */ 33 | char pad[240]; 34 | }; 35 | 36 | #define HELPER_STATUS_INTERVAL 30 37 | 38 | #define HELPER_STATUS 1 39 | 40 | struct helper_status { 41 | uint8_t type; 42 | uint8_t status; 43 | uint16_t len; 44 | }; 45 | 46 | int run_helper(int in_fd, int out_fd, int log_stderr); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/rindex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __RINDEX_H__ 10 | #define __RINDEX_H__ 11 | 12 | int rindex_format(struct task *task, struct sanlk_rindex *ri); 13 | int rindex_rebuild(struct task *task, struct sanlk_rindex *ri, uint32_t cmd_flags); 14 | 15 | int rindex_lookup(struct task *task, struct sanlk_rindex *ri, 16 | struct sanlk_rentry *re, struct sanlk_rentry *re_ret, uint32_t cmd_flags); 17 | int rindex_update(struct task *task, struct sanlk_rindex *ri, 18 | struct sanlk_rentry *re, struct sanlk_rentry *re_ret, uint32_t cmd_flags); 19 | 20 | int rindex_create(struct task *task, struct sanlk_rindex *ri, 21 | struct sanlk_rentry *re, struct sanlk_rentry *re_ret, 22 | uint32_t num_hosts, uint32_t max_hosts); 23 | int rindex_delete(struct task *task, struct sanlk_rindex *ri, 24 | struct sanlk_rentry *re, struct sanlk_rentry *re_ret); 25 | #endif 26 | -------------------------------------------------------------------------------- /src/paxos_dblock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #ifndef __PAXOS_DBLOCK_H__ 11 | #define __PAXOS_DBLOCK_H__ 12 | 13 | /* The first dblock (for host_id 1) is in the third sector of a paxos lease. 14 | The first sector holds the leader record, and the second sector holds the 15 | request record. */ 16 | 17 | #define DBLOCK_CHECKSUM_LEN 48 /* ends before checksum field */ 18 | 19 | #define DBLOCK_FL_RELEASED 0x00000001 20 | 21 | struct paxos_dblock { 22 | uint64_t mbal; 23 | uint64_t bal; 24 | uint64_t inp; /* host_id */ 25 | uint64_t inp2; /* host_id generation */ 26 | uint64_t inp3; /* host_id's timestamp */ 27 | uint64_t lver; 28 | uint32_t checksum; 29 | uint32_t flags; /* DBLOCK_FL_ */ 30 | }; 31 | 32 | /* 33 | * This struct cannot grow any larger than MBLOCK_OFFSET (128) 34 | * because the mode_block starts at that offset in the same sector. 35 | */ 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /reset/sanlk_reset.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __SANLK_RESET_H__ 10 | #define __SANLK_RESET_H__ 11 | 12 | #define EVENT_RESET 1 13 | #define EVENT_RESETTING 2 14 | #define EVENT_REBOOT 4 15 | #define EVENT_REBOOTING 8 16 | 17 | #define SANLK_RESETD_RUNDIR "/run/sanlk-resetd" 18 | #define SANLK_RESETD_SOCKET SANLK_RESETD_RUNDIR "/sanlk-resetd.sock" 19 | #define SANLK_RESETD_SOCKET_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) 20 | 21 | #define UPDATE_SIZE 256 /* sendmsg size on unix socket */ 22 | 23 | static inline int setup_resetd_socket(void) 24 | { 25 | int s; 26 | 27 | s = socket(AF_LOCAL, SOCK_DGRAM, 0); 28 | if (s < 0) 29 | return s; 30 | 31 | memset(&update_addr, 0, sizeof(update_addr)); 32 | update_addr.sun_family = AF_LOCAL; 33 | strcpy(update_addr.sun_path, SANLK_RESETD_SOCKET); 34 | update_addrlen = sizeof(sa_family_t) + strlen(update_addr.sun_path) + 1; 35 | 36 | return s; 37 | } 38 | 39 | #endif 40 | 41 | -------------------------------------------------------------------------------- /src/sanlock_direct.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __SANLOCK_DIRECT_H__ 10 | #define __SANLOCK_DIRECT_H__ 11 | 12 | /* 13 | * Use num_hosts = 0 for default value. 14 | * Provide either lockspace or resource, not both 15 | * 16 | * (Old api, see write_lockspace/resource) 17 | */ 18 | 19 | int sanlock_direct_init(struct sanlk_lockspace *ls, 20 | struct sanlk_resource *res, 21 | int max_hosts_unused, int num_hosts, int use_aio); 22 | 23 | /* 24 | * write a lockspace to disk 25 | * (also see sanlock_write_lockspace) 26 | */ 27 | 28 | int sanlock_direct_write_lockspace(struct sanlk_lockspace *ls, int max_hosts_unused, 29 | uint32_t flags, uint32_t io_timeout); 30 | 31 | /* 32 | * format a resource lease area on disk 33 | * (also see sanlock_write_resource) 34 | */ 35 | 36 | int sanlock_direct_write_resource(struct sanlk_resource *res, 37 | int max_hosts_unused, int num_hosts, uint32_t flags); 38 | 39 | /* 40 | * Returns the alignment in bytes required by sanlock_direct_init() 41 | * (1MB for disks with 512 sectors, 8MB for disks with 4096 sectors) 42 | */ 43 | 44 | int sanlock_direct_align(struct sanlk_disk *disk); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/sanlock.conf: -------------------------------------------------------------------------------- 1 | # sanlock config file 2 | # 3 | # Values set here can be overriden on the command line. 4 | # See 'man sanlock' and 'sanlock -h' for more information. 5 | # 6 | # Example settings: 7 | # 8 | # quiet_fail = 1 9 | # command line: -Q 0|1 10 | # 11 | # debug_renew = 0 12 | # command line: -R 0|1 13 | # 14 | # logfile_priority = 4 15 | # command line: -L 4 16 | # 17 | # logfile_use_utc = 0 18 | # command line: n/a 19 | # 20 | # syslog_priority = 3 21 | # command line: -S 3 22 | # 23 | # names_log_priority = 4 24 | # command line: n/a 25 | # 26 | # use_watchdog = 1 27 | # command line: -w 1 28 | # 29 | # high_priority = 1 30 | # command line: -h 1 31 | # 32 | # mlock_level = 1 33 | # command line: -l 1 34 | # 35 | # sh_retries = 8 36 | # command line: n/a 37 | # 38 | # uname = sanlock 39 | # command line: -U 40 | # 41 | # gname = sanlock 42 | # command line: -G 43 | # 44 | # our_host_name = 45 | # command line: -e 46 | # 47 | # renewal_read_extend_sec = 48 | # command line: n/a 49 | # 50 | # paxos_debug_all = 0 51 | # command line: n/a 52 | # 53 | # debug_io = 54 | # command line: n/a 55 | # 56 | # max_sectors_kb = 57 | # command line: n/a 58 | # 59 | # debug_clients = 0 60 | # command line: n/a 61 | # 62 | # debug_cmd = + 63 | # debug_cmd = - 64 | # ... 65 | # command line: n/a 66 | # 67 | # write_init_io_timeout = 68 | # command line: n/a 69 | # 70 | # max_worker_threads = 8 71 | # command line: -t 8 72 | # 73 | # io_timeout = 10 74 | # command line: -o 75 | # 76 | # watchdog_fire_timeout = 60 77 | # command line: n/a 78 | -------------------------------------------------------------------------------- /reset/sanlk-resetd.8: -------------------------------------------------------------------------------- 1 | .TH SANLK\-RESETD 8 2014-08-14 2 | 3 | .SH NAME 4 | sanlk\-resetd \- host reset daemon 5 | 6 | .SH SYNOPSIS 7 | .B sanlk\-resetd 8 | [OPTIONS] 9 | .IR lockspace_name " ..." 10 | 11 | .SH DESCRIPTION 12 | 13 | The sanlk\-resetd daemon gets events from specified sanlock lockspaces. 14 | Events are defined to cause sanlk\-resetd to: 15 | .br 16 | - use wdmd/watchdog to reset the host 17 | .br 18 | - use /proc/sysrq\-trigger to reboot the host 19 | 20 | The sanlk\-reset program can be run on another host to request that 21 | sanlk\-resetd reset the host it is running on. Both hosts must be 22 | operational and have continued access to a common lockspace for the reset 23 | request to succeed. After setting the event, the sanlk\-reset program 24 | monitors the host status in the sanlock lockspace until the target host is 25 | dead. 26 | 27 | The sanlk\-reset program can also be run on the same host as sanlk\-resetd 28 | to update which lockspaces the local sanlk\-resetd is watching for events. 29 | 30 | .SH OPTIONS 31 | .TP 32 | .B \-\-version, \-V 33 | Print version. 34 | 35 | .TP 36 | .B \-\-help, \-h 37 | Print usage. 38 | 39 | .TP 40 | .B \-\-foreground, \-f 41 | Don't fork. 42 | 43 | .TP 44 | .B \-\-daemon\-debug, \-D 45 | Enable debugging to stderr and don't fork. 46 | 47 | .TP 48 | .B \-\-sysrq\-reboot, \-b 0|1 49 | Enable/Disable (1/0) use of /proc/sysrq\-trigger to reboot. 50 | 51 | .TP 52 | .BI "\-\-sysrq\-delay, \-d " sec 53 | Delay this many seconds before using /proc/sysrq\-trigger. 54 | 55 | .TP 56 | .B \-\-resource-mode, \-R 0|1 57 | Resource leases are used (1) or not used (0) to protect storage. 58 | 59 | .SH SEE ALSO 60 | .BR sanlk\-reset (8) 61 | .BR sanlock (8) 62 | .BR wdmd (8) 63 | -------------------------------------------------------------------------------- /tests/sanlk_lockr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "sanlock.h" 20 | #include "sanlock_resource.h" 21 | 22 | /* gcc with -lsanlock */ 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | char rd[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)]; 27 | struct sanlk_resource *res; 28 | int sleep_sec; 29 | int fd, rv; 30 | 31 | if (argc < 6) { 32 | printf("acquire, [sleep], release\n"); 33 | printf("sanlk_lockr \n"); 34 | return -1; 35 | } 36 | 37 | memset(rd, 0, sizeof(rd)); 38 | 39 | res = (struct sanlk_resource *)&rd; 40 | 41 | strcpy(res->lockspace_name, argv[1]); 42 | strcpy(res->name, argv[2]); 43 | res->num_disks = 1; 44 | strcpy(res->disks[0].path, argv[3]); 45 | res->disks[0].offset = atoi(argv[4]); 46 | 47 | sleep_sec = atoi(argv[5]); 48 | 49 | fd = sanlock_register(); 50 | if (fd < 0) { 51 | fprintf(stderr, "register error %d\n", fd); 52 | return -1; 53 | } 54 | 55 | rv = sanlock_acquire(fd, -1, 0, 1, &res, NULL); 56 | if (rv < 0) { 57 | fprintf(stderr, "acquire error %d\n", rv); 58 | return -1; 59 | } 60 | 61 | if (sleep_sec) 62 | sleep(sleep_sec); 63 | 64 | rv = sanlock_release(fd, -1, 0, 1, &res); 65 | if (rv < 0) { 66 | fprintf(stderr, "release error %d\n", rv); 67 | return -1; 68 | } 69 | 70 | return 0; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /fence_sanlock/Makefile: -------------------------------------------------------------------------------- 1 | TARGET1 = fence_sanlockd 2 | TARGET2 = fence_sanlock 3 | 4 | SOURCE1 = fence_sanlockd.c 5 | SOURCE2 = fence_sanlock.in 6 | 7 | OPTIMIZE_FLAG = -O2 -Wp,-D_FORTIFY_SOURCE=2 8 | ifeq ($(DEBUG), 1) 9 | OPTIMIZE_FLAG = -O0 10 | CFLAGS += -g 11 | endif 12 | 13 | CFLAGS += -D_GNU_SOURCE -g \ 14 | -Wall \ 15 | -Wformat \ 16 | -Wformat-security \ 17 | -Wnested-externs \ 18 | -Wpointer-arith \ 19 | -Wextra -Wshadow \ 20 | -Wcast-align \ 21 | -Wwrite-strings \ 22 | -Waggregate-return \ 23 | -Wstrict-prototypes \ 24 | -Winline \ 25 | -Wredundant-decls \ 26 | -Wno-sign-compare \ 27 | -fexceptions \ 28 | -fasynchronous-unwind-tables \ 29 | -fdiagnostics-show-option \ 30 | $(OPTIMIZE_FLAG) \ 31 | $(NULL) 32 | 33 | VER=$(shell cat ../VERSION) 34 | CFLAGS += -DVERSION=\"$(VER)\" -I../src -I../wdmd 35 | CFLAGS += -fPIE -DPIE 36 | 37 | LDFLAGS = -Wl,-z,now -Wl,-z,relro -pie 38 | LDADD = -lrt -laio -lblkid -lsanlock -lwdmd 39 | 40 | all: $(TARGET1) $(TARGET2) 41 | 42 | $(TARGET1): $(SOURCE1) 43 | $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCE1) $(LDADD) -o $@ -L. -L../src -L../wdmd 44 | 45 | $(TARGET2): $(SOURCE2) 46 | cat $(SOURCE2) | sed \ 47 | -e 's#@VERSION@#${VER}#g' \ 48 | > $(TARGET2) 49 | chmod 755 $(TARGET2) 50 | 51 | clean: 52 | rm -f *.o *.so *.so.* $(TARGET1) $(TARGET2) 53 | 54 | INSTALL=$(shell which install) 55 | 56 | DESTDIR= 57 | BINDIR=/usr/sbin 58 | LIBDIR=/usr/lib64 59 | HEADIR=/usr/include 60 | MANDIR=/usr/share/man 61 | 62 | .PHONY: install 63 | install: all 64 | $(INSTALL) -d $(DESTDIR)/$(BINDIR) 65 | $(INSTALL) -d $(DESTDIR)/$(MANDIR)/man8 66 | $(INSTALL) -c -m 755 $(TARGET1) $(TARGET2) $(DESTDIR)/$(BINDIR) 67 | $(INSTALL) -m 644 fence_sanlock.8 $(DESTDIR)/$(MANDIR)/man8/ 68 | $(INSTALL) -m 644 fence_sanlockd.8 $(DESTDIR)/$(MANDIR)/man8/ 69 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 Red Hat, Inc. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | """ 8 | Fixtures for sanlock testing. 9 | """ 10 | from __future__ import absolute_import 11 | 12 | import pytest 13 | import userstorage 14 | 15 | from . import util 16 | 17 | # Mark tests with skip if userstorage is missing 18 | userstorage.missing_handler = pytest.skip 19 | 20 | # Requires relative path from tox basedir 21 | BACKENDS = userstorage.load_config("./tests/storage.py").BACKENDS 22 | 23 | 24 | class SanlockIsRunning(Exception): 25 | """ Raised if sanlock running when it should not """ 26 | 27 | 28 | @pytest.fixture 29 | def sanlock_daemon(): 30 | """ 31 | Run sanlock daemon during a test. 32 | """ 33 | p = util.start_daemon() 34 | try: 35 | util.wait_for_daemon(0.5) 36 | yield 37 | finally: 38 | # Killing sanlock allows terminating without reomving the lockspace, 39 | # which takes about 3 seconds, slowing down the tests. 40 | p.kill() 41 | p.wait() 42 | 43 | 44 | @pytest.fixture(params=[ 45 | BACKENDS["block"], 46 | BACKENDS["file"], 47 | ]) 48 | def user_4k_path(request): 49 | """ 50 | A path to block device or file on file system on top of 4k block device, 51 | provided by the user. 52 | 53 | If storage is not available, skip the tests. 54 | """ 55 | backend = request.param 56 | with backend: 57 | yield backend.path 58 | 59 | 60 | @pytest.fixture 61 | def no_sanlock_daemon(): 62 | if util.sanlock_is_running(): 63 | raise SanlockIsRunning 64 | -------------------------------------------------------------------------------- /wdmd/wdmd_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "wdmd.h" 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | char name[WDMD_NAME_SIZE]; 25 | uint64_t t, last_keepalive; 26 | int test_interval, fire_timeout; 27 | int con, rv; 28 | int i = 0; 29 | int iter = 10; 30 | 31 | if (argc > 1) 32 | iter = atoi(argv[1]); 33 | 34 | memset(name, 0, sizeof(name)); 35 | sprintf(name, "%s", "wdmd_client"); 36 | 37 | con = wdmd_connect(); 38 | printf("wdmd_connect %d\n", con); 39 | if (con < 0) 40 | return con; 41 | 42 | rv = wdmd_register(con, name); 43 | printf("wdmd_register %d\n", rv); 44 | if (rv < 0) 45 | return rv; 46 | 47 | rv = wdmd_status(con, &test_interval, &fire_timeout, &last_keepalive); 48 | printf("wdmd_status %d test_interval %d fire_timeout %d last_keepalive %llu\n", 49 | rv, test_interval, fire_timeout, 50 | (unsigned long long)last_keepalive); 51 | if (rv < 0) 52 | return rv; 53 | 54 | while (1) { 55 | sleep(10); 56 | 57 | t = time(NULL); 58 | 59 | rv = wdmd_test_live(con, t, t + 40); 60 | printf("wdmd_test_live %d %llu %llu\n", rv, 61 | (unsigned long long)t, 62 | (unsigned long long)(t + 40)); 63 | 64 | if (i++ > iter) 65 | break; 66 | } 67 | 68 | rv = wdmd_test_live(con, t, 0); 69 | printf("wdmd_test_live 0 %d\n", rv); 70 | 71 | return 0; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /tests/killpath.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "sanlock.h" 12 | #include "sanlock_resource.h" 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | FILE *out; 17 | char *cmd = argv[0]; 18 | char args[1024]; 19 | char arg[1024]; 20 | char *state = NULL; 21 | int count = 0; 22 | int i, pid, rv; 23 | 24 | if (argc > 1 && !strcmp(argv[1], "-h")) { 25 | printf("%s_args - syslog args\n", cmd); 26 | printf("%s_term - kill SIGTERM\n", cmd); 27 | printf("%s_pause - sanlock_inquire, sanlock_release\n", cmd); 28 | } 29 | 30 | openlog(cmd, LOG_PID, LOG_DAEMON); 31 | 32 | memset(args, 0, sizeof(args)); 33 | 34 | for (i = 1; i < argc; i++) { 35 | memset(arg, 0, sizeof(arg)); 36 | sprintf(arg, "%s ", argv[i]); 37 | strcat(args, arg); 38 | } 39 | 40 | pid = atoi(argv[argc-1]); 41 | 42 | if (strstr(cmd, "args")) { 43 | syslog(LOG_ERR, "pid %d args %s\n", pid, args); 44 | 45 | } else if (strstr(cmd, "term")) { 46 | rv = kill(pid, SIGTERM); 47 | 48 | syslog(LOG_ERR, "sigterm pid %d errno %d\n", pid, errno); 49 | } 50 | 51 | else if (strstr(cmd, "pause")) { 52 | rv = kill(pid, SIGSTOP); 53 | if (rv < 0) 54 | syslog(LOG_ERR, "sigstop pid %d errno %d", pid, errno); 55 | 56 | rv = sanlock_inquire(-1, pid, 0, &count, &state); 57 | 58 | syslog(LOG_ERR, "inquire pid %d rv %d count %d state %s\n", 59 | pid, rv, count, state ? state : ""); 60 | 61 | rv = sanlock_release(-1, pid, SANLK_REL_ALL, 0, NULL); 62 | 63 | syslog(LOG_ERR, "release pid %d rv %d\n", pid, rv); 64 | 65 | out = fopen("/tmp/client-state.txt", "a"); 66 | if (out) { 67 | fprintf(out, "%d %s\n", pid, state); 68 | fclose(out); 69 | } 70 | 71 | if (state) 72 | free(state); 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | TARGET1 = devcount 2 | TARGET2 = sanlk_load 3 | TARGET3 = sanlk_client 4 | TARGET4 = killpath 5 | TARGET5 = sanlk_path 6 | TARGET6 = sanlk_testr 7 | TARGET7 = sanlk_events 8 | TARGET8 = sanlk_mixmsg 9 | 10 | SOURCE1 = devcount.c 11 | SOURCE2 = sanlk_load.c 12 | SOURCE3 = sanlk_client.c 13 | SOURCE4 = killpath.c 14 | SOURCE5 = sanlk_path.c 15 | SOURCE6 = sanlk_testr.c 16 | SOURCE7 = sanlk_events.c 17 | SOURCE8 = sanlk_mixmsg.c 18 | 19 | CFLAGS += -D_GNU_SOURCE -g \ 20 | -Wall \ 21 | -Wformat \ 22 | -Wformat-security \ 23 | -Wnested-externs \ 24 | -Wpointer-arith \ 25 | -Wextra -Wshadow \ 26 | -Wcast-align \ 27 | -Wwrite-strings \ 28 | -Waggregate-return \ 29 | -Wstrict-prototypes \ 30 | -Winline \ 31 | -Wredundant-decls \ 32 | -Wno-sign-compare \ 33 | -Wp,-D_FORTIFY_SOURCE=2 \ 34 | -O2 \ 35 | -fexceptions \ 36 | -fasynchronous-unwind-tables \ 37 | -fdiagnostics-show-option 38 | 39 | LDFLAGS = -lrt -laio -lblkid -lsanlock 40 | 41 | all: $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5) $(TARGET6) $(TARGET7) $(TARGET8) 42 | 43 | $(TARGET1): $(SOURCE1) 44 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src 45 | 46 | $(TARGET2): $(SOURCE2) 47 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src 48 | 49 | $(TARGET3): $(SOURCE3) 50 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src 51 | 52 | $(TARGET4): $(SOURCE4) 53 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src 54 | 55 | $(TARGET5): $(SOURCE5) 56 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src 57 | 58 | $(TARGET6): $(SOURCE6) 59 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src 60 | 61 | $(TARGET7): $(SOURCE7) 62 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src 63 | 64 | $(TARGET8): $(SOURCE8) 65 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src 66 | 67 | clean: 68 | rm -f *.o *.so *.so.* $(TARGET) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5) $(TARGET6) $(TARGET7) $(TARGET8) 69 | 70 | -------------------------------------------------------------------------------- /src/sizeflags.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __SIZES_H__ 10 | #define __SIZES_H__ 11 | 12 | #define ALIGN_SIZE_1M 1048576 13 | #define ALIGN_SIZE_2M (2 * ALIGN_SIZE_1M) 14 | #define ALIGN_SIZE_4M (4 * ALIGN_SIZE_1M) 15 | #define ALIGN_SIZE_8M (8 * ALIGN_SIZE_1M) 16 | 17 | int size_to_max_hosts(int sector_size, int align_size); 18 | int sector_size_to_align_size_old(int sector_size); 19 | const char *align_size_debug_str(int align_size); 20 | 21 | uint32_t leader_align_flag_from_size(int align_size); 22 | int leader_align_size_from_flag(uint32_t flags); 23 | 24 | uint32_t rindex_header_align_flag_from_size(int align_size); 25 | int rindex_header_align_size_from_flag(uint32_t flags); 26 | 27 | int sanlk_lsf_sector_flag_to_size(uint32_t flags); 28 | uint32_t sanlk_lsf_sector_size_to_flag(int sector_size); 29 | int sanlk_lsf_align_flag_to_size(uint32_t flags); 30 | uint32_t sanlk_lsf_align_size_to_flag(int align_size); 31 | void sanlk_lsf_sector_flags_clear(uint32_t *flags); 32 | void sanlk_lsf_align_flags_clear(uint32_t *flags); 33 | 34 | int sanlk_res_sector_flag_to_size(uint32_t flags); 35 | uint32_t sanlk_res_sector_size_to_flag(int sector_size); 36 | int sanlk_res_align_flag_to_size(uint32_t flags); 37 | uint32_t sanlk_res_align_size_to_flag(int align_size); 38 | void sanlk_res_sector_flags_clear(uint32_t *flags); 39 | void sanlk_res_align_flags_clear(uint32_t *flags); 40 | 41 | int sanlk_rif_sector_flag_to_size(uint32_t flags); 42 | uint32_t sanlk_rif_sector_size_to_flag(int sector_size); 43 | int sanlk_rif_align_flag_to_size(uint32_t flags); 44 | uint32_t sanlk_rif_align_size_to_flag(int align_size); 45 | 46 | int sizes_from_flags(uint32_t flags, int *sector_size, int *align_size, int *max_hosts, const char *kind); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /tests/sanlk_rename.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "sanlock.h" 20 | #include "sanlock_resource.h" 21 | 22 | /* gcc with -lsanlock */ 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | char rd[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)]; 27 | char rd2[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)]; 28 | struct sanlk_resource *res; 29 | struct sanlk_resource *res2; 30 | struct sanlk_resource **res_args; 31 | int fd, rv; 32 | 33 | if (argc < 6) { 34 | printf("acquire with old name, release with new name\n"); 35 | printf("sanlk_rename \n"); 36 | return -1; 37 | } 38 | 39 | res_args = malloc(2 * sizeof(struct sanlk_resource *)); 40 | 41 | memset(rd, 0, sizeof(rd)); 42 | memset(rd2, 0, sizeof(rd2)); 43 | 44 | res = (struct sanlk_resource *)&rd; 45 | res2 = (struct sanlk_resource *)&rd2; 46 | 47 | res_args[0] = res; 48 | res_args[1] = res2; 49 | 50 | strcpy(res->lockspace_name, argv[1]); 51 | strcpy(res->name, argv[2]); 52 | strcpy(res2->name, argv[3]); 53 | res->num_disks = 1; 54 | strcpy(res->disks[0].path, argv[4]); 55 | res->disks[0].offset = atoi(argv[5]); 56 | 57 | fd = sanlock_register(); 58 | if (fd < 0) { 59 | fprintf(stderr, "register error %d\n", fd); 60 | return -1; 61 | } 62 | 63 | rv = sanlock_acquire(fd, -1, 0, 1, &res, NULL); 64 | if (rv < 0) { 65 | fprintf(stderr, "acquire error %d\n", rv); 66 | return -1; 67 | } 68 | 69 | rv = sanlock_release(fd, -1, SANLK_REL_RENAME, 2, res_args); 70 | if (rv < 0) { 71 | fprintf(stderr, "release error %d\n", rv); 72 | return -1; 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/ondisk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #ifndef __ONDISK_H__ 11 | #define __ONDISK_H__ 12 | 13 | #include 14 | #include 15 | 16 | /* 17 | * sanlock ondisk format is little endian. 18 | */ 19 | 20 | #if __BYTE_ORDER == __BIG_ENDIAN 21 | #define le16_to_cpu(x) (bswap_16((x))) 22 | #define le32_to_cpu(x) (bswap_32((x))) 23 | #define le64_to_cpu(x) (bswap_64((x))) 24 | #define cpu_to_le16(x) (bswap_16((x))) 25 | #define cpu_to_le32(x) (bswap_32((x))) 26 | #define cpu_to_le64(x) (bswap_64((x))) 27 | #endif 28 | 29 | #if __BYTE_ORDER == __LITTLE_ENDIAN 30 | #define le16_to_cpu(x) (x) 31 | #define le32_to_cpu(x) (x) 32 | #define le64_to_cpu(x) (x) 33 | #define cpu_to_le16(x) (x) 34 | #define cpu_to_le32(x) (x) 35 | #define cpu_to_le64(x) (x) 36 | #endif 37 | 38 | void magic_in(char *end, uint32_t *magic); 39 | void leader_record_in(struct leader_record *end, struct leader_record *lr); 40 | void leader_record_out(struct leader_record *lr, struct leader_record *end); 41 | void request_record_in(struct request_record *end, struct request_record *rr); 42 | void request_record_out(struct request_record *rr, struct request_record *end); 43 | void paxos_dblock_in(struct paxos_dblock *end, struct paxos_dblock *pd); 44 | void paxos_dblock_out(struct paxos_dblock *pd, struct paxos_dblock *end); 45 | void mode_block_in(struct mode_block *end, struct mode_block *mb); 46 | void mode_block_out(struct mode_block *mb, struct mode_block *end); 47 | void rindex_header_in(struct rindex_header *end, struct rindex_header *rh); 48 | void rindex_header_out(struct rindex_header *rh, struct rindex_header *end); 49 | void rindex_entry_in(struct rindex_entry *end, struct rindex_entry *re); 50 | void rindex_entry_out(struct rindex_entry *re, struct rindex_entry *end); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /reset/sanlk-reset.8: -------------------------------------------------------------------------------- 1 | .TH SANLK-RESET 8 2014-08-14 2 | 3 | .SH NAME 4 | sanlk-reset \- host reset program 5 | 6 | .SH SYNOPSIS 7 | .B sanlk\-reset 8 | [OPTIONS] 9 | .I action 10 | .IR lockspace_name " ..." 11 | 12 | .SH DESCRIPTION 13 | 14 | The sanlk\-reset program sets events in specified sanlock lockspaces. 15 | Events are defined to cause sanlk\-resetd on another host to: 16 | .br 17 | - use wdmd/watchdog to reset the host 18 | .br 19 | - use /proc/sysrq\-trigger to reboot the host 20 | 21 | Both hosts must be operational and have continued access to a common 22 | lockspace for the reset request to succeed. After setting the event, the 23 | sanlk\-reset program monitors the host status in the sanlock lockspace 24 | until the target host is dead. 25 | 26 | The sanlk\-reset program can also be run on the same host as sanlk\-resetd 27 | to update which lockspaces the local sanlk\-resetd is watching for events. 28 | 29 | .SH OPTIONS 30 | .TP 31 | .B \-\-version, \-V 32 | Print version. 33 | 34 | .TP 35 | .B \-\-help, \-h 36 | Print usage. 37 | 38 | .SS Reset another host 39 | 40 | The event is set in each lockspace specified. The target host may have a 41 | different host id in each lockspace. 42 | 43 | .B sanlk\-reset reset 44 | .IR lockspace_name:host_id " ..." 45 | 46 | .TP 47 | .BI "\-\-host\-id, \-i " num 48 | Host id to reset. (Use only with single lockspace name.) 49 | 50 | .TP 51 | .BI "\-\-generation, \-g " num 52 | Generation of host. (Use only with single lockspace name.) 53 | 54 | .TP 55 | .B \-\-sysrq\-reboot, \-b 0|1 56 | Enable/Disable (1/0) use of /proc/sysrq\-trigger to reboot. 57 | 58 | .TP 59 | .B \-\-resource\-mode, \-R 0|1 60 | Resource leases are used (1) or not used (0) to protect storage. 61 | 62 | .TP 63 | .B \-\-native\-timeout, \-t " num 64 | Disable native timeout by setting to 0. 65 | 66 | .SS Update the local sanlk\-resetd 67 | 68 | \& 69 | 70 | to watch new lockspaces for reset events: 71 | 72 | .B sanlk\-reset reg 73 | .IR lockspace_name " ..." 74 | 75 | to not watch lockspaces for reset events: 76 | 77 | .B sanlk\-reset end 78 | .IR lockspace_name " ..." 79 | 80 | to clear all lockspaces being watched: 81 | 82 | .B sanlk\-reset clear all 83 | 84 | .SH SEE ALSO 85 | .BR sanlk\-resetd (8) 86 | .BR sanlock (8) 87 | .BR wdmd (8) 88 | -------------------------------------------------------------------------------- /wdmd/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 Red Hat, Inc. All rights reserved. 2 | # 3 | # This copyrighted material is made available to anyone wishing to use, 4 | # modify, copy, or redistribute it subject to the terms and conditions 5 | # of the GNU General Public License v2 or (at your option) any later version. 6 | 7 | include ../common.mk 8 | 9 | CMD_TARGET = wdmd 10 | LIB_TARGET = libwdmd 11 | HEADER_TARGET = wdmd.h 12 | MAN_TARGET = wdmd.8 13 | TEST_TARGET = wdmd_client 14 | 15 | SOMAJOR=1 16 | SOMINOR=0 17 | SHLIB_TARGET = $(LIB_TARGET).so.$(SOMAJOR).$(SOMINOR) 18 | 19 | CMD_SOURCE = main.c wdmd_sock.c 20 | 21 | LIB_SOURCE = client.c wdmd_sock.c 22 | 23 | TEST_SOURCE = wdmd_client.c 24 | 25 | VER=$(shell cat ../VERSION) 26 | CFLAGS += -DVERSION=\"$(VER)\" 27 | 28 | CMD_CFLAGS = $(CFLAGS) -fPIE -DPIE 29 | LIB_CFLAGS = $(CFLAGS) -fPIC 30 | 31 | CMD_LDFLAGS = $(LDFLAGS) -Wl,-z,relro -pie 32 | LIB_LDFLAGS = $(LDFLAGS) -Wl,-z,relro -pie 33 | 34 | CMD_LDADD = -lwdmd -lrt 35 | 36 | TEST_LDFLAGS = $(LDFLAGS) -Wl,-z,relro -pie -lwdmd 37 | 38 | all: $(SHLIB_TARGET) $(CMD_TARGET) 39 | 40 | $(SHLIB_TARGET): $(LIB_SOURCE) 41 | $(CC) $(LIB_CFLAGS) $(LIB_LDFLAGS) -shared -o $@ -Wl,-soname=$(LIB_TARGET).so.$(SOMAJOR) $^ 42 | ln -sf $(SHLIB_TARGET) $(LIB_TARGET).so 43 | ln -sf $(SHLIB_TARGET) $(LIB_TARGET).so.$(SOMAJOR) 44 | 45 | $(CMD_TARGET): $(SHLIB_TARGET) $(CMD_SOURCE) 46 | $(CC) $(CMD_CFLAGS) $(CMD_LDFLAGS) $(CMD_SOURCE) $(CMD_LDADD) -o $@ -L. 47 | 48 | $(TEST_TARGET): $(SHLIB_TARGET) $(TEST_SOURCE) 49 | $(CC) $(CMD_CFLAGS) $(TEST_LDFLAGS) $(TEST_SOURCE) $(CMD_LDADD) -o $@ -L. 50 | 51 | clean: 52 | rm -f *.o *.so *.so.* $(CMD_TARGET) $(TEST_TARGET) 53 | 54 | 55 | INSTALL=$(shell which install) 56 | 57 | DESTDIR= 58 | BINDIR=/usr/sbin 59 | LIBDIR=/usr/lib64 60 | HEADIR=/usr/include 61 | MANDIR=/usr/share/man 62 | 63 | .PHONY: install 64 | install: all 65 | $(INSTALL) -d $(DESTDIR)/$(BINDIR) 66 | $(INSTALL) -d $(DESTDIR)/$(LIBDIR) 67 | $(INSTALL) -d $(DESTDIR)/$(HEADIR) 68 | $(INSTALL) -d $(DESTDIR)/$(MANDIR)/man8 69 | $(INSTALL) -c -m 755 $(CMD_TARGET) $(DESTDIR)/$(BINDIR) 70 | $(INSTALL) -c -m 755 $(SHLIB_TARGET) $(DESTDIR)/$(LIBDIR) 71 | cp -a $(LIB_TARGET).so $(DESTDIR)/$(LIBDIR) 72 | cp -a $(LIB_TARGET).so.$(SOMAJOR) $(DESTDIR)/$(LIBDIR) 73 | $(INSTALL) -c -m 644 $(HEADER_TARGET) $(DESTDIR)/$(HEADIR) 74 | $(INSTALL) -m 644 $(MAN_TARGET) $(DESTDIR)/$(MANDIR)/man8 75 | -------------------------------------------------------------------------------- /src/diskio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __DISKIO_H__ 10 | #define __DISKIO_H__ 11 | 12 | void offset_to_str(unsigned long long offset, int buflen, char *off_str); 13 | 14 | void close_disks(struct sync_disk *disks, int num_disks); 15 | int open_disk(struct sync_disk *disks); 16 | int open_disks(struct sync_disk *disks, int num_disks); 17 | int open_disks_fd(struct sync_disk *disks, int num_disks); 18 | int majority_disks(int num_disks, int num); 19 | 20 | int read_sysfs_size(const char *path, const char *name, unsigned int *val); 21 | int set_max_sectors_kb(struct sync_disk *disk, uint32_t max_sectors_kb); 22 | int get_max_sectors_kb(struct sync_disk *disk, uint32_t *max_sectors_kb); 23 | int read_sysfs_uint(char *path, unsigned int *val); 24 | int write_sysfs_uint(char *path, unsigned int val); 25 | 26 | /* 27 | * iobuf functions require the caller to allocate iobuf using posix_memalign 28 | * and pass it into the function 29 | */ 30 | 31 | int write_iobuf(int fd, uint64_t offset, char *iobuf, int iobuf_len, 32 | struct task *task, int ioto, int *wr_ms); 33 | 34 | int read_iobuf(int fd, uint64_t offset, char *iobuf, int iobuf_len, 35 | struct task *task, int ioto, int *rd_ms); 36 | 37 | int read_iobuf_reap(int fd, uint64_t offset, char *iobuf, int iobuf_len, 38 | struct task *task, uint32_t ioto_msec); 39 | 40 | /* 41 | * sector functions allocate an iobuf themselves, copy into it for read, use it 42 | * for io, copy out of it for write, and free it 43 | */ 44 | 45 | int write_sector(const struct sync_disk *disk, int sector_size, uint64_t sector_nr, 46 | const char *data, int data_len, 47 | struct task *task, int ioto, 48 | const char *blktype); 49 | 50 | int write_sectors(const struct sync_disk *disk, int sector_size, uint64_t sector_nr, 51 | uint32_t sector_count, const char *data, int data_len, 52 | struct task *task, int ioto, 53 | const char *blktype); 54 | 55 | int read_sectors(const struct sync_disk *disk, int sector_size, uint64_t sector_nr, 56 | uint32_t sector_count, char *data, int data_len, 57 | struct task *task, int ioto, 58 | const char *blktype); 59 | #endif 60 | -------------------------------------------------------------------------------- /src/sanlock_rv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #ifndef __SANLOCK_RV_H__ 11 | #define __SANLOCK_RV_H__ 12 | 13 | #define SANLK_OK 1 14 | #define SANLK_NONE 0 /* unused */ 15 | #define SANLK_ERROR -201 16 | #define SANLK_AIO_TIMEOUT -202 17 | #define SANLK_WD_ERROR -203 18 | 19 | /* run_ballot */ 20 | 21 | #define SANLK_DBLOCK_READ -210 22 | #define SANLK_DBLOCK_WRITE -211 23 | #define SANLK_DBLOCK_LVER -212 24 | #define SANLK_DBLOCK_MBAL -213 25 | #define SANLK_DBLOCK_CHECKSUM -214 26 | 27 | /* verify_leader, leader_read, leader_write (paxos or delta) 28 | (when adding to list, check if it should be a corrupt_result()) */ 29 | 30 | #define SANLK_LEADER_READ -220 31 | #define SANLK_LEADER_WRITE -221 32 | #define SANLK_LEADER_DIFF -222 33 | #define SANLK_LEADER_MAGIC -223 34 | #define SANLK_LEADER_VERSION -224 35 | #define SANLK_LEADER_SECTORSIZE -225 36 | #define SANLK_LEADER_LOCKSPACE -226 37 | #define SANLK_LEADER_RESOURCE -227 38 | #define SANLK_LEADER_NUMHOSTS -228 39 | #define SANLK_LEADER_CHECKSUM -229 40 | 41 | #define SANLK_ADDLS_SIZES -230 42 | #define SANLK_ADDLS_INVALID_HOSTID -231 43 | 44 | /* paxos_lease_acquire, paxos_lease_release */ 45 | 46 | #define SANLK_ACQUIRE_LVER -240 47 | #define SANLK_ACQUIRE_LOCKSPACE -241 48 | #define SANLK_ACQUIRE_IDDISK -242 49 | #define SANLK_ACQUIRE_IDLIVE -243 50 | #define SANLK_ACQUIRE_OWNED -244 51 | #define SANLK_ACQUIRE_OTHER -245 52 | #define SANLK_ACQUIRE_SHRETRY -246 53 | #define SANLK_ACQUIRE_OWNED_RETRY -247 54 | 55 | #define SANLK_RELEASE_LVER -250 56 | #define SANLK_RELEASE_OWNER -251 57 | 58 | /* delta_lease_renew, delta_lease_acquire */ 59 | 60 | #define SANLK_RENEW_OWNER -260 61 | #define SANLK_RENEW_DIFF -261 62 | #define SANLK_HOSTID_BUSY -262 63 | 64 | /* request_token */ 65 | 66 | #define SANLK_REQUEST_MAGIC -270 67 | #define SANLK_REQUEST_VERSION -271 68 | #define SANLK_REQUEST_OLD -272 69 | #define SANLK_REQUEST_LVER -273 70 | 71 | /* rindex ops */ 72 | #define SANLK_RINDEX_MAGIC -274 73 | #define SANLK_RINDEX_VERSION -275 74 | #define SANLK_RINDEX_LOCKSPACE -276 75 | #define SANLK_RINDEX_OFFSET -277 76 | #define SANLK_RINDEX_DIFF -278 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /tests/sanlk_client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "sanlock.h" 20 | #include "sanlock_resource.h" 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | char rd[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)]; 25 | char path[SANLK_HELPER_PATH_LEN]; 26 | char args[SANLK_HELPER_PATH_LEN]; 27 | struct sanlk_resource *res; 28 | time_t now, last; 29 | int sock, rv, i; 30 | 31 | if (argc < 6) { 32 | printf("sanlk_client \n"); 33 | return -1; 34 | } 35 | 36 | memset(rd, 0, sizeof(rd)); 37 | memset(path, 0, sizeof(path)); 38 | memset(args, 0, sizeof(args)); 39 | 40 | res = (struct sanlk_resource *)&rd; 41 | 42 | strcpy(res->lockspace_name, argv[1]); 43 | strcpy(res->name, argv[2]); 44 | res->num_disks = 1; 45 | strcpy(res->disks[0].path, argv[3]); 46 | res->disks[0].offset = atoi(argv[4]); 47 | 48 | strcpy(path, argv[5]); 49 | 50 | if (argc > 6) { 51 | for (i = 6; i < argc; i++) { 52 | strcat(args, argv[i]); 53 | strcat(args, " "); 54 | } 55 | } 56 | 57 | sock = sanlock_register(); 58 | if (sock < 0) { 59 | fprintf(stderr, "register error %d\n", sock); 60 | return -1; 61 | } 62 | 63 | if (!strcmp(path, "none")) 64 | goto acquire; 65 | 66 | rv = sanlock_killpath(sock, SANLK_KILLPATH_PID, path, args); 67 | if (rv < 0) { 68 | fprintf(stderr, "killpath error %d\n", rv); 69 | return -1; 70 | } 71 | 72 | acquire: 73 | rv = sanlock_acquire(sock, -1, 0, 1, &res, NULL); 74 | if (rv < 0) { 75 | fprintf(stderr, "acquire error %d\n", rv); 76 | return -1; 77 | } 78 | 79 | rv = sanlock_restrict(sock, SANLK_RESTRICT_ALL); 80 | if (rv < 0) { 81 | fprintf(stderr, "restrict error %d\n", rv); 82 | return -1; 83 | } 84 | 85 | printf("%d running\n", getpid()); 86 | 87 | last = time(NULL); 88 | while (1) { 89 | now = time(NULL); 90 | if (now - last > 2) 91 | printf("%d running (paused %llu sec)\n", 92 | getpid(), (unsigned long long)(now - last)); 93 | last = now; 94 | sleep(1); 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/lockfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "sanlock_internal.h" 28 | #include "log.h" 29 | #include "lockfile.h" 30 | 31 | int lockfile(const char *dir, const char *name, int uid, int gid) 32 | { 33 | char path[PATH_MAX]; 34 | char buf[16]; 35 | struct flock lock; 36 | mode_t old_umask; 37 | int fd, rv; 38 | 39 | /* Make rundir group writable, allowing creation of the lockfile when 40 | * starting as root. */ 41 | 42 | old_umask = umask(0002); 43 | rv = mkdir(dir, 0775); 44 | if (rv < 0 && errno != EEXIST) { 45 | umask(old_umask); 46 | return rv; 47 | } 48 | umask(old_umask); 49 | 50 | rv = chown(dir, uid, gid); 51 | if (rv < 0) { 52 | log_error("lockfile chown error %s: %s", 53 | dir, strerror(errno)); 54 | return rv; 55 | } 56 | 57 | snprintf(path, PATH_MAX, "%s/%s", dir, name); 58 | 59 | fd = open(path, O_CREAT|O_WRONLY|O_CLOEXEC, 0644); 60 | if (fd < 0) { 61 | log_error("lockfile open error %s: %s", 62 | path, strerror(errno)); 63 | return -1; 64 | } 65 | 66 | lock.l_type = F_WRLCK; 67 | lock.l_start = 0; 68 | lock.l_whence = SEEK_SET; 69 | lock.l_len = 0; 70 | 71 | rv = fcntl(fd, F_SETLK, &lock); 72 | if (rv < 0) { 73 | log_error("lockfile setlk error %s: %s", 74 | path, strerror(errno)); 75 | goto fail; 76 | } 77 | 78 | rv = ftruncate(fd, 0); 79 | if (rv < 0) { 80 | log_error("lockfile truncate error %s: %s", 81 | path, strerror(errno)); 82 | goto fail; 83 | } 84 | 85 | memset(buf, 0, sizeof(buf)); 86 | snprintf(buf, sizeof(buf), "%d\n", getpid()); 87 | 88 | rv = write(fd, buf, strlen(buf)); 89 | if (rv <= 0) { 90 | log_error("lockfile write error %s: %s", 91 | path, strerror(errno)); 92 | goto fail; 93 | } 94 | 95 | return fd; 96 | fail: 97 | close(fd); 98 | return -1; 99 | } 100 | -------------------------------------------------------------------------------- /tests/devcountn: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -le 3 ]; then 4 | echo "" 5 | echo "Start N devcount commands" 6 | echo "" 7 | echo "devcountn N init LOCKDEV_BASE COUNTDEV_BASE" 8 | echo "devcountn N rw COUNTDEV_BASE SEC1 SEC2 HOSTID" 9 | echo "devcountn N lock LOCKDEV_BASE rw COUNTDEV_BASE SEC1 SEC2 HOSTID" 10 | echo "devcountn N relock LOCKDEV_BASE rw COUNTDEV_BASE SEC1 SEC2 HOSTID" 11 | echo "devcountn N wrap LOCKDEV_BASE rw COUNTDEV_BASE SEC1 SEC2 HOSTID" 12 | echo "devcountn N migrate LOCKDEV_BASE rw COUNTDEV_BASE SEC1 SEC2 HOSTID MAXID" 13 | echo "devcountn N expire LOCKDEV_BASE rw COUNTDEV_BASE SEC1 SEC2 HOSTID" 14 | echo "" 15 | echo "devcount LOCKDEV1 rw COUNTDEV1 ..." 16 | echo "devcount LOCKDEV2 rw COUNTDEV2 ..." 17 | echo "devcount LOCKDEV3 rw COUNTDEV3 ..." 18 | echo ... 19 | echo "devcount LOCKDEVN rw COUNTDEVN ..." 20 | echo "" 21 | echo "Examples" 22 | echo "" 23 | echo "devcountn 3 init /dev/lock /dev/count" 24 | echo " devcount init /dev/lock1 /dev/count1" 25 | echo " devcount init /dev/lock2 /dev/count2" 26 | echo " devcount init /dev/lock3 /dev/count3" 27 | echo "" 28 | echo "devcountn 3 rw /dev/count 5 5 1" 29 | echo " devcount rw /dev/count1 5 5 1" 30 | echo " devcount rw /dev/count2 5 5 1" 31 | echo " devcount rw /dev/count3 5 5 1" 32 | echo "" 33 | echo "devcountn 3 lock /dev/lock rw /dev/count 5 5 1" 34 | echo " sanlock add_lockspace -s devcount:1:/dev/lock1:0" 35 | echo " (the add_lockspace command from each subsequent devcount will fail)" 36 | echo " devcount lock /dev/lock1 rw /dev/count1 5 5 1" 37 | echo " devcount lock /dev/lock2 rw /dev/count2 5 5 1" 38 | echo " devcount lock /dev/lock3 rw /dev/count3 5 5 1" 39 | echo "" 40 | exit 0 41 | fi 42 | 43 | num=$1 44 | cmd1=$2 45 | 46 | if [ "$cmd1" != "init" ]; then 47 | deva=$3 48 | cmd2=$4 49 | devb=$5 50 | sec1=$6 51 | sec2=$7 52 | hostid=$8 53 | maxid=$9 54 | 55 | i=1 56 | echo sanlock add_lockspace -s devcount:$hostid:$deva$i:0 57 | sanlock add_lockspace -s devcount:$hostid:$deva$i:0 58 | fi 59 | 60 | end=`expr $num - 1` 61 | for i in `seq 0 $end`; do 62 | if [ "$cmd1" == "init" ]; then 63 | deva=$3 64 | devb=$4 65 | echo ./devcount init $deva$i $devb$i 66 | ./devcount init $deva$i $devb$i 67 | elif [ "$cmd1" == "rw" ] || [ "$cmd1" == "wr" ]; then 68 | echo ./devcount $cmd1 $deva$i $sec1 $sec2 $hostid 69 | ./devcount $cmd1 $deva$i $sec1 $sec2 $hostid & 70 | else 71 | echo ./devcount $cmd1 $deva$i $cmd2 $devb$i $sec1 $sec2 $hostid $maxid 72 | ./devcount $cmd1 $deva$i $cmd2 $devb$i $sec1 $sec2 $hostid $maxid & 73 | fi 74 | done 75 | 76 | -------------------------------------------------------------------------------- /src/paxos_lease.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __PAXOS_LEASE_H__ 10 | #define __PAXOS_LEASE_H__ 11 | 12 | #define PAXOS_ACQUIRE_FORCE 0x00000001 13 | #define PAXOS_ACQUIRE_QUIET_FAIL 0x00000002 14 | #define PAXOS_ACQUIRE_SHARED 0x00000004 15 | #define PAXOS_ACQUIRE_OWNER_NOWAIT 0x00000008 16 | #define PAXOS_ACQUIRE_DEBUG_ALL 0x00000010 17 | 18 | uint32_t leader_checksum(struct leader_record *lr); 19 | 20 | uint32_t dblock_checksum(struct paxos_dblock *pd); 21 | 22 | int paxos_lease_leader_read(struct task *task, 23 | struct token *token, 24 | struct leader_record *leader_ret, 25 | const char *caller); 26 | 27 | int paxos_lease_acquire(struct task *task, 28 | struct token *token, 29 | uint32_t flags, 30 | struct leader_record *leader_ret, 31 | struct paxos_dblock *dblock_ret, 32 | uint64_t acquire_lver, 33 | int new_num_hosts); 34 | 35 | int paxos_lease_release(struct task *task, 36 | struct token *token, 37 | struct sanlk_resource *resrename, 38 | struct leader_record *leader_last, 39 | struct leader_record *leader_ret); 40 | 41 | int paxos_lease_init(struct task *task, 42 | struct token *token, 43 | int num_hosts, int write_clear); 44 | 45 | int paxos_lease_request_read(struct task *task, struct token *token, 46 | struct request_record *rr); 47 | 48 | int paxos_lease_request_write(struct task *task, struct token *token, 49 | struct request_record *rr); 50 | 51 | int paxos_read_resource(struct task *task, 52 | struct token *token, 53 | struct sanlk_resource *res); 54 | 55 | int paxos_read_buf(struct task *task, 56 | struct token *token, 57 | char **buf_out); 58 | 59 | int paxos_verify_leader(struct token *token, 60 | struct sync_disk *disk, 61 | struct leader_record *lr, 62 | uint32_t checksum, 63 | const char *caller); 64 | 65 | int paxos_erase_dblock(struct task *task, 66 | struct token *token, 67 | uint64_t host_id); 68 | 69 | int paxos_lease_leader_clobber(struct task *task, 70 | struct token *token, 71 | struct leader_record *leader, 72 | const char *caller); 73 | #endif 74 | -------------------------------------------------------------------------------- /init.d/sanlock: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # sanlock - SAN-based lock manager 4 | # 5 | # chkconfig: 2345 97 03 6 | # description: starts and stops sanlock daemon 7 | # 8 | 9 | 10 | ### BEGIN INIT INFO 11 | # Provides: sanlock 12 | # Required-Start: $time $syslog wdmd 13 | # Required-Stop: $syslog 14 | # Should-Start: 15 | # Should-Stop: 16 | # Default-Start: 2 3 4 5 17 | # Default-Stop: 0 1 6 18 | # Short-Description: starts and stops sanlock daemon 19 | # Description: starts and stops sanlock daemon 20 | ### END INIT INFO 21 | 22 | . /etc/rc.d/init.d/functions 23 | 24 | prog="sanlock" 25 | runfile="/run/$prog/$prog.pid" 26 | lockfile="/var/lock/subsys/$prog" 27 | exec="/usr/sbin/$prog" 28 | 29 | SANLOCKUSER="sanlock" 30 | SANLOCKOPTS="-U $SANLOCKUSER -G $SANLOCKUSER" 31 | 32 | [ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog 33 | 34 | start() { 35 | [ -x $exec ] || exit 5 36 | 37 | if [ ! -d /run/$prog ]; then 38 | install -d -o $SANLOCKUSER -g $SANLOCKUSER -m 775 /run/$prog 39 | [ -x /sbin/restorecon ] && restorecon /run/$prog 40 | fi 41 | 42 | echo -n $"Starting $prog: " 43 | daemon $prog daemon $SANLOCKOPTS 44 | retval=$? 45 | echo 46 | [ $retval -eq 0 ] && touch $lockfile 47 | return $retval 48 | } 49 | 50 | stop() { 51 | PID=$(pidofproc -p $runfile $prog) 52 | 53 | echo -n $"Sending stop signal $prog ($PID): " 54 | killproc -p $runfile $prog -TERM 55 | retval=$? 56 | echo 57 | 58 | if [ $retval -ne 0 ]; then 59 | return $retval 60 | fi 61 | 62 | echo -n $"Waiting for $prog ($PID) to stop:" 63 | 64 | timeout=10 65 | while checkpid $PID; do 66 | sleep 1 67 | timeout=$((timeout - 1)) 68 | if [ "$timeout" -le 0 ]; then 69 | failure; echo 70 | return 1 71 | fi 72 | done 73 | 74 | success; echo 75 | rm -f $lockfile 76 | return $retval 77 | } 78 | 79 | restart() { 80 | rh_status_q && stop 81 | start 82 | } 83 | 84 | reload() { 85 | restart 86 | } 87 | 88 | rh_status() { 89 | status $prog 90 | } 91 | 92 | rh_status_q() { 93 | rh_status >/dev/null 2>&1 94 | } 95 | 96 | case "$1" in 97 | start) 98 | rh_status_q && exit 0 99 | $1 100 | ;; 101 | stop) 102 | rh_status_q || exit 0 103 | $1 104 | ;; 105 | restart) 106 | $1 107 | ;; 108 | reload) 109 | rh_status_q || exit 7 110 | $1 111 | ;; 112 | force-reload) 113 | force_reload 114 | ;; 115 | status) 116 | rh_status 117 | ;; 118 | condrestart|try-restart) 119 | rh_status_q || exit 0 120 | restart 121 | ;; 122 | *) 123 | echo $"Usage $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" 124 | exit 2 125 | esac 126 | exit $? 127 | -------------------------------------------------------------------------------- /tests/sanlk_testr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "sanlock.h" 10 | #include "sanlock_admin.h" 11 | #include "sanlock_resource.h" 12 | 13 | void print_res(struct sanlk_resource *res) 14 | { 15 | int i; 16 | 17 | printf("struct fields: \"%s\" \"%s\"", res->lockspace_name, res->name); 18 | 19 | for (i = 0; i < res->num_disks; i++) { 20 | printf(" \"%s\" %llu", res->disks[i].path, 21 | (unsigned long long)res->disks[i].offset); 22 | } 23 | printf(" flags %x", res->flags); 24 | printf(" lver %llu\n", (unsigned long long)res->lver); 25 | } 26 | 27 | int main(int argc, char *argv[]) 28 | { 29 | struct sanlk_resource *res = NULL; 30 | struct sanlk_host *hosts = NULL; 31 | struct sanlk_host *owners = NULL; 32 | struct sanlk_host *host, *owner; 33 | int hosts_count = 0; 34 | int owners_count = 0; 35 | uint32_t test_flags = 0; 36 | int i, rv; 37 | 38 | if (argc < 2) { 39 | printf("%s RESOURCE\n", argv[0]); 40 | return 0; 41 | } 42 | 43 | rv = sanlock_str_to_res(argv[1], &res); 44 | if (rv < 0) { 45 | printf("str_to_res %d\n", rv); 46 | goto out; 47 | } 48 | 49 | rv = sanlock_get_hosts(res->lockspace_name, 0, &hosts, &hosts_count, 0); 50 | if (rv < 0) { 51 | printf("get_hosts %d\n", rv); 52 | goto out; 53 | } 54 | 55 | rv = sanlock_read_resource_owners(res, 0, &owners, &owners_count); 56 | if (rv < 0) { 57 | printf("read_resource_owners %d\n", rv); 58 | goto out; 59 | } 60 | 61 | rv = sanlock_test_resource_owners(res, 0, 62 | owners, owners_count, 63 | hosts, hosts_count, 64 | &test_flags); 65 | if (rv < 0) { 66 | printf("test_resource_owners %d\n", rv); 67 | goto out; 68 | } 69 | 70 | printf("lockspace hosts:\n"); 71 | 72 | host = hosts; 73 | for (i = 0; i < hosts_count; i++) { 74 | printf("host %llu gen %llu state %u\n", 75 | (unsigned long long)host->host_id, 76 | (unsigned long long)host->generation, 77 | host->flags & SANLK_HOST_MASK); 78 | host++; 79 | } 80 | 81 | printf("resource owners:\n"); 82 | 83 | owner = owners; 84 | for (i = 0; i < owners_count; i++) { 85 | printf("owner %llu gen %llu\n", 86 | (unsigned long long)owner->host_id, 87 | (unsigned long long)owner->generation); 88 | owner++; 89 | } 90 | 91 | printf("test_flags %x\n", test_flags); 92 | 93 | out: 94 | if (res) 95 | free(res); 96 | if (hosts) 97 | free(hosts); 98 | if (owners) 99 | free(owners); 100 | 101 | return 0; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __RESOURCE_H__ 10 | #define __RESOURCE_H__ 11 | 12 | /* 13 | * We mostly avoid holding resource_mutex and spaces_mutex at once. When they 14 | * are held at once, the order is spaces_mutex, then resource_mutex. 15 | */ 16 | 17 | /* locks resource_mutex */ 18 | void send_state_resources(int fd); 19 | 20 | /* locks resource_mutex */ 21 | int lockspace_is_used(struct sanlk_lockspace *ls); 22 | 23 | /* locks resource_mutex */ 24 | int resource_orphan_count(char *space_name); 25 | 26 | /* no locks */ 27 | void check_mode_block(struct token *token, uint64_t next_lver, int q, char *dblock); 28 | 29 | /* locks resource_mutex */ 30 | int convert_token(struct task *task, struct sanlk_resource *res, struct token *cl_token, uint32_t cmd_flags); 31 | 32 | /* locks resource_mutex */ 33 | int acquire_token(struct task *task, struct token *token, uint32_t cmd_flags, 34 | char *killpath, char *killargs); 35 | 36 | 37 | /* locks resource_mutex */ 38 | int release_token(struct task *task, struct token *token, 39 | struct sanlk_resource *resrename); 40 | 41 | /* locks resource_mutex */ 42 | void release_token_async(struct token *token); 43 | 44 | /* no locks */ 45 | int request_token(struct task *task, struct token *token, uint32_t force_mode, 46 | uint64_t *owner_id, int next_lver); 47 | 48 | /* locks resource_mutex */ 49 | int set_resource_examine(char *space_name, char *res_name); 50 | 51 | /* locks resource_mutex */ 52 | int res_set_lvb(struct sanlk_resource *res, char *lvb, int lvblen); 53 | 54 | /* locks resource_mutex */ 55 | int res_get_lvb(struct sanlk_resource *res, char **lvb_out, int *lvblen); 56 | 57 | /* no locks */ 58 | int read_resource_owners(struct task *task, struct token *token, 59 | struct sanlk_resource *res, 60 | char **send_buf, int *send_len, int *count); 61 | 62 | /* locks resource_mutex */ 63 | void rem_resources(void); 64 | 65 | /* locks resource_mutex */ 66 | int release_orphan(struct sanlk_resource *res); 67 | 68 | /* locks resource_mutex */ 69 | void purge_resource_orphans(char *space_name); 70 | void purge_resource_free(char *space_name); 71 | 72 | /* locks resource_mutex */ 73 | void add_host_event(uint32_t space_id, struct sanlk_host_event *he, 74 | uint64_t from_host_id, uint64_t from_generation); 75 | 76 | int setup_token_manager(void); 77 | void close_token_manager(void); 78 | 79 | #endif 80 | 81 | -------------------------------------------------------------------------------- /src/direct.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __DIRECT_H__ 10 | #define __DIRECT_H__ 11 | 12 | int direct_acquire(struct task *task, int io_timeout, 13 | struct sanlk_resource *res, 14 | int num_hosts, 15 | uint64_t local_host_id, 16 | uint64_t local_host_generation, 17 | struct leader_record *leader_ret); 18 | 19 | int direct_release(struct task *task, int io_timeout, 20 | struct sanlk_resource *res, 21 | struct leader_record *leader_ret); 22 | 23 | int direct_acquire_id(struct task *task, int io_timeout, 24 | struct sanlk_lockspace *ls, 25 | char *our_host_name); 26 | 27 | int direct_release_id(struct task *task, int io_timeout, 28 | struct sanlk_lockspace *ls); 29 | 30 | int direct_renew_id(struct task *task, int io_timeout, 31 | struct sanlk_lockspace *ls); 32 | 33 | int direct_align(struct sync_disk *disk); 34 | 35 | /* io_timeout is written in the leader record and used for the 36 | write call itself */ 37 | int direct_write_lockspace(struct task *task, struct sanlk_lockspace *ls, 38 | uint32_t io_timeout); 39 | 40 | int direct_write_resource(struct task *task, struct sanlk_resource *res, 41 | int num_hosts, int write_clear); 42 | 43 | int direct_read_leader(struct task *task, int io_timeout, 44 | struct sanlk_lockspace *ls, 45 | struct sanlk_resource *res, 46 | struct leader_record *leader_ret); 47 | 48 | int direct_write_leader(struct task *task, 49 | int io_timeout, 50 | struct sanlk_lockspace *ls, 51 | struct sanlk_resource *res, 52 | struct leader_record *leader); 53 | 54 | int direct_dump(struct task *task, char *dump_path, int force_mode); 55 | 56 | int direct_next_free(struct task *task, char *path); 57 | 58 | int direct_rindex_format(struct task *task, struct sanlk_rindex *ri); 59 | int direct_rindex_rebuild(struct task *task, struct sanlk_rindex *ri, 60 | uint32_t cmd_flags); 61 | int direct_rindex_lookup(struct task *task, struct sanlk_rindex *ri, 62 | struct sanlk_rentry *re, uint32_t cmd_flags); 63 | int direct_rindex_update(struct task *task, struct sanlk_rindex *ri, 64 | struct sanlk_rentry *re, uint32_t cmd_flags); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /tests/sanlk_events.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "sanlock.h" 20 | #include "sanlock_admin.h" 21 | #include "../src/sanlock_sock.h" 22 | 23 | static int prog_stop; 24 | 25 | static void sigterm_handler(int sig) 26 | { 27 | if (sig == SIGTERM) 28 | prog_stop = 1; 29 | } 30 | 31 | int main(int argc, char *argv[]) 32 | { 33 | struct sigaction act; 34 | struct sanlk_host_event he; 35 | struct pollfd pollfd; 36 | uint64_t from_host, from_gen; 37 | char *ls_name; 38 | int fd, rv; 39 | 40 | if (argc < 2) { 41 | printf("sanlk_events \n"); 42 | return -1; 43 | } 44 | 45 | memset(&act, 0, sizeof(act)); 46 | act.sa_handler = sigterm_handler; 47 | sigaction(SIGTERM, &act, NULL); 48 | 49 | ls_name = argv[1]; 50 | 51 | printf("reg_event %s\n", ls_name); 52 | 53 | fd = sanlock_reg_event(ls_name, &he, 0); 54 | if (fd < 0) { 55 | printf("reg error %d\n", fd); 56 | return -1; 57 | } 58 | 59 | memset(&pollfd, 0, sizeof(pollfd)); 60 | pollfd.fd = fd; 61 | pollfd.events = POLLIN; 62 | 63 | while (1) { 64 | rv = poll(&pollfd, 1, 1000); 65 | if (rv == -1 && errno == EINTR) 66 | continue; 67 | 68 | if (prog_stop) 69 | break; 70 | 71 | if (rv < 0) { 72 | printf("poll error %d\n", rv); 73 | break; 74 | } 75 | 76 | if (pollfd.revents & POLLIN) { 77 | while (1) { 78 | rv = sanlock_get_event(fd, 0, &he, &from_host, &from_gen); 79 | if (rv == -EAGAIN) { 80 | /* no more events */ 81 | break; 82 | } 83 | if (rv < 0) { 84 | printf("get_event error %d\n", rv); 85 | break; 86 | } 87 | 88 | printf("get_event host_id %llu generation %llu event 0x%llx data 0x%llx from %llu %llu\n", 89 | (unsigned long long)he.host_id, 90 | (unsigned long long)he.generation, 91 | (unsigned long long)he.event, 92 | (unsigned long long)he.data, 93 | (unsigned long long)from_host, 94 | (unsigned long long)from_gen); 95 | } 96 | } 97 | 98 | if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { 99 | printf("poll revents %x\n", pollfd.revents); 100 | break; 101 | } 102 | } 103 | 104 | printf("end_event %s\n", ls_name); 105 | sanlock_end_event(fd, ls_name, 0); 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /README.dev: -------------------------------------------------------------------------------- 1 | Prerequisites 2 | ============= 3 | 4 | For Fedora/CentOS install the following packages: 5 | 6 | $ sudo yum install -y gcc make libaio-devel libblkid-devel libuuid-devel 7 | 8 | For Ubuntu/Debian install the following packages: 9 | 10 | $ sudo apt install -y gcc make libaio-dev libblkid-dev uuid-dev 11 | 12 | 13 | How to test sanlock 14 | =================== 15 | 16 | To run the python based tests, you need tox. The best way to install a 17 | recent version is to use pip: 18 | 19 | $ pip install tox 20 | 21 | To run the tests with python 2.7 and 3.6: 22 | 23 | $ tox 24 | 25 | Note: python 3.6 tests will fail now, since sanlock extension module needs 26 | changes to compile on python 3. 27 | 28 | To run only python 2.7: 29 | 30 | $ tox -e py27 31 | 32 | To run only test from some modules: 33 | 34 | $ tox tests/daemon_test.py 35 | 36 | To run only tests matching the substring "foo": 37 | 38 | $ tox -- -k foo 39 | 40 | To run basic lint and style check: 41 | 42 | $ tox -e flake8 43 | 44 | Sometimes when debugging failing tests verbose mode is useful. You can 45 | enable it using: 46 | 47 | $ tox -e py36 tests/python_test.py -- -vv 48 | 49 | Or using environment variable: 50 | 51 | export PYTEST_ADDOPTS=-vv 52 | 53 | 54 | Testing 4K support 55 | ================== 56 | 57 | To enable the 4k tests, you need to have userstorage installed. 58 | First, you need to create a virtual environment 59 | (https://docs.python.org/3/library/venv.html), and then install 60 | the userstorage library from the requirements.txt. 61 | This only needs to be done once: 62 | 63 | $ python3 -m venv ~/.venv/sanlock 64 | $ source ~/.venv/sanlock/bin/activate 65 | $ pip install --upgrade pip 66 | $ pip install -r requirements.txt 67 | $ deactivate 68 | 69 | Before running the tests, you need to enter the virtual environment: 70 | 71 | $ source ~/.venv/sanlock/bin/activate 72 | 73 | The shell prompt will change to show the virtual environment name: 74 | 75 | (sanlock) [user@hostname sanlock]$ 76 | 77 | Then, you just need to setup 4k storage for the tests: 78 | 79 | $ userstorage create tests/storage.py 80 | 81 | This creates two loop devices with 4k sector size; one for testing sanlock with 82 | 4k block device, and the other for testing with a filesystem backed by a 4k 83 | block device. 84 | 85 | To teardown the storage: 86 | 87 | $ userstorage delete tests/storage.py 88 | 89 | The script unmounts the filesystem and detaches the loop devices. 90 | 91 | The storage helper script uses sudo to perform privileged operations. The best 92 | way to use it is to setup the environment once at the start of the session, and 93 | teardown when you finish. 94 | 95 | To deactivate the virtual environment: 96 | 97 | $ deactivate 98 | -------------------------------------------------------------------------------- /src/delta_lease.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __DELTA_LEASE_H__ 10 | #define __DELTA_LEASE_H__ 11 | 12 | int delta_lease_leader_read(struct task *task, 13 | int sector_size, 14 | int io_timeout, 15 | struct sync_disk *disk, 16 | char *space_name, 17 | uint64_t host_id, 18 | struct leader_record *leader_ret, 19 | const char *caller); 20 | 21 | int delta_lease_acquire(struct task *task, 22 | struct space *sp, 23 | struct sync_disk *disk, 24 | char *space_name, 25 | char *our_host_name, 26 | uint64_t host_id, 27 | struct leader_record *leader_ret); 28 | 29 | int delta_lease_renew(struct task *task, 30 | struct space *sp, 31 | struct sync_disk *disk, 32 | char *space_name, 33 | char *bitmap, 34 | struct delta_extra *extra, 35 | int prev_result, 36 | int *read_result, 37 | int log_renewal_level, 38 | struct leader_record *leader_last, 39 | struct leader_record *leader_ret, 40 | int *rd_ms, int *wr_ms); 41 | 42 | int delta_lease_release(struct task *task, 43 | struct space *sp, 44 | struct sync_disk *disk, 45 | char *space_name GNUC_UNUSED, 46 | struct leader_record *leader_last, 47 | struct leader_record *leader_ret); 48 | 49 | int delta_lease_init(struct task *task, 50 | struct sanlk_lockspace *ls, 51 | int io_timeout, 52 | struct sync_disk *disk); 53 | 54 | int delta_read_lockspace(struct task *task, 55 | struct sync_disk *disk, 56 | int sector_size_hint, 57 | int align_size_hint, 58 | uint64_t host_id, 59 | struct sanlk_lockspace *ls, 60 | int io_timeout, 61 | int *io_timeout_ret); 62 | 63 | int delta_read_lockspace_sizes(struct task *task, 64 | struct sync_disk *disk, 65 | int io_timeout, 66 | int *sector_size, 67 | int *align_size); 68 | 69 | int delta_lease_leader_clobber(struct task *task, int io_timeout, 70 | struct sync_disk *disk, 71 | uint64_t host_id, 72 | struct leader_record *leader, 73 | const char *caller); 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /python/example.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 Red Hat, Inc. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | 8 | from __future__ import print_function 9 | 10 | import pwd 11 | import grp 12 | import os 13 | import time 14 | import signal 15 | import tempfile 16 | import sanlock 17 | 18 | HOST_ID = 1 19 | LOCKSPACE_NAME = "lockspace1" 20 | RESOURCE_NAME = "resource1" 21 | 22 | 23 | def sigTermHandler(): 24 | print("SIGTERM signal received") 25 | 26 | 27 | def main(): 28 | signal.signal(signal.SIGTERM, sigTermHandler) 29 | 30 | print("Creating the sanlock disk") 31 | fd, disk = tempfile.mkstemp() 32 | os.close(fd) 33 | 34 | os.chown( 35 | disk, pwd.getpwnam("sanlock").pw_uid, grp.getgrnam("sanlock").gr_gid) 36 | offset = sanlock.get_alignment(disk) 37 | 38 | SNLK_DISKS = [(disk, offset)] 39 | 40 | print("Registering to sanlock") 41 | fd = sanlock.register() 42 | 43 | print("Initializing '%s'" % (LOCKSPACE_NAME,)) 44 | sanlock.write_lockspace(LOCKSPACE_NAME, disk, align=1048576, sector=512) 45 | 46 | print("Initializing '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME)) 47 | sanlock.write_resource( 48 | LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, align=1048576, sector=512) 49 | 50 | print("Acquiring the id '%i' on '%s'" % (HOST_ID, LOCKSPACE_NAME)) 51 | sanlock.add_lockspace(LOCKSPACE_NAME, HOST_ID, disk) 52 | 53 | try: 54 | print("Acquiring '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME)) 55 | sanlock.acquire( 56 | LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd, version=0) 57 | 58 | while True: 59 | print("Trying to get lockspace '%s' hosts" % LOCKSPACE_NAME) 60 | try: 61 | hosts_list = sanlock.get_hosts(LOCKSPACE_NAME) 62 | except sanlock.SanlockException as e: 63 | if e.errno != os.errno.EAGAIN: 64 | raise 65 | else: 66 | print("Lockspace '%s' hosts: " % LOCKSPACE_NAME, hosts_list) 67 | break 68 | time.sleep(5) 69 | 70 | owners = sanlock.read_resource_owners( 71 | LOCKSPACE_NAME, 72 | RESOURCE_NAME, 73 | SNLK_DISKS, 74 | align=1048576, 75 | sector=512) 76 | print("Resource '%s' owners: %s" % (RESOURCE_NAME, owners)) 77 | 78 | print("Releasing '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME)) 79 | sanlock.release(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd) 80 | except Exception as e: 81 | print("Exception: ", e) 82 | finally: 83 | print("Releasing the id '%i' on '%s'" % (HOST_ID, LOCKSPACE_NAME)) 84 | sanlock.rem_lockspace(LOCKSPACE_NAME, HOST_ID, disk) 85 | 86 | print("Removing the sanlock disk") 87 | os.remove(disk) 88 | 89 | 90 | if __name__ == '__main__': 91 | main() 92 | -------------------------------------------------------------------------------- /tests/sanlk_lvb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "sanlock.h" 20 | #include "sanlock_resource.h" 21 | 22 | /* gcc with -lsanlock */ 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | char rd[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)]; 27 | struct sanlk_resource *res; 28 | char lvb[512]; 29 | char *filename; 30 | char *act; 31 | FILE *fp; 32 | int fd, rv; 33 | int set = 0, get = 0; 34 | 35 | memset(lvb, 0, sizeof(lvb)); 36 | 37 | if (argc < 7) { 38 | printf("read file, write it to lvb:\n"); 39 | printf("sanlk_lvb set \n"); 40 | printf("\n"); 41 | printf("read lvb, write it to file:\n"); 42 | printf("sanlk_lvb get \n"); 43 | return -1; 44 | } 45 | 46 | memset(rd, 0, sizeof(rd)); 47 | 48 | res = (struct sanlk_resource *)&rd; 49 | 50 | act = argv[1]; 51 | strcpy(res->lockspace_name, argv[2]); 52 | strcpy(res->name, argv[3]); 53 | res->num_disks = 1; 54 | strcpy(res->disks[0].path, argv[4]); 55 | res->disks[0].offset = atoi(argv[5]); 56 | filename = argv[6]; 57 | 58 | if (!strcmp(act, "set")) { 59 | set = 1; 60 | fp = fopen(filename, "r"); 61 | } else if (!strcmp(act, "get")) { 62 | get = 1; 63 | fp = fopen(filename, "w"); 64 | } else { 65 | printf("bad action %s\n", act); 66 | return -1; 67 | } 68 | 69 | if (!fp) { 70 | printf("fopen failed %s\n", strerror(errno)); 71 | return -1; 72 | } 73 | 74 | fd = sanlock_register(); 75 | if (fd < 0) { 76 | printf("register error %d\n", fd); 77 | return -1; 78 | } 79 | 80 | rv = sanlock_acquire(fd, -1, SANLK_ACQUIRE_LVB, 1, &res, NULL); 81 | if (rv < 0) { 82 | printf("acquire error %d\n", rv); 83 | return -1; 84 | } 85 | 86 | if (get) { 87 | rv = sanlock_get_lvb(0, res, lvb, sizeof(lvb)); 88 | if (rv < 0) { 89 | printf("get_lvb error %d\n", rv); 90 | return -1; 91 | } 92 | 93 | fwrite(lvb, sizeof(lvb), 1, fp); 94 | if (ferror(fp)) { 95 | printf("fwrite error\n"); 96 | return -1; 97 | } 98 | 99 | } 100 | 101 | if (set) { 102 | fread(lvb, sizeof(lvb), 1, fp); 103 | if (ferror(fp)) { 104 | printf("fread error\n"); 105 | return -1; 106 | } 107 | 108 | rv = sanlock_set_lvb(0, res, lvb, sizeof(lvb)); 109 | if (rv < 0) { 110 | printf("set_lvb error %d\n", rv); 111 | return -1; 112 | } 113 | } 114 | 115 | fclose(fp); 116 | 117 | rv = sanlock_release(fd, -1, 0, 1, &res); 118 | if (rv < 0) { 119 | fprintf(stderr, "release error %d\n", rv); 120 | return -1; 121 | } 122 | 123 | return 0; 124 | } 125 | 126 | -------------------------------------------------------------------------------- /src/sanlock_sock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #ifndef __SANLOCK_SOCK_H__ 11 | #define __SANLOCK_SOCK_H__ 12 | 13 | #define SANLK_SOCKET_NAME "sanlock.sock" 14 | 15 | #define SM_MAGIC 0x04282010 16 | #define SM_PROTO 0x00000001 17 | 18 | #define SM_CB_PROTO 0x00000001 19 | 20 | #define MAX_CLIENT_MSG (1024 * 1024) /* TODO: this is random */ 21 | 22 | enum { 23 | SM_CMD_REGISTER = 1, 24 | SM_CMD_ADD_LOCKSPACE = 2, 25 | SM_CMD_REM_LOCKSPACE = 3, 26 | SM_CMD_SHUTDOWN = 4, 27 | SM_CMD_STATUS = 5, 28 | SM_CMD_LOG_DUMP = 6, 29 | SM_CMD_ACQUIRE = 7, 30 | SM_CMD_RELEASE = 8, 31 | SM_CMD_INQUIRE = 9, 32 | SM_CMD_RESTRICT = 10, 33 | SM_CMD_REQUEST = 11, 34 | SM_CMD_ALIGN = 12, 35 | SM_CMD_EXAMINE_LOCKSPACE = 13, 36 | SM_CMD_EXAMINE_RESOURCE = 14, 37 | SM_CMD_HOST_STATUS = 15, 38 | SM_CMD_INQ_LOCKSPACE = 16, 39 | SM_CMD_KILLPATH = 17, 40 | SM_CMD_WRITE_LOCKSPACE = 18, 41 | SM_CMD_WRITE_RESOURCE = 19, 42 | SM_CMD_READ_LOCKSPACE = 20, 43 | SM_CMD_READ_RESOURCE = 21, 44 | SM_CMD_GET_LOCKSPACES = 22, 45 | SM_CMD_GET_HOSTS = 23, 46 | SM_CMD_READ_RESOURCE_OWNERS = 24, 47 | SM_CMD_SET_LVB = 25, 48 | SM_CMD_GET_LVB = 26, 49 | SM_CMD_CONVERT = 27, 50 | SM_CMD_VERSION = 28, 51 | SM_CMD_SHUTDOWN_WAIT = 29, 52 | SM_CMD_REG_EVENT = 30, 53 | SM_CMD_END_EVENT = 31, 54 | SM_CMD_SET_EVENT = 32, 55 | SM_CMD_SET_CONFIG = 33, 56 | SM_CMD_RENEWAL = 34, 57 | SM_CMD_FORMAT_RINDEX = 35, 58 | SM_CMD_UPDATE_RINDEX = 36, 59 | SM_CMD_LOOKUP_RINDEX = 37, 60 | SM_CMD_CREATE_RESOURCE = 38, 61 | SM_CMD_DELETE_RESOURCE = 39, 62 | SM_CMD_REBUILD_RINDEX = 40, 63 | }; 64 | 65 | #define SM_CB_GET_EVENT 1 66 | 67 | struct sm_header { 68 | uint32_t magic; 69 | uint32_t version; 70 | uint32_t cmd; /* SM_CMD_ */ 71 | uint32_t cmd_flags; 72 | uint32_t length; 73 | uint32_t seq; 74 | uint32_t data; 75 | uint32_t data2; 76 | }; 77 | 78 | #define SANLK_STATE_MAXSTR 4096 79 | 80 | #define SANLK_STATE_DAEMON 1 81 | #define SANLK_STATE_CLIENT 2 82 | #define SANLK_STATE_LOCKSPACE 3 83 | #define SANLK_STATE_RESOURCE 4 84 | #define SANLK_STATE_HOST 5 85 | #define SANLK_STATE_RENEWAL 6 86 | 87 | struct sanlk_state { 88 | uint32_t type; /* SANLK_STATE_ */ 89 | uint32_t flags; 90 | uint32_t data32; /* pid (for client) */ 91 | uint64_t data64; 92 | char name[SANLK_NAME_LEN]; /* client name or resource name */ 93 | uint32_t str_len; 94 | char str[0]; /* string of internal state */ 95 | }; 96 | 97 | int sanlock_socket_address(const char *dir, struct sockaddr_un *addr); 98 | 99 | struct event_cb { 100 | struct sm_header h; 101 | struct sanlk_host_event he; 102 | uint64_t from_host_id; 103 | uint64_t from_generation; 104 | }; 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /src/lockspace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __LOCKSPACE_H__ 10 | #define __LOCKSPACE__H__ 11 | 12 | /* See resource.h for lock ordering between spaces_mutex and resource_mutex. */ 13 | 14 | /* no locks */ 15 | struct space *find_lockspace(const char *name); 16 | 17 | /* no locks */ 18 | int _lockspace_info(const char *space_name, struct space_info *spi); 19 | 20 | /* locks spaces_mutex */ 21 | int lockspace_info(const char *space_name, struct space_info *spi); 22 | 23 | /* locks spaces_mutex */ 24 | int lockspace_disk(char *space_name, struct sync_disk *disk, int *sector_size); 25 | 26 | /* locks spaces_mutex */ 27 | int host_info(char *space_name, uint64_t host_id, struct host_status *hs_out); 28 | 29 | /* locks spaces_mutex, locks sp */ 30 | int host_status_set_bit(char *space_name, uint64_t host_id); 31 | 32 | /* no locks */ 33 | int test_id_bit(int host_id, char *bitmap); 34 | 35 | /* no locks */ 36 | void set_id_bit(int host_id, char *bitmap, char *c); 37 | 38 | /* locks sp */ 39 | int check_our_lease(struct space *sp, int *check_all, char *check_buf); 40 | 41 | /* locks resource_mutex (add_host_event), locks resource_mutex (set_resource_examine) */ 42 | void check_other_leases(struct space *sp, char *buf); 43 | 44 | /* locks spaces_mutex */ 45 | int add_lockspace_start(struct sanlk_lockspace *ls, uint32_t io_timeout, struct space **sp_out); 46 | 47 | /* locks sp, locks spaces_mutex */ 48 | int add_lockspace_wait(struct space *sp); 49 | 50 | /* locks spaces_mutex */ 51 | int inq_lockspace(struct sanlk_lockspace *ls); 52 | 53 | /* locks spaces_mutex */ 54 | int rem_lockspace_start(struct sanlk_lockspace *ls, unsigned int *space_id); 55 | 56 | /* locks spaces_mutex */ 57 | int rem_lockspace_wait(struct sanlk_lockspace *ls, unsigned int space_id); 58 | 59 | /* locks spaces_mutex, locks sp */ 60 | void free_lockspaces(int wait); 61 | 62 | /* locks spaces_mutex */ 63 | int get_lockspaces(char *buf, int *len, int *count, int maxlen); 64 | 65 | /* locks spaces_mutex */ 66 | int get_hosts(struct sanlk_lockspace *ls, char *buf, int *len, int *count, int maxlen); 67 | 68 | /* locks spaces_mutex, locks sp */ 69 | int lockspace_set_event(struct sanlk_lockspace *ls, struct sanlk_host_event *he, uint32_t flags); 70 | 71 | /* locks spaces_mutex, locks sp */ 72 | int lockspace_reg_event(struct sanlk_lockspace *ls, int fd, uint32_t flags); 73 | 74 | /* locks spaces_mutex, locks sp */ 75 | int lockspace_end_event(struct sanlk_lockspace *ls); 76 | 77 | /* locks spaces_mutex, locks sp */ 78 | int send_event_callbacks(uint32_t space_id, uint64_t from_host_id, uint64_t from_generation, struct sanlk_host_event *he); 79 | 80 | /* locks spaces_mutex, locks sp */ 81 | int lockspace_set_config(struct sanlk_lockspace *ls, uint32_t flags, uint32_t cmd); 82 | 83 | int lockspace_begin_rindex_op(char *space_name, int rindex_op, struct space_info *spi); 84 | int lockspace_clear_rindex_op(char *space_name); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /init.d/wdmd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # wdmd - watchdog multiplexing daemon 4 | # 5 | # chkconfig: 2345 97 03 6 | # description: starts and stops wdmd daemon 7 | # 8 | 9 | 10 | ### BEGIN INIT INFO 11 | # Provides: wdmd 12 | # Required-Start: $time $syslog 13 | # Required-Stop: $syslog 14 | # Should-Start: 15 | # Should-Stop: 16 | # Default-Start: 2 3 4 5 17 | # Default-Stop: 0 1 6 18 | # Short-Description: starts and stops wdmd daemon 19 | # Description: starts and stops wdmd daemon 20 | ### END INIT INFO 21 | 22 | . /etc/rc.d/init.d/functions 23 | 24 | prog="wdmd" 25 | runfile="/run/$prog/$prog.pid" 26 | lockfile="/var/lock/subsys/$prog" 27 | exec="/usr/sbin/$prog" 28 | 29 | WDMDGROUP="sanlock" 30 | WDMDOPTS="-G $WDMDGROUP" 31 | 32 | [ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog 33 | 34 | watchdog_probe() { 35 | $exec --probe > /dev/null 2>&1 36 | retval=$? 37 | return $retval 38 | } 39 | 40 | watchdog_check() { 41 | watchdog_probe 42 | retval=$? 43 | 44 | if [ $retval -ne 0 ]; then 45 | echo -n $"Loading the softdog kernel module: " 46 | modprobe softdog && udevadm settle 47 | 48 | watchdog_probe 49 | retval=$? 50 | if [ $retval -ne 0 ]; then 51 | failure; echo 52 | return 1 53 | fi 54 | success; echo 55 | fi 56 | } 57 | 58 | start() { 59 | watchdog_check 60 | 61 | [ -x $exec ] || exit 5 62 | 63 | if [ ! -d /run/$prog ]; then 64 | install -d -g $WDMDGROUP -m 775 /run/$prog 65 | [ -x /sbin/restorecon ] && restorecon /run/$prog 66 | fi 67 | 68 | echo -n $"Starting $prog: " 69 | daemon $prog $WDMDOPTS 70 | retval=$? 71 | echo 72 | [ $retval -eq 0 ] && touch $lockfile 73 | return $retval 74 | } 75 | 76 | stop() { 77 | PID=$(pidofproc -p $runfile $prog) 78 | 79 | echo -n $"Sending stop signal $prog ($PID): " 80 | killproc -p $runfile $prog -TERM 81 | retval=$? 82 | echo 83 | 84 | if [ $retval -ne 0 ]; then 85 | return $retval 86 | fi 87 | 88 | echo -n $"Waiting for $prog ($PID) to stop:" 89 | 90 | timeout=10 91 | while checkpid $PID; do 92 | sleep 1 93 | timeout=$((timeout - 1)) 94 | if [ "$timeout" -le 0 ]; then 95 | failure; echo 96 | return 1 97 | fi 98 | done 99 | 100 | success; echo 101 | rm -f $lockfile 102 | return $retval 103 | } 104 | 105 | restart() { 106 | rh_status_q && stop 107 | start 108 | } 109 | 110 | reload() { 111 | restart 112 | } 113 | 114 | rh_status() { 115 | status $prog 116 | } 117 | 118 | rh_status_q() { 119 | rh_status >/dev/null 2>&1 120 | } 121 | 122 | case "$1" in 123 | start) 124 | rh_status_q && exit 0 125 | $1 126 | ;; 127 | stop) 128 | rh_status_q || exit 0 129 | $1 130 | ;; 131 | restart) 132 | $1 133 | ;; 134 | reload) 135 | rh_status_q || exit 7 136 | $1 137 | ;; 138 | watchdog-check) 139 | watchdog_check 140 | ;; 141 | force-reload) 142 | force_reload 143 | ;; 144 | status) 145 | rh_status 146 | ;; 147 | condrestart|try-restart) 148 | rh_status_q || exit 0 149 | restart 150 | ;; 151 | *) 152 | echo $"Usage $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" 153 | exit 2 154 | esac 155 | exit $? 156 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __LOG_H__ 10 | #define __LOG_H__ 11 | 12 | #define LOG_CLIENT LOG_LOCAL0 13 | #define LOG_CMD LOG_LOCAL1 14 | 15 | /* 16 | * Log levels are used mainly to indicate where the message 17 | * should be recorded: 18 | * 19 | * log_error() write to /var/log/messages and /var/log/sanlock.log 20 | * log_level(WARNING) write to /var/log/sanlock.log 21 | * log_debug() write to incore buffer, not to file 22 | * 23 | * Anything in /var/log/messages should not happen and should be reported. 24 | * So anything we want to visible and reported should be LOG_ERR. 25 | * 26 | * If we want to log something to assist in debugging, but not be reported, 27 | * it should be LOG_WARNING (goes only to sanlock.log) 28 | */ 29 | 30 | void log_level(uint32_t space_id, uint32_t res_id, char *name_in, int level, const char *fmt, ...) 31 | __attribute__((format(printf, 5, 6))); 32 | 33 | int setup_logging(void); 34 | void close_logging(void); 35 | void copy_log_dump(char *buf, int *len); 36 | 37 | #define log_debug(fmt, args...) log_level(0, 0, NULL, LOG_DEBUG, fmt, ##args) 38 | #define log_space(space, fmt, args...) log_level(space->space_id, 0, NULL, LOG_DEBUG, fmt, ##args) 39 | #define log_token(token, fmt, args...) log_level(token->space_id, token->res_id, NULL, LOG_DEBUG, fmt, ##args) 40 | #define log_sid(space_id, fmt, args...) log_level(space_id, 0, NULL, LOG_DEBUG, fmt, ##args) 41 | #define log_rid(res_id, fmt, args...) log_level(res_id, 0, NULL, LOG_DEBUG, fmt, ##args) 42 | 43 | #define log_warn(fmt, args...) log_level(0, 0, NULL, LOG_WARNING, fmt, ##args) 44 | #define log_warns(space, fmt, args...) log_level(space->space_id, 0, NULL, LOG_WARNING, fmt, ##args) 45 | #define log_warnt(token, fmt, args...) log_level(token->space_id, token->res_id, NULL, LOG_WARNING, fmt, ##args) 46 | 47 | #define log_error(fmt, args...) log_level(0, 0, NULL, LOG_ERR, fmt, ##args) 48 | #define log_erros(space, fmt, args...) log_level(space->space_id, 0, NULL, LOG_ERR, fmt, ##args) 49 | #define log_errot(token, fmt, args...) log_level(token->space_id, token->res_id, NULL, LOG_ERR, fmt, ##args) 50 | 51 | #define log_taske(task, fmt, args...) log_level(0, 0, task->name, LOG_ERR, fmt, ##args) 52 | #define log_taskw(task, fmt, args...) log_level(0, 0, task->name, LOG_WARNING, fmt, ##args) 53 | #define log_taskd(task, fmt, args...) log_level(0, 0, task->name, LOG_DEBUG, fmt, ##args) 54 | 55 | #define log_client(ci, fd, fmt, args...) log_level(ci, fd, NULL, LOG_CLIENT, fmt, ##args) 56 | 57 | #define log_cmd(cmd, fmt, args...) log_level(cmd, 0, NULL, LOG_CMD, fmt, ##args) 58 | 59 | /* use log_tool for tool actions (non-daemon), and for daemon until 60 | logging is set up */ 61 | 62 | #define log_tool(fmt, args...) \ 63 | do { \ 64 | printf(fmt "\n", ##args); \ 65 | } while (0) 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/leader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __LEADER_H__ 10 | #define __LEADER_H__ 11 | 12 | /* does not include terminating null byte */ 13 | /* NB NAME_ID_SIZE must match SANLK_NAME_LEN */ 14 | /* NB NAME_ID_SIZE is part of ondisk format */ 15 | 16 | #define NAME_ID_SIZE 48 17 | 18 | /* 19 | * paxos minor version changes: 20 | * 4: add ALIGN leader flags 21 | * 22 | * delta minor version changes: 23 | * 4: add ALIGN leader flags 24 | */ 25 | 26 | #define PAXOS_DISK_MAGIC 0x06152010 27 | #define PAXOS_DISK_CLEAR 0x11282016 28 | #define PAXOS_DISK_VERSION_MAJOR 0x00060000 29 | #define PAXOS_DISK_VERSION_MINOR 0x00000004 30 | 31 | #define DELTA_DISK_MAGIC 0x12212010 32 | #define DELTA_DISK_VERSION_MAJOR 0x00030000 33 | #define DELTA_DISK_VERSION_MINOR 0x00000004 34 | 35 | /* for all disk structures: 36 | uint64 aligned on 8 byte boundaries, 37 | uint32 aligned on 4 byte boundaries, etc */ 38 | 39 | /* NB. adjust LEADER_COMPARE_LEN and LEADER_CHECKSUM_LEN when changing 40 | this struct. 41 | LEADER_CHECKSUM_LEN should end just before the checksum field. 42 | LEADER_COMPARE_LEN should end just before timestamp. 43 | The checksum field should follow the timestamp field. 44 | 45 | The leader may be partially through updating the timestamp on 46 | multiple leader blocks in a lease, but for the purpose of counting 47 | repetitions of a leader block owned by a single host they should be 48 | counted together, so COMPARE_LEN should exclude timestamp. */ 49 | 50 | #define LEADER_COMPARE_LEN 152 51 | #define LEADER_CHECKSUM_LEN 168 52 | #define LEASE_FREE 0 53 | 54 | /* leader_record flags */ 55 | #define LFL_SHORT_HOLD 0x00000001 56 | /* skip ahead in flag numbers so these align flags match other defines */ 57 | #define LFL_ALIGN_1M 0x00000010 58 | #define LFL_ALIGN_2M 0x00000020 59 | #define LFL_ALIGN_4M 0x00000040 60 | #define LFL_ALIGN_8M 0x00000080 61 | 62 | struct leader_record { 63 | uint32_t magic; 64 | uint32_t version; 65 | uint32_t flags; 66 | uint32_t sector_size; 67 | uint64_t num_hosts; 68 | uint64_t max_hosts; 69 | uint64_t owner_id; /* host_id of owner */ 70 | uint64_t owner_generation; 71 | uint64_t lver; 72 | char space_name[NAME_ID_SIZE]; /* lockspace for resource */ 73 | char resource_name[NAME_ID_SIZE]; /* resource being locked */ 74 | uint64_t timestamp; 75 | uint64_t unused1; 76 | uint32_t checksum; 77 | uint16_t unused2; 78 | uint16_t io_timeout; 79 | uint64_t write_id; /* for extra info, debug */ 80 | uint64_t write_generation; /* for extra info, debug */ 81 | uint64_t write_timestamp; /* for extra info, debug */ 82 | }; 83 | 84 | /* leader_record can use first 256 bytes of a sector, 85 | bitmap uses the last 256 bytes */ 86 | 87 | #define LEADER_RECORD_MAX 256 88 | #define HOSTID_BITMAP_OFFSET 256 89 | #define HOSTID_BITMAP_SIZE 256 90 | 91 | /* the request record is in the sector following the leader record 92 | for a paxos lease. */ 93 | 94 | #define REQ_DISK_MAGIC 0x08292011 95 | #define REQ_DISK_VERSION_MAJOR 0x00010000 96 | #define REQ_DISK_VERSION_MINOR 0x00000001 97 | 98 | struct request_record { 99 | uint32_t magic; 100 | uint32_t version; 101 | uint64_t lver; 102 | uint32_t force_mode; 103 | }; 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /wdmd/client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "wdmd.h" 24 | #include "wdmd_sock.h" 25 | 26 | int wdmd_connect(void) 27 | { 28 | int rv, s; 29 | struct sockaddr_un addr; 30 | 31 | s = socket(AF_LOCAL, SOCK_STREAM, 0); 32 | if (s < 0) 33 | return -errno; 34 | 35 | rv = wdmd_socket_address(&addr); 36 | if (rv < 0) 37 | return rv; 38 | 39 | rv = connect(s, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)); 40 | if (rv < 0) { 41 | rv = -errno; 42 | close(s); 43 | return rv; 44 | } 45 | return s; 46 | } 47 | 48 | int wdmd_register(int con, char *name) 49 | { 50 | struct wdmd_header h; 51 | int rv; 52 | 53 | if (strlen(name) > WDMD_NAME_SIZE) 54 | return -ENAMETOOLONG; 55 | 56 | memset(&h, 0, sizeof(h)); 57 | h.cmd = CMD_REGISTER; 58 | strncpy(h.name, name, WDMD_NAME_SIZE); 59 | 60 | rv = send(con, (void *)&h, sizeof(struct wdmd_header), 0); 61 | if (rv < 0) 62 | return -errno; 63 | return 0; 64 | } 65 | 66 | static int send_header(int con, int cmd) 67 | { 68 | struct wdmd_header h; 69 | int rv; 70 | 71 | memset(&h, 0, sizeof(h)); 72 | h.cmd = cmd; 73 | 74 | rv = send(con, (void *)&h, sizeof(struct wdmd_header), 0); 75 | if (rv < 0) 76 | return -errno; 77 | return 0; 78 | } 79 | 80 | int wdmd_open_watchdog(int con, int fire_timeout) 81 | { 82 | struct wdmd_header h; 83 | int rv; 84 | 85 | memset(&h, 0, sizeof(h)); 86 | h.cmd = CMD_OPEN_WATCHDOG; 87 | h.fire_timeout = fire_timeout; 88 | 89 | rv = send(con, (void *)&h, sizeof(struct wdmd_header), 0); 90 | if (rv < 0) 91 | return -errno; 92 | 93 | memset(&h, 0, sizeof(h)); 94 | rv = recv(con, &h, sizeof(h), MSG_WAITALL); 95 | if (rv < 0) 96 | return -errno; 97 | 98 | if (h.fire_timeout != fire_timeout) 99 | return -1; 100 | return 0; 101 | } 102 | 103 | int wdmd_refcount_set(int con) 104 | { 105 | return send_header(con, CMD_REFCOUNT_SET); 106 | } 107 | 108 | int wdmd_refcount_clear(int con) 109 | { 110 | return send_header(con, CMD_REFCOUNT_CLEAR); 111 | } 112 | 113 | int wdmd_test_live(int con, uint64_t renewal_time, uint64_t expire_time) 114 | { 115 | struct wdmd_header h; 116 | int rv; 117 | 118 | memset(&h, 0, sizeof(h)); 119 | h.cmd = CMD_TEST_LIVE; 120 | h.renewal_time = renewal_time; 121 | h.expire_time = expire_time; 122 | 123 | rv = send(con, (void *)&h, sizeof(struct wdmd_header), 0); 124 | if (rv < 0) 125 | return -errno; 126 | return 0; 127 | } 128 | 129 | int wdmd_status(int con, int *test_interval, int *fire_timeout, 130 | uint64_t *last_keepalive) 131 | { 132 | struct wdmd_header h; 133 | int rv; 134 | 135 | rv = send_header(con, CMD_STATUS); 136 | if (rv < 0) 137 | return rv; 138 | 139 | rv = recv(con, &h, sizeof(h), MSG_WAITALL); 140 | if (rv < 0) 141 | return -errno; 142 | 143 | *test_interval = h.test_interval; 144 | *fire_timeout = h.fire_timeout; 145 | *last_keepalive = h.last_keepalive; 146 | return 0; 147 | } 148 | 149 | -------------------------------------------------------------------------------- /src/task.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "sanlock_internal.h" 26 | #include "log.h" 27 | #include "task.h" 28 | 29 | void setup_task_aio(struct task *task, int use_aio, int cb_size) 30 | { 31 | int rv; 32 | 33 | task->use_aio = use_aio; 34 | 35 | memset(&task->aio_ctx, 0, sizeof(task->aio_ctx)); 36 | 37 | /* main task doesn't actually do disk io so it passes in, 38 | * cb_size 0, but it still wants use_aio set for other 39 | * tasks to copy */ 40 | 41 | if (!use_aio) 42 | return; 43 | 44 | if (!cb_size) 45 | return; 46 | 47 | rv = io_setup(cb_size, &task->aio_ctx); 48 | if (rv < 0) 49 | goto fail; 50 | 51 | task->cb_size = cb_size; 52 | task->callbacks = malloc(cb_size * sizeof(struct aicb)); 53 | if (!task->callbacks) { 54 | rv = -ENOMEM; 55 | goto fail_setup; 56 | } 57 | memset(task->callbacks, 0, cb_size * sizeof(struct aicb)); 58 | return; 59 | 60 | fail_setup: 61 | io_destroy(task->aio_ctx); 62 | fail: 63 | task->use_aio = 0; 64 | } 65 | 66 | void close_task_aio(struct task *task) 67 | { 68 | struct timespec ts; 69 | struct io_event event; 70 | uint64_t last_warn; 71 | uint64_t begin; 72 | uint64_t now; 73 | int rv, i, used, lvl; 74 | 75 | if (!task->use_aio) 76 | goto skip_aio; 77 | 78 | memset(&ts, 0, sizeof(struct timespec)); 79 | ts.tv_sec = com.io_timeout; 80 | 81 | last_warn = time(NULL); 82 | begin = last_warn; 83 | 84 | /* wait for all outstanding aio to complete before 85 | destroying aio context, freeing iocb and buffers */ 86 | 87 | while (1) { 88 | now = time(NULL); 89 | 90 | if (now - last_warn >= (com.io_timeout * 6)) { 91 | last_warn = now; 92 | lvl = LOG_ERR; 93 | } else { 94 | lvl = LOG_DEBUG; 95 | } 96 | 97 | used = 0; 98 | 99 | for (i = 0; i < task->cb_size; i++) { 100 | if (!task->callbacks[i].used) 101 | continue; 102 | used++; 103 | 104 | log_level(0, 0, task->name, lvl, "close_task_aio %d %p busy", 105 | i, &task->callbacks[i]); 106 | } 107 | 108 | if (!used) 109 | break; 110 | 111 | if (now - begin >= 120) 112 | break; 113 | 114 | memset(&event, 0, sizeof(event)); 115 | 116 | rv = io_getevents(task->aio_ctx, 1, 1, &event, &ts); 117 | if (rv == -EINTR) 118 | continue; 119 | if (rv < 0) 120 | break; 121 | if (rv == 1) { 122 | struct iocb *ev_iocb = event.obj; 123 | struct aicb *ev_aicb = container_of(ev_iocb, struct aicb, iocb); 124 | 125 | if (ev_aicb->buf == task->iobuf) 126 | task->iobuf = NULL; 127 | 128 | log_taske(task, "aio collect %p:%p:%p result %ld:%ld close free", 129 | ev_aicb, ev_iocb, ev_aicb->buf, event.res, event.res2); 130 | 131 | ev_aicb->used = 0; 132 | free(ev_aicb->buf); 133 | ev_aicb->buf = NULL; 134 | } 135 | } 136 | 137 | if (used) 138 | log_taskd(task, "close_task_aio destroy %d incomplete ops", used); 139 | 140 | io_destroy(task->aio_ctx); 141 | 142 | if (used) 143 | log_taske(task, "close_task_aio destroyed %d incomplete ops", used); 144 | 145 | if (task->iobuf) 146 | free(task->iobuf); 147 | 148 | skip_aio: 149 | if (task->callbacks) 150 | free(task->callbacks); 151 | task->callbacks = NULL; 152 | } 153 | 154 | -------------------------------------------------------------------------------- /tests/sanlk_string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "sanlock.h" 10 | #include "sanlock_resource.h" 11 | 12 | void print_res(struct sanlk_resource *res) 13 | { 14 | int i; 15 | 16 | printf("struct fields: \"%s\" \"%s\"", res->lockspace_name, res->name); 17 | 18 | for (i = 0; i < res->num_disks; i++) { 19 | printf(" \"%s\" %llu", res->disks[i].path, 20 | (unsigned long long)res->disks[i].offset); 21 | } 22 | printf(" flags %x", res->flags); 23 | printf(" lver %llu\n", (unsigned long long)res->lver); 24 | } 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | struct sanlk_lockspace ls; 29 | struct sanlk_resource *res; 30 | struct sanlk_resource **res_args = NULL; 31 | char *state; 32 | int res_count; 33 | int rv, i; 34 | 35 | if (argc < 2) { 36 | printf("%s RESOURCE RESOURCE ...\n", argv[0]); 37 | printf("%s -s LOCKSPACE\n", argv[0]); 38 | return 0; 39 | } 40 | 41 | if (!strcmp(argv[1], "-s")) { 42 | memset(&ls, 0, sizeof(ls)); 43 | 44 | rv = sanlock_str_to_lockspace(argv[2], &ls); 45 | 46 | printf("struct fields: \"%s\" %llu %u \"%s\" %llu\n", 47 | ls.name, 48 | (unsigned long long)ls.host_id, 49 | ls.flags, 50 | ls.host_id_disk.path, 51 | (unsigned long long)ls.host_id_disk.offset); 52 | return rv; 53 | } 54 | 55 | state = malloc(1024 * 1024); 56 | memset(state, 0, 1024 * 1024); 57 | 58 | printf("\n"); 59 | printf("sanlock_str_to_res for each argv\n", rv); 60 | printf("--------------------------------------------------------------------------------\n"); 61 | 62 | for (i = 1; i < argc; i++) { 63 | rv = sanlock_str_to_res(argv[i], &res); 64 | 65 | print_res(res); 66 | 67 | free(res); 68 | res = NULL; 69 | 70 | if (i > 1) 71 | strcat(state, " "); 72 | strcat(state, argv[i]); 73 | } 74 | 75 | printf("\n"); 76 | printf("combined argv input for state_to_args\n"); 77 | printf("--------------------------------------------------------------------------------\n"); 78 | printf("\"%s\"\n", state); 79 | 80 | rv = sanlock_state_to_args(state, &res_count, &res_args); 81 | 82 | printf("\n"); 83 | printf("sanlock_state_to_args %d res_count %d\n", rv, res_count); 84 | printf("--------------------------------------------------------------------------------\n"); 85 | for (i = 0; i < res_count; i++) { 86 | res = res_args[i]; 87 | print_res(res); 88 | } 89 | 90 | free(state); 91 | state = NULL; 92 | 93 | rv = sanlock_args_to_state(res_count, res_args, &state); 94 | 95 | printf("\n"); 96 | printf("sanlock_args_to_state %d\n", rv); 97 | printf("--------------------------------------------------------------------------------\n"); 98 | printf("\"%s\"\n", state); 99 | 100 | return 0; 101 | } 102 | 103 | #if 0 104 | 105 | [root@bull-02 tests]# ./res_string 'LA:R1:/dev/foo1\:xx:0:/dev/foo2\:yy:0' 'LB:R2:/dev/bar:11' 106 | 107 | sanlock_str_to_res for each argv 108 | -------------------------------------------------------------------------------- 109 | struct fields: "LA" "R1" "/dev/foo1:xx" 0 "/dev/foo2:yy" 0 0 110 | struct fields: "LB" "R2" "/dev/bar" 11 0 111 | 112 | combined argv input for state_to_args 113 | -------------------------------------------------------------------------------- 114 | "LA:R1:/dev/foo1\:xx:0:/dev/foo2\:yy:0 LB:R2:/dev/bar:11" 115 | 116 | sanlock_state_to_args 0 res_count 2 117 | -------------------------------------------------------------------------------- 118 | struct fields: "LA" "R1" "/dev/foo1:xx" 0 "/dev/foo2:yy" 0 0 119 | struct fields: "LB" "R2" "/dev/bar" 11 0 120 | 121 | sanlock_args_to_state 0 122 | -------------------------------------------------------------------------------- 123 | "LA:R1:/dev/foo1\:xx:0:/dev/foo2\:yy:0:0 LB:R2:/dev/bar:11:0" 124 | 125 | #endif 126 | 127 | -------------------------------------------------------------------------------- /wdmd/wdmd.8: -------------------------------------------------------------------------------- 1 | .TH WDMD 8 2011-08-01 2 | 3 | .SH NAME 4 | wdmd \- watchdog multiplexing daemon 5 | 6 | .SH SYNOPSIS 7 | .B wdmd 8 | [OPTIONS] 9 | 10 | .SH DESCRIPTION 11 | 12 | This daemon opens /dev/watchdog and allows multiple independent sources to 13 | detmermine whether each KEEPALIVE is done. Every test interval (default 10 14 | seconds), the daemon tests each source. If any test fails, the KEEPALIVE 15 | is not done. In the default configuration, the watchdog timer will reset 16 | the system if no KEEPALIVE is done for 60 seconds ("fire timeout"). This 17 | means that if a single test fails 5-6 times in row, the watchdog will fire 18 | and reset the system. With multiple test sources, fewer separate failures 19 | back to back can also cause a reset, e.g. 20 | 21 | T seconds, P pass, F fail 22 | .br 23 | T00: test1 P, test2 P, test3 P: KEEPALIVE done 24 | .br 25 | T10: test1 F, test2 F, test3 P: KEEPALIVE skipped 26 | .br 27 | T20: test1 F, test2 P, test3 P: KEEPALIVE skipped 28 | .br 29 | T30: test1 P, test2 F, test3 P: KEEPALIVE skipped 30 | .br 31 | T40: test1 P, test2 P, test3 F: KEEPALIVE skipped 32 | .br 33 | T50: test1 F, test2 F, test3 P: KEEPALIVE skipped 34 | .br 35 | T60: test1 P, test2 F, test3 P: KEEPALIVE skipped 36 | .br 37 | T60: watchdog fires, system resets 38 | 39 | (Depending on timings, the system may be reset sometime shortly before 40 | T60, and the tests at T60 would not be run.) 41 | 42 | A crucial aspect to the design and function of wdmd is that if any single 43 | source does not pass the test for the length of the fire timeout, the watchdog 44 | is guaranteed to fire, regardless of whether other sources on the system have 45 | passed or failed. A spurious reset due to the combined effects of 46 | multiple failing tests as shown above, is an accepted side effect. 47 | 48 | The wdmd init script will load the softdog module if no other watchdog 49 | module has been loaded. 50 | 51 | wdmd cannot be used on the system with any other program that needs to 52 | open /dev/watchdog, e.g. watchdog(8). 53 | 54 | .SS Test Source: clients 55 | 56 | Using libwdmd, programs connect to wdmd via a unix socket, and send 57 | regular messages to wdmd to update an expiry time for their connection. 58 | Every test interval, wdmd will check if the expiry time for a connection 59 | has been reached. If so, the test for that client fails. 60 | 61 | .SS Test Source: scripts 62 | 63 | wdmd will run scripts from a designated directory every test interval. 64 | If a script exits with 0, the test is considered a success, otherwise 65 | a failure. If a script does not exit by the end of the test interval, 66 | it is considered a failure. 67 | 68 | .SH OPTIONS 69 | .TP 70 | .B \-\-version, \-V 71 | Print version. 72 | 73 | .TP 74 | .B \-\-help, \-h 75 | Print usage. 76 | 77 | .TP 78 | .B \-\-dump, \-d 79 | Print debug information from the daemon. 80 | 81 | .TP 82 | .B \-\-probe, \-p 83 | Print path of functional watchdog device. Exit code 0 indicates a 84 | functional device was found. Exit code 1 indicates a functional device 85 | was not found. 86 | 87 | .TP 88 | .B \-D 89 | Enable debugging to stderr and don't fork. 90 | 91 | .TP 92 | .BI \-H " 0|1" 93 | Enable (1) or disable (0) high priority features such as realtime 94 | scheduling priority and mlockall. 95 | 96 | .TP 97 | .BI \-G " name" 98 | Group ownership for the socket. 99 | 100 | .TP 101 | .BI \-S " 0|1" 102 | Enable (1) or disable (0) script tests. 103 | 104 | .TP 105 | .BI \-s " path" 106 | Path to scripts dir. 107 | 108 | .TP 109 | .BI \-k " num" 110 | Kill unfinished scripts after num seconds. 111 | 112 | .TP 113 | .BI \-w " path" 114 | The path to the watchdog device to try first. 115 | 116 | .TP 117 | .BI "\-\-trytimeout, \-t" " seconds" 118 | Set the timeout for the watchdog device. Use this to check for supported 119 | timeout values. 120 | 121 | .TP 122 | .B \-\-forcefire, \-F 123 | Force the watchdog to fire and reset the machine. Use with -t. 124 | 125 | 126 | -------------------------------------------------------------------------------- /src/rindex_disk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #ifndef __RINDEX_DISK_H__ 10 | #define __RINDEX_DISK_H__ 11 | 12 | /* 13 | * The resource index uses two align-size areas: 14 | * 15 | * 1. The first area (the rindex itself) holds a header and 16 | * entries. with each entry recording a resource lease name 17 | * and the offset of that lease (the resource lease disk areads 18 | * follow the two align-size disk areas used by the resource index.) 19 | * 20 | * 2. The second area holds an internal paxos lease that sanlock 21 | * uses to protect updates to the rindex in the first area. 22 | * 23 | * The rindex is one align-size area containing between 256 and 24 | * 2048 sectors, depending on the sector_size and align_size. 25 | * 26 | * sector 0 of the index holds the rindex_header. 27 | * After this, sectors 1 to 250/500/1000/2000 hold rindex_entry's. 28 | * The remaining sectors in the align-size area are unused. 29 | * 30 | * 512 byte sectors hold 8 entries per sector, 31 | * 4096 byte sectors hold 64 entries per sector. 32 | * 33 | * ALIGN1M / SECTOR512 = 2000 sectors used for rindex, 16000 max entries 34 | * ALIGN1M / SECTOR4K = 250 sectors used for rindex, 16000 max entries 35 | * ALIGN2M / SECTOR4K = 500 sectors used for rindex, 32000 max entries 36 | * ALIGN4M / SECTOR4K = 1000 sectors used for rindex, 64000 max entries 37 | * ALIGN8M / SECTOR4K = 2000 sectors used for rindex, 128000 max entries 38 | * 39 | * rindex_header.sector_size = 512 | 4096 40 | * 41 | * area_size = 1M | 2M | 4M | 8M 42 | * 43 | * rindex_header.max_resources defaults to 4096 to limit searching. 44 | * The caller can specify max_resources up to the max supported by 45 | * the sector_size/align_size combination. 46 | * 47 | * rindex_header.rindex_offset: 48 | * location of rindex_header from start of device, set by caller, 49 | * must be multiple of area_size. (rindex_offset will often be 50 | * 1*area_size because rindex typically follows the lockspace area 51 | * which typically starts at offset 0 on the device.) 52 | * 53 | * entry_size = 64 bytes 54 | * 55 | * entry_index = N = 0 to (max_resources - 1) 56 | * 57 | * rindex_entry N offset = rindex_offset + sector_size + (N * entry_size) 58 | * (the sector_size contains the rindex_header) 59 | * 60 | * rindex_entry N holds information about the resource lease in 61 | * the N'th area following the two areas used by the resource index. 62 | * 63 | * resource_leases_start = rindex_offset + (2 * area_size) 64 | * resource leases begin after the two resource index areas. 65 | * (rindex_offset will often be area_size, so resource_leases_start 66 | * will often by 3*area_size) 67 | * 68 | * resource lease N offset = resource_leases_start + (N * area_size) 69 | * 70 | * rindex_entry[N].res_offset = resource lease N offset 71 | */ 72 | 73 | #define RINDEX_DISK_MAGIC 0x01042018 74 | #define RINDEX_DISK_VERSION_MAJOR 0x00010000 75 | #define RINDEX_DISK_VERSION_MINOR 0x00000002 76 | 77 | /* MINOR 2: addition of align flags */ 78 | 79 | /* rindex_header flags */ 80 | #define RHF_ALIGN_1M 0x00000001 81 | #define RHF_ALIGN_2M 0x00000002 82 | #define RHF_ALIGN_4M 0x00000004 83 | #define RHF_ALIGN_8M 0x00000008 84 | 85 | struct rindex_header { 86 | uint32_t magic; 87 | uint32_t version; 88 | uint32_t flags; /* RHF_ */ 89 | uint32_t sector_size; 90 | uint32_t max_resources; 91 | uint32_t unused; 92 | uint64_t rx_offset; /* location of rindex_header from start of disk */ 93 | char lockspace_name[NAME_ID_SIZE]; 94 | }; 95 | 96 | #define MAX_RINDEX_ENTRIES_1M 16000 97 | #define MAX_RINDEX_ENTRIES_8M 128000 98 | 99 | /* The entry size is fixed */ 100 | 101 | struct rindex_entry { 102 | uint64_t res_offset; /* location of resource from start of disk */ 103 | uint32_t flags; 104 | uint32_t unused; 105 | char name[NAME_ID_SIZE]; 106 | }; 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /tests/clientn: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | num=$1 4 | cmd=$2 5 | dev=$3 6 | 7 | if [ "$cmd" == "init" ]; then 8 | 9 | echo sanlock direct init -s test:0:$dev:0 10 | sanlock direct init -s test:0:$dev:0 11 | 12 | for i in `seq 1 $num`; do 13 | off=`expr $i \* 1048576` 14 | echo sanlock direct init -r test:r$i:$dev:$off 15 | sanlock direct init -r test:r$i:$dev:$off 16 | done 17 | 18 | elif [ "$cmd" == "start" ]; then 19 | 20 | hostid=$4 21 | killpath=$5 22 | 23 | echo sanlock client add_lockspace -s test:$hostid:$dev:0 24 | sanlock client add_lockspace -s test:$hostid:$dev:0 25 | 26 | for i in `seq 1 $num`; do 27 | off=`expr $i \* 1048576` 28 | echo ./sanlk_client test r$i $dev $off $killpath & 29 | ./sanlk_client test r$i $dev $off $killpath & 30 | done 31 | 32 | elif [ "$cmd" == "delay" ]; then 33 | 34 | sec=$3 35 | 36 | pid=`cat /run/sanlock/sanlock.pid` 37 | 38 | echo sync with daemon renewals 39 | kill -s SIGSTOP $pid 40 | sleep 20 41 | kill -s SIGCONT $pid 42 | sleep 1 43 | 44 | echo sigstop sanlock pid $pid 45 | kill -s SIGSTOP $pid 46 | 47 | echo sleep $sec 48 | sleep $sec 49 | 50 | echo sigcont sanlock pid $pid 51 | kill -s SIGCONT $pid 52 | 53 | elif [ "$cmd" == "iodelay" ]; then 54 | 55 | sec=$4 56 | 57 | pid=`cat /run/sanlock/sanlock.pid` 58 | 59 | echo sync with daemon renewals 60 | kill -s SIGSTOP $pid 61 | sleep 20 62 | kill -s SIGCONT $pid 63 | sleep 2 64 | 65 | echo save linear 66 | rm -f /tmp/client-state.txt 67 | rm -f /tmp/client-linear.txt 68 | rm -f /tmp/client-error.txt 69 | dmsetup table $dev > /tmp/client-linear.txt 70 | sed "s/linear/error/" /tmp/client-linear.txt > /tmp/client-error.txt 71 | 72 | echo load error 73 | dmsetup suspend $dev 74 | dmsetup load $dev /tmp/client-error.txt 75 | dmsetup resume $dev 76 | 77 | echo sleep $sec 78 | sleep $sec 79 | 80 | echo load linear 81 | dmsetup suspend $dev 82 | dmsetup load $dev /tmp/client-linear.txt 83 | dmsetup resume $dev 84 | 85 | elif [ "$cmd" == "error" ]; then 86 | 87 | echo save linear 88 | rm -f /tmp/client-state.txt 89 | rm -f /tmp/client-linear.txt 90 | rm -f /tmp/client-error.txt 91 | dmsetup table $dev > /tmp/client-linear.txt 92 | sed "s/linear/error/" /tmp/client-linear.txt > /tmp/client-error.txt 93 | 94 | echo load error 95 | dmsetup suspend $dev 96 | dmsetup load $dev /tmp/client-error.txt 97 | dmsetup resume $dev 98 | 99 | elif [ "$cmd" == "linear" ]; then 100 | 101 | echo load linear 102 | dmsetup suspend $dev 103 | dmsetup load $dev /tmp/client-linear.txt 104 | dmsetup resume $dev 105 | 106 | elif [ "$cmd" == "resume" ]; then 107 | 108 | hostid=$4 109 | 110 | echo load linear 111 | dmsetup suspend $dev 112 | dmsetup load $dev /tmp/client-linear.txt 113 | dmsetup resume $dev 114 | 115 | echo sanlock client add_lockspace -s test:$hostid:$dev:0 116 | sanlock client add_lockspace -s test:$hostid:$dev:0 117 | 118 | while read pid state; do 119 | echo sanlock client acquire -p $pid -r $state 120 | sanlock client acquire -p $pid -r $state 121 | ret=$? 122 | if [ $ret == 0 ]; then 123 | kill -s SIGCONT $pid 124 | else 125 | kill -s SIGKILL $pid 126 | fi 127 | done < /tmp/client-state.txt 128 | 129 | else 130 | echo "" 131 | echo "clientn N init DEV" 132 | echo " sanlock direct init -s test:0:DEV:0" 133 | echo " sanlock direct init -r test:rI:DEV:OFF" 134 | echo "" 135 | echo "clientn N start DEV HOSTID KILLPATH" 136 | echo " sanlock client add_lockspace -s test:HOSTID:DEV:0" 137 | echo " starts N ./sanlk_client processes" 138 | echo "" 139 | echo "clientn N delay SEC" 140 | echo " sigstop sanlock daemon" 141 | echo " sleep SEC" 142 | echo " sigcont sanlock daemon" 143 | echo "" 144 | echo "clientn N iodelay DEV SEC" 145 | echo " block i/o to DEV" 146 | echo " sleep SEC" 147 | echo " unblock i/o to DEV" 148 | echo "" 149 | echo "clientn N linear DEV" 150 | echo " unblock i/o to DEV" 151 | echo "" 152 | echo "clientn N error DEV" 153 | echo " blocks i/o to DEV" 154 | echo " causes KILLPATH to run" 155 | echo " causes lockspace to be removed" 156 | echo "" 157 | echo "clientn N resume DEV HOSTID" 158 | echo " sanlock client add_lockspace -s test:HOSTID:DEV:0" 159 | echo " reacquires leases for sanlk_client pids paused by" 160 | echo " killpath_pause, based on inquire state saved by killpath" 161 | fi 162 | 163 | -------------------------------------------------------------------------------- /init.d/fence_sanlockd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # fence_sanlockd - daemon for fence_sanlock agent 4 | # 5 | # chkconfig: 2345 20 80 6 | # description: starts and stops fence_sanlockd 7 | # 8 | 9 | 10 | ### BEGIN INIT INFO 11 | # Provides: fence_sanlockd 12 | # Required-Start: $time $syslog 13 | # Required-Stop: $syslog 14 | # Should-Start: 15 | # Should-Stop: 16 | # Default-Start: 2 3 4 5 17 | # Default-Stop: 0 1 6 18 | # Short-Description: starts and stops fence_sanlockd 19 | # Description: starts and stops fence_sanlockd 20 | ### END INIT INFO 21 | 22 | . /etc/rc.d/init.d/functions 23 | 24 | prog="fence_sanlockd" 25 | agent="fence_sanlock" 26 | runfile="/run/$prog/$prog.pid" 27 | fifofile="/run/$prog/$prog.fifo" 28 | lockfile="/var/lock/subsys/$prog" 29 | exec="/usr/sbin/$prog" 30 | 31 | FENCESANLOCKDOPTS="-w" 32 | 33 | [ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog 34 | 35 | start() { 36 | [ -x $exec ] || exit 5 37 | 38 | # start wdmd and sanlock daemons if they aren't running 39 | 40 | service wdmd status > /dev/null 2>&1 || service wdmd start 41 | 42 | service sanlock status > /dev/null 2>&1 || service sanlock start 43 | 44 | [ ! -d /run/$prog ] && install -d -m 775 /run/$prog 45 | 46 | [ ! -d /run/$agent ] && install -d -m 775 /run/$agent 47 | 48 | [ -n "$(which restorecon)" ] && \ 49 | [ -x "$(which restorecon)" ] && \ 50 | restorecon /run/$prog 51 | 52 | [ -n "$(which restorecon)" ] && \ 53 | [ -x "$(which restorecon)" ] && \ 54 | restorecon /run/$agent 55 | 56 | echo -n $"Starting $prog: " 57 | daemon $prog $FENCESANLOCKDOPTS 58 | retval=$? 59 | echo 60 | [ $retval -eq 0 ] && touch $lockfile 61 | return $retval 62 | } 63 | 64 | stop() { 65 | agent_ps="$(ps ax -o pid,args | grep fence_sanlock | grep -v grep | grep -v fence_sanlockd)" 66 | 67 | [ -n "$agent_ps" ] && { 68 | agent_pid="$(echo $agent_ps | awk '{print $1}')" 69 | echo -n "cannot stop while $agent $agent_pid is running" 70 | failure; echo 71 | return 1 72 | } 73 | 74 | # Ideally, we'd like a general way to check if anything 75 | # needs fencing to continue running, but without that, 76 | # check what we know, which is that dlm requires it. 77 | 78 | if [ -d /sys/kernel/dlm/ ]; then 79 | count="$(ls -A /sys/kernel/dlm/ | wc -l)" 80 | if [ $count -ne 0 ]; then 81 | echo -n "cannot stop while dlm lockspaces exist" 82 | failure; echo 83 | return 1 84 | fi 85 | fi 86 | 87 | if [ -d /sys/kernel/config/dlm/cluster ]; then 88 | # this dir exists while dlm_controld is running 89 | echo -n "cannot stop while dlm is running" 90 | failure; echo 91 | return 1 92 | fi 93 | 94 | PID=$(pidofproc -p $runfile $prog) 95 | 96 | # We have to use SIGHUP to mean stop because sanlock 97 | # uses SIGTERM to mean that the lockspace failed. 98 | 99 | echo -n $"Sending stop signal $prog ($PID): " 100 | killproc -p $runfile $prog -HUP 101 | retval=$? 102 | echo 103 | 104 | if [ $retval -ne 0 ]; then 105 | return $retval 106 | fi 107 | 108 | # fence_sanlockd won't see the SIGHUP if it's 109 | # still waiting for config from the fifo, so 110 | # send invalid config to the fifo to make it fail. 111 | 112 | if [ -p $fifofile ]; then 113 | echo "" > $fifofile 114 | fi 115 | 116 | echo -n $"Waiting for $prog ($PID) to stop:" 117 | 118 | timeout=10 119 | while checkpid $PID; do 120 | sleep 1 121 | timeout=$((timeout - 1)) 122 | if [ "$timeout" -le 0 ]; then 123 | failure; echo 124 | return 1 125 | fi 126 | done 127 | 128 | success; echo 129 | rm -f $lockfile 130 | 131 | # stop wdmd and sanlock daemons if they are running 132 | 133 | service sanlock status > /dev/null 2>&1 && service sanlock stop 134 | 135 | service wdmd status > /dev/null 2>&1 && service wdmd stop 136 | 137 | return $retval 138 | } 139 | 140 | restart() { 141 | rh_status_q && stop 142 | start 143 | } 144 | 145 | reload() { 146 | restart 147 | } 148 | 149 | rh_status() { 150 | status $prog 151 | } 152 | 153 | rh_status_q() { 154 | rh_status >/dev/null 2>&1 155 | } 156 | 157 | case "$1" in 158 | start) 159 | rh_status_q && exit 0 160 | $1 161 | ;; 162 | stop) 163 | rh_status_q || exit 0 164 | $1 165 | ;; 166 | restart) 167 | $1 168 | ;; 169 | reload) 170 | rh_status_q || exit 7 171 | $1 172 | ;; 173 | force-reload) 174 | force_reload 175 | ;; 176 | status) 177 | rh_status 178 | ;; 179 | condrestart|try-restart) 180 | rh_status_q || exit 0 181 | restart 182 | ;; 183 | *) 184 | echo $"Usage $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" 185 | exit 2 186 | esac 187 | exit $? 188 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2010-2011 Red Hat, Inc. 2 | # 3 | # This copyrighted material is made available to anyone wishing to use, 4 | # modify, copy, or redistribute it subject to the terms and conditions 5 | # of the GNU General Public License v2 or (at your option) any later version. 6 | 7 | include ../common.mk 8 | 9 | CMD_TARGET = sanlock 10 | HEADER_TARGET = sanlock.h sanlock_rv.h sanlock_resource.h sanlock_admin.h sanlock_direct.h 11 | MAN_TARGET = sanlock.8 12 | 13 | SOMAJOR=1 14 | SOMINOR=0 15 | 16 | LIB_ENTIRE_TARGET = libsanlock 17 | LIB_CLIENT_TARGET = libsanlock_client 18 | LIBPC_ENTIRE_TARGET = libsanlock.pc 19 | LIBPC_CLIENT_TARGET = libsanlock_client.pc 20 | LIBSO_ENTIRE_TARGET = $(LIB_ENTIRE_TARGET).so.$(SOMAJOR).$(SOMINOR) 21 | LIBSO_CLIENT_TARGET = $(LIB_CLIENT_TARGET).so.$(SOMAJOR).$(SOMINOR) 22 | 23 | CMD_SOURCE = \ 24 | crc32c.c \ 25 | delta_lease.c \ 26 | direct.c \ 27 | diskio.c \ 28 | ondisk.c \ 29 | sizeflags.c \ 30 | helper.c \ 31 | lockspace.c \ 32 | lockfile.c \ 33 | log.c \ 34 | main.c \ 35 | paxos_lease.c \ 36 | task.c \ 37 | timeouts.c \ 38 | resource.c \ 39 | rindex.c \ 40 | watchdog.c \ 41 | monotime.c \ 42 | cmd.c \ 43 | client_cmd.c \ 44 | sanlock_sock.c \ 45 | env.c 46 | 47 | LIB_ENTIRE_SOURCE = \ 48 | client.c \ 49 | sanlock_sock.c \ 50 | crc32c.c \ 51 | diskio.c \ 52 | ondisk.c \ 53 | sizeflags.c \ 54 | delta_lease.c \ 55 | paxos_lease.c \ 56 | rindex.c \ 57 | direct.c \ 58 | task.c \ 59 | timeouts.c \ 60 | direct_lib.c \ 61 | monotime.c \ 62 | env.c 63 | 64 | LIB_CLIENT_SOURCE = \ 65 | client.c \ 66 | sanlock_sock.c \ 67 | env.c 68 | 69 | LIBPC_ENTIRE_SOURCE = libsanlock.pc.in 70 | LIBPC_CLIENT_SOURCE = libsanlock_client.pc.in 71 | 72 | VER=$(shell cat ../VERSION) 73 | CFLAGS += -DVERSION=\"$(VER)\" 74 | 75 | CMD_CFLAGS = $(CFLAGS) -fPIE -DPIE 76 | LIB_ENTIRE_CFLAGS = $(CFLAGS) -fPIC 77 | LIB_CLIENT_CFLAGS = $(CFLAGS) -fPIC 78 | 79 | CMD_LDFLAGS = $(LDFLAGS) -Wl,-z,relro -pie 80 | LIB_ENTIRE_LDFLAGS = $(LDFLAGS) -Wl,-z,relro -pie 81 | LIB_CLIENT_LDFLAGS = $(LDFLAGS) -Wl,-z,relro -pie 82 | 83 | CMD_LDADD = -lpthread -luuid -lrt -laio -lblkid -lsanlock -L../wdmd -lwdmd 84 | LIB_ENTIRE_LDADD = -lpthread -lrt -laio -lblkid -L../wdmd -lwdmd 85 | 86 | all: $(LIBSO_ENTIRE_TARGET) $(LIBSO_CLIENT_TARGET) $(CMD_TARGET) $(LIBPC_ENTIRE_TARGET) $(LIBPC_CLIENT_TARGET) 87 | 88 | $(LIBSO_ENTIRE_TARGET): $(LIB_ENTIRE_SOURCE) 89 | $(CC) $(LIB_ENTIRE_CFLAGS) $(LIB_ENTIRE_LDFLAGS) -shared -o $@ -Wl,-soname=$(LIB_ENTIRE_TARGET).so.$(SOMAJOR) $^ $(LIB_ENTIRE_LDADD) 90 | ln -sf $(LIBSO_ENTIRE_TARGET) $(LIB_ENTIRE_TARGET).so 91 | ln -sf $(LIBSO_ENTIRE_TARGET) $(LIB_ENTIRE_TARGET).so.$(SOMAJOR) 92 | 93 | $(LIBSO_CLIENT_TARGET): $(LIB_CLIENT_SOURCE) 94 | $(CC) $(LIB_CLIENT_CFLAGS) $(LIB_CLIENT_LDFLAGS) -shared -o $@ -Wl,-soname=$(LIB_CLIENT_TARGET).so.$(SOMAJOR) $^ 95 | ln -sf $(LIBSO_CLIENT_TARGET) $(LIB_CLIENT_TARGET).so 96 | ln -sf $(LIBSO_CLIENT_TARGET) $(LIB_CLIENT_TARGET).so.$(SOMAJOR) 97 | 98 | $(CMD_TARGET): $(LIBSO_ENTIRE_TARGET) $(CMD_SOURCE) 99 | $(CC) $(CMD_CFLAGS) $(CMD_LDFLAGS) $(CMD_SOURCE) $(CMD_LDADD) -o $@ -L. 100 | 101 | $(LIBPC_ENTIRE_TARGET): $(LIBPC_ENTIRE_SOURCE) 102 | sed -e "s/@VERSION@/$(VER)/" $(LIBPC_ENTIRE_SOURCE) > $(LIBPC_ENTIRE_TARGET) 103 | 104 | $(LIBPC_CLIENT_TARGET): $(LIBPC_CLIENT_SOURCE) 105 | sed -e "s/@VERSION@/$(VER)/" $(LIBPC_CLIENT_SOURCE) > $(LIBPC_CLIENT_TARGET) 106 | 107 | clean: 108 | rm -f *.o *.so *.so.* $(CMD_TARGET) $(LIBSO_ENTIRE_TARGET) $(LIBSO_CLIENT_TARGET) $(LIBPC_ENTIRE_TARGET) $(LIBPC_CLIENT_TARGET) 109 | 110 | INSTALL=$(shell which install) 111 | 112 | DESTDIR= 113 | BINDIR=/usr/sbin 114 | LIBDIR=/usr/lib64 115 | HEADIR=/usr/include 116 | MANDIR=/usr/share/man 117 | 118 | .PHONY: install 119 | install: all 120 | $(INSTALL) -d $(DESTDIR)/$(BINDIR) 121 | $(INSTALL) -d $(DESTDIR)/$(LIBDIR) 122 | $(INSTALL) -d $(DESTDIR)/$(HEADIR) 123 | $(INSTALL) -d $(DESTDIR)/$(MANDIR)/man8 124 | $(INSTALL) -d $(DESTDIR)/$(LIBDIR)/pkgconfig 125 | $(INSTALL) -c -m 755 $(CMD_TARGET) $(DESTDIR)/$(BINDIR) 126 | $(INSTALL) -c -m 755 $(LIBSO_ENTIRE_TARGET) $(DESTDIR)/$(LIBDIR) 127 | $(INSTALL) -c -m 755 $(LIBSO_CLIENT_TARGET) $(DESTDIR)/$(LIBDIR) 128 | $(INSTALL) -c -m 644 $(LIBPC_ENTIRE_TARGET) $(DESTDIR)/$(LIBDIR)/pkgconfig 129 | $(INSTALL) -c -m 644 $(LIBPC_CLIENT_TARGET) $(DESTDIR)/$(LIBDIR)/pkgconfig 130 | cp -a $(LIB_ENTIRE_TARGET).so $(DESTDIR)/$(LIBDIR) 131 | cp -a $(LIB_CLIENT_TARGET).so $(DESTDIR)/$(LIBDIR) 132 | cp -a $(LIB_ENTIRE_TARGET).so.$(SOMAJOR) $(DESTDIR)/$(LIBDIR) 133 | cp -a $(LIB_CLIENT_TARGET).so.$(SOMAJOR) $(DESTDIR)/$(LIBDIR) 134 | $(INSTALL) -c -m 644 $(HEADER_TARGET) $(DESTDIR)/$(HEADIR) 135 | $(INSTALL) -m 644 $(MAN_TARGET) $(DESTDIR)/$(MANDIR)/man8/ 136 | -------------------------------------------------------------------------------- /src/direct_lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define EXTERN 18 | #include "sanlock_internal.h" 19 | #include "sanlock_direct.h" 20 | #include "sanlock_admin.h" 21 | #include "diskio.h" 22 | #include "direct.h" 23 | #include "task.h" 24 | #include "timeouts.h" 25 | 26 | void log_level(uint32_t space_id GNUC_UNUSED, uint32_t res_id GNUC_UNUSED, 27 | char *name GNUC_UNUSED, 28 | int level GNUC_UNUSED, const char *fmt GNUC_UNUSED, ...); 29 | 30 | void log_level(uint32_t space_id GNUC_UNUSED, uint32_t res_id GNUC_UNUSED, 31 | char *name GNUC_UNUSED, 32 | int level GNUC_UNUSED, const char *fmt GNUC_UNUSED, ...) 33 | { 34 | } 35 | 36 | int lockspace_begin_rindex_op(char *space_name GNUC_UNUSED, int rindex_op GNUC_UNUSED, struct space_info *spi GNUC_UNUSED); 37 | int lockspace_begin_rindex_op(char *space_name GNUC_UNUSED, int rindex_op GNUC_UNUSED, struct space_info *spi GNUC_UNUSED) 38 | { 39 | return -1; 40 | } 41 | 42 | int lockspace_clear_rindex_op(char *space_name GNUC_UNUSED); 43 | int lockspace_clear_rindex_op(char *space_name GNUC_UNUSED) 44 | { 45 | return -1; 46 | } 47 | 48 | int lockspace_disk(char *space_name GNUC_UNUSED, struct sync_disk *disk GNUC_UNUSED); 49 | 50 | int lockspace_disk(char *space_name GNUC_UNUSED, struct sync_disk *disk GNUC_UNUSED) 51 | { 52 | return -1; 53 | } 54 | 55 | int host_info(char *space_name, uint64_t host_id, struct host_status *hs_out); 56 | 57 | int host_info(char *space_name GNUC_UNUSED, uint64_t host_id GNUC_UNUSED, struct host_status *hs_out GNUC_UNUSED) 58 | { 59 | return -1; 60 | } 61 | 62 | struct token; 63 | 64 | void check_mode_block(struct token *token GNUC_UNUSED, int q GNUC_UNUSED, char *dblock GNUC_UNUSED); 65 | 66 | void check_mode_block(struct token *token GNUC_UNUSED, int q GNUC_UNUSED, char *dblock GNUC_UNUSED) 67 | { 68 | } 69 | 70 | /* copied from host_id.c */ 71 | 72 | int test_id_bit(int host_id, char *bitmap); 73 | 74 | int test_id_bit(int host_id, char *bitmap) 75 | { 76 | char *byte = bitmap + ((host_id - 1) / 8); 77 | unsigned int bit = (host_id - 1) % 8; 78 | char mask; 79 | 80 | mask = 1 << bit; 81 | 82 | return (*byte & mask); 83 | } 84 | 85 | int get_rand(int a, int b); 86 | 87 | int get_rand(int a, int b) 88 | { 89 | return a + (int) (((float)(b - a + 1)) * random() / (RAND_MAX+1.0)); 90 | } 91 | 92 | static void setup_task_lib(struct task *task, int use_aio) 93 | { 94 | memset(task, 0, sizeof(struct task)); 95 | setup_task_aio(task, use_aio, LIB_AIO_CB_SIZE); 96 | sprintf(task->name, "%s", "lib"); 97 | } 98 | 99 | 100 | int sanlock_direct_write_lockspace(struct sanlk_lockspace *ls, int max_hosts_unused, 101 | uint32_t flags GNUC_UNUSED, uint32_t io_timeout) 102 | { 103 | struct task task; 104 | int rv; 105 | 106 | setup_task_lib(&task, 1); 107 | 108 | rv = direct_write_lockspace(&task, ls, io_timeout); 109 | 110 | close_task_aio(&task); 111 | 112 | return rv; 113 | } 114 | 115 | int sanlock_direct_write_resource(struct sanlk_resource *res, 116 | int max_hosts_unused, int num_hosts, 117 | uint32_t flags) 118 | { 119 | struct task task; 120 | int rv; 121 | 122 | setup_task_lib(&task, 1); 123 | 124 | rv = direct_write_resource(&task, res, num_hosts, 125 | (flags & SANLK_WRITE_CLEAR) ? 1 : 0); 126 | 127 | close_task_aio(&task); 128 | 129 | return rv; 130 | } 131 | 132 | int sanlock_direct_init(struct sanlk_lockspace *ls, 133 | struct sanlk_resource *res, 134 | int max_hosts_unused, int num_hosts, int use_aio) 135 | { 136 | struct task task; 137 | int rv; 138 | 139 | setup_task_lib(&task, use_aio); 140 | 141 | if (ls) 142 | rv = direct_write_lockspace(&task, ls, 0); 143 | else 144 | rv = direct_write_resource(&task, res, num_hosts, 0); 145 | 146 | close_task_aio(&task); 147 | 148 | return rv; 149 | } 150 | 151 | int sanlock_direct_align(struct sanlk_disk *disk_in) 152 | { 153 | struct sync_disk disk; 154 | int align_size, rv; 155 | 156 | memset(&disk, 0, sizeof(disk)); 157 | 158 | memcpy(disk.path, disk_in->path, SANLK_PATH_LEN); 159 | 160 | rv = open_disk(&disk); 161 | if (rv < 0) 162 | return rv; 163 | 164 | align_size = direct_align(&disk); 165 | 166 | close(disk.fd); 167 | 168 | return align_size; 169 | } 170 | 171 | -------------------------------------------------------------------------------- /src/crc32c.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copied from the btrfs-progs source code, which... 3 | * Copied from the kernel source code, lib/libcrc32c.c. 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the Free 7 | * Software Foundation; either version 2 of the License, or (at your option) 8 | * any later version. 9 | */ 10 | #include 11 | #include 12 | 13 | /* 14 | * This is the CRC-32C table 15 | * Generated with: 16 | * width = 32 bits 17 | * poly = 0x1EDC6F41 18 | * reflect input bytes = true 19 | * reflect output bytes = true 20 | */ 21 | 22 | static const uint32_t crc32c_table[256] = { 23 | 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 24 | 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 25 | 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 26 | 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 27 | 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, 28 | 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 29 | 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 30 | 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 31 | 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, 32 | 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 33 | 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 34 | 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 35 | 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 36 | 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, 37 | 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 38 | 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 39 | 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 40 | 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, 41 | 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 42 | 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 43 | 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 44 | 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 45 | 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, 46 | 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 47 | 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, 48 | 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 49 | 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 50 | 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 51 | 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 52 | 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, 53 | 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 54 | 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 55 | 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 56 | 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, 57 | 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 58 | 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 59 | 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 60 | 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 61 | 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 62 | 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 63 | 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 64 | 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 65 | 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, 66 | 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 67 | 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, 68 | 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 69 | 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 70 | 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 71 | 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 72 | 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, 73 | 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 74 | 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 75 | 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 76 | 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, 77 | 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 78 | 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 79 | 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 80 | 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 81 | 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, 82 | 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 83 | 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 84 | 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 85 | 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, 86 | 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L 87 | }; 88 | 89 | /* 90 | * Steps through buffer one byte at at time, calculates reflected 91 | * crc using table. 92 | */ 93 | 94 | uint32_t crc32c(uint32_t crc, uint8_t *data, size_t length); 95 | 96 | uint32_t crc32c(uint32_t crc, uint8_t *data, size_t length) 97 | { 98 | while (length--) 99 | crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8); 100 | 101 | return crc; 102 | } 103 | -------------------------------------------------------------------------------- /tests/direct_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 Red Hat, Inc. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | """ 8 | Test sanlock direct options. 9 | """ 10 | from __future__ import absolute_import 11 | 12 | import io 13 | import os 14 | import struct 15 | 16 | from . import constants 17 | from . import util 18 | from . units import MiB 19 | 20 | 21 | def test_init_lockspace(tmpdir): 22 | path = tmpdir.join("lockspace") 23 | size = MiB 24 | util.create_file(str(path), size) 25 | 26 | lockspace = "name:1:%s:0" % path 27 | util.sanlock("direct", "init", "-s", lockspace) 28 | 29 | with io.open(str(path), "rb") as f: 30 | magic, = struct.unpack("< I", f.read(4)) 31 | assert magic == constants.DELTA_DISK_MAGIC 32 | 33 | # TODO: check more stuff here... 34 | 35 | util.check_guard(str(path), size) 36 | 37 | 38 | def test_dump_lockspace_empty(tmpdir): 39 | path = tmpdir.join("lockspace") 40 | size = MiB 41 | util.create_file(str(path), size) 42 | 43 | lockspace = "name:1:%s:0" % path 44 | util.sanlock("direct", "init", "-s", lockspace) 45 | 46 | dump = "%s:0:1M" % path 47 | out = util.sanlock("direct", "dump", dump) 48 | 49 | lines = out.decode("utf-8").splitlines() 50 | spaces = [line.split() for line in lines] 51 | 52 | # Empty lockspace has no hosts. 53 | assert spaces == [ 54 | ['offset', 'lockspace', 'resource', 'timestamp', 'own', 'gen', 'lver'] 55 | ] 56 | 57 | 58 | def test_init_resource(tmpdir): 59 | path = tmpdir.join("resources") 60 | size = MiB 61 | util.create_file(str(path), size) 62 | 63 | resource = "ls_name:res_name:%s:0" % path 64 | util.sanlock("direct", "init", "-r", resource) 65 | 66 | with io.open(str(path), "rb") as f: 67 | magic, = struct.unpack("< I", f.read(4)) 68 | assert magic == constants.PAXOS_DISK_MAGIC 69 | 70 | # TODO: check more stuff here... 71 | 72 | util.check_guard(str(path), size) 73 | 74 | 75 | def test_dump_resources(tmpdir): 76 | path = tmpdir.join("resources") 77 | size = 8 * MiB 78 | util.create_file(str(path), size) 79 | 80 | # Write 2 resources with a hole between them. 81 | for i in [0, 2]: 82 | res = "ls_name:res_%d:%s:%dM" % (i, path, i) 83 | util.sanlock("direct", "init", "-r", res) 84 | 85 | dump = "%s:0:8M" % path 86 | out = util.sanlock("direct", "dump", dump) 87 | 88 | lines = out.decode("utf-8").splitlines() 89 | resources = [line.split() for line in lines] 90 | assert resources == [ 91 | ['offset', 'lockspace', 'resource', 'timestamp', 'own', 'gen', 'lver'], 92 | ['00000000', 'ls_name', 'res_0', '0000000000', '0000', '0000', '0'], 93 | ['02097152', 'ls_name', 'res_2', '0000000000', '0000', '0000', '0'], 94 | ] 95 | 96 | 97 | def test_dump_resources_start_before(tmpdir): 98 | path = tmpdir.join("resources") 99 | size = 8 * MiB 100 | util.create_file(str(path), size) 101 | 102 | # Write 2 resources at middle. 103 | for i in [4, 5]: 104 | res = "ls_name:res_%d:%s:%dM" % (i, path, i) 105 | util.sanlock("direct", "init", "-r", res) 106 | 107 | dump = "%s:2M:8M" % path 108 | out = util.sanlock("direct", "dump", dump) 109 | 110 | lines = out.decode("utf-8").splitlines() 111 | resources = [line.split() for line in lines] 112 | assert resources == [ 113 | ['offset', 'lockspace', 'resource', 'timestamp', 'own', 'gen', 'lver'], 114 | ['04194304', 'ls_name', 'res_4', '0000000000', '0000', '0000', '0'], 115 | ['05242880', 'ls_name', 'res_5', '0000000000', '0000', '0000', '0'], 116 | ] 117 | 118 | 119 | def test_path_with_colon(tmpdir): 120 | path = str(tmpdir.mkdir("with:colon").join("resources")) 121 | size = 8 * MiB 122 | util.create_file(path, size) 123 | 124 | # sanlock direct init does not support escaped colons in path. 125 | dirname, filename = os.path.split(path) 126 | res = "ls_name:res_0:%s:0M" % filename 127 | util.sanlock("direct", "init", "-r", res, cwd=dirname) 128 | 129 | # sanlock direct dump supports escaped colons in path. 130 | escaped_path = path.replace(":", "\\:") 131 | dump = "%s:0:8M" % escaped_path 132 | out = util.sanlock("direct", "dump", dump) 133 | 134 | lines = out.decode("utf-8").splitlines() 135 | resources = [line.split() for line in lines] 136 | assert resources == [ 137 | ['offset', 'lockspace', 'resource', 'timestamp', 'own', 'gen', 'lver'], 138 | ['00000000', 'ls_name', 'res_0', '0000000000', '0000', '0000', '0'], 139 | ] 140 | -------------------------------------------------------------------------------- /tests/sanlk_path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "sanlock.h" 7 | #include "sanlock_resource.h" 8 | 9 | #define DSTMAXSIZE 1024 10 | 11 | static int __test_passed = 0; 12 | 13 | #define check_perror(expression, fmt, args...) \ 14 | if (expression) { \ 15 | __test_passed++; \ 16 | } \ 17 | else { \ 18 | fprintf(stderr, "%s:%i " fmt "\n", __FILE__, __LINE__, ##args); \ 19 | exit(1); \ 20 | } 21 | 22 | void test_sanlock_path_export(void) 23 | { 24 | int rv, dst_len; 25 | char dst_str[DSTMAXSIZE]; 26 | const char *src_str, *dst_exp; 27 | 28 | /* regular behavior, no escapes */ 29 | src_str = "Hello World"; 30 | dst_exp = src_str; 31 | dst_len = strlen(dst_exp); 32 | 33 | memset(dst_str, 'X', DSTMAXSIZE); 34 | 35 | /* destination too short */ 36 | rv = sanlock_path_export(dst_str, src_str, dst_len); 37 | check_perror(rv == 0, "sanlock_path_export wrong return code: %u", rv); 38 | check_perror(dst_str[dst_len] == 'X', 39 | "sanlock_path_export buffer overflow"); 40 | 41 | /* destination long enough */ 42 | rv = sanlock_path_export(dst_str, src_str, dst_len + 1); 43 | check_perror(rv == dst_len, 44 | "sanlock_path_export wrong return code: %u", rv); 45 | check_perror(dst_str[dst_len] == '\0', 46 | "sanlock_path_import destination not terminated"); 47 | check_perror(!strncmp(dst_str, dst_exp, dst_len), 48 | "sanlock_path_export destination is different"); 49 | 50 | /* special behavior, escapes */ 51 | src_str = "Hello World:"; 52 | dst_exp = "Hello World\\:"; 53 | dst_len = strlen(dst_exp); 54 | 55 | memset(dst_str, 'X', DSTMAXSIZE); 56 | 57 | /* destination too short */ 58 | rv = sanlock_path_export(dst_str, src_str, dst_len); 59 | check_perror(rv == 0, "sanlock_path_export wrong return code: %u", rv); 60 | check_perror(dst_str[dst_len] == 'X', 61 | "sanlock_path_export buffer overflow"); 62 | 63 | /* destination long enough */ 64 | rv = sanlock_path_export(dst_str, src_str, dst_len + 1); 65 | check_perror(rv == dst_len, 66 | "sanlock_path_export wrong return code: %u", rv); 67 | check_perror(dst_str[dst_len] == '\0', 68 | "sanlock_path_import destination not terminated"); 69 | check_perror(!strncmp(dst_str, dst_exp, dst_len), 70 | "sanlock_path_export destination is different"); 71 | } 72 | 73 | void test_sanlock_path_import(void) 74 | { 75 | int rv, dst_len; 76 | char dst_str[DSTMAXSIZE]; 77 | const char *src_str, *dst_exp; 78 | 79 | /* regular behavior, no escapes */ 80 | src_str = "Hello World"; 81 | dst_exp = src_str; 82 | dst_len = strlen(dst_exp); 83 | 84 | memset(dst_str, 'X', DSTMAXSIZE); 85 | 86 | /* destination too short */ 87 | rv = sanlock_path_import(dst_str, src_str, dst_len); 88 | check_perror(rv == 0, "sanlock_path_import wrong return code: %u", rv); 89 | check_perror(dst_str[dst_len] == 'X', 90 | "sanlock_path_import buffer overflow"); 91 | 92 | /* destination long enough */ 93 | rv = sanlock_path_import(dst_str, src_str, dst_len + 1); 94 | check_perror(rv == dst_len, 95 | "sanlock_path_import wrong return code: %u", rv); 96 | check_perror(dst_str[dst_len] == '\0', 97 | "sanlock_path_import destination not terminated"); 98 | check_perror(!strncmp(dst_str, dst_exp, dst_len), 99 | "sanlock_path_import destination is different"); 100 | 101 | /* special behavior, escapes */ 102 | src_str = "Hello World\\:"; 103 | dst_exp = "Hello World:"; 104 | dst_len = strlen(dst_exp); 105 | 106 | memset(dst_str, 'X', DSTMAXSIZE); 107 | 108 | /* destination too short */ 109 | rv = sanlock_path_import(dst_str, src_str, dst_len); 110 | check_perror(rv == 0, "sanlock_path_import wrong return code: %u", rv); 111 | check_perror(dst_str[dst_len] == 'X', 112 | "sanlock_path_import buffer overflow"); 113 | 114 | /* destination long enough */ 115 | rv = sanlock_path_import(dst_str, src_str, dst_len + 1); 116 | check_perror(rv == dst_len, 117 | "sanlock_path_import wrong return code: %u", rv); 118 | check_perror(dst_str[dst_len] == '\0', 119 | "sanlock_path_import destination not terminated"); 120 | check_perror(!strncmp(dst_str, dst_exp, dst_len), 121 | "sanlock_path_import destination is different"); 122 | } 123 | 124 | int main(int argc __attribute__ ((unused)), 125 | char *argv[] __attribute__ ((unused))) 126 | { 127 | test_sanlock_path_export(); 128 | test_sanlock_path_import(); 129 | printf("OK, %i tests sucessfully passed.\n", __test_passed); 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /src/watchdog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2011 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "sanlock_internal.h" 28 | #include "log.h" 29 | #include "watchdog.h" 30 | 31 | /* 32 | * Purpose of watchdog: to forcibly reset the host in the case where a 33 | * supervised pid is running but sanlock daemon does not renew its lease 34 | * and does not kill the pid (or it kills the pid but the pid does not 35 | * exit). So, just before the pid begins running with granted leases, 36 | * /dev/watchdog needs to be armed to reboot the host if things go bad right 37 | * after the pid goes ahead. 38 | */ 39 | 40 | #include "../wdmd/wdmd.h" 41 | 42 | /* tell wdmd to open the watchdog device, set the fire timeout and begin keepalives */ 43 | int open_watchdog(int con, int fire_timeout) 44 | { 45 | int rv; 46 | 47 | if (!com.use_watchdog) 48 | return 0; 49 | 50 | rv = wdmd_open_watchdog(con, fire_timeout); 51 | if (rv < 0) { 52 | log_error("wdmd_open_watchdog fire_timeout %d error", fire_timeout); 53 | return -1; 54 | } 55 | 56 | return 0; 57 | } 58 | 59 | /* tell wdmd that this connection is still good and watchdog pings can continue for it */ 60 | void update_watchdog(struct space *sp, uint64_t timestamp, 61 | int id_renewal_fail_seconds) 62 | { 63 | int rv; 64 | 65 | if (!com.use_watchdog) 66 | return; 67 | 68 | rv = wdmd_test_live(sp->wd_fd, timestamp, timestamp + id_renewal_fail_seconds); 69 | if (rv < 0) 70 | log_erros(sp, "wdmd_test_live %llu failed %d", 71 | (unsigned long long)timestamp, rv); 72 | } 73 | 74 | /* connects to the wdmd daemon */ 75 | int connect_watchdog(struct space *sp) 76 | { 77 | int con; 78 | 79 | if (!com.use_watchdog) 80 | return 0; 81 | 82 | con = wdmd_connect(); 83 | if (con < 0) { 84 | log_erros(sp, "wdmd_connect failed %d", con); 85 | return -1; 86 | } 87 | 88 | return con; 89 | } 90 | 91 | /* associate wdmd keepalives to the continued liveness of this lockspace */ 92 | int activate_watchdog(struct space *sp, uint64_t timestamp, 93 | int id_renewal_fail_seconds, int con) 94 | { 95 | char name[WDMD_NAME_SIZE]; 96 | int test_interval, fire_timeout; 97 | uint64_t last_keepalive; 98 | int rv; 99 | 100 | if (!com.use_watchdog) 101 | return 0; 102 | 103 | memset(name, 0, sizeof(name)); 104 | 105 | snprintf(name, WDMD_NAME_SIZE - 1, "sanlock_%s:%llu", 106 | sp->space_name, (unsigned long long)sp->host_id); 107 | 108 | rv = wdmd_register(con, name); 109 | if (rv < 0) { 110 | log_erros(sp, "wdmd_register failed %d", rv); 111 | goto fail_close; 112 | } 113 | 114 | /* the refcount tells wdmd that it should not cleanly exit */ 115 | 116 | rv = wdmd_refcount_set(con); 117 | if (rv < 0) { 118 | log_erros(sp, "wdmd_refcount_set failed %d", rv); 119 | goto fail_close; 120 | } 121 | 122 | rv = wdmd_status(con, &test_interval, &fire_timeout, &last_keepalive); 123 | if (rv < 0) { 124 | log_erros(sp, "wdmd_status failed %d", rv); 125 | goto fail_clear; 126 | } 127 | 128 | if (fire_timeout != com.watchdog_fire_timeout) { 129 | log_erros(sp, "wdmd invalid fire_timeout %d vs %d", 130 | fire_timeout, com.watchdog_fire_timeout); 131 | goto fail_clear; 132 | } 133 | 134 | rv = wdmd_test_live(con, timestamp, timestamp + id_renewal_fail_seconds); 135 | if (rv < 0) { 136 | log_erros(sp, "wdmd_test_live in create failed %d", rv); 137 | goto fail_clear; 138 | } 139 | 140 | sp->wd_fd = con; 141 | return 0; 142 | 143 | fail_clear: 144 | wdmd_refcount_clear(con); 145 | fail_close: 146 | close(con); 147 | return -1; 148 | } 149 | 150 | void deactivate_watchdog(struct space *sp) 151 | { 152 | int rv; 153 | 154 | if (!com.use_watchdog) 155 | return; 156 | 157 | log_space(sp, "wdmd_test_live 0 0 to disable"); 158 | 159 | rv = wdmd_test_live(sp->wd_fd, 0, 0); 160 | if (rv < 0) { 161 | log_erros(sp, "wdmd_test_live in deactivate failed %d", rv); 162 | 163 | /* We really want this to succeed to avoid a reset, so retry 164 | after a short delay in case the problem was transient... */ 165 | 166 | usleep(500000); 167 | 168 | rv = wdmd_test_live(sp->wd_fd, 0, 0); 169 | if (rv < 0) 170 | log_erros(sp, "wdmd_test_live in deactivate 2 failed %d", rv); 171 | } 172 | 173 | wdmd_refcount_clear(sp->wd_fd); 174 | } 175 | 176 | void disconnect_watchdog(struct space *sp) 177 | { 178 | if (!com.use_watchdog) 179 | return; 180 | 181 | close(sp->wd_fd); 182 | } 183 | 184 | -------------------------------------------------------------------------------- /tests/sanlk_mixmsg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "sanlock.h" 21 | #include "sanlock_resource.h" 22 | #include "sanlock_admin.h" 23 | #include "sanlock_sock.h" 24 | 25 | /* gcc with -lsanlock */ 26 | 27 | /* 28 | * sanlock direct init -s 1271384c-24db-4c9b-bebf-61a1916b6cb1:0:/dev/test/main:0 29 | * sanlock add_lockspace -s 1271384c-24db-4c9b-bebf-61a1916b6cb1:1:/dev/test/main:0 30 | */ 31 | 32 | /* copied from client.c */ 33 | static int send_header(int sock, int cmd, uint32_t cmd_flags, int datalen, 34 | uint32_t data, uint32_t data2) 35 | { 36 | struct sm_header header; 37 | int rv; 38 | 39 | memset(&header, 0, sizeof(header)); 40 | header.magic = SM_MAGIC; 41 | header.version = SM_PROTO; 42 | header.cmd = cmd; 43 | header.cmd_flags = cmd_flags; 44 | header.length = sizeof(header) + datalen; 45 | header.data = data; 46 | header.data2 = data2; 47 | 48 | retry: 49 | rv = send(sock, (void *) &header, sizeof(header), 0); 50 | if (rv == -1 && errno == EINTR) 51 | goto retry; 52 | 53 | if (rv < 0) 54 | return -errno; 55 | 56 | return 0; 57 | } 58 | 59 | int main(int argc, char *argv[]) 60 | { 61 | char rd1[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)]; 62 | char rd2[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)]; 63 | struct sanlk_resource *res1; 64 | struct sanlk_resource *res2; 65 | const char *lsname; 66 | const char *resname1; 67 | const char *resname2; 68 | char *path; 69 | int fd, rv; 70 | 71 | if (argc < 2) { 72 | printf("%s \n", argv[0]); 73 | return -1; 74 | } 75 | 76 | path = argv[1]; 77 | 78 | lsname = "1271384c-24db-4c9b-bebf-61a1916b6cb1"; 79 | resname1 = "2e794e7a-5a9c-4617-8cd0-dc03c917d7a1"; 80 | resname2 = "2e794e7a-5a9c-4617-8cd0-dc03c917d7a2"; 81 | 82 | memset(rd1, 0, sizeof(rd1)); 83 | memset(rd2, 0, sizeof(rd2)); 84 | 85 | res1 = (struct sanlk_resource *)&rd1; 86 | res2 = (struct sanlk_resource *)&rd2; 87 | 88 | strcpy(res1->lockspace_name, lsname); 89 | sprintf(res1->name, "%s", resname1); 90 | res1->num_disks = 1; 91 | strcpy(res1->disks[0].path, path); 92 | res1->disks[0].offset = 1048576; 93 | 94 | strcpy(res2->lockspace_name, lsname); 95 | sprintf(res2->name, "%s", resname2); 96 | res2->num_disks = 1; 97 | strcpy(res2->disks[0].path, path); 98 | res2->disks[0].offset = 2 * 1048576; 99 | 100 | /* 101 | struct sanlk_lockspace ls = { 0 }; 102 | sprintf(ls.name, lsname); 103 | sprintf(ls.host_id_disk.path, path); 104 | 105 | rv = sanlock_write_lockspace(&ls, 0, 0, 0); 106 | if (rv < 0) { 107 | printf("write_lockspace error %d\n", rv); 108 | return -1; 109 | } 110 | */ 111 | 112 | rv = sanlock_write_resource(res1, 0, 0, 0); 113 | if (rv < 0) { 114 | printf("write_resource1 error %d\n", rv); 115 | return -1; 116 | } 117 | rv = sanlock_write_resource(res2, 0, 0, 0); 118 | if (rv < 0) { 119 | printf("write_resource2 error %d\n", rv); 120 | return -1; 121 | } 122 | 123 | fd = sanlock_register(); 124 | if (fd < 0) { 125 | printf("register error %d\n", fd); 126 | return -1; 127 | } 128 | 129 | printf("acquiring both leases for registered fd %d\n", fd); 130 | 131 | rv = sanlock_acquire(fd, -1, 0, 1, &res1, NULL); 132 | if (rv < 0) { 133 | printf("acquire res1 error %d\n", rv); 134 | return -1; 135 | } 136 | 137 | rv = sanlock_acquire(fd, -1, 0, 1, &res2, NULL); 138 | if (rv < 0) { 139 | printf("acquire res2 error %d\n", rv); 140 | return -1; 141 | } 142 | 143 | printf("sleeping... check that both leases are held\n"); 144 | sleep(20); 145 | 146 | printf("sending res1 release header only\n"); 147 | rv = send_header(fd, SM_CMD_RELEASE, 0, sizeof(struct sanlk_resource), 1, -1); 148 | if (rv < 0) 149 | printf("send bad header error %d\n", rv); 150 | else 151 | printf("send bad header ok\n"); 152 | 153 | printf("sending res2 release interleaved\n"); 154 | rv = sanlock_release(fd, -1, 0, 1, &res2); 155 | if (rv < 0) 156 | printf("odd release res2 error %d\n", rv); 157 | else 158 | printf("odd release res2 ok\n"); 159 | 160 | printf("sending res1 release body only\n"); 161 | rv = send(fd, res1, sizeof(struct sanlk_resource), 0); 162 | if (rv < 0) 163 | printf("send bad body error %d\n", rv); 164 | else 165 | printf("send bad body ok\n"); 166 | 167 | /* 168 | * This is not simulating the recv() that each sanlock_release 169 | * would do in libsanlock to get a result for each release. 170 | * These would likely just cause the client block indefinitely 171 | * waiting for a reply that won't come because the bad release 172 | * calls were ignored. 173 | */ 174 | 175 | printf("sleeping... check which leases are held\n"); 176 | sleep(20); 177 | 178 | printf("releasing both leases normally\n"); 179 | rv = sanlock_release(fd, -1, 0, 1, &res1); 180 | if (rv < 0) 181 | printf("release res1 error %d\n", rv); 182 | else 183 | printf("release res1 ok\n"); 184 | 185 | rv = sanlock_release(fd, -1, 0, 1, &res2); 186 | if (rv < 0) 187 | printf("release res2 error %d\n", rv); 188 | else 189 | printf("release res2 ok\n"); 190 | 191 | printf("sleeping... check that both leases are released\n"); 192 | sleep(20); 193 | 194 | printf("acquiring lease res1\n"); 195 | rv = sanlock_acquire(fd, -1, 0, 1, &res1, NULL); 196 | if (rv < 0) 197 | printf("acquire res1 error %d\n", rv); 198 | else 199 | printf("acquire res1 ok\n"); 200 | 201 | /* exit should close our registered connection and 202 | automatically release res1 */ 203 | 204 | printf("exiting... check if held lease is released after exit\n"); 205 | 206 | return 0; 207 | } 208 | 209 | -------------------------------------------------------------------------------- /src/timeouts.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "sanlock_internal.h" 26 | #include "log.h" 27 | #include "task.h" 28 | #include "timeouts.h" 29 | 30 | void setup_timeouts(void) 31 | { 32 | /* 33 | * graceful shutdown is client pids stopping their activity and 34 | * releasing their sanlock leases in response to a killpath program 35 | * they configured, or in response to sigterm from sanlock if they 36 | * did not set a killpath program. It's an opportunity for the client 37 | * pid to exit more gracefully than getting sigkill. If the client 38 | * pid does not release leases in response to the killpath/sigterm, 39 | * then eventually sanlock will escalate and send a sigkill. 40 | * 41 | * It's hard to know what portion of recovery time should be allocated 42 | * to graceful shutdown before escalating to sigkill. The smaller the 43 | * watchdog timeout, the less time between entering recovery mode and 44 | * the watchdog potentially firing. 10 seconds before the watchdog 45 | * will fire, the idea is to give up on graceful shutdown and resort 46 | * to sending sigkill to any client pids that have not released their 47 | * leases. This gives 10 sec for the pids to exit from sigkill, 48 | * sanlock to get the exit statuses, clear the expiring wdmd connection, 49 | * and hopefully have wdmd ping the watchdog again before it fires. 50 | * A graceful shutdown period of less than 10/15 sec seems pointless, 51 | * so if there is anything less than 10/15 sec available for a graceful 52 | * shutdown we don't bother and go directly to sigkill (this could 53 | * of course be changed if programs are indeed able to respond 54 | * quickly during graceful shutdown.) 55 | */ 56 | if (!com.kill_grace_set && (com.watchdog_fire_timeout < DEFAULT_WATCHDOG_FIRE_TIMEOUT)) { 57 | if (com.watchdog_fire_timeout < 60 && com.watchdog_fire_timeout >= 30) 58 | com.kill_grace_seconds = 15; 59 | else if (com.watchdog_fire_timeout < 30) 60 | com.kill_grace_seconds = 0; 61 | } 62 | } 63 | 64 | /* 65 | * Some of these timeouts depend on the the io_timeout used by *another* 66 | * host, passed as the arg, not the local io_timeout. 67 | */ 68 | 69 | /* All hosts are required to use the same watchdog_fire_timeout. */ 70 | int calc_host_dead_seconds(int io_timeout) 71 | { 72 | /* id_renewal_fail_seconds + com.watchdog_fire_timeout */ 73 | return (8 * io_timeout) + com.watchdog_fire_timeout; 74 | } 75 | 76 | int calc_id_renewal_seconds(int io_timeout) 77 | { 78 | return 2 * io_timeout; 79 | } 80 | 81 | int calc_id_renewal_fail_seconds(int io_timeout) 82 | { 83 | return 8 * io_timeout; 84 | } 85 | 86 | int calc_id_renewal_warn_seconds(int io_timeout) 87 | { 88 | return 6 * io_timeout; 89 | } 90 | 91 | int calc_set_bitmap_seconds(int io_timeout) 92 | { 93 | if (com.set_bitmap_seconds) 94 | return com.set_bitmap_seconds; 95 | /* 3 * id_renewal_seconds, somewhat random choice */ 96 | return 6 * io_timeout; 97 | } 98 | 99 | void log_timeouts(int io_timeout_arg) 100 | { 101 | int io_timeout_seconds = io_timeout_arg; 102 | int id_renewal_seconds = 2 * io_timeout_seconds; 103 | int id_renewal_fail_seconds = 8 * io_timeout_seconds; 104 | int id_renewal_warn_seconds = 6 * io_timeout_seconds; 105 | 106 | /* those above are chosen by us, the rest are based on them */ 107 | 108 | int host_dead_seconds = id_renewal_fail_seconds + com.watchdog_fire_timeout; 109 | int delta_large_delay = id_renewal_seconds + (6 * io_timeout_seconds); 110 | int delta_short_delay = 2 * io_timeout_seconds; 111 | 112 | int max = host_dead_seconds; 113 | if (delta_large_delay > max) 114 | max = delta_large_delay; 115 | 116 | int delta_acquire_held_max = max + delta_short_delay + (4 * io_timeout_seconds); 117 | int delta_acquire_held_min = max; 118 | int delta_acquire_free_max = delta_short_delay + (3 * io_timeout_seconds); 119 | int delta_acquire_free_min = delta_short_delay; 120 | int delta_renew_max = 2 * io_timeout_seconds; 121 | int delta_renew_min = 0; 122 | int paxos_acquire_held_max = host_dead_seconds + (7 * io_timeout_seconds); 123 | int paxos_acquire_held_min = host_dead_seconds; 124 | int paxos_acquire_free_max = 6 * io_timeout_seconds; 125 | int paxos_acquire_free_min = 0; 126 | int request_finish_seconds = 3 * id_renewal_seconds; /* random */ 127 | 128 | log_debug("io_timeout_seconds %d", io_timeout_seconds); 129 | log_debug("id_renewal_seconds %d", id_renewal_seconds); 130 | log_debug("id_renewal_fail_seconds %d", id_renewal_fail_seconds); 131 | log_debug("id_renewal_warn_seconds %d", id_renewal_warn_seconds); 132 | 133 | log_debug("host_dead_seconds %d", host_dead_seconds); 134 | log_debug("delta_large_delay %d", delta_large_delay); 135 | log_debug("delta_short_delay %d", delta_short_delay); 136 | log_debug("delta_acquire_held_max %d", delta_acquire_held_max); 137 | log_debug("delta_acquire_held_min %d", delta_acquire_held_min); 138 | log_debug("delta_acquire_free_max %d", delta_acquire_free_max); 139 | log_debug("delta_acquire_free_min %d", delta_acquire_free_min); 140 | log_debug("delta_renew_max %d", delta_renew_max); 141 | log_debug("delta_renew_min %d", delta_renew_min); 142 | log_debug("paxos_acquire_held_max %d", paxos_acquire_held_max); 143 | log_debug("paxos_acquire_held_min %d", paxos_acquire_held_min); 144 | log_debug("paxos_acquire_free_max %d", paxos_acquire_free_max); 145 | log_debug("paxos_acquire_free_min %d", paxos_acquire_free_min); 146 | log_debug("request_finish_seconds %d", request_finish_seconds); 147 | } 148 | -------------------------------------------------------------------------------- /tests/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 Red Hat, Inc. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | """ 8 | Testing utilities 9 | """ 10 | from __future__ import absolute_import 11 | 12 | import errno 13 | import io 14 | import os 15 | import socket 16 | import struct 17 | import subprocess 18 | import time 19 | 20 | from . units import KiB 21 | 22 | TESTDIR = os.path.dirname(__file__) 23 | SANLOCK = os.path.join(TESTDIR, os.pardir, "src", "sanlock") 24 | 25 | GUARD = b"X" 26 | GUARD_SIZE = 4 * KiB 27 | 28 | 29 | class TimeoutExpired(Exception): 30 | """ Raised when timeout expired """ 31 | 32 | 33 | class CommandError(Exception): 34 | msg = ("Command {self.cmd} failed with returncode={self.returncode}, " 35 | "stdout={self.stdout!r}, stderr={self.stderr!r}") 36 | 37 | def __init__(self, cmd, returncode, stdout, stderr): 38 | self.cmd = cmd 39 | self.returncode = returncode 40 | self.stdout = stdout 41 | self.stderr = stderr 42 | 43 | def __str__(self): 44 | return self.msg.format(self=self) 45 | 46 | 47 | def start_daemon(): 48 | cmd = [SANLOCK, "daemon", 49 | # no fork and print all logging to stderr 50 | "-D", 51 | # don't use watchdog through wdmd 52 | "-w", "0", 53 | # don't use mlockall 54 | "-l", "0", 55 | # don't use high priority (RR) scheduling 56 | "-h", "0", 57 | # run as current user instead of "sanlock" 58 | "-U", os.environ["USER"], 59 | "-G", os.environ["USER"]] 60 | return subprocess.Popen(cmd) 61 | 62 | 63 | def wait_for_daemon(timeout): 64 | """ 65 | Wait until deamon is accepting connections 66 | """ 67 | deadline = time.time() + timeout 68 | path = os.path.join(os.environ["SANLOCK_RUN_DIR"], "sanlock.sock") 69 | s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 70 | try: 71 | while True: 72 | try: 73 | s.connect(path) 74 | return 75 | except EnvironmentError as e: 76 | if e.errno not in (errno.ECONNREFUSED, errno.ENOENT): 77 | raise # Unexpected error 78 | if time.time() > deadline: 79 | raise TimeoutExpired 80 | time.sleep(0.05) 81 | finally: 82 | s.close() 83 | 84 | 85 | def sanlock(*args, cwd=None): 86 | """ 87 | Run sanlock returning the process stdout, or raising 88 | util.CommandError on failures. 89 | """ 90 | cmd = [SANLOCK] 91 | cmd.extend(args) 92 | p = subprocess.Popen( 93 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) 94 | out, err = p.communicate() 95 | if p.returncode: 96 | raise CommandError(cmd, p.returncode, out, err) 97 | return out 98 | 99 | 100 | def wait_for_termination(p, timeout): 101 | """ 102 | Wait until process terminates, or timeout expires. 103 | """ 104 | deadline = time.time() + timeout 105 | while True: 106 | if p.poll() is not None: 107 | return 108 | if time.time() > deadline: 109 | raise TimeoutExpired 110 | time.sleep(0.05) 111 | 112 | 113 | def create_file(path, size, guard=True): 114 | """ 115 | Create sparse file of size bytes. 116 | 117 | If guard is True, add a guard area beyond the end of the file. 118 | """ 119 | with io.open(path, "wb") as f: 120 | f.truncate(size) 121 | 122 | if guard: 123 | write_guard(path, size) 124 | 125 | 126 | def write_guard(path, offset): 127 | """ 128 | Write guard areas at offset and fill with guard byte. 129 | 130 | Use check_guard() to verify that nothing was written to the guard area. 131 | """ 132 | with io.open(path, "rb+") as f: 133 | f.seek(offset) 134 | f.write(GUARD * GUARD_SIZE) 135 | 136 | 137 | def check_guard(path, offset): 138 | """ 139 | Assert that guard area at offset was not modified. 140 | """ 141 | with io.open(path, "rb") as f: 142 | f.seek(offset) 143 | assert f.read(GUARD_SIZE) == GUARD * GUARD_SIZE 144 | 145 | 146 | def check_rindex_entry(entry, name, offset=None, flags=None): 147 | # See src/ondisk.c rindex_entry_in() 148 | e_offset, e_flags, e_unused, e_name = struct.unpack(":::[::...]: 39 | * 48 SANLK_NAME_LEN 40 | * + 1 colon 41 | * + 48 SANLK_NAME_LEN 42 | * + 1 colon 43 | * + 4184 (4 MAX_DISKS * (1024 SANLK_PATH_LEN + 1 colon + 20 offset + 1 colon)) 44 | * + 20 lver 45 | * ------ 46 | * 4302 47 | */ 48 | 49 | #define SANLK_MAX_RES_STR 4400 50 | 51 | /* TODO: add more padding to sanlk_disk so we can extend sync_disk 52 | later without changing abi */ 53 | 54 | struct sanlk_disk { 55 | char path[SANLK_PATH_LEN]; /* must include terminating \0 */ 56 | uint64_t offset; 57 | uint32_t pad1; 58 | uint32_t pad2; 59 | }; 60 | 61 | /* 62 | * PERSISTENT: if the pid holding the resource lease exits, 63 | * the lease will not be released, but will be moved to the 64 | * orphans list. On disk and from the perspective of other 65 | * hosts, nothing changes when a lease is orphaned; it continues 66 | * to be held by the host. 67 | * 68 | * (If persistent shared locks are used on a resource, then 69 | * all the locks on that resource should be persistent.) 70 | * 71 | * A new process can acquire an orphan resource using 72 | * the ACQUIRE_ORPHAN flag. This implies that the lockspace 73 | * had continued running and the resource not released by the 74 | * host between the time the resource became an orphan and was 75 | * then transferred to a new process. 76 | * 77 | * Orphan impact on the lockspace: if the lockspace is stopping 78 | * because of rem, or lease failure, the ls config option 79 | * USED_BY_ORPHANS will block the release of the lockspace 80 | * (like the USED option), if orphans exist for the lockspace. 81 | * Without USED_BY_ORPHANS, the lockspace would exit and 82 | * leave the orphan resources unchanged (not released) on disk. 83 | * The unreleased orphan resources could be acquired by another 84 | * host if the lockspace lease is cleanly released. 85 | */ 86 | 87 | #define SANLK_RES_LVER 0x00000001 /* lver field is set */ 88 | #define SANLK_RES_NUM_HOSTS 0x00000002 /* data32 field is new num_hosts */ 89 | #define SANLK_RES_SHARED 0x00000004 90 | #define SANLK_RES_PERSISTENT 0x00000008 91 | #define SANLK_RES_ALIGN1M 0x00000010 92 | #define SANLK_RES_ALIGN2M 0x00000020 93 | #define SANLK_RES_ALIGN4M 0x00000040 94 | #define SANLK_RES_ALIGN8M 0x00000080 95 | #define SANLK_RES_SECTOR512 0x00000100 96 | #define SANLK_RES_SECTOR4K 0x00000200 97 | 98 | struct sanlk_resource { 99 | char lockspace_name[SANLK_NAME_LEN]; /* terminating \0 not required */ 100 | char name[SANLK_NAME_LEN]; /* terminating \0 not required */ 101 | uint64_t lver; /* use with SANLK_RES_LVER */ 102 | uint64_t data64; /* per-resource command-specific data */ 103 | uint32_t data32; /* per-resource command-specific data */ 104 | uint32_t unused; 105 | uint32_t flags; /* SANLK_RES_ */ 106 | uint32_t num_disks; 107 | /* followed by num_disks sanlk_disk structs */ 108 | struct sanlk_disk disks[0]; 109 | }; 110 | 111 | /* make these values match the RES equivalent in case of typos */ 112 | #define SANLK_RIF_ALIGN1M 0x00000010 113 | #define SANLK_RIF_ALIGN2M 0x00000020 114 | #define SANLK_RIF_ALIGN4M 0x00000040 115 | #define SANLK_RIF_ALIGN8M 0x00000080 116 | #define SANLK_RIF_SECTOR512 0x00000100 117 | #define SANLK_RIF_SECTOR4K 0x00000200 118 | 119 | struct sanlk_rindex { 120 | uint32_t flags; /* SANLK_RIF_ */ 121 | uint32_t max_resources; /* the max res structs that will follow rindex */ 122 | uint64_t unused; 123 | char lockspace_name[SANLK_NAME_LEN]; /* terminating \0 not required */ 124 | struct sanlk_disk disk; /* location of rindex */ 125 | }; 126 | 127 | struct sanlk_rentry { 128 | char name[SANLK_NAME_LEN]; /* terminating \0 not required */ 129 | uint64_t offset; 130 | uint32_t flags; 131 | uint32_t unused; 132 | }; 133 | 134 | /* command-specific command options (can include per resource data, but 135 | that requires the extra work of segmenting it by resource name) */ 136 | 137 | struct sanlk_options { 138 | char owner_name[SANLK_NAME_LEN]; /* optional user friendly name */ 139 | uint32_t flags; 140 | uint32_t len; /* unused and ignored */ 141 | /* followed by len bytes (unused and ignored) */ 142 | char str[0]; 143 | }; 144 | 145 | #define SANLK_LSF_ADD 0x00000001 146 | #define SANLK_LSF_REM 0x00000002 147 | 148 | /* make these values match the RES equivalent in case of typos */ 149 | #define SANLK_LSF_ALIGN1M 0x00000010 150 | #define SANLK_LSF_ALIGN2M 0x00000020 151 | #define SANLK_LSF_ALIGN4M 0x00000040 152 | #define SANLK_LSF_ALIGN8M 0x00000080 153 | #define SANLK_LSF_SECTOR512 0x00000100 154 | #define SANLK_LSF_SECTOR4K 0x00000200 155 | 156 | struct sanlk_lockspace { 157 | char name[SANLK_NAME_LEN]; 158 | uint64_t host_id; 159 | uint32_t flags; /* SANLK_LSF_ */ 160 | struct sanlk_disk host_id_disk; 161 | }; 162 | 163 | struct sanlk_host { 164 | uint64_t host_id; 165 | uint64_t generation; 166 | uint64_t timestamp; 167 | uint32_t io_timeout; 168 | uint32_t flags; 169 | }; 170 | 171 | struct sanlk_host_event { 172 | uint64_t host_id; 173 | uint64_t generation; 174 | uint64_t event; 175 | uint64_t data; 176 | }; 177 | 178 | size_t sanlock_path_export(char *dst, const char *src, size_t dstlen); 179 | size_t sanlock_path_import(char *dst, const char *src, size_t dstlen); 180 | 181 | const char *sanlock_strerror(int rv); 182 | 183 | #endif 184 | -------------------------------------------------------------------------------- /src/helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Red Hat, Inc. 3 | * 4 | * This copyrighted material is made available to anyone wishing to use, 5 | * modify, copy, or redistribute it subject to the terms and conditions 6 | * of the GNU General Public License v2 or (at your option) any later version. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "sanlock.h" 31 | #include "monotime.h" 32 | #include "helper.h" 33 | 34 | /* only need sysfs functions */ 35 | struct sync_disk; 36 | struct task; 37 | #include "diskio.h" 38 | 39 | #define MAX_AV_COUNT 8 40 | 41 | static void run_path(struct helper_msg *hm) 42 | { 43 | char arg[SANLK_HELPER_ARGS_LEN]; 44 | char *args = hm->args; 45 | char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */ 46 | int av_count = 0; 47 | int i, arg_len, args_len; 48 | 49 | for (i = 0; i < MAX_AV_COUNT + 1; i++) 50 | av[i] = NULL; 51 | 52 | av[av_count++] = strdup(hm->path); 53 | 54 | if (!args[0]) 55 | goto pid_arg; 56 | 57 | /* this should already be done, but make sure */ 58 | args[SANLK_HELPER_ARGS_LEN - 1] = '\0'; 59 | 60 | memset(&arg, 0, sizeof(arg)); 61 | arg_len = 0; 62 | args_len = strlen(args); 63 | 64 | for (i = 0; i < args_len; i++) { 65 | if (!args[i]) 66 | break; 67 | 68 | if (av_count == MAX_AV_COUNT) 69 | break; 70 | 71 | if (args[i] == '\\') { 72 | if (i == (args_len - 1)) 73 | break; 74 | i++; 75 | 76 | if (args[i] == '\\') { 77 | arg[arg_len++] = args[i]; 78 | continue; 79 | } 80 | if (isspace(args[i])) { 81 | arg[arg_len++] = args[i]; 82 | continue; 83 | } else { 84 | break; 85 | } 86 | } 87 | 88 | if (isalnum(args[i]) || ispunct(args[i])) { 89 | arg[arg_len++] = args[i]; 90 | } else if (isspace(args[i])) { 91 | if (arg_len) 92 | av[av_count++] = strdup(arg); 93 | 94 | memset(arg, 0, sizeof(arg)); 95 | arg_len = 0; 96 | } else { 97 | break; 98 | } 99 | } 100 | 101 | if ((av_count < MAX_AV_COUNT) && arg_len) { 102 | av[av_count++] = strdup(arg); 103 | } 104 | 105 | pid_arg: 106 | if ((av_count < MAX_AV_COUNT) && hm->pid) { 107 | memset(arg, 0, sizeof(arg)); 108 | snprintf(arg, sizeof(arg)-1, "%d", hm->pid); 109 | av[av_count++] = strdup(arg); 110 | } 111 | 112 | execvp(av[0], av); 113 | } 114 | 115 | static int read_hm(int fd, struct helper_msg *hm) 116 | { 117 | int rv; 118 | retry: 119 | rv = read(fd, hm, sizeof(struct helper_msg)); 120 | if (rv == -1 && errno == EINTR) 121 | goto retry; 122 | 123 | if (rv != sizeof(struct helper_msg)) 124 | return -1; 125 | return 0; 126 | } 127 | 128 | static int send_status(int fd) 129 | { 130 | struct helper_status hs; 131 | int rv; 132 | 133 | memset(&hs, 0, sizeof(hs)); 134 | 135 | hs.type = HELPER_STATUS; 136 | 137 | rv = write(fd, &hs, sizeof(hs)); 138 | 139 | if (rv == sizeof(hs)) 140 | return 0; 141 | return -1; 142 | } 143 | 144 | #define log_debug(fmt, args...) \ 145 | do { \ 146 | if (log_stderr) \ 147 | fprintf(stderr, "helper %ld " fmt "\n", time(NULL), ##args); \ 148 | } while (0) 149 | 150 | #define STANDARD_TIMEOUT_MS (HELPER_STATUS_INTERVAL*1000) 151 | #define RECOVERY_TIMEOUT_MS 1000 152 | 153 | int run_helper(int in_fd, int out_fd, int log_stderr) 154 | { 155 | unsigned int sysfs_val; 156 | char name[16]; 157 | struct pollfd pollfd; 158 | struct helper_msg hm; 159 | unsigned int fork_count = 0; 160 | unsigned int wait_count = 0; 161 | time_t now, last_send, last_good = 0; 162 | int timeout = STANDARD_TIMEOUT_MS; 163 | int rv, pid, status; 164 | 165 | memset(name, 0, sizeof(name)); 166 | sprintf(name, "%s", "sanlock-helper"); 167 | prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); 168 | 169 | rv = setgroups(0, NULL); 170 | if (rv < 0) 171 | log_debug("error clearing helper groups errno %i", errno); 172 | 173 | memset(&pollfd, 0, sizeof(pollfd)); 174 | pollfd.fd = in_fd; 175 | pollfd.events = POLLIN; 176 | 177 | now = monotime(); 178 | last_send = now; 179 | rv = send_status(out_fd); 180 | if (!rv) 181 | last_good = now; 182 | 183 | while (1) { 184 | rv = poll(&pollfd, 1, timeout); 185 | if (rv == -1 && errno == EINTR) 186 | continue; 187 | 188 | if (rv < 0) 189 | exit(0); 190 | 191 | now = monotime(); 192 | 193 | if (now - last_good >= HELPER_STATUS_INTERVAL && 194 | now - last_send >= 2) { 195 | last_send = now; 196 | rv = send_status(out_fd); 197 | if (!rv) 198 | last_good = now; 199 | } 200 | 201 | memset(&hm, 0, sizeof(hm)); 202 | 203 | if (pollfd.revents & POLLIN) { 204 | rv = read_hm(in_fd, &hm); 205 | if (rv) 206 | continue; 207 | 208 | if (hm.type == HELPER_MSG_RUNPATH) { 209 | pid = fork(); 210 | if (!pid) { 211 | run_path(&hm); 212 | exit(-1); 213 | } 214 | 215 | fork_count++; 216 | 217 | /* 218 | log_debug("helper fork %d count %d %d %s %s", 219 | pid, fork_count, wait_count, 220 | hm.path, hm.args); 221 | */ 222 | } else if (hm.type == HELPER_MSG_KILLPID) { 223 | kill(hm.pid, hm.sig); 224 | 225 | } else if (hm.type == HELPER_MSG_WRITE_SYSFS) { 226 | sysfs_val = atoi(hm.args); 227 | rv = write_sysfs_uint(hm.path, sysfs_val); 228 | log_debug("write_sysfs %s %u rv %d", hm.path, sysfs_val, rv); 229 | } 230 | } 231 | 232 | if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) 233 | exit(0); 234 | 235 | /* collect child exits until no more children exist (ECHILD) 236 | or none are ready (WNOHANG) */ 237 | 238 | while (1) { 239 | rv = waitpid(-1, &status, WNOHANG); 240 | if (rv > 0) { 241 | wait_count++; 242 | 243 | /* 244 | log_debug("helper wait %d count %d %d", 245 | rv, fork_count, wait_count); 246 | */ 247 | continue; 248 | } 249 | 250 | /* no more children to wait for or no children 251 | have exited */ 252 | 253 | if (rv < 0 && errno == ECHILD) { 254 | if (timeout == RECOVERY_TIMEOUT_MS) { 255 | log_debug("helper no children count %d %d", 256 | fork_count, wait_count); 257 | } 258 | timeout = STANDARD_TIMEOUT_MS; 259 | } else { 260 | timeout = RECOVERY_TIMEOUT_MS; 261 | } 262 | break; 263 | } 264 | } 265 | 266 | return 0; 267 | } 268 | -------------------------------------------------------------------------------- /tests/test-recovery.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # recovery tests based on 10 sec io timeout 5 | # 6 | 7 | 8 | dev=$1 9 | 10 | echo test lockspace storage loss, recovery by lease release using killpath 11 | echo messages: sanlock check lease warn/fail, kill 100, all pids clear 12 | echo messages: wdmd warn, close, fail 13 | echo messages: killpath_pause 14 | date 15 | set -x 16 | ./clientn 4 start $dev 1 /root/killpath_pause 17 | sleep 5 18 | ./clientn 4 error $dev 19 | sleep 150 20 | ./clientn 4 resume $dev 1 21 | sleep 5 22 | killall -9 sanlk_client 23 | sleep 5 24 | set +x 25 | 26 | 27 | echo test lockspace storage loss, recovery by escalation from killpath to sigkill 28 | echo messages: sanlock check lease warn/fail, kill 100, kill 9, dead, all pids clear 29 | echo messages: wdmd warn, close, fail 30 | echo messages: killpath_args 31 | date 32 | set -x 33 | ./clientn 4 start $dev 1 /root/killpath_args 34 | sleep 5 35 | ./clientn 4 error $dev 36 | sleep 150 37 | ./clientn 4 linear $dev 1 38 | sleep 5 39 | set +x 40 | 41 | 42 | echo test lockspace storage loss, recovery by pid exit using killpath 43 | echo messages: sanlock check lease warn/fail, kill 100, dead, all pids clear 44 | echo messages: wdmd warn, close, fail 45 | echo messages: killpath_term 46 | date 47 | set -x 48 | ./clientn 4 start $dev 1 /root/killpath_term 49 | sleep 5 50 | ./clientn 4 error $dev 51 | sleep 150 52 | ./clientn 4 linear $dev 1 53 | sleep 5 54 | set +x 55 | 56 | 57 | echo test lockspace storage loss, recovery by pid sigterm without killpath 58 | echo messages: sanlock check lease warn/fail, kill 15, dead, all pids clear 59 | echo messages: wdmd warn, close, fail 60 | date 61 | set -x 62 | ./clientn 4 start $dev 1 none 63 | sleep 5 64 | ./clientn 4 error $dev 65 | sleep 150 66 | ./clientn 4 linear $dev 1 67 | sleep 5 68 | set +x 69 | 70 | 71 | echo test lockspace storage delay, small enough to have no effect 72 | echo messages: none 73 | date 74 | set -x 75 | ./clientn 4 start $dev 1 none 76 | sleep 22 77 | ./clientn 4 iodelay $dev 57 78 | sleep 5 79 | killall -9 sanlk_client 80 | sleep 5 81 | set +x 82 | 83 | 84 | echo test lockspace storage delay, long enough to produce sanlock warning, 85 | echo but not failure, not long enough for wdmd warn or close 86 | echo messages: sanlock check lease warn 87 | date 88 | set -x 89 | ./clientn 4 start $dev 1 none 90 | sleep 22 91 | ./clientn 4 iodelay $dev 67 92 | sleep 5 93 | killall -9 sanlk_client 94 | sleep 5 95 | set +x 96 | 97 | 98 | echo test lockspace storage delay, long enough to produce sanlock warning, 99 | echo but not failure/recovery, long enough for wdmd warn and close 100 | echo messages: sanlock check lease warn 101 | echo messages: wdmd warn, close 102 | date 103 | set -x 104 | ./clientn 4 start $dev 1 none 105 | sleep 22 106 | ./clientn 4 iodelay $dev 77 107 | sleep 5 108 | killall -9 sanlk_client 109 | sleep 5 110 | set +x 111 | 112 | 113 | echo test lockspace storage delay, long enough to produce sanlock warning, 114 | echo failure/recovery, recovery by lease release using killpath 115 | echo messages: sanlock check lease warn/fail, kill 100, all pids clear 116 | echo messages: killpath_pause 117 | echo messages: wdmd warn, close, fail 118 | date 119 | set -x 120 | ./clientn 4 start $dev 1 /root/killpath_pause 121 | sleep 22 122 | ./clientn 4 iodelay $dev 87 123 | sleep 5 124 | set +x 125 | 126 | 127 | echo test lockspace storage delay, long enough to produce sanlock warning, 128 | echo failure/recovery, recovery by pid sigterm without killpath 129 | echo messages: sanlock check lease warn/fail, kill 15, dead, all pids clear 130 | echo messages: wdmd warn, close, fail 131 | date 132 | set -x 133 | ./clientn 4 start $dev 1 none 134 | sleep 22 135 | ./clientn 4 iodelay $dev 87 136 | sleep 5 137 | set +x 138 | 139 | 140 | echo test daemon run delay, small enough to have no effect 141 | echo messages: none 142 | date 143 | set -x 144 | ./clientn 4 start $dev 1 none 145 | sleep 22 146 | ./clientn 4 delay 58 147 | sleep 5 148 | killall -9 sanlk_client 149 | sleep 5 150 | set +x 151 | 152 | 153 | echo test daemon run delay, long enough to produce sanlock warning, 154 | echo but not failure, not long enough for wdmd warn or close 155 | echo messages: sanlock check lease warn 156 | date 157 | set -x 158 | ./clientn 4 start $dev 1 none 159 | sleep 22 160 | ./clientn 4 delay 68 161 | sleep 5 162 | killall -9 sanlk_client 163 | sleep 5 164 | set +x 165 | 166 | 167 | echo test daemon run delay, long enough to produce sanlock warning, 168 | echo but not failure, long enough for wdmd warn and close 169 | echo messages: sanlock check lease warn 170 | echo messages: wdmd warn, close 171 | date 172 | set -x 173 | ./clientn 4 start $dev 1 none 174 | sleep 22 175 | ./clientn 4 delay 78 176 | sleep 5 177 | killall -9 sanlk_client 178 | sleep 5 179 | set +x 180 | 181 | 182 | echo test daemon run delay, long enough to produce sanlock 183 | echo failure/recovery, recovery by lease release using killpath 184 | echo messages: sanlock check lease fail, kill 100, all pids clear 185 | echo messages: wdmd warn, close, fail 186 | echo messages: killpath_pause 187 | date 188 | set -x 189 | ./clientn 4 start $dev 1 /root/killpath_pause 190 | sleep 22 191 | ./clientn 4 delay 88 192 | sleep 5 193 | ./clientn 4 resume $dev 1 194 | sleep 5 195 | killall -9 sanlk_client 196 | sleep 5 197 | set +x 198 | 199 | 200 | echo test daemon run delay, long enough to produce sanlock 201 | echo failure/recovery, recovery by pid sigterm without killpath 202 | echo messages: sanlock check lease fail, kill 15, dead, all pids clear 203 | echo messages: wdmd warn, close, fail 204 | date 205 | set -x 206 | ./clientn 4 start $dev 1 none 207 | sleep 22 208 | ./clientn 4 delay 88 209 | sleep 5 210 | set +x 211 | 212 | 213 | echo test daemon run delay, long enough to produce sanlock 214 | echo failure/recovery, recovery by pid sigkill after skipping killpath 215 | echo messages: sanlock check lease fail, kill 9, dead, all pids clear 216 | echo messages: wdmd warn, close, fail 217 | date 218 | set -x 219 | ./clientn 4 start $dev 1 /root/killpath_pause 220 | sleep 22 221 | ./clientn 4 delay 130 222 | sleep 5 223 | set +x 224 | 225 | 226 | echo test daemon run delay, long enough to produce sanlock 227 | echo failure/recovery, recovery by pid sigkill without killpath 228 | echo messages: sanlock check lease fail, kill 9, dead, all pids clear 229 | echo messages: wdmd warn, close, fail 230 | date 231 | set -x 232 | ./clientn 4 start $dev 1 none 233 | sleep 22 234 | ./clientn 4 delay 130 235 | sleep 5 236 | set +x 237 | 238 | 239 | echo test daemon run delay, long enough to produce watchdog firing 240 | echo messages: wdmd warn, close, fail 241 | date 242 | set -x 243 | ./clientn 4 start $dev 1 none 244 | sleep 22 245 | ./clientn 4 delay 140 246 | echo should not get here 247 | 248 | -------------------------------------------------------------------------------- /sanlock.spec.in: -------------------------------------------------------------------------------- 1 | # NOTE: this spec should be used only for developmemnt. 2 | # 3 | # To find the real sanlock spec use: 4 | # - Fedora: fedpkg clone sanlock 5 | # - RHEL: rhpkg clone sanlock 6 | # 7 | # This spec was created from Fedora spec and modified to work on CentOS. 8 | 9 | Name: sanlock 10 | Version: @VERSION@ 11 | Release: @RELEASE@%{?dist} 12 | Summary: A shared storage lock manager 13 | 14 | License: GPLv2 and GPLv2+ and LGPLv2+ 15 | URL: https://pagure.io/sanlock/ 16 | BuildRequires: gcc 17 | BuildRequires: libaio-devel 18 | BuildRequires: libblkid-devel 19 | BuildRequires: libuuid-devel 20 | BuildRequires: make 21 | BuildRequires: python3 22 | BuildRequires: python3-devel 23 | BuildRequires: python3-setuptools 24 | BuildRequires: systemd-units 25 | Requires: %{name}-lib = %{version}-%{release} 26 | Requires(pre): /usr/sbin/groupadd 27 | Requires(pre): /usr/sbin/useradd 28 | Requires(post): systemd-units 29 | Requires(post): systemd-sysv 30 | Requires(preun): systemd-units 31 | Requires(postun): systemd-units 32 | Source0: https://releases.pagure.org/sanlock/%{name}-%{version}.tar.gz 33 | 34 | %global python_package python3-%{name} 35 | 36 | %description 37 | The sanlock daemon manages leases for applications on hosts using shared storage. 38 | 39 | %prep 40 | %setup -q 41 | 42 | %build 43 | %if 0%{?fedora} 44 | %set_build_flags 45 | %endif 46 | # upstream does not require configure 47 | # upstream does not support _smp_mflags 48 | CFLAGS=$RPM_OPT_FLAGS make -C wdmd 49 | CFLAGS=$RPM_OPT_FLAGS make -C src 50 | CFLAGS=$RPM_OPT_FLAGS make -C python 51 | CFLAGS=$RPM_OPT_FLAGS make -C reset 52 | 53 | %install 54 | rm -rf $RPM_BUILD_ROOT 55 | make -C src \ 56 | install LIBDIR=%{_libdir} \ 57 | DESTDIR=$RPM_BUILD_ROOT 58 | make -C wdmd \ 59 | install LIBDIR=%{_libdir} \ 60 | DESTDIR=$RPM_BUILD_ROOT 61 | make -C python \ 62 | install LIBDIR=%{_libdir} \ 63 | DESTDIR=$RPM_BUILD_ROOT 64 | make -C reset \ 65 | install LIBDIR=%{_libdir} \ 66 | DESTDIR=$RPM_BUILD_ROOT 67 | 68 | 69 | install -D -m 0644 init.d/sanlock.service.native $RPM_BUILD_ROOT/%{_unitdir}/sanlock.service 70 | install -D -m 0755 init.d/wdmd $RPM_BUILD_ROOT/usr/lib/systemd/systemd-wdmd 71 | install -D -m 0644 init.d/wdmd.service.native $RPM_BUILD_ROOT/%{_unitdir}/wdmd.service 72 | install -D -m 0644 init.d/sanlk-resetd.service $RPM_BUILD_ROOT/%{_unitdir}/sanlk-resetd.service 73 | 74 | install -D -m 0644 src/logrotate.sanlock \ 75 | $RPM_BUILD_ROOT/etc/logrotate.d/sanlock 76 | 77 | install -D -m 0644 src/sanlock.conf \ 78 | $RPM_BUILD_ROOT/etc/sanlock/sanlock.conf 79 | 80 | install -D -m 0644 init.d/wdmd.sysconfig \ 81 | $RPM_BUILD_ROOT/etc/sysconfig/wdmd 82 | 83 | install -Dd -m 0755 $RPM_BUILD_ROOT/etc/wdmd.d 84 | install -Dd -m 0775 $RPM_BUILD_ROOT/%{_rundir}/sanlock 85 | install -Dd -m 0775 $RPM_BUILD_ROOT/%{_rundir}/sanlk-resetd 86 | 87 | %pre 88 | getent group sanlock > /dev/null || /usr/sbin/groupadd \ 89 | -g 179 sanlock 90 | getent passwd sanlock > /dev/null || /usr/sbin/useradd \ 91 | -u 179 -c "sanlock" -s /sbin/nologin -r \ 92 | -g 179 -d /run/sanlock sanlock 93 | /usr/sbin/usermod -a -G disk sanlock 94 | 95 | %post 96 | %systemd_post wdmd.service sanlock.service 97 | 98 | %preun 99 | %systemd_preun wdmd.service sanlock.service 100 | 101 | %postun 102 | %systemd_postun wdmd.service sanlock.service 103 | 104 | %files 105 | /usr/lib/systemd/systemd-wdmd 106 | %{_unitdir}/sanlock.service 107 | %{_unitdir}/wdmd.service 108 | %{_sbindir}/sanlock 109 | %{_sbindir}/wdmd 110 | %dir %{_sysconfdir}/wdmd.d 111 | %dir %{_sysconfdir}/sanlock 112 | %dir %attr(-,sanlock,sanlock) %{_rundir}/sanlock 113 | %{_mandir}/man8/wdmd* 114 | %{_mandir}/man8/sanlock* 115 | %config(noreplace) %{_sysconfdir}/logrotate.d/sanlock 116 | %config(noreplace) %{_sysconfdir}/sanlock/sanlock.conf 117 | %config(noreplace) %{_sysconfdir}/sysconfig/wdmd 118 | %doc init.d/sanlock 119 | %doc init.d/sanlock.service 120 | %doc init.d/wdmd.service 121 | 122 | %package lib 123 | Summary: A shared storage lock manager library 124 | 125 | %description lib 126 | The %{name}-lib package contains the runtime libraries for sanlock, 127 | a shared storage lock manager. 128 | Hosts connected to a common SAN can use this to synchronize their 129 | access to the shared disks. 130 | 131 | %ldconfig_scriptlets lib 132 | 133 | %files lib 134 | %{_libdir}/libsanlock.so.* 135 | %{_libdir}/libsanlock_client.so.* 136 | %{_libdir}/libwdmd.so.* 137 | 138 | %package -n %{python_package} 139 | Summary: Python bindings for the sanlock library 140 | Requires: %{name}-lib = %{version}-%{release} 141 | %if 0%{?fedora} 142 | %{?python_provide:%python_provide %{python_package}} 143 | %endif # fedora 144 | 145 | %description -n %{python_package} 146 | The %{python_package} package contains a module that permits applications 147 | written in the Python programming language to use the interface 148 | supplied by the sanlock library. 149 | 150 | %files -n %{python_package} 151 | %{python3_sitearch}/sanlock_python-*.egg-info 152 | %{python3_sitearch}/sanlock*.so 153 | 154 | %package devel 155 | Summary: Development files for %{name} 156 | Requires: %{name}-lib = %{version}-%{release} 157 | 158 | %description devel 159 | The %{name}-devel package contains libraries and header files for 160 | developing applications that use %{name}. 161 | 162 | %files devel 163 | %{_libdir}/libwdmd.so 164 | %{_includedir}/wdmd.h 165 | %{_libdir}/libsanlock.so 166 | %{_libdir}/libsanlock_client.so 167 | %{_includedir}/sanlock.h 168 | %{_includedir}/sanlock_rv.h 169 | %{_includedir}/sanlock_admin.h 170 | %{_includedir}/sanlock_resource.h 171 | %{_includedir}/sanlock_direct.h 172 | %{_libdir}/pkgconfig/libsanlock.pc 173 | %{_libdir}/pkgconfig/libsanlock_client.pc 174 | 175 | %package -n sanlk-reset 176 | Summary: Host reset daemon and client using sanlock 177 | Requires: sanlock = %{version}-%{release} 178 | Requires: sanlock-lib = %{version}-%{release} 179 | 180 | %description -n sanlk-reset 181 | The sanlk-reset package contains the reset daemon and client. 182 | A cooperating host running the daemon can be reset by a host 183 | running the client, so long as both maintain access to a 184 | common sanlock lockspace. 185 | 186 | %files -n sanlk-reset 187 | %{_sbindir}/sanlk-reset 188 | %{_sbindir}/sanlk-resetd 189 | %{_unitdir}/sanlk-resetd.service 190 | %dir %attr(-,root,root) %{_rundir}/sanlk-resetd 191 | %{_mandir}/man8/sanlk-reset* 192 | 193 | 194 | %changelog 195 | * Wed Jun 12 2019 Nir Soffer - 3.8.0-1 196 | - Convert spec to python 3 197 | 198 | * Mon Mar 25 2019 Nir Soffer - 3.7.0-1 199 | - Import spec from Fedora master branch (371e11a) 200 | - Fix spec to work on CentOS (20efe91) 201 | -------------------------------------------------------------------------------- /src/ondisk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Red Hat, Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "sanlock_internal.h" 17 | #include "ondisk.h" 18 | 19 | /* 20 | * "end" variables point to ondisk format (endian converted) structures. 21 | */ 22 | 23 | void magic_in(char *end, uint32_t *magic) 24 | { 25 | uint32_t magic_end; 26 | 27 | memcpy(&magic_end, end, sizeof(uint32_t)); 28 | 29 | *magic = le32_to_cpu(magic_end); 30 | } 31 | 32 | void leader_record_in(struct leader_record *end, struct leader_record *lr) 33 | { 34 | lr->magic = le32_to_cpu(end->magic); 35 | lr->version = le32_to_cpu(end->version); 36 | lr->flags = le32_to_cpu(end->flags); 37 | lr->sector_size = le32_to_cpu(end->sector_size); 38 | lr->num_hosts = le64_to_cpu(end->num_hosts); 39 | lr->max_hosts = le64_to_cpu(end->max_hosts); 40 | lr->owner_id = le64_to_cpu(end->owner_id); 41 | lr->owner_generation = le64_to_cpu(end->owner_generation); 42 | lr->lver = le64_to_cpu(end->lver); 43 | memcpy(lr->space_name, end->space_name, NAME_ID_SIZE); 44 | memcpy(lr->resource_name, end->resource_name, NAME_ID_SIZE); 45 | lr->timestamp = le64_to_cpu(end->timestamp); 46 | lr->unused1 = le64_to_cpu(end->unused1); 47 | lr->checksum = le32_to_cpu(end->checksum); 48 | lr->unused2 = le16_to_cpu(end->unused2); 49 | lr->io_timeout = le16_to_cpu(end->io_timeout); 50 | lr->write_id = le64_to_cpu(end->write_id); 51 | lr->write_generation = le64_to_cpu(end->write_generation); 52 | lr->write_timestamp = le64_to_cpu(end->write_timestamp); 53 | } 54 | 55 | void leader_record_out(struct leader_record *lr, struct leader_record *end) 56 | { 57 | end->magic = cpu_to_le32(lr->magic); 58 | end->version = cpu_to_le32(lr->version); 59 | end->flags = cpu_to_le32(lr->flags); 60 | end->sector_size = cpu_to_le32(lr->sector_size); 61 | end->num_hosts = cpu_to_le64(lr->num_hosts); 62 | end->max_hosts = cpu_to_le64(lr->max_hosts); 63 | end->owner_id = cpu_to_le64(lr->owner_id); 64 | end->owner_generation = cpu_to_le64(lr->owner_generation); 65 | end->lver = cpu_to_le64(lr->lver); 66 | memcpy(end->space_name, lr->space_name, NAME_ID_SIZE); 67 | memcpy(end->resource_name, lr->resource_name, NAME_ID_SIZE); 68 | end->timestamp = cpu_to_le64(lr->timestamp); 69 | end->unused1 = cpu_to_le64(lr->unused1); 70 | /* N.B. the checksum must be computed after the byte swapping */ 71 | /* leader_record_out(lr, end); checksum = compute(end); end->checksum = cpu_to_le32(checksum); */ 72 | end->unused2 = cpu_to_le16(lr->unused2); 73 | end->io_timeout = cpu_to_le16(lr->io_timeout); 74 | end->write_id = cpu_to_le64(lr->write_id); 75 | end->write_generation = cpu_to_le64(lr->write_generation); 76 | end->write_timestamp = cpu_to_le64(lr->write_timestamp); 77 | } 78 | 79 | void request_record_in(struct request_record *end, struct request_record *rr) 80 | { 81 | rr->magic = le32_to_cpu(end->magic); 82 | rr->version = le32_to_cpu(end->version); 83 | rr->lver = le64_to_cpu(end->lver); 84 | rr->force_mode = le32_to_cpu(end->force_mode); 85 | } 86 | 87 | void request_record_out(struct request_record *rr, struct request_record *end) 88 | { 89 | end->magic = cpu_to_le32(rr->magic); 90 | end->version = cpu_to_le32(rr->version); 91 | end->lver = cpu_to_le64(rr->lver); 92 | end->force_mode = cpu_to_le32(rr->force_mode); 93 | } 94 | 95 | void paxos_dblock_in(struct paxos_dblock *end, struct paxos_dblock *pd) 96 | { 97 | pd->mbal = le64_to_cpu(end->mbal); 98 | pd->bal = le64_to_cpu(end->bal); 99 | pd->inp = le64_to_cpu(end->inp); 100 | pd->inp2 = le64_to_cpu(end->inp2); 101 | pd->inp3 = le64_to_cpu(end->inp3); 102 | pd->lver = le64_to_cpu(end->lver); 103 | pd->checksum = le32_to_cpu(end->checksum); 104 | pd->flags = le32_to_cpu(end->flags); 105 | } 106 | 107 | void paxos_dblock_out(struct paxos_dblock *pd, struct paxos_dblock *end) 108 | { 109 | end->mbal = cpu_to_le64(pd->mbal); 110 | end->bal = cpu_to_le64(pd->bal); 111 | end->inp = cpu_to_le64(pd->inp); 112 | end->inp2 = cpu_to_le64(pd->inp2); 113 | end->inp3 = cpu_to_le64(pd->inp3); 114 | end->lver = cpu_to_le64(pd->lver); 115 | /* N.B. the checksum must be computed after the byte swapping */ 116 | /* paxos_dblock_out(pd, end); checksum = compute(end), end->checksum = cpu_to_le32(checksum); */ 117 | end->flags = cpu_to_le32(pd->flags); 118 | } 119 | 120 | void mode_block_in(struct mode_block *end, struct mode_block *mb) 121 | { 122 | mb->flags = le32_to_cpu(end->flags); 123 | mb->generation = le64_to_cpu(end->generation); 124 | } 125 | 126 | void mode_block_out(struct mode_block *mb, struct mode_block *end) 127 | { 128 | end->flags = cpu_to_le32(mb->flags); 129 | end->generation = cpu_to_le64(mb->generation); 130 | } 131 | 132 | void rindex_header_in(struct rindex_header *end, struct rindex_header *rh) 133 | { 134 | rh->magic = le32_to_cpu(end->magic); 135 | rh->version = le32_to_cpu(end->version); 136 | rh->flags = le32_to_cpu(end->flags); 137 | rh->sector_size = le32_to_cpu(end->sector_size); 138 | rh->max_resources = le32_to_cpu(end->max_resources); 139 | rh->unused = le32_to_cpu(end->unused); 140 | rh->rx_offset = le64_to_cpu(end->rx_offset); 141 | memcpy(rh->lockspace_name, end->lockspace_name, NAME_ID_SIZE); 142 | } 143 | 144 | void rindex_header_out(struct rindex_header *rh, struct rindex_header *end) 145 | { 146 | end->magic = cpu_to_le32(rh->magic); 147 | end->version = cpu_to_le32(rh->version); 148 | end->flags = cpu_to_le32(rh->flags); 149 | end->sector_size = cpu_to_le32(rh->sector_size); 150 | end->max_resources = cpu_to_le32(rh->max_resources); 151 | end->unused = cpu_to_le32(rh->unused); 152 | end->rx_offset = cpu_to_le64(rh->rx_offset); 153 | memcpy(end->lockspace_name, rh->lockspace_name, NAME_ID_SIZE); 154 | } 155 | 156 | void rindex_entry_in(struct rindex_entry *end, struct rindex_entry *re) 157 | { 158 | re->res_offset = le64_to_cpu(end->res_offset); 159 | re->flags = le32_to_cpu(end->flags); 160 | re->unused = le32_to_cpu(end->unused); 161 | memcpy(re->name, end->name, NAME_ID_SIZE); 162 | } 163 | 164 | void rindex_entry_out(struct rindex_entry *re, struct rindex_entry *end) 165 | { 166 | end->res_offset = cpu_to_le64(re->res_offset); 167 | end->flags = cpu_to_le32(re->flags); 168 | end->unused = cpu_to_le32(re->unused); 169 | memcpy(end->name, re->name, NAME_ID_SIZE); 170 | } 171 | 172 | --------------------------------------------------------------------------------