nix-community / impermanence

Modules to help you handle persistent state on systems with ephemeral root storage [maintainer=@talyz]
MIT License
1.09k stars 80 forks source link

Race condition with syncthing #94

Open tgharib opened 2 years ago

tgharib commented 2 years ago

If a directory is being shared with syncthing and that same directory is also bind mounted, syncthing appears to execute first, creating an empty sync folder which causes the bind mount to fail.

Workaround:

systemd.services.syncthing.serviceConfig.ExecStartPre = "${pkgs.coreutils-full}/bin/sleep 5";

Alternative workaround:

systemd.services.syncthing.serviceConfig.Type = "idle";
nakoo commented 2 years ago

I don't think there is a solution for this. If the directory mounts with multiple locations, the latest one will be shown. You can simply test like this:

touch ./test1/test1
touch ./test2/test2

mount -o bind ./test1 /tmp/test
mount -o bind /.test2 /tmp/test

ls /tmp/test
test2

My suggestion is mounting the parent folder with impermanence, and use sub-directory as your syncthing folder.

tgharib commented 2 years ago

Running mount on my linux system, it doesn't seem syncthing mounts the shared folder. It just syncs the files inside the folder.

nakoo commented 2 years ago

Running mount on my linux system, it doesn't seem syncthing mounts the shared folder. It just syncs the files inside the folder.

Can you share your configuration.nix? I would like to see how you set it up.

tgharib commented 2 years ago

Sure.

{ pkgs, ... }:
{
  services.syncthing = {
    enable = true;
    user = "owner";
    group = "users";
    configDir = "/home/owner/.config/syncthing"; # DO NOT SYNC OR ELSE SYNCTHING BREAKS
    dataDir = "/home/owner";
    openDefaultPorts = false;
    guiAddress = "127.0.0.1:8384";
    overrideDevices = true;
    overrideFolders = true;
    devices = {
      "desktop" = { id = "snipped"; };
      "laptop" = { id = "snipped"; };
    };
    folders = {
      "sync" = {
        path = "/home/owner/sync";
        devices = [ "desktop" "laptop" ];
        versioning = {
          type = "staggered";
          params = {
            cleanInterval = "3600"; # 1 hour
            maxAge = "15768000"; # 180 days
          };
        };
      };
    };
  };

  # Workaround since syncthing creates empty sync/ before impermanence gets a chance to bind mount sync/
  systemd.services.syncthing.serviceConfig = {
    ExecStartPre = "${pkgs.coreutils-full}/bin/sleep 5";
  };
}
nakoo commented 2 years ago

How did you set impermanence.nix?

talyz commented 2 years ago

I think the proper solution would be to make the syncthing unit depend on the bind mount unit, but that would have to be done in your own configuration, we can't really solve it here. Another thing to check is if we can make the bind mount units start in an earlier target, which would also solve the issue, possibly for other programs too.