1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Pavel Filipenský
e37e4d16e9 s3:open.c: Fix a typo
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>

Autobuild-User(master): Pavel Filipensky <pfilipensky@samba.org>
Autobuild-Date(master): Tue Dec 17 11:23:50 UTC 2024 on atb-devel-224
2024-12-17 11:23:50 +00:00
Pavel Filipenský
02d4f58a2f selftest: Add test for vfs crossrename module
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15724

Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
2024-12-17 10:27:34 +00:00
Pavel Filipenský
94c9a99c56 docs:manpage: vfs_crossrename is not fully stackable VFS module
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15724

Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
2024-12-17 10:27:34 +00:00
Jones Syue
1a089a16c4 s3:vfs_crossrename: add back checking for errno ENOENT
strace gives a clue: samba try to remove 'file.txt' in the dst folder but
actually it is not existed yet, and got an errno = ENOENT,

renameat(32, "file.txt", 31, "file.txt") = -1 EXDEV (Invalid cross-device link)
unlinkat(31, "file.txt", 0)             = -1 ENOENT (No such file or directory)

Commit 5c18f074be ("s3: VFS: crossrename. Use real dirfsp for
SMB_VFS_RENAMEAT()") seems unintentionally removed errno ENOENT checking,
so add it back could address 1st issue.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15724

Signed-off-by: Jones Syue <jonessyue@qnap.com>
Reviewed-by: Ralph Boehme <slow@samba.org>
2024-12-17 10:27:34 +00:00
Pavel Filipenský
0a9adc85e7 s3:vfs_crossrename: crossrename_renameat() needs to return 0 if copy_reg() is successful
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15724

Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
2024-12-17 10:27:34 +00:00
Pavel Filipenský
0a5da82f75 s3:vfs_crossrename: avoid locking panic in copy_reg()
Use low level backend functions that don't go through the FSA layer.
Done via calling transfer_file() as it was in version before 5c18f07

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15724

Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
2024-12-17 10:27:34 +00:00
Pavel Filipenský
7b73c574d9 docs:manpages: Update 'net ads keytab create'
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>

Autobuild-User(master): Pavel Filipensky <pfilipensky@samba.org>
Autobuild-Date(master): Mon Dec 16 19:32:32 UTC 2024 on atb-devel-224
2024-12-16 19:32:31 +00:00
Martin Schwenke
86cdaf5a2e ctdb-scripts: Change default persistent DB for statd_callout_helper
This database isn't use throughout CTDB, so name the it more
specifically.

Note that this might cause locks to be lost during upgrade to the
first version containing this change.

For testing, a different name is chosen to exercise related
functionality.

Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>

Autobuild-User(master): Amitay Isaacs <amitay@samba.org>
Autobuild-Date(master): Fri Dec 13 15:01:10 UTC 2024 on atb-devel-224
2024-12-13 15:01:10 +00:00
Martin Schwenke
16df4de954 ctdb-scripts: Support CTDB_STATD_CALLOUT_SHARED_STORAGE=none
Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2024-12-13 13:57:32 +00:00
Martin Schwenke
112c6b43bc ctdb-tests: Update statd-callout tests to handle both modes
Add support for shared_dir mode.

Instead of duplicating all of the tests, update them so they can be
wrapped.  Created new tests for shared_dir mode that source the
"original" tests.

Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2024-12-13 13:57:32 +00:00
Martin Schwenke
08310072aa ctdb-scripts: Support storing statd-callout state in cluster filesystem
CTDB_STATD_CALLOUT_SHARED_STORAGE is a new configuration variable
indicating where statd-callout should store its NFS client locking
data.  See the update to ctdb-script.options(5) for details.

This adds back functionality that was removed in commit
12cc826231.  The commit message doesn't
say why this was changed but it was most likely due to a cluster
filesystem hanging at inopportune times.  Hence, this is re-added as a
non-default option.  There are 2 justifications for re-adding it:

* The existing method (persistent_db) relies on dequeuing data during
  the monitor event, which loses any queued data on node crash.

* NFS-Ganesha writes NFSv4 client locking data to a cluster
  filesystem, by default.  Something similar might as well exist for
  NFSv3.

Note that this could create the files for sm-notify in add-client.
However, this would require an alternate implementation of
send_notifies() (or a change to the implementation for persistent_db
too).  It seems better to leave add-client lightweight and do the work
in notify, since add-client is a more frequent operation.

Unconditionally create the state directory on startup.  This is
currently implicitly created for persistent_db when the queue
directory is created.  However, it isn't created anywhere else for
shared_dir, so do it in a common place.

In test mode, the shared storage location has a prefix added so files
are created within the test environment.

Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2024-12-13 13:57:32 +00:00
Martin Schwenke
2e84621354 ctdb-scripts: Fix impending SM_NOTIFY versus record deletion race
SM_NOTIFYs are sent before client records are deleted.  Theoretically,
this means new records resulting from lock reclaim can be deleted.

This doesn't actually happen at the moment because any new "records"
resulting from lock reclaim are entered into the queue directory and
only dequeued to the database during a later monitor event.  Since a
monitor event can't collide with an ipreallocated event, no records
can be dequeeued into the database during the ipreallocated event, so
they can't be deleted by delete_records().

However, a subsequent commit will add direct writing of records into a
shared cluster filesystem directory.  This means that add-client
events will cause records to be added directly to that directory so,
without a fix, the race will be able to occur.

So, delete records before sending SM_NOTIFYs.  In theory, the script
could be killed before all SM_NOTIFYs are successfully sent, resulting
in loss of locks.  However, given the overall lack of error checking,
there are other, more likely problems.

Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2024-12-13 13:57:32 +00:00
Martin Schwenke
c415208a49 ctdb-scripts: Factor out some statd-callout functions
This captures all of the persistent database (currently ctdb.tdb)
implementation-specific details in functions.  Alternate
implementations can now be easily added.

Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2024-12-13 13:57:32 +00:00
Martin Schwenke
e6a85d128f ctdb-scripts: Improve update and listing code
Drop the complexity associated with using awk to escape dots in IPv4
addresses to protect them from sed, and generate a grep -F filter
instead.

For listing, the pipeline is now longer, but the steps are now
clearer:

1. List DB records
2. Extract keys
3. Keep only keys machine hosted public IPs
4. Parse out server IP and client IP
5. Sort

Performance here isn't critical, so having clearer code is preferable.

Use temporary files to avoid command-line length limits.

Also, drop the cd to the queue directory during update.

Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2024-12-13 13:57:32 +00:00
Martin Schwenke
b8fe8a5fd2 ctdb-scripts: Drop TCP tuning comments from statd_callout_helper
Commits caad5dc38d and
f022df1d40 commented out these lines
back in 2007.

2 things are clear from the commit messages:

* These setting should not be required in the real world - they are:

    mainly useful for avoiding ack-storms when doing very rapid
    failover/failback during testing

* If they are needed, they are not specific to
  statd_callout/statd_callout_helper

Let's remove these comments to avoid confusing people.

Reported-by: Ulrich Sibiller <ulrich.sibiller@eviden.com>
Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2024-12-13 13:57:32 +00:00
Martin Schwenke
b2084281a4 ctdb-scripts: Fix some bit-rotted comments and whitespace
The top comment in the file is no longer true.

The comment about notifications doesn't really apply anymore since
upstream sm-notify is used and it does "the right thing".

shfmt wants to remove a space before a semicolon, so do that too.

Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2024-12-13 13:57:32 +00:00
Martin Schwenke
e704eb580a ctdb-scripts: Use CTDB_NFS_SHARED_STATE_DIR in nfs-ganesha-callout
Rename CTDB_NFS_STATE_MNT to CTDB_NFS_SHARED_STATE_DIR.  It doesn't
have to be a mount but can be any directory in a cluster filesystem.
CTDB_NFS_SHARED_STATE_DIR will soon be used in statd_callout_helper,
so the variable name might as well be better.

With this change, it will still only be used by nfs-ganesha-callout,
which isn't yet supported (i.e. it still lives in doc/examples).  The
rest of the comments below refer to behaviour changes in that script.

CTDB_NFS_SHARED_STATE_DIR is now mandatory when GPFS is used.  This is
much saner that choosing the first GPFS filesystem - if the state
directory changes then connection metadata can be lost.

Drop CTDB_NFS_STATE_FS_TYPE.  The filesystem type is now determined
from CTDB_NFS_SHARED_STATE_DIR and it is now checked against supported
filesystems.  This will catch the case when the filesystem for the
specified directory has not been mounted and the filesystem for the
mountpoint (e.g. ext4) is not a supported filesystem for shared state.

A side-effect is that the filesystem containing
CTDB_NFS_SHARED_STATE_DIR must be mounted when nfs-ganesha-callout is
first run.

While touching this file, my shfmt pre-commit hook wants to insert a
trailing ;; into a case statement.  Let's sneak that in here too.

Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
2024-12-13 13:57:32 +00:00
35 changed files with 897 additions and 213 deletions

View File

@ -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

View 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>

View File

@ -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

View File

@ -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
}

View File

@ -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();

View File

@ -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,

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.001.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.002.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.003.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.004.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.005.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.006.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="shared_dir"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.007.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.001.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.002.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.003.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.004.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.005.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.006.sh"

View File

@ -0,0 +1,6 @@
#!/bin/sh
CTDB_STATD_CALLOUT_SHARED_STORAGE="none"
_dir=$(dirname "$0")
. "${_dir}/statd-callout.007.sh"

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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;

View File

@ -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"

View File

@ -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'])

View File

@ -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