Newer
Older
skyworks-Nix-infra / hosts / skydick / DATAPOOL.md

Skydick Data Pool — User & Service Guide

Server: skydick (10.0.1.1), pool: dick

Network: bonded 2×40G ConnectX-3 (LACP 802.3ad, interface bond40g), jumbo frames MTU 9200, subnet 10.0.0.0/16.

Pool: 10 × Seagate Exos/Mach2 ST14000NM0001 14TB SAS (4Kn), each presenting 2 LUNs.
8 mirrors (from 8 drives) + 2 hot spares + 2 × Intel DC P4600 Optane 750GB. ~50.9T usable.
NVMe tier: mirrored 690G special vdev (metadata + small blocks ≤128K) + mirrored 8G SLOG.
See datapool.nix header comments for the full drive inventory and mirror layout.

Available shares

Share Server path SMB name NFS mount Access
Public files /srv/public \\SKYDICK\public /public rw, all @storage users
Media library /srv/media/library \\SKYDICK\media /media/library ro, all @storage users
Torrent payload /srv/media/data \\SKYDICK\torrents /media (via data/) ro, all @storage users — browse & re-seed
Personal files /srv/users/<you>/files \\SKYDICK\<you> /users/<you> rw, SMB owner-authenticated; NFS network-trusted all_squash to owner

The NFS mount paths in the table above are for Linux/Unix NFSv4 clients using the pseudo-root
(/srv on the server, exported with fsid=0).

Windows Client for NFS is different: Microsoft documents it as supporting only NFSv2/v3, not
NFSv4.1, so it does not use the pseudo-root form above. Windows clients must mount the strict
exported server path instead, for example:

  • 10.0.1.1:/srv/public
  • 10.0.1.1:/srv/media/library
  • 10.0.1.1:/srv/users/<you>

For Windows clients, SMB is the preferred protocol unless a workflow specifically requires NFS.

The final storage layout is live on skydick:

  • dick/public mounted at /srv/public
  • dick/media mounted at /srv/media, with data/ and library/ directories in one hardlink domain
  • dick/users/<user>/{files,bt-state,vm} for per-user private data
  • dick/system/{backup,vm} for centrally managed system storage
  • dick/templates/vm for shared read-only VM base images
  • dick should carry atime=off, so child datasets inherit a read-optimized default unless explicitly overridden

The old dick/{share,backup,torrent,vm} layout is no longer part of the design. Torrent payload now
lives under /srv/media/data, and organized media under /srv/media/library.

Identity and authentication

  • skydick resolves POSIX users and groups using certificate-verified StartTLS at
    ldap://ldap.skyw.top/, base dc=skyw,dc=top
  • SMB now uses Samba's LDAP passdb (ldapsam) against the same directory tree
  • On this standalone server, the Samba account-domain object is expected to be
    sambaDomainName=SKYDICK, matching the NetBIOS name, not the browse workgroup WORKGROUP
  • Shared public / media access is carried by the LDAP posixGroup
    cn=storage,ou=posix_groups,dc=skyw,dc=top with gidNumber: 997
  • NFS still does not authenticate users; it trusts client IPs and export options
  • LDAP remains the password source of truth. After a user's SMB access is bootstrapped once,
    password changes should happen through the LDAP password-change flow (the password web UI or
    ldappasswd), which keeps Samba's sambaSamAccount password data aligned.

Current admin users on skydick intentionally use the same canonical usernames as their LDAP
identities, for example ye-lw21. In those collisions, local NSS lookup still wins for the final
Unix UID/GID/group resolution on the server, while SMB password data still comes from LDAP.

The bootstrap LDIF for the Samba domain object, the LDAP storage group, and the machine OU is
checked in at samba-ldap-bootstrap.ldif.

Quick start

What a user needs before using the data pool

  • A real LDAP account under ou=people,dc=skyw,dc=top
  • For shared public and media access: membership in LDAP group
    cn=storage,ou=posix_groups,dc=skyw,dc=top
  • For private personal storage: a provisioned /srv/users/<you> subtree on skydick
  • For SMB: one-time admin bootstrap with smbpasswd -a <you>

After the one-time SMB bootstrap, your ongoing password is your LDAP password. Change it through
the LDAP password-change flow, not routine smbpasswd use.

What an admin must do before telling a user "it is ready"

  1. Create or verify the LDAP posixAccount for the user.
  2. Add the user's uid to LDAP group storage if they should access public and media.
  3. If the user needs private storage, provision the per-user Nix export/tmpfiles entries and the
    ZFS subtree under dick/users/<user>.
  4. Deploy the updated skydick NixOS configuration if step 3 changed it.
  5. If the user needs SMB, run smbpasswd -a <user> once on skydick.
  6. If the bootstrap password was admin-set, tell the user to immediately change it through the LDAP
    password-change flow.
  7. Verify getent passwd <user>, zfs list -r dick/users/<user> if applicable, and
    pdbedit -L | grep '^<user>:' if SMB was enabled.

Password rules

  • First SMB use: admin runs smbpasswd -a <user> on skydick once to create the user's
    sambaSamAccount in LDAP.
  • Normal password changes after that: use the LDAP password web UI or ldappasswd.
  • Do not use smbpasswd as the normal password-change workflow. It is for first-time SMB bootstrap
    and emergency repair only.

Example ldappasswd command for users who have LDAP CLI access:

ldappasswd -x -H ldap://10.0.0.1 \
  -D "uid=<you>,ou=people,dc=skyw,dc=top" \
  -W -S "uid=<you>,ou=people,dc=skyw,dc=top"

This changes the LDAP password, and the LDAP server keeps Samba password hashes aligned for users
that already have a sambaSamAccount.

Connecting via SMB (Windows / macOS / Linux GUI)

Windows

Open File Explorer, type in the address bar:

\\10.0.1.1\public
\\10.0.1.1\media
\\10.0.1.1\torrents
\\10.0.1.1\<your-username>

When prompted, enter your LDAP password after the one-time SMB bootstrap. For a user's first SMB
login, an admin must bootstrap the account once on skydick with smbpasswd -a <user>, which
creates the LDAP sambaSamAccount data for that user. After that, change passwords through the
LDAP password UI or ldappasswd so LDAP remains authoritative and SMB stays in sync.

macOS

Finder → Go → Connect to Server (Cmd+K):

smb://10.0.1.1/public
smb://10.0.1.1/media
smb://10.0.1.1/torrents
smb://10.0.1.1/<your-username>

Linux (GUI)

Nautilus/Dolphin/Thunar address bar:

smb://10.0.1.1/public
smb://10.0.1.1/<your-username>

Linux (CLI / fstab)

# One-off mount
sudo mount -t cifs //10.0.1.1/public /mnt/public -o username=<you>,uid=$(id -u),gid=$(id -g)

# /etc/fstab (persistent) — store password in /root/.smbcredentials (chmod 600)
//10.0.1.1/public  /mnt/public  cifs  credentials=/root/.smbcredentials,uid=1000,gid=100,_netdev  0  0

/root/.smbcredentials:

username=<you>
password=<your-smb-password>

Connecting via NFS (Linux)

NFS uses NFSv4 with a read-only pseudo-root at /srv. Mount paths omit /srv.
Every intended child dataset is exported explicitly; the pseudo-root does not use crossmnt, so a
new ZFS dataset is not reachable until its export is reviewed and added.

One-off mount

# Public shared files
sudo mount -t nfs4 10.0.1.1:/public /mnt/public

# Media library (read-only)
sudo mount -t nfs4 10.0.1.1:/media/library /mnt/media

# Your private tree (all writes become your UID via all_squash)
sudo mount -t nfs4 10.0.1.1:/users/<you> /mnt/skydick-home

Persistent mount (/etc/fstab)

10.0.1.1:/public         /mnt/public        nfs4  rw,hard,_netdev                         0  0
10.0.1.1:/media/library  /mnt/media         nfs4  ro,hard,_netdev                         0  0
10.0.1.1:/users/<you>    /mnt/skydick-home  nfs4  rw,hard,_netdev                         0  0

Performance tuning (10GbE)

For large transfers on 10GbE with jumbo frames, add NFS mount options:

rsize=1048576,wsize=1048576,nconnect=16

Example:

10.0.1.1:/users/ldx  /mnt/skydick  nfs4  rw,hard,rsize=1048576,wsize=1048576,nconnect=16,_netdev  0  0

Connecting via NFS (Windows)

Windows Client for NFS does not use the NFSv4 pseudo-root paths above. Use the full exported
server path instead.

First check what the server exports:

showmount -e 10.0.1.1

Then mount using the strict exported path:

mount 10.0.1.1:/srv/public Z:
mount 10.0.1.1:/srv/media/library Y:
mount 10.0.1.1:/srv/users/<you> X:

Notes:

  • Windows NFS access is network-trusted, not user-authenticated
  • The per-user export still maps all writes to the server-side owner via all_squash
  • If the client is Windows, prefer SMB unless you specifically need NFS

For SMB on skydick, keep Samba on its Linux defaults for socket buffers and SMB multichannel
unless a benchmark proves a specific override helps. The host-side low-risk storage tuning is
atime=off on the dick pool root so reads do not create extra metadata writes across child
datasets.

Share details

Public (/srv/public)

Collaborative shared space. All users in the storage group can read and write. New files
inherit group storage via setgid (mode 2775).

  • SMB: read-write for @storage
  • NFS: read-write with root_squash (root maps to nobody, normal UIDs pass through)

Shared access is governed by LDAP membership in cn=storage,ou=posix_groups,dc=skyw,dc=top.
skydick also keeps a local storage group at GID 997 so on-disk ownership, service accounts,
and same-name local admin overlays stay stable.

Media library (/srv/media/library)

Read-only organized media (movies, TV, music). Managed by the automation stack (qBittorrent +
Sonarr/Radarr/Lidarr). Users consume but do not write here.

  • SMB: read-only for @storage
  • NFS: read-only via /media/library export

The qBittorrent + arr writer stack runs on door-pek (not on skydick) and writes
/srv/media over NFS as the qbittorrent service account (UID 900, via the /srv/media
export's all_squash,anonuid=900); skydick only serves the dataset. The full /srv/media
dataset (including /srv/media/data with raw torrent payload) is therefore only
writable* by
that one service account. Hardlinks between data/ and library/ work because they are
directories on the same ZFS dataset.

Torrents (/srv/media/data)

Read-only view of the raw per-tracker download tree (BYRBT, M-Team - TP, TJUPT,
IPTorrents, qbit, tv, movies, music, incomplete). door-pek's qBittorrent (UID 900)
is the sole writer, over NFS; everyone else gets read-only access so they can re-seed the
same files without re-downloading
(seeding only needs to read the payload + the .torrent
piece hashes). Most users want the organized media share instead — this is the unorganized
payload.

  • SMB: read-only for @storage as \\SKYDICK\torrents
  • NFS: reachable read-only under the /srv/media export at data/ (do not mount it
    writable from a second client — two writers to the same payload corrupts files / *arr
    hardlinks)

Re-seeding an existing torrent (without re-downloading the data):

  1. Mount the payload read-only: smb://10.0.1.1/torrents (macOS/Linux GUI), or
    sudo mount -t cifs //10.0.1.1/torrents /mnt/torrents -o ro,username=<you>,vers=3.1.1.
  2. Get the matching .torrent (re-grab it from the tracker, or copy it from door-pek's
    qBittorrent BT_backup/). The .torrent is tiny metadata — only the multi-GB payload must
    not be re-downloaded.
  3. In your own client, add the torrent with the save path pointing at the existing bytes
    on the read-only mount (e.g. save-path /mnt/torrents/movies for a release under
    /srv/media/data/movies/…). Leave "skip hash check" off.
  4. Force-recheck → it reads the pieces off the read-only mount, verifies hashes, jumps to
    100% / Seeding with 0 B downloaded. Your client's .fastresume/session live in your own
    local config (or your /srv/users/<you>/bt-state), never in the read-only data tree.

Personal files (/srv/users/<you>/files)

Private per-user storage. Only you can access your tree.

  • SMB: Samba [homes] share — connect as \\SKYDICK\<you>, authenticates with your Samba password
  • SMB bootstrap: one-time smbpasswd -a <you> on skydick creates your sambaSamAccount
  • SMB password changes after bootstrap: use the LDAP password UI or ldappasswd
  • NFS: /users/<you> export with all_squash mapping all operations to your UID/GID

Your NFS export maps every client UID to your server-side UID. This means any process on any
host in 10.0.0.0/16 that mounts your export will write as you. NFS does not authenticate —
it trusts the network. For stronger isolation, use SMB (which requires a password).

First-time user checklist

  1. Confirm your LDAP username with the admin.
  2. Confirm whether you should have only a private home, or also shared public and media
    access via LDAP group storage.
  3. If you will use SMB, ask the admin whether your first-time SMB bootstrap has been done.
  4. If the admin set a temporary SMB password for bootstrap, change it immediately through the LDAP
    password-change flow.
  5. Connect with either SMB or NFS using the paths in this guide.

Per-user subtree layout

/srv/users/<you>/
├── files/          ← personal files (SMB [homes] points here)
├── bt-state/       ← private torrent/arr client state
│   ├── watch/      ← .torrent watch directory
│   ├── session/    ← client session/resume data
│   └── config/     ← client configuration
└── vm/
    └── files/      ← VM disk images (file-backed, NFS-visible by default)

bt-state holds your torrent client's configuration and state databases. The actual media
payload lives on the shared dick/media dataset, not here. This separation means:

  • No duplicate media storage across users
  • Your client state is private and independent
  • The shared media tree has one writer (the automation stack)

VM zvols (block devices for iSCSI) are created as ZFS children of dick/users/<you>/vm/<name>
and are managed by the admin. They are not visible in the filesystem tree.

Admin runbook

The workflow below is the full procedure for onboarding a new data-pool user.

Adding a new user

Admin procedure — run on skydick as root unless a step explicitly happens on the LDAP host:

1. Create or verify the user in LDAP

Preferred for storage-only users. The LDAP entry should already contain:

  • uid
  • uidNumber
  • gidNumber
  • homeDirectory
  • objectClass: posixAccount

If the user should see public and media, also add their LDAP uid as a memberUid of
cn=storage,ou=posix_groups,dc=skyw,dc=top.

Check it on skydick:

getent passwd <newuser>

2. Add a local NixOS user only if needed

Only do this if the user needs SSH login, sudo, or an intentional local override. If you do create
a same-name local admin user, remember that skydick will use the local Unix UID/GID for on-server
authorization while SMB passwords still come from LDAP.

In hosts/skydick/default.nix:

users.users.<newuser> = {
  extraGroups = [ "storage" ];
  hashedPassword = "<hash>";  # mkpasswd -m yescrypt
};

In modules/users.nix (if the user needs SSH/sudo access across all hosts):

users.users.<newuser> = {
  isNormalUser = true;
  extraGroups = [ "wheel" ];
  openssh.authorizedKeys.keys = [ "ssh-ed25519 ..." ];
};

3. Add per-user tmpfiles and NFS export

Use numeric UID/GID in tmpfiles rules for LDAP-only users. This avoids boot-time dependence on NSS
name resolution.

First get the IDs:

uid=$(getent passwd <newuser> | cut -d: -f3)
gid=$(getent passwd <newuser> | cut -d: -f4)

In hosts/skydick/datapool.nix, add to systemd.tmpfiles.rules:

"d /srv/users/<newuser> 0700 <UID> <GID> -"
"d /srv/users/<newuser>/files 0750 <UID> <GID> -"
"d /srv/users/<newuser>/bt-state 0750 <UID> <GID> -"
"d /srv/users/<newuser>/vm 0750 <UID> <GID> -"
"d /srv/users/<newuser>/vm/files 0750 <UID> <GID> -"

Add the parent and each mounted child to services.nfs.server.exports. Use exact client addresses;
an owner-mapped all_squash export to the whole LAN lets any LAN host act as that user.

/srv/users/<newuser>          <CLIENT_IP>(rw,sync,no_subtree_check,all_squash,anonuid=<UID>,anongid=<GID>)
/srv/users/<newuser>/files    <CLIENT_IP>(rw,sync,nohide,no_subtree_check,all_squash,anonuid=<UID>,anongid=<GID>)
/srv/users/<newuser>/bt-state <CLIENT_IP>(rw,sync,nohide,no_subtree_check,all_squash,anonuid=<UID>,anongid=<GID>)
/srv/users/<newuser>/vm       <CLIENT_IP>(rw,sync,nohide,no_subtree_check,all_squash,anonuid=<UID>,anongid=<GID>)

Replace <CLIENT_IP>, <UID>, and <GID> with the assigned host address and LDAP-backed numeric
IDs. Add a second client term only when another stable address is an intentional owner endpoint.

Example: the user previously called ylw in local NixOS config is now canonicalized to
ye-lw21 everywhere, so the per-user share path is /srv/users/ye-lw21.

4. Deploy NixOS config

sudo git -C /etc/nixos pull && sudo nixos-rebuild switch --flake /etc/nixos

5. Create per-user ZFS datasets on skydick

The shared namespace datasets (dick/public, dick/media, dick/system, dick/templates, and
dick/users) already exist on the host. For a new user, create only that user's subtree:

# Get the user's UID/GID
uid=$(getent passwd <newuser> | cut -d: -f3)
gid=$(getent passwd <newuser> | cut -d: -f4)

# Create datasets
zfs create -o mountpoint=/srv/users/<newuser> -o quota=10T               dick/users/<newuser>
zfs create -o recordsize=128K -o mountpoint=/srv/users/<newuser>/files   dick/users/<newuser>/files
zfs create -o recordsize=16K  -o mountpoint=/srv/users/<newuser>/bt-state dick/users/<newuser>/bt-state
zfs create -o recordsize=64K  -o mountpoint=/srv/users/<newuser>/vm      dick/users/<newuser>/vm
mkdir -p /srv/users/<newuser>/vm/files

# Set ownership
chown "$uid:$gid" /srv/users/<newuser> && chmod 0700 /srv/users/<newuser>
for d in files bt-state vm vm/files; do
  chown "$uid:$gid" /srv/users/<newuser>/$d && chmod 0750 /srv/users/<newuser>/$d
done

dick is expected to have atime=off; the child datasets above inherit it automatically. Verify
after creation:

zfs get atime dick dick/users/<newuser> dick/users/<newuser>/files

6. Bootstrap SMB login if the user needs SMB

smbpasswd -a <newuser>

This one-time step is required even if the user already exists as a POSIX account in LDAP.
smbpasswd -a creates the user's sambaSamAccount attributes in LDAP and sets an initial SMB
password.

After this bootstrap, future password changes should happen through the LDAP password UI or
ldappasswd, not routine smbpasswd use. That keeps LDAP as the password source of truth while
the LDAP server updates the Samba password hashes.

The user can now connect via SMB and NFS.

7. Re-export NFS

exportfs -ra

8. Verify before handing over to the user

getent passwd <newuser>
id <newuser>
zfs list -r dick/users/<newuser>
exportfs -v | grep "/srv/users/<newuser>"

If SMB was enabled:

pdbedit -L | grep "^<newuser>:"

Then tell the user:

  • Their exact username
  • Whether they have public / media access or only the private home
  • Whether SMB bootstrap is done
  • To use the LDAP password-change flow for future password changes

Existing user enabling SMB for the first time

If a user already exists in LDAP and already has the private dataset/export, but has never used SMB
before, only this step is needed:

smbpasswd -a <user>

After that, the user should change the password through the LDAP password-change flow if the admin
set the initial value.

Provisioning an iSCSI block volume (admin)

iSCSI hands a client a raw block device (a ZFS zvol) instead of a shared filesystem. Unlike SMB/NFS,
iSCSI targets are imperative, secret-bearing state. The root-only state lives in
/var/lib/target; /etc/target is a directory symlink so targetcli's atomic saveconfig rename stays
on persistent storage. iscsi-target.service (note: not target.service) restores it at boot.
The Nix configuration validates that the root-only JSON has a target, block backstore, non-wildcard
portal, explicit IQN ACL, CHAP credentials, and LUN mapping, and that every backing device exists. It
never copies CHAP material into the world-readable Nix store.

An iSCSI "account" = a target LUN + a per-initiator ACL (allowlists the client's initiator IQN) +
CHAP (username/password). Both together gate access.

Prerequisites:

  • The client's initiator IQN, from cat /etc/iscsi/initiatorname.iscsi on the client (needs root).
  • A name for the volume/target. Central/host-owned LUNs live under dick/system/vm/<name>;
    user-owned ones under dick/users/<user>/vm/<name>.
  • Check pool headroom first — a thick zvol reserves its full size immediately. On a near-full pool
    use a thin/sparse volume (-s), which reserves nothing and consumes only real writes:
    zfs list dick (watch AVAIL).

Steps (run on skydick as root):

# 1. Back up the existing secret-bearing state before every target change.
install -d -m 0700 /root/backups/target
stamp=$(date -u +%Y%m%dT%H%M%SZ)
cp --preserve=all /etc/target/saveconfig.json /root/backups/target/saveconfig.json.$stamp
targetcli ls > /root/backups/target/targetcli-ls.$stamp.txt

# 2. Create the backing zvol. -s = thin/sparse. 16K volblocksize per pool convention.
zfs create -s -V 8T -o volblocksize=16K dick/system/vm/<name>

# 3. Build the LIO target. Generate a CHAP secret (openssl is not on the box):
CHAP=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 16); echo "$CHAP"
CLIENT_IQN=iqn.1993-08.org.debian:01:xxxxxxxxxxxx      # from the client
TGT=iqn.2026-07.top.skyw.skydick:<name>

targetcli <<EOF
/backstores/block create name=<name> dev=/dev/zvol/dick/system/vm/<name>
/backstores/block/<name> set attribute emulate_tpu=1
/iscsi create $TGT
/iscsi/$TGT/tpg1/luns create /backstores/block/<name>
/iscsi/$TGT/tpg1/acls create $CLIENT_IQN
/iscsi/$TGT/tpg1/acls/$CLIENT_IQN set auth userid=<name> password=$CHAP
/iscsi/$TGT/tpg1 set attribute authentication=1 generate_node_acls=0 cache_dynamic_acls=0
/iscsi/$TGT/tpg1/portals delete ::0 3260
/iscsi/$TGT/tpg1/portals create 10.0.1.1 3260
saveconfig
EOF

# 4. Re-run the non-mutating persistence/backstore guard.
systemctl restart iscsi-target-config-ready.service

Notes / gotchas:

  • emulate_tpu=1 enables UNMAP so client discard/fstrim returns freed blocks to the thin pool.
  • LIO auto-creates a default portal on the IPv6 wildcard [::0]:3260, not 0.0.0.0. Delete
    ::0 3260 before creating a specific 10.0.1.1 3260 portal, or the specific bind fails with
    EINVAL (the wildcard already holds the port).
  • generate_node_acls=0 + authentication=1 means only the listed IQN, with the correct CHAP, can
    attach. The host firewall additionally admits TCP 3260 only from the declared initiator at
    10.0.200.11; update that source ACL deliberately when provisioning another initiator.
  • In targetcli sessions detail, the parenthetical NOT AUTHENTICATED label refers to optional
    mutual CHAP (authenticate_target), not whether the initiator supplied its CHAP credential. The
    persistence guard checks the initiator-side chap_userid and chap_password fields directly.
  • nixos-rebuild switch never restarts iscsi-target.service; perform a target restart only in an
    explicit maintenance window because its stop action clears the live kernel target.
  • Verify: targetcli ls /iscsi and ss -ltnp | grep 3260.

Client side (open-iscsi, run as root on the client):

TGT=iqn.2026-07.top.skyw.skydick:<name>
iscsiadm -m discovery -t sendtargets -p 10.0.1.1
iscsiadm -m node -T $TGT -p 10.0.1.1 --op update -n node.session.auth.authmethod -v CHAP
iscsiadm -m node -T $TGT -p 10.0.1.1 --op update -n node.session.auth.username   -v <name>
iscsiadm -m node -T $TGT -p 10.0.1.1 --op update -n node.session.auth.password   -v <CHAP>
iscsiadm -m node -T $TGT -p 10.0.1.1 --login
iscsiadm -m node -T $TGT -p 10.0.1.1 --op update -n node.startup -v automatic   # reconnect on boot

A new block device (/dev/sdX) of the LUN size appears; format/LVM it as normal. Mount with discard
or run periodic fstrim so deletes flow back to the thin pool.

First target provisioned this way: dick/system/vm/rh1288v3RH1288V3-CPUserver (10.0.200.11),
2026-07-14.

Quotas

When a user's dick/users/<user> dataset exists, its ZFS quota (default 10TB in the examples
above) caps the total across all child datasets (files + bt-state + vm). Check usage:

zfs list -o name,used,quota -r dick/users

Adjust quota:

zfs set quota=20T dick/users/<user>

The shared dick/media dataset has no per-user quota — it is managed at the service level.

Monitoring

Check pool health:

zpool status dick

Check dataset usage:

zfs list -o name,used,avail,refer,quota -r dick

Check the datapool access-time policy:

zfs get -r atime dick

Check NFS exports:

exportfs -v

Check active NFS clients:

ss -tn | grep :2049

Troubleshooting

"Permission denied" on NFS mount

  • Verify your IP is in 10.0.0.0/16: ip addr
  • Check the export exists: showmount -e 10.0.1.1
  • Per-user exports use all_squash — your local UID does not matter, everything maps to
    the server-side owner UID

"Permission denied" writing to NFS

  • Public: your server-side UID must be in the storage group
  • Media: read-only for all users (write is via the automation service account only)
  • Personal: should always work — if not, check that the ZFS datasets are mounted:
    ssh skydick zfs list -r dick/users/<you>

SMB authentication fails

  • Samba uses LDAP-backed sambaSamAccount entries for SMB auth, not just the Unix userPassword
  • getent passwd <user> succeeding only proves Unix account lookup works; it does not create an SMB login
  • If the user has never used SMB before, admin must run smbpasswd -a <user> once on skydick to
    bootstrap the sambaSamAccount
  • After bootstrap, change the password through the LDAP password UI or ldappasswd so Unix and
    SMB passwords stay aligned
  • If pdbedit -L shows the user but SMB still fails, reset with smbpasswd -a <user> and then
    have the user change the password again through the LDAP password-change flow
  • If public or media access fails but the home share works, check LDAP storage membership and
    verify the memberUid list for cn=storage,ou=posix_groups,dc=skyw,dc=top

Slow NFS transfers

  • Ensure jumbo frames (MTU 9200 on skydick's bond40g) are set on both client and server interfaces
  • Add nconnect=16 to mount options for parallel NFS connections
  • Add rsize=1048576,wsize=1048576 for 1MB read/write blocks
  • Check link speed: ethtool <interface> | grep Speed

Slow SMB transfers

  • Do not force Samba socket options buffer sizes unless you have benchmark data; Linux autotuning is usually better
  • Confirm the datapool inherits atime=off: zfs get -r atime dick
  • Check live SMB sessions and negotiated dialect: smbstatus -b
  • Check the active link speed on skydick: ethtool <interface> | grep Speed

Files not showing up in media library

The arr stack (Sonarr/Radarr/Lidarr) hardlinks files from /srv/media/data/ to
/srv/media/library/. If a file exists in data/ but not in library/, the
arr
import/rename has not run yet. Do not manually copy files into library/ — let the
automation stack manage it to preserve hardlinks and metadata.