about summary refs log tree commit diff
path: root/nixos/modules/tasks/filesystems/nfs.nix
blob: e9a7ccc721a9c768d04def2fc41c54b1c952d8ea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
{ config, lib, pkgs, ... }:

with lib;

let

  inInitrd = any (fs: fs == "nfs") config.boot.initrd.supportedFilesystems;

  nfsStateDir = "/var/lib/nfs";

  rpcMountpoint = "${nfsStateDir}/rpc_pipefs";

  idmapdConfFile = pkgs.writeText "idmapd.conf" ''
    [General]
    Pipefs-Directory = ${rpcMountpoint}
    ${optionalString (config.networking.domain != null)
      "Domain = ${config.networking.domain}"}

    [Mapping]
    Nobody-User = nobody
    Nobody-Group = nogroup

    [Translation]
    Method = nsswitch
  '';

  cfg = config.services.nfs;

in

{
  ###### interface

  options = {

    services.nfs = {
      statdPort = mkOption {
        default = null;
        example = 4000;
        description = ''
          Use a fixed port for <command>rpc.statd</command>. This is
          useful if the NFS server is behind a firewall.
        '';
      };
      lockdPort = mkOption {
        default = null;
        example = 4001;
        description = ''
          Use a fixed port for the NFS lock manager kernel module
          (<literal>lockd/nlockmgr</literal>).  This is useful if the
          NFS server is behind a firewall.
        '';
      };
    };
  };

  ###### implementation

  config = mkIf (any (fs: fs == "nfs" || fs == "nfs4") config.boot.supportedFilesystems) {

    services.rpcbind.enable = true;

    system.fsPackages = [ pkgs.nfs-utils ];

    boot.extraModprobeConfig = mkIf (cfg.lockdPort != null) ''
      options lockd nlm_udpport=${toString cfg.lockdPort} nlm_tcpport=${toString cfg.lockdPort}
    '';

    boot.kernelModules = [ "sunrpc" ];

    boot.initrd.kernelModules = mkIf inInitrd [ "nfs" ];

    # FIXME: should use upstream units from nfs-utils.

    systemd.services.statd =
      { description = "NFSv3 Network Status Monitor";

        path = [ pkgs.nfs-utils pkgs.sysvtools pkgs.utillinux ];

        wants = [ "remote-fs-pre.target" ];
        before = [ "remote-fs-pre.target" ];
        wantedBy = [ "remote-fs.target" ];
        requires = [ "basic.target" "rpcbind.service" ];
        after = [ "basic.target" "rpcbind.service" ];

        unitConfig.DefaultDependencies = false; # don't stop during shutdown

        preStart =
          ''
            mkdir -p ${nfsStateDir}/sm
            mkdir -p ${nfsStateDir}/sm.bak
            sm-notify -d
          '';

        serviceConfig.Type = "forking";
        serviceConfig.ExecStart = ''
          @${pkgs.nfs-utils}/sbin/rpc.statd rpc.statd --no-notify \
              ${if cfg.statdPort != null then "-p ${toString cfg.statdPort}" else ""}
        '';
        serviceConfig.Restart = "always";
      };

    systemd.services.idmapd =
      { description = "NFSv4 ID Mapping Daemon";

        path = [ pkgs.sysvtools pkgs.utillinux ];

        wants = [ "remote-fs-pre.target" ];
        before = [ "remote-fs-pre.target" ];
        wantedBy = [ "remote-fs.target" ];
        requires = [ "rpcbind.service" ];
        after = [ "rpcbind.service" ];

        preStart =
          ''
            mkdir -p ${rpcMountpoint}
            mount -t rpc_pipefs rpc_pipefs ${rpcMountpoint}
          '';

        postStop =
          ''
            umount ${rpcMountpoint}
          '';

        serviceConfig.Type = "forking";
        serviceConfig.ExecStart = "@${pkgs.nfs-utils}/sbin/rpc.idmapd rpc.idmapd -c ${idmapdConfFile}";
        serviceConfig.Restart = "always";
      };

  };
}