mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
Compare commits
17 Commits
cb27914403
...
e37e4d16e9
Author | SHA1 | Date | |
---|---|---|---|
|
e37e4d16e9 | ||
|
02d4f58a2f | ||
|
94c9a99c56 | ||
|
1a089a16c4 | ||
|
0a9adc85e7 | ||
|
0a5da82f75 | ||
|
7b73c574d9 | ||
|
86cdaf5a2e | ||
|
16df4de954 | ||
|
112c6b43bc | ||
|
08310072aa | ||
|
2e84621354 | ||
|
c415208a49 | ||
|
e6a85d128f | ||
|
b8fe8a5fd2 | ||
|
b2084281a4 | ||
|
e704eb580a |
@ -1160,11 +1160,8 @@ nfs_callout_init()
|
||||
export CTDB_NFS_CALLOUT_STATE_DIR="${_state_dir}/callout-state"
|
||||
|
||||
# Export, if set, for use by clustered NFS callouts
|
||||
if [ -n "$CTDB_NFS_STATE_FS_TYPE" ]; then
|
||||
export CTDB_NFS_STATE_FS_TYPE
|
||||
fi
|
||||
if [ -n "$CTDB_NFS_STATE_MNT" ]; then
|
||||
export CTDB_NFS_STATE_MNT
|
||||
if [ -n "$CTDB_NFS_SHARED_STATE_DIR" ]; then
|
||||
export CTDB_NFS_SHARED_STATE_DIR
|
||||
fi
|
||||
if [ -n "$CTDB_NFS_EXPORTS_FILE" ]; then
|
||||
export CTDB_NFS_EXPORTS_FILE
|
||||
|
@ -975,6 +975,19 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
CTDB_NFS_SHARED_STATE_DIR=<parameter>DIRECTORY</parameter>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
DIRECTORY where clustered NFS shared state will be
|
||||
located. DIRECTORY should be in a cluster filesystem
|
||||
that is shared between the nodes. No default.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
CTDB_NFS_SKIP_SHARE_CHECK=yes|no
|
||||
@ -1030,25 +1043,81 @@ CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
CTDB_NFS_STATE_FS_TYPE=<parameter>TYPE</parameter>
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE=<parameter>LOCATION</parameter>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The type of filesystem used for a clustered NFS' shared
|
||||
state. No default.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
CTDB_NFS_STATE_MNT=<parameter>DIR</parameter>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The directory where a clustered NFS' shared state will be
|
||||
located. No default.
|
||||
LOCATION where NFSv3 statd state will be stored. Valid
|
||||
values are:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
persistent_db<optional>:<parameter>TDB</parameter></optional>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Data is queued to local storage and then dequeued
|
||||
to TDB during monitor events. This means there is
|
||||
a window where locking state may be lost.
|
||||
However, this works around performance limitations
|
||||
in CTDB's persistent database handling.
|
||||
</para>
|
||||
<para>
|
||||
If :TDB is omitted then TDB defaults to
|
||||
<filename>ctdb_statd_callout.tdb</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
shared_dir<optional>:<parameter>DIRECTORY</parameter></optional>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
DIRECTORY is a directory in a cluster filesystem
|
||||
that is shared between the nodes. If DIRECTORY is
|
||||
relative (i.e. does not start with '/') then it is
|
||||
appended to CTDB_NFS_SHARED_STATE_DIR. If
|
||||
:DIRECTORY is omitted then DIRECTORY defaults to
|
||||
<filename>statd</filename>.
|
||||
</para>
|
||||
<para>
|
||||
Using a shared directory may result in performance
|
||||
and/or stability problems. rpc.statd is
|
||||
single-threaded and its HA callout is called
|
||||
synchronously, causing any latency introduced by
|
||||
the callout to be cumulative. Stability issues
|
||||
are most likely if thousands of clients reclaim
|
||||
locks after failover and use of the cluster
|
||||
filesystem introduces too much additional
|
||||
latency. Too much latency in in the HA callout
|
||||
may cause rpc.statd to fail health monitoring.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
none
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
No cluster-aware handling of NFSv3 statd state is
|
||||
done. NFSv3 lock reclaim will not occur and
|
||||
applications that use locking over NFSv3 are
|
||||
likely to lose or corrupt data.
|
||||
</para>
|
||||
<para>
|
||||
This should be used with care and only in the case
|
||||
where no applications are using POSIX locks in
|
||||
NFSv3 mounts. It should probably be considered an
|
||||
option to test the latency of
|
||||
<filename>statd_callout</filename>, without
|
||||
including any storage costs.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -255,8 +255,7 @@ CTDB_NFS_CHECKS_DIR
|
||||
CTDB_NFS_SKIP_SHARE_CHECK
|
||||
CTDB_RPCINFO_LOCALHOST
|
||||
CTDB_RPCINFO_LOCALHOST6
|
||||
CTDB_NFS_STATE_FS_TYPE
|
||||
CTDB_NFS_STATE_MNT
|
||||
CTDB_NFS_SHARED_STATE_DIR
|
||||
# 70.iscsi
|
||||
CTDB_START_ISCSI_SCRIPTS
|
||||
# 00.ctdb
|
||||
|
@ -36,10 +36,40 @@
|
||||
# Exit on 1st error
|
||||
set -e
|
||||
|
||||
# Filesystem type and mount point for the (typically clustered)
|
||||
# volume that will contain the NFS-Ganesha state.
|
||||
state_fs="${CTDB_NFS_STATE_FS_TYPE:-gpfs}"
|
||||
state_dir="${CTDB_NFS_STATE_MNT}" # No sane default.
|
||||
die()
|
||||
{
|
||||
echo "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Shared directory, typically on a cluster filesystem, that will
|
||||
# contain the NFS-Ganesha state
|
||||
if [ -z "$CTDB_NFS_SHARED_STATE_DIR" ]; then
|
||||
die "$0: CTDB_NFS_SHARED_STATE_DIR is not set"
|
||||
fi
|
||||
|
||||
if [ ! -d "$CTDB_NFS_SHARED_STATE_DIR" ]; then
|
||||
t="$CTDB_NFS_SHARED_STATE_DIR" # Readability, below
|
||||
die "$0: CTDB_NFS_SHARED_STATE_DIR=${t} not found"
|
||||
fi
|
||||
|
||||
state_fs=$(findmnt -n --target "$CTDB_NFS_SHARED_STATE_DIR" -o FSTYPE)
|
||||
|
||||
case "$state_fs" in
|
||||
glusterfs | gpfs)
|
||||
:
|
||||
;;
|
||||
fuse.glusterfs)
|
||||
state_fs="glusterfs"
|
||||
;;
|
||||
*)
|
||||
d="$CTDB_NFS_SHARED_STATE_DIR"
|
||||
die "$0: filesystem type \"${state_fs}\" is not supported for ${d}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Always put NFS-Ganesha state in its own subdirectory
|
||||
state_dir="${CTDB_NFS_SHARED_STATE_DIR}/ganesha"
|
||||
|
||||
# Location of exports file
|
||||
nfs_exports_file="${CTDB_NFS_EXPORTS_FILE:-/etc/ganesha/ganesha.conf}"
|
||||
@ -47,7 +77,6 @@ nfs_exports_file="${CTDB_NFS_EXPORTS_FILE:-/etc/ganesha/ganesha.conf}"
|
||||
# To change the following, edit the default values below. Do not set
|
||||
# these - they aren't configuration variables, just hooks for testing.
|
||||
nfs_service="${CTDB_NFS_SERVICE:-nfs-ganesha}"
|
||||
ganesha_rec_subdir=${CTDB_GANESHA_REC_SUBDIR:-.ganesha}
|
||||
procfs=${PROCFS_PATH:-/proc}
|
||||
|
||||
case "$state_fs" in
|
||||
@ -55,13 +84,9 @@ gpfs)
|
||||
GANRECDIR="/var/lib/nfs/ganesha"
|
||||
;;
|
||||
glusterfs)
|
||||
if [ -z "${state_dir}" ]; then
|
||||
echo "CTDB_NFS_STATE_MNT not defined for GlusterFS"
|
||||
exit 1
|
||||
fi
|
||||
host=$(hostname)
|
||||
NODESTATEDIR="$state_dir/nfs-ganesha/$host"
|
||||
GANSTATEDIR="$state_dir/nfs-ganesha/.noderefs"
|
||||
NODESTATEDIR="${state_dir}/${host}"
|
||||
GANSTATEDIR="${state_dir}/.noderefs"
|
||||
NODESTATELN="$GANSTATEDIR/$host"
|
||||
;;
|
||||
esac
|
||||
@ -184,21 +209,10 @@ get_cluster_fs_state()
|
||||
|
||||
create_ganesha_recdirs()
|
||||
{
|
||||
if ! _mounts=$(mount | grep "$state_fs"); then
|
||||
echo "Failed to find mounts of type $state_fs"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$_mounts" ]; then
|
||||
echo "startup $state_fs not ready"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case "$state_fs" in
|
||||
gpfs)
|
||||
_mntpt=$(echo "$_mounts" | sort | awk 'NR == 1 {print $3}')
|
||||
_link_dst="${_mntpt}/${ganesha_rec_subdir}"
|
||||
mkdir -vp "$_link_dst"
|
||||
check_ln "$_link_dst" "$GANRECDIR"
|
||||
mkdir -vp "$state_dir"
|
||||
check_ln "$state_dir" "$GANRECDIR"
|
||||
;;
|
||||
glusterfs)
|
||||
[ -d /var/lib/nfs.backup ] ||
|
||||
@ -279,6 +293,7 @@ nfs_stats()
|
||||
# unhelpful for avoiding an unhealthy service
|
||||
echo "Not implemented" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
@ -35,11 +35,16 @@
|
||||
* The first line is the mode. Currently supported modes are:
|
||||
*
|
||||
* persistent_db
|
||||
* shared_dir
|
||||
* none
|
||||
*
|
||||
* In this mode, the file contains 2 subsequent lines of text:
|
||||
* In persistent_db and shared_dir modes, the file contains 2
|
||||
* subsequent lines of text:
|
||||
*
|
||||
* path: directory where files should be created
|
||||
* ips_file: file containing node's currently assigned public IP addresses
|
||||
*
|
||||
* In none mode, there are no subsequent lines.
|
||||
*/
|
||||
#define CONFIG_FILE CTDB_VARDIR "/scripts/statd_callout.conf"
|
||||
|
||||
@ -48,6 +53,8 @@ static const char *progname;
|
||||
struct {
|
||||
enum {
|
||||
CTDB_SC_MODE_PERSISTENT_DB,
|
||||
CTDB_SC_MODE_SHARED_DIR,
|
||||
CTDB_SC_MODE_NONE,
|
||||
} mode;
|
||||
union {
|
||||
struct {
|
||||
@ -87,10 +94,14 @@ static void free_config(void)
|
||||
{
|
||||
switch (config.mode) {
|
||||
case CTDB_SC_MODE_PERSISTENT_DB:
|
||||
case CTDB_SC_MODE_SHARED_DIR:
|
||||
free(config.path);
|
||||
config.path = NULL;
|
||||
free(config.ips_file);
|
||||
config.ips_file = NULL;
|
||||
break;
|
||||
case CTDB_SC_MODE_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,6 +138,10 @@ static void read_config(void)
|
||||
}
|
||||
if (strcmp(mode, "persistent_db") == 0) {
|
||||
config.mode = CTDB_SC_MODE_PERSISTENT_DB;
|
||||
} else if (strcmp(mode, "shared_dir") == 0) {
|
||||
config.mode = CTDB_SC_MODE_SHARED_DIR;
|
||||
} else if (strcmp(mode, "none") == 0) {
|
||||
config.mode = CTDB_SC_MODE_NONE;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"%s: unknown mode=%s in %s\n",
|
||||
@ -140,6 +155,7 @@ static void read_config(void)
|
||||
|
||||
switch (config.mode) {
|
||||
case CTDB_SC_MODE_PERSISTENT_DB:
|
||||
case CTDB_SC_MODE_SHARED_DIR:
|
||||
status = getline_strip(&config.path, &n, f);
|
||||
if (!status) {
|
||||
goto parse_error;
|
||||
@ -150,6 +166,8 @@ static void read_config(void)
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
break;
|
||||
case CTDB_SC_MODE_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -288,6 +306,51 @@ static void del_client_persistent_db(const char *cip)
|
||||
for_each_sip(del_client_persistent_db_line, cip);
|
||||
}
|
||||
|
||||
static void add_client_shared_dir_line(const char *sip, const char *cip)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
FILE *f;
|
||||
|
||||
make_path(path, sizeof(path), sip, cip);
|
||||
|
||||
f = fopen(path, "w");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr,
|
||||
"%s: unable to open for writing %s\n",
|
||||
progname,
|
||||
path);
|
||||
exit(1);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void add_client_shared_dir(const char *cip)
|
||||
{
|
||||
for_each_sip(add_client_shared_dir_line, cip);
|
||||
}
|
||||
|
||||
static void del_client_shared_dir_line(const char *sip, const char *cip)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
make_path(path, sizeof(path), sip, cip);
|
||||
|
||||
ret = unlink(path);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr,
|
||||
"%s: unable to remove %s\n",
|
||||
progname,
|
||||
path);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void del_client_shared_dir(const char *cip)
|
||||
{
|
||||
for_each_sip(del_client_shared_dir_line, cip);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("usage: %s: { add-client | del-client } <client-ip>\n", progname);
|
||||
@ -313,6 +376,11 @@ int main(int argc, const char *argv[])
|
||||
case CTDB_SC_MODE_PERSISTENT_DB:
|
||||
add_client_persistent_db(mon_name);
|
||||
break;
|
||||
case CTDB_SC_MODE_SHARED_DIR:
|
||||
add_client_shared_dir(mon_name);
|
||||
break;
|
||||
case CTDB_SC_MODE_NONE:
|
||||
break;
|
||||
}
|
||||
} else if (strcmp(event, "del-client") == 0) {
|
||||
mon_name = argv[2];
|
||||
@ -320,6 +388,11 @@ int main(int argc, const char *argv[])
|
||||
case CTDB_SC_MODE_PERSISTENT_DB:
|
||||
del_client_persistent_db(mon_name);
|
||||
break;
|
||||
case CTDB_SC_MODE_SHARED_DIR:
|
||||
del_client_shared_dir(mon_name);
|
||||
break;
|
||||
case CTDB_SC_MODE_NONE:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
usage();
|
||||
|
@ -1,10 +1,28 @@
|
||||
setup()
|
||||
{
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="$1"
|
||||
|
||||
setup_public_addresses
|
||||
ctdb_set_pnn
|
||||
setup_date "1234567890"
|
||||
|
||||
export FAKE_NFS_HOSTNAME="cluster1"
|
||||
|
||||
case "$CTDB_STATD_CALLOUT_SHARED_STORAGE" in
|
||||
"" | persistent_db)
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="persistent_db:statd_foo.tdb"
|
||||
;;
|
||||
shared_dir)
|
||||
export CTDB_NFS_SHARED_STATE_DIR="/clusterfs"
|
||||
;;
|
||||
esac
|
||||
|
||||
export CTDB_STATD_CALLOUT_SHARED_STORAGE
|
||||
statd_callout_mode="${CTDB_STATD_CALLOUT_SHARED_STORAGE%%:*}"
|
||||
statd_callout_location="${CTDB_STATD_CALLOUT_SHARED_STORAGE#*:}"
|
||||
if [ "$statd_callout_location" = "$CTDB_STATD_CALLOUT_SHARED_STORAGE" ]; then
|
||||
statd_callout_location=""
|
||||
fi
|
||||
}
|
||||
|
||||
ctdb_catdb_format_pairs()
|
||||
@ -44,12 +62,64 @@ EOF
|
||||
done |
|
||||
ctdb_catdb_format_pairs | {
|
||||
ok
|
||||
simple_test_command ctdb catdb ctdb.tdb
|
||||
simple_test_command ctdb catdb "$statd_callout_location"
|
||||
} || exit $?
|
||||
}
|
||||
|
||||
check_shared_dir_statd_state()
|
||||
{
|
||||
ctdb_get_my_public_addresses |
|
||||
while read -r _ _sip _; do
|
||||
for _cip; do
|
||||
echo "statd-state@${_sip}@${_cip}"
|
||||
done
|
||||
done |
|
||||
sort | {
|
||||
ok
|
||||
_dir="${CTDB_TEST_TMP_DIR}${statd_callout_location}"
|
||||
mkdir -p "$_dir"
|
||||
(cd "$_dir" && simple_test_command ls)
|
||||
} || exit $?
|
||||
}
|
||||
|
||||
check_shared_storage_statd_state()
|
||||
{
|
||||
case "$statd_callout_mode" in
|
||||
persistent_db)
|
||||
if [ -z "$statd_callout_location" ]; then
|
||||
statd_callout_location="statd_foo.tdb"
|
||||
fi
|
||||
check_ctdb_tdb_statd_state "$@"
|
||||
;;
|
||||
shared_dir)
|
||||
if [ -z "$statd_callout_location" ]; then
|
||||
statd_callout_location="statd"
|
||||
fi
|
||||
case "$statd_callout_location" in
|
||||
/*)
|
||||
:
|
||||
;;
|
||||
*)
|
||||
_t="$CTDB_NFS_SHARED_STATE_DIR"
|
||||
statd_callout_location="${_t}/${statd_callout_location}"
|
||||
;;
|
||||
esac
|
||||
check_shared_dir_statd_state "$@"
|
||||
;;
|
||||
none)
|
||||
:
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
check_statd_callout_smnotify()
|
||||
{
|
||||
case "$statd_callout_mode" in
|
||||
none)
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
# The state here doesn't really matter because the date stub
|
||||
# generates a fixed value (as per above setup() function,
|
||||
# which happens to set it to an even value). In reality,
|
||||
|
@ -2,13 +2,18 @@
|
||||
|
||||
. "${TEST_SCRIPTS_DIR}/unit.sh"
|
||||
|
||||
define_test "single add-client"
|
||||
if [ -z "$CTDB_STATD_CALLOUT_SHARED_STORAGE" ]; then
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="persistent_db"
|
||||
fi
|
||||
mode="$CTDB_STATD_CALLOUT_SHARED_STORAGE"
|
||||
|
||||
setup
|
||||
define_test "${mode} - single add-client"
|
||||
|
||||
setup "$mode"
|
||||
|
||||
ok_null
|
||||
simple_test_event "startup"
|
||||
simple_test_event "add-client" "192.168.123.45"
|
||||
simple_test_event "update"
|
||||
|
||||
check_ctdb_tdb_statd_state "192.168.123.45"
|
||||
check_shared_storage_statd_state "192.168.123.45"
|
||||
|
@ -2,9 +2,14 @@
|
||||
|
||||
. "${TEST_SCRIPTS_DIR}/unit.sh"
|
||||
|
||||
define_test "2 x add-client, update"
|
||||
if [ -z "$CTDB_STATD_CALLOUT_SHARED_STORAGE" ]; then
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="persistent_db"
|
||||
fi
|
||||
mode="$CTDB_STATD_CALLOUT_SHARED_STORAGE"
|
||||
|
||||
setup
|
||||
define_test "${mode} - 2 x add-client, update"
|
||||
|
||||
setup "$mode"
|
||||
|
||||
ok_null
|
||||
simple_test_event "startup"
|
||||
@ -12,4 +17,4 @@ simple_test_event "add-client" "192.168.123.45"
|
||||
simple_test_event "add-client" "192.168.123.46"
|
||||
simple_test_event "update"
|
||||
|
||||
check_ctdb_tdb_statd_state "192.168.123.45" "192.168.123.46"
|
||||
check_shared_storage_statd_state "192.168.123.45" "192.168.123.46"
|
||||
|
@ -2,9 +2,14 @@
|
||||
|
||||
. "${TEST_SCRIPTS_DIR}/unit.sh"
|
||||
|
||||
define_test "add-client, update, del-client, update"
|
||||
if [ -z "$CTDB_STATD_CALLOUT_SHARED_STORAGE" ]; then
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="persistent_db"
|
||||
fi
|
||||
mode="$CTDB_STATD_CALLOUT_SHARED_STORAGE"
|
||||
|
||||
setup
|
||||
define_test "${mode} - add-client, update, del-client, update"
|
||||
|
||||
setup "$mode"
|
||||
|
||||
ok_null
|
||||
simple_test_event "startup"
|
||||
@ -14,4 +19,4 @@ simple_test_event "update"
|
||||
simple_test_event "del-client" "192.168.123.45"
|
||||
simple_test_event "update"
|
||||
|
||||
check_ctdb_tdb_statd_state
|
||||
check_shared_storage_statd_state
|
||||
|
@ -2,17 +2,22 @@
|
||||
|
||||
. "${TEST_SCRIPTS_DIR}/unit.sh"
|
||||
|
||||
define_test "single add-client, notify"
|
||||
if [ -z "$CTDB_STATD_CALLOUT_SHARED_STORAGE" ]; then
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="persistent_db"
|
||||
fi
|
||||
mode="$CTDB_STATD_CALLOUT_SHARED_STORAGE"
|
||||
|
||||
setup
|
||||
define_test "${mode} - single add-client, notify"
|
||||
|
||||
setup "$mode"
|
||||
|
||||
ok_null
|
||||
simple_test_event "startup"
|
||||
simple_test_event "add-client" "192.168.123.45"
|
||||
simple_test_event "update"
|
||||
|
||||
check_ctdb_tdb_statd_state "192.168.123.45"
|
||||
check_shared_storage_statd_state "192.168.123.45"
|
||||
|
||||
check_statd_callout_smnotify "192.168.123.45"
|
||||
|
||||
check_ctdb_tdb_statd_state
|
||||
check_shared_storage_statd_state
|
||||
|
@ -2,9 +2,14 @@
|
||||
|
||||
. "${TEST_SCRIPTS_DIR}/unit.sh"
|
||||
|
||||
define_test "2 x add-client to different nodes, notify on 1"
|
||||
if [ -z "$CTDB_STATD_CALLOUT_SHARED_STORAGE" ]; then
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="persistent_db"
|
||||
fi
|
||||
mode="$CTDB_STATD_CALLOUT_SHARED_STORAGE"
|
||||
|
||||
setup
|
||||
define_test "${mode} - 2 x add-client to different nodes, notify on 1"
|
||||
|
||||
setup "$mode"
|
||||
|
||||
ok_null
|
||||
simple_test_event "startup"
|
||||
@ -24,4 +29,4 @@ check_statd_callout_smnotify "192.168.123.45"
|
||||
|
||||
ctdb_set_pnn 1
|
||||
|
||||
check_ctdb_tdb_statd_state "192.168.123.46"
|
||||
check_shared_storage_statd_state "192.168.123.46"
|
||||
|
@ -2,9 +2,14 @@
|
||||
|
||||
. "${TEST_SCRIPTS_DIR}/unit.sh"
|
||||
|
||||
define_test "2 x add-client to different nodes, notify on both"
|
||||
if [ -z "$CTDB_STATD_CALLOUT_SHARED_STORAGE" ]; then
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="persistent_db"
|
||||
fi
|
||||
mode="$CTDB_STATD_CALLOUT_SHARED_STORAGE"
|
||||
|
||||
setup
|
||||
define_test "${mode} - 2 x add-client to different nodes, notify on both"
|
||||
|
||||
setup "$mode"
|
||||
|
||||
ok_null
|
||||
simple_test_event "startup"
|
||||
@ -26,4 +31,4 @@ ctdb_set_pnn 1
|
||||
|
||||
check_statd_callout_smnotify "192.168.123.46"
|
||||
|
||||
check_ctdb_tdb_statd_state
|
||||
check_shared_storage_statd_state
|
||||
|
@ -2,9 +2,14 @@
|
||||
|
||||
. "${TEST_SCRIPTS_DIR}/unit.sh"
|
||||
|
||||
define_test "add-client, del-client, update"
|
||||
if [ -z "$CTDB_STATD_CALLOUT_SHARED_STORAGE" ]; then
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="persistent_db"
|
||||
fi
|
||||
mode="$CTDB_STATD_CALLOUT_SHARED_STORAGE"
|
||||
|
||||
setup
|
||||
define_test "${mode} - add-client, del-client, update"
|
||||
|
||||
setup "$mode"
|
||||
|
||||
ok_null
|
||||
simple_test_event "startup"
|
||||
@ -12,4 +17,4 @@ simple_test_event "add-client" "192.168.123.45"
|
||||
simple_test_event "del-client" "192.168.123.45"
|
||||
simple_test_event "update"
|
||||
|
||||
check_ctdb_tdb_statd_state
|
||||
check_shared_storage_statd_state
|
||||
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.101.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.101.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.001.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.102.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.102.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.002.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.103.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.103.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.003.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.104.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.104.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.004.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.105.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.105.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.005.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.106.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.106.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.006.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.107.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.107.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.007.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.201.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.201.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.001.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.202.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.202.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.002.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.203.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.203.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.003.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.204.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.204.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.004.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.205.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.205.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.005.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.206.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.206.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.006.sh"
|
6
ctdb/tests/UNIT/eventscripts/statd-callout.207.sh
Executable file
6
ctdb/tests/UNIT/eventscripts/statd-callout.207.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
|
||||
|
||||
_dir=$(dirname "$0")
|
||||
. "${_dir}/statd-callout.007.sh"
|
@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
# statd must be configured to use this script as its high availability call-out.
|
||||
# statd must be configured to use statd_callout, CTDB's binary
|
||||
# counterpart to this script, as its availability call-out.
|
||||
#
|
||||
# Modern NFS utils versions use /etc/nfs.conf:
|
||||
#
|
||||
@ -24,7 +25,7 @@
|
||||
# silently if /proc/fs/lockd/nlm_end_grace is not found.
|
||||
#
|
||||
|
||||
if [ -z "$CTDB_BASE" ] ; then
|
||||
if [ -z "$CTDB_BASE" ]; then
|
||||
export CTDB_BASE="/usr/local/etc/ctdb"
|
||||
fi
|
||||
|
||||
@ -37,6 +38,8 @@ die()
|
||||
exit 1
|
||||
}
|
||||
|
||||
load_script_options "service" "60.nfs"
|
||||
|
||||
############################################################
|
||||
|
||||
ctdb_setup_state_dir "service" "nfs"
|
||||
@ -78,8 +81,49 @@ create_add_del_client_dir()
|
||||
# shellcheck disable=SC2154
|
||||
statd_callout_state_dir="${script_state_dir}/statd_callout"
|
||||
|
||||
statd_callout_db="ctdb.tdb"
|
||||
statd_callout_queue_dir="${statd_callout_state_dir}/queue"
|
||||
# Set default value, if necessary
|
||||
: "${CTDB_STATD_CALLOUT_SHARED_STORAGE:=persistent_db}"
|
||||
|
||||
statd_callout_mode="${CTDB_STATD_CALLOUT_SHARED_STORAGE%%:*}"
|
||||
statd_callout_location="${CTDB_STATD_CALLOUT_SHARED_STORAGE#*:}"
|
||||
# If not given then mode determines the default location
|
||||
if [ "$statd_callout_location" = "$CTDB_STATD_CALLOUT_SHARED_STORAGE" ]; then
|
||||
statd_callout_location=""
|
||||
fi
|
||||
|
||||
case "$statd_callout_mode" in
|
||||
persistent_db)
|
||||
statd_callout_db="${statd_callout_location:-ctdb_statd_callout.tdb}"
|
||||
statd_callout_queue_dir="${statd_callout_state_dir}/queue"
|
||||
;;
|
||||
shared_dir)
|
||||
statd_callout_shared_dir="${statd_callout_location:-statd}"
|
||||
case "$statd_callout_shared_dir" in
|
||||
/*)
|
||||
:
|
||||
;;
|
||||
*)
|
||||
if [ -z "$CTDB_NFS_SHARED_STATE_DIR" ]; then
|
||||
die "CTDB_NFS_SHARED_STATE_DIR is not set"
|
||||
fi
|
||||
t="${CTDB_NFS_SHARED_STATE_DIR}/${statd_callout_shared_dir}"
|
||||
statd_callout_shared_dir="$t"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "$CTDB_TEST_MODE" ]; then
|
||||
t="${CTDB_TEST_TMP_DIR}${statd_callout_shared_dir}"
|
||||
statd_callout_shared_dir="$t"
|
||||
fi
|
||||
;;
|
||||
none)
|
||||
:
|
||||
;;
|
||||
*)
|
||||
mode="$statd_callout_mode"
|
||||
die "error: unknown CTDB_STATD_CALLOUT_SHARED_STORAGE mode ${mode}"
|
||||
;;
|
||||
esac
|
||||
|
||||
############################################################
|
||||
|
||||
@ -139,7 +183,83 @@ send_notifies()
|
||||
done
|
||||
}
|
||||
|
||||
delete_records()
|
||||
############################################################
|
||||
|
||||
# Use file/key names of the form statd-state@<server-IP>@<client-IP>
|
||||
# to track the last "add-client" or "del-client". These files contain
|
||||
# the key and a value, quoted and ready to pass to "ctdb ptrans". For
|
||||
# add-client the value is the date (for debugging) and for del-client
|
||||
# the value is empty (representing a delete). These get pushed to
|
||||
# $statd_callout_db during "update", which will generally be run once each
|
||||
# "monitor" cycle. In this way we avoid scalability problems with
|
||||
# flood of persistent transactions after a "notify" when all the
|
||||
# clients reclaim their locks.
|
||||
|
||||
startup_persistent_db()
|
||||
{
|
||||
_config_file="$1"
|
||||
|
||||
create_add_del_client_dir "$statd_callout_queue_dir"
|
||||
|
||||
$CTDB attach "$statd_callout_db" persistent
|
||||
|
||||
cat >"$_config_file" <<EOF
|
||||
persistent_db
|
||||
${statd_callout_queue_dir}
|
||||
${CTDB_MY_PUBLIC_IPS_CACHE}
|
||||
EOF
|
||||
}
|
||||
|
||||
# Used via 'grep -F -f "$persistent_db_grep_filter"' to match database
|
||||
# keys currently hosted public IPs
|
||||
persistent_db_grep_filter="${statd_callout_state_dir}/.grep_filter"
|
||||
|
||||
persistent_db_make_grep_filter()
|
||||
{
|
||||
while read -r _ip; do
|
||||
echo "statd-state@${_ip}@"
|
||||
done <"$CTDB_MY_PUBLIC_IPS_CACHE" >"$persistent_db_grep_filter"
|
||||
}
|
||||
|
||||
update_persistent_db()
|
||||
{
|
||||
_files="${statd_callout_state_dir}/.file_list"
|
||||
find "$statd_callout_queue_dir" -name "statd-state@*" >"$_files"
|
||||
if [ ! -s "$_files" ]; then
|
||||
# No files!
|
||||
rm "$_files"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
persistent_db_make_grep_filter
|
||||
|
||||
# Use cat instead of direct grep since POSIX grep does not
|
||||
# have -h
|
||||
_items="${statd_callout_state_dir}/.items"
|
||||
xargs cat <"$_files" | grep -F -f "$persistent_db_grep_filter" >"$_items"
|
||||
|
||||
if [ -s "$_items" ]; then
|
||||
if $CTDB ptrans "$statd_callout_db" <"$_items"; then
|
||||
xargs rm -f <"$_files"
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -f "$_files" "$persistent_db_grep_filter" "$_items"
|
||||
}
|
||||
|
||||
list_records_persistent_db()
|
||||
{
|
||||
persistent_db_make_grep_filter
|
||||
|
||||
$CTDB catdb "$statd_callout_db" |
|
||||
sed -n -e 's|^key([0-9]*) = "\([^"]*\)".*|\1|p' |
|
||||
grep -F -f "$persistent_db_grep_filter" |
|
||||
sed -e 's|statd-state@\([^@]*\)@\(.*\)|\1 \2|'
|
||||
|
||||
rm -f "$persistent_db_grep_filter"
|
||||
}
|
||||
|
||||
delete_records_persistent_db()
|
||||
{
|
||||
while read -r _sip _cip; do
|
||||
_key="statd-state@${_sip}@${_cip}"
|
||||
@ -147,30 +267,152 @@ delete_records()
|
||||
done | $CTDB ptrans "$statd_callout_db"
|
||||
}
|
||||
|
||||
cleanup_persistent_db()
|
||||
{
|
||||
# Remove any stale touch files (i.e. for IPs not currently
|
||||
# hosted on this node and created since the last "update").
|
||||
# There's nothing else we can do with them at this stage.
|
||||
_pnn=$(ctdb_get_pnn)
|
||||
_ctdb_all_ips=$($CTDB ip all | tail -n +2)
|
||||
echo "$_ctdb_all_ips" |
|
||||
awk -v pnn="$_pnn" 'pnn != $2 { print $1 }' |
|
||||
while read -r _sip; do
|
||||
rm -f "${statd_callout_queue_dir}/statd-state@${_sip}@"*
|
||||
done
|
||||
}
|
||||
|
||||
############################################################
|
||||
|
||||
# Keep a file per server-IP/client-IP pair, to keep track of the last
|
||||
# "add-client" or "del-client'. These get pushed to a database during
|
||||
# "update", which will generally be run once each "monitor" cycle. In
|
||||
# this way we avoid scalability problems with flood of persistent
|
||||
# transactions after a "notify" when all the clients re-take their
|
||||
# locks.
|
||||
# Use file/key names of the form statd-state@<server-IP>@<client-IP>
|
||||
# to track the "add-client" and "del-client". statd_callout add and
|
||||
# removes files directly in $statd_callout_shared_dir. This may
|
||||
# result in performance problems if thousands of clients reclaim locks
|
||||
# after failover and the cluster filesystem is unable to handle the
|
||||
# load.
|
||||
|
||||
startup()
|
||||
startup_shared_dir()
|
||||
{
|
||||
create_add_del_client_dir "$statd_callout_queue_dir"
|
||||
_config_file="$1"
|
||||
|
||||
$CTDB attach "$statd_callout_db" persistent
|
||||
create_add_del_client_dir "$statd_callout_shared_dir"
|
||||
|
||||
_default="${CTDB_SCRIPT_VARDIR}/statd_callout.conf"
|
||||
_config_file="${CTDB_STATD_CALLOUT_CONFIG_FILE:-"${_default}"}"
|
||||
cat >"$_config_file" <<EOF
|
||||
persistent_db
|
||||
${statd_callout_queue_dir}
|
||||
shared_dir
|
||||
${statd_callout_shared_dir}
|
||||
${CTDB_MY_PUBLIC_IPS_CACHE}
|
||||
EOF
|
||||
}
|
||||
|
||||
update_shared_dir()
|
||||
{
|
||||
:
|
||||
}
|
||||
|
||||
list_records_shared_dir()
|
||||
{
|
||||
while read -r _ip; do
|
||||
ls "${statd_callout_shared_dir}/statd-state@${_ip}@"*
|
||||
done <"$CTDB_MY_PUBLIC_IPS_CACHE" |
|
||||
while read -r _f; do
|
||||
if [ ! -f "$_f" ]; then
|
||||
continue
|
||||
fi
|
||||
_t="${_f#"${statd_callout_shared_dir}/statd-state@"}"
|
||||
_sip="${_t%@*}"
|
||||
_cip="${_t#*@}"
|
||||
echo "$_sip" "$_cip"
|
||||
done
|
||||
}
|
||||
|
||||
delete_records_shared_dir()
|
||||
{
|
||||
while read -r _sip _cip; do
|
||||
echo "${statd_callout_shared_dir}/statd-state@${_sip}@${_cip}"
|
||||
done | xargs rm -f
|
||||
}
|
||||
|
||||
cleanup_shared_dir()
|
||||
{
|
||||
:
|
||||
}
|
||||
|
||||
############################################################
|
||||
|
||||
# No-op implementation
|
||||
|
||||
startup_none()
|
||||
{
|
||||
_config_file="$1"
|
||||
|
||||
cat >"$_config_file" <<EOF
|
||||
none
|
||||
EOF
|
||||
}
|
||||
|
||||
update_none()
|
||||
{
|
||||
:
|
||||
}
|
||||
|
||||
list_records_none()
|
||||
{
|
||||
:
|
||||
}
|
||||
|
||||
delete_records_none()
|
||||
{
|
||||
:
|
||||
}
|
||||
|
||||
cleanup_none()
|
||||
{
|
||||
:
|
||||
}
|
||||
|
||||
############################################################
|
||||
|
||||
# Per-mode initialisation
|
||||
startup()
|
||||
{
|
||||
_default="${CTDB_SCRIPT_VARDIR}/statd_callout.conf"
|
||||
_config_file="${CTDB_STATD_CALLOUT_CONFIG_FILE:-"${_default}"}"
|
||||
|
||||
mkdir -p "$statd_callout_state_dir"
|
||||
|
||||
"startup_${statd_callout_mode}" "$_config_file"
|
||||
}
|
||||
|
||||
# Process a record queue in local storage and use it to update cluster
|
||||
# storage. For implementations that update cluster storage directly,
|
||||
# this will be a no-op.
|
||||
update()
|
||||
{
|
||||
"update_${statd_callout_mode}"
|
||||
}
|
||||
|
||||
# Query cluster storage for entries matching this node's server IPs
|
||||
# and Write pairs of:
|
||||
# server-IP client-IP
|
||||
# to stdout.
|
||||
list_records()
|
||||
{
|
||||
"list_records_${statd_callout_mode}" | sort
|
||||
}
|
||||
|
||||
# Read pairs of:
|
||||
# server-IP client-IP
|
||||
# from stdin and delete associated records during notify.
|
||||
delete_records()
|
||||
{
|
||||
"delete_records_${statd_callout_mode}"
|
||||
}
|
||||
|
||||
# Do any required cleanup
|
||||
cleanup()
|
||||
{
|
||||
"cleanup_${statd_callout_mode}"
|
||||
}
|
||||
|
||||
############################################################
|
||||
|
||||
case "$1" in
|
||||
@ -179,25 +421,7 @@ startup)
|
||||
;;
|
||||
|
||||
update)
|
||||
cd "$statd_callout_queue_dir" ||
|
||||
die "Failed to change directory to \"${statd_callout_queue_dir}\""
|
||||
files=$(echo statd-state@*)
|
||||
if [ "$files" = "statd-state@*" ]; then
|
||||
# No files!
|
||||
exit 0
|
||||
fi
|
||||
sed_expr=$(awk '{
|
||||
ip = $1; gsub(/\./, "\\.", ip);
|
||||
printf "/statd-state@%s@/p\n", ip }' "$CTDB_MY_PUBLIC_IPS_CACHE")
|
||||
# Intentional multi-word expansion for multiple files
|
||||
# shellcheck disable=SC2086
|
||||
items=$(sed -n "$sed_expr" $files)
|
||||
if [ -n "$items" ]; then
|
||||
if echo "$items" | $CTDB ptrans "$statd_callout_db"; then
|
||||
# shellcheck disable=SC2086
|
||||
rm $files
|
||||
fi
|
||||
fi
|
||||
update
|
||||
;;
|
||||
|
||||
notify)
|
||||
@ -206,12 +430,6 @@ notify)
|
||||
# conflicting locks through other nodes before all locks have been
|
||||
# reclaimed)
|
||||
|
||||
# we need these settings to make sure that no tcp connections survive
|
||||
# across a very fast failover/failback
|
||||
#echo 10 > /proc/sys/net/ipv4/tcp_fin_timeout
|
||||
#echo 0 > /proc/sys/net/ipv4/tcp_max_tw_buckets
|
||||
#echo 0 > /proc/sys/net/ipv4/tcp_max_orphans
|
||||
|
||||
# Delete the notification list for statd, we don't want it to
|
||||
# ping any clients
|
||||
dir=$(find_statd_sm_dir)
|
||||
@ -227,53 +445,19 @@ notify)
|
||||
sleep 2
|
||||
"$CTDB_NFS_CALLOUT" "start" "nlockmgr" >/dev/null 2>&1
|
||||
|
||||
# we now need to send out additional statd notifications to ensure
|
||||
# that clients understand that the lockmanager has restarted.
|
||||
# we have three cases:
|
||||
# 1, clients that ignore the ip address the stat notification came from
|
||||
# and ONLY care about the 'name' in the notify packet.
|
||||
# these clients ONLY work with lock failover IFF that name
|
||||
# can be resolved into an ipaddress that matches the one used
|
||||
# to mount the share. (==linux clients)
|
||||
# This is handled when starting lockmanager above, but those
|
||||
# packets are sent from the "wrong" ip address, something linux
|
||||
# clients are ok with, buth other clients will barf at.
|
||||
# 2, Some clients only accept statd packets IFF they come from the
|
||||
# 'correct' ip address.
|
||||
# Send out the notification using the 'correct' ip address and also
|
||||
# specify the 'correct' hostname in the statd packet.
|
||||
# Some clients require both the correct source address and also the
|
||||
# correct name. (these clients also ONLY work if the ip addresses
|
||||
# used to map the share can be resolved into the name returned in
|
||||
# the notify packet.)
|
||||
#
|
||||
# For all IPs we serve, collect info and push to the config database
|
||||
statd_state="${statd_callout_state_dir}/.statd_state"
|
||||
list_records >"$statd_state"
|
||||
|
||||
# Construct a sed expression to take catdb output and produce pairs of:
|
||||
# server-IP client-IP
|
||||
# but only for the server-IPs that are hosted on this node.
|
||||
sed_expr=$(awk '{
|
||||
ip = $1; gsub(/\./, "\\.", ip);
|
||||
printf "s/^key.*=.*statd-state@\\(%s\\)@\\([^\"]*\\).*/\\1 \\2/p\n", ip }' \
|
||||
"$CTDB_MY_PUBLIC_IPS_CACHE")
|
||||
if [ ! -s "$statd_state" ]; then
|
||||
rm -f "$statd_state"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
statd_state=$($CTDB catdb "$statd_callout_db" |
|
||||
sed -n "$sed_expr" |
|
||||
sort)
|
||||
[ -n "$statd_state" ] || exit 0
|
||||
delete_records <"$statd_state"
|
||||
send_notifies <"$statd_state"
|
||||
|
||||
echo "$statd_state" | send_notifies
|
||||
echo "$statd_state" | delete_records
|
||||
rm -f "$statd_state"
|
||||
|
||||
# Remove any stale touch files (i.e. for IPs not currently
|
||||
# hosted on this node and created since the last "update").
|
||||
# There's nothing else we can do with them at this stage.
|
||||
pnn=$(ctdb_get_pnn)
|
||||
$CTDB ip all |
|
||||
tail -n +2 |
|
||||
awk -v pnn="$pnn" 'pnn != $2 { print $1 }' |
|
||||
while read -r sip; do
|
||||
rm -f "${statd_callout_queue_dir}/statd-state@${sip}@"*
|
||||
done
|
||||
cleanup
|
||||
;;
|
||||
esac
|
||||
|
@ -1548,12 +1548,33 @@ to show in the result.
|
||||
<title>ADS KEYTAB <replaceable>CREATE</replaceable></title>
|
||||
|
||||
<para>
|
||||
Creates a new keytab file if one doesn't exist with default entries. Default
|
||||
entries are kerberos principals created from the machinename of the
|
||||
client, the UPN (if it exists) and any Windows SPN(s) associated with the
|
||||
computer AD account for the client. If a keytab file already exists then only
|
||||
missing kerberos principals from the default entries are added. No changes
|
||||
are made to the computer AD account.
|
||||
Since Samba 4.21.0, keytab file is created as specified in <smbconfoption
|
||||
name="sync machine password to keytab"/>. The keytab is created only for
|
||||
<smbconfoption name="kerberos method">secrets only</smbconfoption> and
|
||||
<smbconfoption name="kerberos method">secrets and keytab</smbconfoption>. With
|
||||
the smb.conf default values for <smbconfoption name="kerberos method"> secrets
|
||||
only</smbconfoption> and <smbconfoption name="sync machine password to keytab"/>
|
||||
(default is empty) the keytab is not generated at all. Keytab with a default
|
||||
name and SPNs synced from AD is created for <smbconfoption name="kerberos
|
||||
method">secrets and keytab</smbconfoption> if <smbconfoption name="sync machine
|
||||
password to keytab"/> is missing.
|
||||
</para>
|
||||
<para>
|
||||
Till Samba 4.20.0, two more entries were created by default: the machinename of
|
||||
the client (ending with '$') and the UPN (host/domain@REALM). If these two
|
||||
entries are still needed, each must be specified in an own keytab file.
|
||||
Example below will generate three keytab files that contain SPNs synced from
|
||||
AD, host UPN and machine$ SPN:
|
||||
</para>
|
||||
<programlisting>
|
||||
<smbconfoption name="sync machine password to keytab">
|
||||
/etc/krb5.keytab0:sync_spns:machine_password,
|
||||
/etc/krb5.keytab1:spns=host/smb.com@SMB.COM:machine_password,
|
||||
/etc/krb5.keytab2:account_name:machine_password
|
||||
</smbconfoption>
|
||||
</programlisting>
|
||||
<para>
|
||||
No changes are made to the computer AD account.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
|
@ -62,7 +62,10 @@
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>This module is stackable.</para>
|
||||
<para> This module is not fully stackable. It can be combined with other
|
||||
modules, but should be the last module in the <command>vfs objects</command>
|
||||
list. It directly access the files in the OS filesystem.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
|
@ -2783,6 +2783,9 @@ sub provision($$)
|
||||
my $recycle_shrdir="$shrdir/recycle";
|
||||
push(@dirs,$recycle_shrdir);
|
||||
|
||||
my $recycle_shrdir2="$shrdir/recycle2";
|
||||
push(@dirs,$recycle_shrdir2);
|
||||
|
||||
my $fakedircreatetimes_shrdir="$shrdir/fakedircreatetimes";
|
||||
push(@dirs,$fakedircreatetimes_shrdir);
|
||||
|
||||
@ -3718,6 +3721,15 @@ sub provision($$)
|
||||
recycle : exclude = *.tmp
|
||||
recycle : directory_mode = 755
|
||||
|
||||
[recycle2]
|
||||
copy = tmp
|
||||
path = $recycle_shrdir2
|
||||
vfs objects = recycle crossrename
|
||||
recycle : repository = .trash
|
||||
recycle : exclude = *.tmp
|
||||
recycle : directory_mode = 755
|
||||
wide links = yes
|
||||
|
||||
[fakedircreatetimes]
|
||||
copy = tmp
|
||||
path = $fakedircreatetimes_shrdir
|
||||
|
@ -54,10 +54,12 @@ static NTSTATUS copy_reg(vfs_handle_struct *handle,
|
||||
struct files_struct *dstfsp,
|
||||
const struct smb_filename *dest)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct smb_filename *full_fname_src = NULL;
|
||||
struct smb_filename *full_fname_dst = NULL;
|
||||
NTSTATUS status = NT_STATUS_OK;
|
||||
int ret;
|
||||
off_t off;
|
||||
int ifd = -1;
|
||||
int ofd = -1;
|
||||
struct timespec ts[2];
|
||||
|
||||
if (!VALID_STAT(source->st)) {
|
||||
status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
@ -79,64 +81,105 @@ static NTSTATUS copy_reg(vfs_handle_struct *handle,
|
||||
goto out;
|
||||
}
|
||||
|
||||
full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
|
||||
srcfsp,
|
||||
source);
|
||||
if (full_fname_src == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
|
||||
dstfsp,
|
||||
dest);
|
||||
if (full_fname_dst == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = SMB_VFS_NEXT_UNLINKAT(handle,
|
||||
dstfsp,
|
||||
dest,
|
||||
0);
|
||||
if (ret == -1) {
|
||||
if (ret == -1 && errno != ENOENT) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ifd = openat(fsp_get_pathref_fd(srcfsp),
|
||||
source->base_name,
|
||||
O_RDONLY,
|
||||
0);
|
||||
if (ifd < 0) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ofd = openat(fsp_get_pathref_fd(dstfsp),
|
||||
dest->base_name,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW,
|
||||
0600);
|
||||
if (ofd < 0) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
off = transfer_file(ifd, ofd, source->st.st_ex_size);
|
||||
if (off == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fchown(ofd, source->st.st_ex_uid, source->st.st_ex_gid);
|
||||
if (ret == -1 && errno != EPERM) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy_internals() takes attribute values from the NTrename call.
|
||||
*
|
||||
* From MS-CIFS:
|
||||
*
|
||||
* "If the attribute is 0x0000, then only normal files are renamed.
|
||||
* If the system file or hidden attributes are specified, then the
|
||||
* rename is inclusive of both special types."
|
||||
* fchown turns off set[ug]id bits for non-root,
|
||||
* so do the chmod last.
|
||||
*/
|
||||
status = copy_internals(talloc_tos(),
|
||||
handle->conn,
|
||||
NULL,
|
||||
srcfsp, /* src_dirfsp */
|
||||
full_fname_src,
|
||||
dstfsp, /* dst_dirfsp */
|
||||
full_fname_dst,
|
||||
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = SMB_VFS_NEXT_UNLINKAT(handle,
|
||||
srcfsp,
|
||||
source,
|
||||
0);
|
||||
if (ret == -1) {
|
||||
ret = fchmod(ofd, source->st.st_ex_mode & 07777);
|
||||
if (ret == -1 && errno != EPERM) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
/* Try to copy the old file's modtime and access time. */
|
||||
ts[0] = source->st.st_ex_atime;
|
||||
ts[1] = source->st.st_ex_mtime;
|
||||
ret = futimens(ofd, ts);
|
||||
if (ret == -1) {
|
||||
DBG_DEBUG("Updating the time stamp on destinaton '%s' failed "
|
||||
"with '%s'. Rename operation can continue.\n",
|
||||
dest->base_name,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
ret = close(ifd);
|
||||
if (ret == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto out;
|
||||
}
|
||||
ifd = -1;
|
||||
|
||||
ret = close(ofd);
|
||||
if (ret == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto out;
|
||||
}
|
||||
ofd = -1;
|
||||
|
||||
ret = SMB_VFS_NEXT_UNLINKAT(handle, srcfsp, source, 0);
|
||||
if (ret == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
}
|
||||
|
||||
out:
|
||||
if (ifd != -1) {
|
||||
ret = close(ifd);
|
||||
if (ret == -1) {
|
||||
DBG_DEBUG("Failed to close %s (%d): %s.\n",
|
||||
source->base_name,
|
||||
ifd,
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
if (ofd != -1) {
|
||||
ret = close(ofd);
|
||||
if (ret == -1) {
|
||||
DBG_DEBUG("Failed to close %s (%d): %s.\n",
|
||||
dest->base_name,
|
||||
ofd,
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
TALLOC_FREE(full_fname_src);
|
||||
TALLOC_FREE(full_fname_dst);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -170,6 +213,7 @@ static int crossrename_renameat(vfs_handle_struct *handle,
|
||||
smb_fname_src,
|
||||
dstfsp,
|
||||
smb_fname_dst);
|
||||
result = 0;
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
errno = map_errno_from_nt_status(status);
|
||||
result = -1;
|
||||
|
@ -29,7 +29,8 @@ export SAMBA_DEPRECATED_SUPPRESS
|
||||
|
||||
# Define the test environment/filenames.
|
||||
#
|
||||
share_test_dir="$LOCAL_PATH"
|
||||
share_test_dir="$LOCAL_PATH/recycle"
|
||||
share_test_dir2="$LOCAL_PATH/recycle2"
|
||||
|
||||
#
|
||||
# Cleanup function.
|
||||
@ -43,6 +44,13 @@ do_cleanup()
|
||||
rm -f testfile2.tmp
|
||||
rm -rf .trash
|
||||
)
|
||||
(
|
||||
#subshell.
|
||||
cd "$share_test_dir2" || return
|
||||
rm -f testfile3
|
||||
rm -f testfile4.tmp
|
||||
rm -rf .trash
|
||||
)
|
||||
}
|
||||
|
||||
#
|
||||
@ -50,6 +58,25 @@ do_cleanup()
|
||||
#
|
||||
do_cleanup
|
||||
|
||||
# Setup .trash on a different filesystem to test crossrename
|
||||
# /tmp or /dev/shm should provide tmpfs
|
||||
#
|
||||
for T in /tmp /dev/shm
|
||||
do
|
||||
if df --portability --print-type $T 2>/dev/null | grep -q tmpfs; then
|
||||
TRASHDIR=$T
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z $TRASHDIR ]; then
|
||||
echo "No tmpfs filesystem found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TRASHDIR=$(mktemp -d /$TRASHDIR/.trash_XXXXXX)
|
||||
chmod 0755 $TRASHDIR
|
||||
ln -s $TRASHDIR $share_test_dir2/.trash
|
||||
|
||||
test_recycle()
|
||||
{
|
||||
@ -90,12 +117,61 @@ quit
|
||||
return 0
|
||||
}
|
||||
|
||||
test_recycle_crossrename()
|
||||
{
|
||||
tmpfile=$PREFIX/smbclient_interactive_prompt_commands
|
||||
echo "
|
||||
put $tmpfile testfile3
|
||||
put $tmpfile testfile4.tmp
|
||||
del testfile3
|
||||
del testfile4.tmp
|
||||
quit
|
||||
" > $tmpfile
|
||||
cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/recycle2 -I$SERVER_IP $ADDARGS < $tmpfile 2>&1'
|
||||
eval echo "$cmd"
|
||||
out=$(eval "$cmd")
|
||||
ret=$?
|
||||
rm -f "$tmpfile"
|
||||
|
||||
if [ $ret != 0 ]; then
|
||||
printf "%s\n" "$out"
|
||||
printf "failed recycle smbclient run with error %s\n" "$ret"
|
||||
return 1
|
||||
fi
|
||||
|
||||
test -e "$share_test_dir2/.trash/testfile3" || {
|
||||
printf ".trash/testfile3 expected to exist but does NOT exist\n"
|
||||
return 1
|
||||
}
|
||||
test -e "$share_test_dir2/.trash/testfile4.tmp" && {
|
||||
printf ".trash/testfile4.tmp not expected to exist but DOES exist\n"
|
||||
return 1
|
||||
}
|
||||
deviceid1=`stat -c '%d' "$share_test_dir2/"`
|
||||
deviceid2=`stat -c '%d' "$share_test_dir2/.trash/"`
|
||||
test "$deviceid1=" != "$deviceid2" || {
|
||||
printf ".trash/ should be on a different filesystem!\n"
|
||||
return 1
|
||||
}
|
||||
perm_want=755
|
||||
perm_is=`stat -c '%a' "$share_test_dir2/.trash/"`
|
||||
test "$perm_is" = "$perm_want" || {
|
||||
printf ".trash/ permission should be $perm_want but is $perm_is\n"
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
panic_count_0=$(grep -c PANIC $SMBD_TEST_LOG)
|
||||
|
||||
testit "recycle" \
|
||||
test_recycle ||
|
||||
failed=$((failed + 1))
|
||||
|
||||
testit "recycle_crossrename" \
|
||||
test_recycle_crossrename ||
|
||||
failed=$((failed + 1))
|
||||
|
||||
panic_count_1=$(grep -c PANIC $SMBD_TEST_LOG)
|
||||
|
||||
testit "check_panic" test $panic_count_0 -eq $panic_count_1 || failed=$(expr $failed + 1)
|
||||
@ -103,5 +179,7 @@ testit "check_panic" test $panic_count_0 -eq $panic_count_1 || failed=$(expr $fa
|
||||
#
|
||||
# Cleanup.
|
||||
do_cleanup
|
||||
# Cleanup above only deletes a symlink, delete also /tmp/.trash_XXXXXX dir
|
||||
rm -rf "$TRASHDIR"
|
||||
|
||||
testok "$0" "$failed"
|
||||
|
@ -784,7 +784,7 @@ for env in ["fileserver"]:
|
||||
plantestsuite("samba3.blackbox.force_create_mode", env, [os.path.join(samba3srcdir, "script/tests/test_force_create_mode.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', env, smbclient3])
|
||||
plantestsuite("samba3.blackbox.dropbox", env, [os.path.join(samba3srcdir, "script/tests/test_dropbox.sh"), '$SERVER', '$DOMAIN', 'gooduser', '$PASSWORD', '$PREFIX', env, smbclient3])
|
||||
plantestsuite("samba3.blackbox.offline", env, [os.path.join(samba3srcdir, "script/tests/test_offline.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/offline', smbclient3])
|
||||
plantestsuite("samba3.blackbox.recycle", env, [os.path.join(samba3srcdir, "script/tests/test_recycle.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/recycle', '$PREFIX', smbclient3])
|
||||
plantestsuite("samba3.blackbox.recycle", env, [os.path.join(samba3srcdir, "script/tests/test_recycle.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', '$PREFIX', smbclient3])
|
||||
plantestsuite("samba3.blackbox.fakedircreatetimes", env, [os.path.join(samba3srcdir, "script/tests/test_fakedircreatetimes.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/fakedircreatetimes', '$PREFIX', smbclient3])
|
||||
plantestsuite("samba3.blackbox.shadow_copy2.NT1", env + "_smb1_done", [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3, '-m', 'NT1'])
|
||||
plantestsuite("samba3.blackbox.shadow_copy2.SMB3", env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3, '-m', 'SMB3'])
|
||||
|
@ -4749,7 +4749,7 @@ mkdir_first:
|
||||
&rhow);
|
||||
if (ret == -1 && errno == EINVAL) {
|
||||
/*
|
||||
* This is the strategie we use without having
|
||||
* This is the strategy we use without having
|
||||
* renameat2(RENAME_NOREPLACE):
|
||||
*
|
||||
* renameat() is able to replace a directory if the source is
|
||||
|
Loading…
Reference in New Issue
Block a user