--- name: storage-management description: Detect, partition, format, mount, and back up storage drives on Linux servers — including fstab setup, rsync backup workflows, and permission management. version: 1.0.0 author: Hermes Agent license: MIT platforms: [linux] metadata: hermes: tags: [storage, disks, drives, rsync, backup, fstab, mount] related_skills: [server-health-check] --- # Storage & Drive Management Manage physical storage drives on Linux — detection, partitioning, formatting, persistent mounting, and full-drive backup via rsync. ## Detecting New Drives ```bash # Full overview: include TRAN(transport) to distinguish USB from SATA/NVMe lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,MODEL,TRAN # Unmounted drives (device listed but no mountpoint) lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,MODEL,TRAN | grep -E 'disk$|part$' | awk '$5 == ""' # Get UUIDs for fstab sudo blkid # Find by USB vendor/model (useful for identifying thumb drives) ls -la /dev/disk/by-id/usb* 2>/dev/null ``` The `TRAN` column shows `usb`, `sata`, or `nvme` — immediately tells you how the drive is connected. A drive showing in `lsblk` with no partitions and no mount point is ready to be set up. ## Partitioning & Formatting ### Step 1 — Create GPT partition table + single partition ```bash sudo parted /dev/sdX mklabel gpt sudo parted /dev/sdX mkpart primary ext4 0% 100% sudo partprobe /dev/sdX # reload partition table ``` ### Step 2 — Format with ext4 (label it for easy identification) ```bash sudo mkfs.ext4 /dev/sdX1 -L DriveLabel ``` **Note:** `mkfs` is on the unconditional blocklist in Hermes. The agent cannot run it. Ask the user to run the command directly, then proceed with mounting and fstab. ### Step 3 — Create mount point and mount ```bash sudo mkdir -p /mnt/drive-label sudo mount /dev/sdX1 /mnt/drive-label ``` ### Step 4 — Add to fstab for persistence ```bash # Get UUID sudo blkid /dev/sdX1 # Add entry (ext4 example) echo 'UUID=xxxx-xxxx /mnt/drive-label ext4 defaults,noatime 0 2' | sudo tee -a /etc/fstab ``` **fstab format:** ` ` | Field | Meaning | |-------|---------| | `UUID=...` | Use UUID, not `/dev/sdX` — survives re-enumeration | | mount point | Directory to mount at | | type | `ext4`, `ntfs-3g`, `exfat`, `vfat` | | options | `defaults`, `noatime` (skip access time updates), `uid=1000,gid=1000,umask=000` (permissions for NTFS/exFAT) | | dump | 0 (no backup) | | pass | `2` (non-root fsck), `1` (root fsck), `0` (no fsck) | ### External/Removable Drives **ALWAYS add `nofail` to external drives in fstab.** Without it, systemd waits for the drive at boot and either hangs or drops to emergency mode if the drive is unplugged. ```bash # WRONG — hangs at boot if drive missing UUID=xxxx /mnt/external ext4 defaults,noatime 0 2 # RIGHT — skips silently if drive not present UUID=xxxx /mnt/external ext4 defaults,noatime,nofail 0 0 ``` Also use `pass=0` (last column) for external drives — a missing drive that's flagged for fsck (`0 2`) will cause a boot stall even with `nofail`. ### Step 5 — Verify ```bash sudo mount -a # re-read fstab, mount any missing entries df -h /mnt/drive-label lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT ``` ## Unmounting Drives Always unmount before physically disconnecting a drive to avoid data corruption. ```bash sudo umount /mnt/drive-label ``` ### When umount hangs or times out If `umount` hangs (e.g., a process still has open file handles or I/O is stalled), use lazy unmount: ```bash sudo umount -l /mnt/drive-label ``` `-l` (lazy) detaches the filesystem from the mount tree immediately and cleans up references once they're no longer in use. The drive is safe to disconnect after `umount -l` returns successfully — you'll either get a clean detach or `not mounted` (meaning the original umount actually completed despite the timeout). If even `umount -l` reports `not mounted`, the drive is already detached — safe to remove. ### Filesystem-Specific Notes | FS | Install Package | Mount Type | Special Options | |----|----------------|------------|-----------------| | **ext4** | built-in | default | `defaults,noatime` | | **NTFS** | `ntfs-3g` | `ntfs-3g` | `uid=1000,gid=1000,umask=000` (full user access) | | **exFAT** | `exfatprogs` | `exfat` | `uid=1000,gid=1000,umask=000` | > ⚠️ **NTFS on Linux:** Always specify `-t ntfs-3g` explicitly. The kernel `ntfs3` driver (in-tree) is experimental and can corrupt data. Use the userspace `ntfs-3g` which is battle-tested. ## Full-Drive Backup with rsync For copying an entire drive (or large directories) to another local drive: ### Single-Instance rsync (Recommended for USB Drives) Multiple parallel rsync instances on the same USB source cause I/O contention errors (`error in socket IO`, `Broken pipe`, `errors selecting input/output files`). Always use a **single instance** when the source is a USB/external drive. ```bash # Local disk-to-disk copy (fastest approach) sudo rsync -avhW --progress /mnt/source/ /mnt/dest/backup-folder/ \ --exclude='$RECYCLE.BIN' --exclude='System Volume Information' ``` | Flag | Meaning | |------|---------| | `-a` | Archive mode (preserves permissions, timestamps, symlinks) | | `-v` | Verbose | | `-h` | Human-readable sizes | | `-W` | **Whole-file** (skip delta checksum) — faster for local copies | | `--progress` | Show per-file transfer progress | **Why `-W` for local copies:** rsync normally reads blocks of each file to compute checksums for delta transfer. On a local copy there's no network benefit — `-W` just copies the whole file, eliminating the checksum overhead. For deep rsync best practices (USB I/O contention, ionice scheduling, progress monitoring, post-backup reorganization, performance expectations), see `references/rsync-best-practices.md` (absorbed from `data-migration`). ### Permission Handling - **Before running non-sudo rsync, check destination ownership:** `ls -la /mnt/dest/` — if the parent directory is root-owned (e.g., `drwxr-xr-x root root`), rsync will fail with `Permission denied` on `mkdir`. Fix: `sudo chown user:user /mnt/dest/` first. - If rsync runs with `sudo`, dest dirs are owned by root - Subsequent non-sudo rsync runs fail with `Permission denied` on mkdir - **Fix:** `sudo chown -R user:user /mnt/dest/` or chmod on target dirs - Or just always run the rsync with `sudo` ### Progress Monitoring ```bash # Check size transferred so far df -h /mnt/dest-drive # Check process is alive ps aux | grep rsync | grep -v grep # Recent log lines tail -5 /path/to/rsync.log # File count (slow for large dirs) find /mnt/dest/backup-folder/ -type f | wc -l ``` ### Expected Speeds | Source Type | Typical Speed | Notes | |-------------|--------------|-------| | USB 3.0 HDD → SATA SSD | 80-120 MB/s | Source-limited | | USB 2.0 HDD → any | 20-40 MB/s | Interface bottleneck | | NVMe → NVMe | 500+ MB/s | Only if both are internal | ### Resume Behavior rsync automatically resumes partial transfers. Files with matching name, size, and mtime are skipped. You can safely kill and restart — only new/changed files transfer. ## Exposing Drives Over the Network (Samba) After mounting a drive, you can share it over the network via Samba (SMB/CIFS) so Windows, macOS, and Linux machines on the LAN can access it as a network drive. ### Check Samba Status ```bash which smbd && smbd --version # check if installed cat /etc/samba/smb.conf # existing config ``` ### Add a New Share Samba uses a simple INI-style config at `/etc/samba/smb.conf`. Append a new share section: ```bash sudo tee -a /etc/samba/smb.conf << 'EOF' [share-name] path = /mnt/drive browseable = yes read only = no guest ok = yes force user = ray create mask = 0777 directory mask = 0777 EOF ``` | Option | Meaning | |--------|---------| | `guest ok = yes` | No password required on connect | | `force user = ray` | All files written over SMB owned by `ray` | | `create mask = 0777` | New files get full permissions | | `directory mask = 0777` | New directories get full permissions | ### Restart & Verify ```bash sudo systemctl restart smbd # Verify the share shows up smbclient -L //localhost -U ray --no-pass | grep share-name # Find server LAN IP ip -4 addr show | grep -oP 'inet \K[^/]+' | grep -v 127.0.0.1 ``` ### Connecting from Clients | OS | How | |----|-----| | **Windows** | `\\192.168.x.x\share-name` in File Explorer | | **macOS** | ⌘K → `smb://192.168.x.x/share-name` | | **Linux** | `smb://192.168.x.x/share-name` in file manager | ### Password-Protected Shares (Alternative) ```bash sudo smbpasswd -a ray # set SMB password (interactive) # or from a script: echo 'password' | sudo smbpasswd -a -s ray ``` Then use `valid users = ray` and `guest ok = no` in the share section. ### Pitfalls - **SMB password ≠ system password.** Setting a Samba password with `smbpasswd` is a separate step from the user's Linux login password. - **`$` in share paths:** The `$RECYCLE.BIN` directory on NTFS drives contains a literal `$`. When writing Samba configs or rsync excludes, the `$` must be quoted or escaped to prevent shell variable expansion. - **Firewall:** If clients can't connect, check Samba ports: `sudo ufw allow samba` or `sudo ufw allow 139,445/tcp`. ## Pitfalls - **Mounted drives are root-owned by default** — `cp`, `rsync`, `mkdir`, and any write to a freshly mounted drive will fail with `Permission denied` unless you use `sudo`. After sudo operations, subdirectories are owned by root and non-sudo writes keep failing. Either always use `sudo` for writes to mounted drives, or `sudo chown user:user /mnt/mountpoint/` after mounting to grant user-level access. - **fstab doesn't evaluate shell commands** — `UUID=$(sudo blkid ...)` doesn't work in fstab. Use the literal UUID from `sudo blkid`. - **External drives MUST have `nofail`** — missing external drives without `nofail` cause systemd to hang at boot (waits 90s per drive) or drop to emergency mode. Always add `nofail` and `pass=0` to fstab entries for removable/external drives. - **Parallel rsync on USB drives** causes `I/O error` / `Broken pipe` / `socket IO error`. The USB controller can't handle concurrent reads. Use a single instance. - **Drive re-enumeration** — `/dev/sdb` may become `/dev/sdc` after reboot or replug. Always use UUIDs in fstab. - **Permissions gap after sudo rsync** — subsequent non-sudo runs fail on directories the first run created as root. Either always use sudo, or chown after the first run. - **NTFS write support** — `ntfs-3g` not `ntfs3`. The kernel ntfs3 driver is experimental. Install `ntfs-3g` explicitly. - **exFAT on modern Ubuntu** — package is `exfatprogs` (not `exfat-utils` which is deprecated). Ubuntu 24.04+ has kernel exFAT support, but still needs the tools package. ## References - `references/drive-selection-guide.md` — SMR vs CMR guidance, speed tiers, physical/electrical compatibility checklist, OEM RAM upgrade assessment (for when the user asks "will this drive fit?" or "how does this compare to my current drive?") - `references/rsync-best-practices.md` — rsync pattern reference for USB I/O - `references/rayserver-shares.md` — rayserver-specific Samba share inventory (absorbed from `samba-nas`)