[SOLVED] zfs pool, mount --bind: Syncthing deleting files from dirs after unmount

Hi,

my setup is as follows:

  • ZFS pool /pool0
  • /pool0/Software/IrfanView is a “real-data” folder
  • /view/pool0 is a “real-data” folder
  • Pool is auto-mounted on startup

I intended to work around using Symlinks with mount --bind. I had no problems setting up the following bind mount: /view/pool0/IrfanView -> /pool0/Software/IrfanView . Done via shell, it lasts until I reboot the server.

My intention is to get a software repository up which could sync some “virtually visible” folder structures form the (big) main repository. To be clear: /pool0 are the “real files” and /view/pool0 should be the “virtual” view achieved by the bind mounts below that folder.

mkdir -p /view/pool0/IrfanView
mount --bind /pool0/sync/Install/IrfanView/ /view/pool0/IrfanView

image

After setting up, the contents of “IrfanView” appear correctly in the view:

Syncthing picks them up correctly:

image

Now I’m testing what happens on loosing the pool which underlies the mount --bind.

zpool export pool0

Syncthing announces everything as “deleted” to the other nodes. This is correct from Synchting’s perspective, but bad for me as everything has to be resynced later.

image

I’m now having this state on the /view/… folders.

image

image

Do you have any ideas for me how I could solve this. I’d wish Syncthing could detect this somehow but it seems difficult due to the nature of the mount point in /view/… which is an empty folder until anyone issues the “mount --bind” command after the pool re-mount again.

I thought about the .stfolder, perhaps I could mount --bind this too but it has the same drawback. Would it work for Syncthing’s code to allow .stfolder to be a symlink and then detecting the bad state of the “view folder” when the .stfolder symlink is dangling? Then I’d place .stfolder as a symlink to a dummy folder on the pool. Or is there a better way?

Sure, I could use scripting and systemd to try at least to ensure as max as possible the pool unmounts expectedly after a Syncthing service shutdown but in case of an error or apt-get dist-upgrade replacing the ZFS driver or delay in reboot I see my thing failing.

Regards, Catfriend1

Or, just thinking more over about it:

  • Can it use a sub-subfolder relative to the Syncthing folder root, e.g. /IrfanView/dummyfolder as a folder marker?

  • Any chance, I could use /IrfanView/dummyignore.txt as an include at /view/pool0/.stignore and the folder will stop in time when the included file goes unavailable?

Ideas welcome :slight_smile:

There is no safeguards for bind-mounts disappearing inside the directory tree.

You can override the marker name, so perhaps pointing it to some file in the directory would work, but in theory, your folder root should be an IfranView and not where it is now.

1 Like

I’ll try that, best would be if I could point the marker to a sub-subdir

Wew, good news:

I’ve got it working with official Syncthing by setting my folder marker to “IrfanView/.stsubfolder” which is an empty directory I’ve just created.

Settings > Advanced:

image

Content on file server:

image

Now Syncthing scans / syncs the folder while the ZFS pool as origin of data is available.

image

When I simulate a “pool interrupt” by making it suddenly unavailable by

zpool export pool0

Syncthing stops without advertising unwanted deletions to other nodes:

image

So if this will be constantly supported in the future, I can clearly recommend this approach as preferred over “symlink code hacks”.

Thumbs up from me that devs made this advanced option possible :-). :+1: :+1: :+1: :+1:

1 Like

To ensure, mount --bind is executed at system boot and reproducibly creates the same view every time the system starts as long as the data source has the same root folders in place, I’ve made the following adjustments.

Edit the “/usr/lib/systemd/system/syncthing.service” systemd unit file and add “ExecStartPre=”.

[Unit]
Description=Syncthing - Open Source Continuous File Synchronization for %I
Documentation=man:syncthing(1)
After=network.target

[Service]
User=root
ExecStartPre=/bin/sh /root/fs-create-view.sh
ExecStart=/usr/bin/syncthing -no-browser -no-restart -logflags=0
Restart=on-failure
SuccessExitStatus=3 4
RestartForceExitStatus=3 4

# Hardening
ProtectSystem=full
PrivateTmp=true
SystemCallArchitectures=native
MemoryDenyWriteExecute=true
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

Create the “mount --bind” script “/root/fs-create-view.sh” and adjust the consts and createMountBind statements to your virtual folder structure need.

#!/bin/sh
#
# Consts.
DATA_ROOT="/pool0"
DATA_ROOT_MOUNT_INDICATOR=".ZFS_POOL_MOUNTED"
#
VIEW_ROOT="/view/pool0"
#
# Check prerequisites.
if [ ! -e "${DATA_ROOT}/${DATA_ROOT_MOUNT_INDICATOR}" ]; then
	echo "[ERROR] DATA_ROOT=[${DATA_ROOT}] is not mounted. Stop."
	exit 99
fi
#
#####################
# FUNCTIONS START	#
#####################
createMountBind () {
	TMP_CMB_VIEW_DIR="${VIEW_ROOT}/${1}"
	TMP_CMB_DATA_DIR="${DATA_ROOT}/${2}"
	#
	if [ ! -e "${TMP_CMB_DATA_DIR}" ]; then
		echo "[ERROR] createMountBind: DATA_DIR=[${TMP_CMB_DATA_DIR}] does not exist. Stop."
		exit 99
	fi
	#
	echo "[INFO] Creating view at [${TMP_CMB_VIEW_DIR}] with contents of [${TMP_CMB_DATA_DIR}]."
	if ( mount | grep -Fq " on ${TMP_CMB_VIEW_DIR} type " ); then
		umount "${TMP_CMB_VIEW_DIR}"
	fi
	if [ ! -e "${TMP_CMB_VIEW_DIR}" ]; then
		mkdir -p "${TMP_CMB_VIEW_DIR}"
	fi
	mount --bind "${TMP_CMB_DATA_DIR}" "${TMP_CMB_VIEW_DIR}"
	if [ $? -ne 0 ]; then
		echo "[ERROR] createMountBind: Failed to mount DATA_DIR=[${TMP_CMB_DATA_DIR}] to VIEW_DIR=[${TMP_CMB_VIEW_DIR}]. Stop."
		exit 99
	fi
	return
}
#
# Create view root.
mkdir -p "${VIEW_ROOT}"
#
# Mount sub directories from the data root to the view root.
## Example:
### createMountBind [REL_VIEW_DIR] [REL_DATA_DIR]
#
createMountBind "Chrome" "sync/Install/Chrome"
createMountBind "IrfanView" "sync/Install/IrfanView"
#
echo "[INFO] Done."
exit 0

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.