Chapter 4. Filesystem Maintenance

Using Disks and Filesystems

df

Display available space on mounted filesystems.

lsblk

List disks and other block devices.

mount

Make a disk partition accessible.

umount

Unmount a disk partition (make it inaccessible).

fsck

Check a disk partition for errors.

Linux systems can have multiple disks or partitions. In casual conversation, these are variously called devices, filesystems, volumes, even directories. I’ll try to be more precise.

A disk is a mass storage device, which may be divided into partitions that act as independent devices. Disks and partitions are represented on Linux systems as special files in the directory /dev. For example, /dev/sda7 could be a partition on your hard drive. Some common devices in /dev are:

sda

First block device, such as SCSI, SATA, or USB hard drives; partitions are sda1, sda2, …​.

sdb

Second block device; partitions are sdb1, sdb2, …​. Likewise for sdc, sdd, etc.

md0

First RAID device; partitions are md0p1, md0p2, …​. Likewise for md1, md2, etc.

nvme0n1

First NVMe SSD device; partitions are nvme0n1p1, nvme0n1p2, …​. Likewise for nvme1n1, nvme2n1, etc. The second integer, like the 1 in nvme0n1p2, is called the namespace ID, and most users can ignore it.

Before a partition can hold files, it is formatted by a program that creates a filesystem on it (see “Creating and Modifying Filesystems”). A filesystem defines how files are represented; examples are ext4 (a Linux journaling filesystem) and NTFS (a Microsoft Windows filesystem). Formatting is generally done for you when you install Linux.

After creating a filesystem, make it available by mounting its partition on an empty directory.1 For example, if you mount a Windows filesystem on a directory /mnt/win, it becomes part of your system’s directory tree, and you can create and edit files like /mnt/win/myfile.txt. Mounting generally happens automatically at boot time. You can also unmount partitions to make them inaccessible via the filesystem for maintenance.

df

stdin

stdout

- file

-- opt

--help

--version

df [options] [disk devices | files | directories]

The df (disk free) command shows you the size, used space, and free space on a given disk partition. If you supply a file or directory, df describes the disk device on which that file or directory resides. With no arguments, df reports on all mounted filesystems:

df
Filesystem 1k-blocks    Used    Avail Use% Mounted on
/dev/sda     1011928  225464   735060  24% /
/dev/sda9     521748  249148   246096  51% /var
/dev/sda8    8064272 4088636  3565984  54% /usr
/dev/sda10   8064272 4586576  3068044  60% /home

The df command may list all sorts of devices besides disks. To limit the display to disks, try these options (and create an alias if it’s helpful):

df -h -x tmpfs -x devtmpfs -x squashfs

Useful options

-k

List sizes in KB (the default).

-m

List sizes in MB.

-B N

Display sizes in blocks of N bytes. (Default = 1024)

-h

-H

Print human-readable output and choose the most appropriate unit for each size. For example, if your two disks have 1 gigabyte and 25 KB free, respectively, df -h prints 1G and 25K. The -h option uses powers of 1024, whereas -H uses powers of 1000.

-l

Display only local filesystems, not networked filesystems.

-T

Include the filesystem type (ext3, vfat, etc.) in the output.

-t type

Display only filesystems of the given type.

-x type

Don’t display filesystems of the given type.

-i

Inode mode. Display total, used, and free inodes for each filesystem, instead of disk blocks. When all inodes on a filesystem are used, the filesystem is “full” even if free disk space remains.

lsblk

stdin

stdout

- file

-- opt

--help

--version

lsblk [options] [devices]

The lsblk command lists the mass storage devices, known as block devices, available on a Linux system, such as hard disks, SSDs, and RAM disks.

lsblk
NAME         MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
sda            8:0    0    20G  0 disk
├─sda1         8:1    0     1M  0 part
├─sda2         8:2    0   513M  0 part  /boot/efi
├─sda3         8:3    0  19.5G  0 part  /
sdb            8:80   0   7.6G  0 disk
└─sdb1         8:81   1   7.6G  0 part  /mnt/usb-key

The output shows a hard drive at /dev/sda with three partitions, and a USB thumb drive at /dev/sdb with a single partition. lsblk has a ton of formatting options and can limit itself to particular devices.

lsblk -o NAME,SIZE /dev/sda
NAME    SIZE
sda      20G
├─sda1    1M
├─sda2  513M
└─sda3 19.5G

Useful options

-l

Display a simple list instead of a tree.

-a

Show all block devices, including those normally hidden.

-f

Add information about the filesystems on each device.

-o columns

Print only the given columns, which you provide as a comma-separated list. View the available columns with lsblk --help.

-J

Print the list in JSON format for easy processing by programs.

mount

stdin

stdout

- file

-- opt

--help

--version

mount [options] [device | directory]

The mount command makes a partition accessible. Most commonly it handles disk drives (say, /dev/sda1) and removable media (e.g., USB keys), making them accessible via an existing directory (say, /mnt/mydir):

sudo mkdir /mnt/mydirls /mnt/mydir                      Notice it’s emptysudo mount /dev/sda1 /mnt/mydirls /mnt/mydir
file1  file2  file3         Files on the mounted partitiondf /mnt/mydir
Filesystem 1K-blocks   Used  Avail Use% Mounted on
/dev/sda1    1011928 285744 674780  30% /mnt/mydir

mount has many uses; I discuss only the most basic. In most common cases, mount reads the file /etc/fstab (filesystem table, pronounced “F S tab”) to learn how to mount a desired disk. For example, if you run mount /usr, the mount command looks up “/usr” in /etc/fstab, whose line might look like this:

/dev/sda8    /usr    ext4    defaults    1    2

Here mount learns that device /dev/sda8 should be mounted on /usr as a Linux ext4-formatted filesystem with default options. Mount it with either of these commands:

sudo mount /dev/sda8     By devicesudo mount /usr          By directory

mount is run typically by the superuser, but common removable devices like USB keys and DVDs often can be mounted and unmounted by any user.

Useful options

-t type

Specify the type of filesystem, such as ext4 or ntfs.

-l

List all mounted filesystems; works with -t too.

-a

Mount all filesystems listed in /etc/fstab. Ignores entries that include the noauto option. Works well with -t too.

-r

Mount the filesystem read-only (see the manpage for disclaimers).

umount

stdin

stdout

- file

-- opt

--help

--version

umount [options] [device | directory]

umount does the opposite of mount: it makes a disk partition unavailable via the filesystem.2 For instance, if you’ve mounted a USB thumb drive, umount it before you unplug it:

umount "/media/smith/My Vacation Photos"

Always unmount any removable medium before ejecting it, particularly if it’s writable, or you risk damage to its filesystem. To unmount all mounted devices:

sudo umount -a

Don’t unmount a filesystem that’s in use; in fact, the umount command refuses to do so for safety reasons.

fsck

stdin

stdout

- file

-- opt

--help

--version

fsck [options] [devices]

The fsck (filesystem check) command validates a Linux disk filesystem and, if requested, repairs errors found on it. fsck runs automatically when your system boots, or manually. In general, unmount a device before checking it, so no other programs are operating on it at the same time:

sudo umount /dev/sda10sudo fsck -f /dev/sda10
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/home: 172/1281696 files (11.6% non-contiguous), ...

You cannot use fsck to fix your root filesystem while your system is running normally. Boot first on a Linux USB thumb drive or other rescue media, then run fsck.

fsck is a frontend for a set of filesystem-checking commands found in /sbin, with names beginning “fsck”. Only certain types of filesystems are supported; list them with the command:

ls /sbin/fsck.* | cut -d. -f2 | column
cramfs     ext3       fat        hfsplus    msdos
ext2       ext4       hfs        minix      vfat

Useful options

-A

Check all disks listed in /etc/fstab, in order.

-f

Force fsck to run even if no errors are apparent.

-N

Print a description of the checking that would be done, but exit without performing any checking.

-r

Fix errors interactively, prompting before each fix.

-a

Fix errors automatically (use only if you really know what you’re doing; if not, you can seriously mess up a filesystem).

Creating and Modifying Filesystems

mkfs

Format (create a filesystem on) a disk partition.

resize2fs

Grow or shrink a disk partition.

e2label

Change the volume label on a disk partition.

Disk-related operations like partitioning and formatting can be complex at the command line. In general, for anything more complicated than formatting a single partition, I recommend using a graphical application such as gparted. Honestly, it’s easier and less error-prone.

Nevertheless, I still run a few operations at the command line that are quick and easy. One is listing the partitions of a storage device like /dev/sda with fdisk:

sudo fdisk -l /dev/sda
Disk /dev/sda: 20 GiB, 21474836480 bytes, ...
⋮
Device       Start      End  Sectors  Size Type
/dev/sda1     2048     4095     2048    1M BIOS boot
/dev/sda2     4096  1054719  1050624  513M EFI System
/dev/sda3  1054720 41940991 40886272 19.5G Linux

or similarly with parted:

sudo parted /dev/sda -- print

Another is exporting the partition table of a storage device for safekeeping. (Store it on a USB thumb drive or other device, not the disk you’re working on!)

sudo sfdisk -d /dev/sda > /mnt/thumb/sda.txt

Later, if you mess up a risky partitioning operation, you can restore the partition table (but be careful to specify the correct disk device or you’ll overwrite the wrong partition table):

sudo sfdisk /dev/device < /mnt/thumb/sda.txt

The commands that follow are also relatively basic operations on disks and filesystems without graphical tools.

mkfs

stdin

stdout

- file

-- opt

--help

--version

mke2fs [options] device

mkfs.ext3 [options] device

mkfs.ext4 [options] device

mkntfs [options] device

mkfs.ntfs [options] device ...and many other variations...

The mkfs family of commands formats a Linux storage device for a variety of filesystems. The storage device is usually a partition, such as /dev/sdb1.

Warning

mkfs erases a storage device. Make sure the device name you provide is the correct one!

Examples:

sudo mkfs.ext4 /dev/device    Standard Linux filesystemsudo mke2fs /dev/device       Standard Linux filesystemsudo mkfs.ntfs /dev/device    Microsoft Windows filesystemsudo mkntfs /dev/device       Microsoft Windows filesystem

As you can see, most of the command names are “mkfs” followed by a dot and a filesystem type, like mkfs.ext4. They may also have alternate names (links) with the filesystem type embedded in the middle of “mkfs”, such as mke2fs for an “ext” filesystem. To list all such commands installed on your system, run:

ls /usr/*bin/mkfs.*
/usr/sbin/mkfs.ext2    /usr/sbin/mkfs.hfs
/usr/sbin/mkfs.ext3    /usr/sbin/mkfs.minix
/usr/sbin/mkfs.ext4    /usr/sbin/mkfs.msdos
/usr/sbin/mkfs.fat     /usr/sbin/mkfs.ntfs

Useful options

-n

Dry-run mode: don’t format anything. Just display what would be done.

-L name

Label the formatted volume with the given name, which can be up to 16 bytes long.

-b N

Set the block size to N bytes.

resize2fs

stdin

stdout

- file

-- opt

--help

--version

resize2fs [options] device [size]

The resize2fs command grows or shrinks a standard Linux filesystem of type ext2, ext3, or ext4. To enlarge a filesystem:

  1. Confirm that the device has enough free space immediately following the current partition.

  2. Unmount the filesystem.

  3. Enlarge its disk partition with gparted or similar program. (This requires free space just after the current partition.)

  4. Check the filesystem with fsck.

  5. Run resize2fs with appropriate arguments. In modern kernels, the filesystem may be mounted during resizing.

To shrink a filesystem:

  1. Confirm with df that the data in the filesystem (the “Used” column) will fit within the proposed new size.

  2. Unmount the filesystem.

  3. Run resize2fs with appropriate arguments.

  1. Shrink its disk partition with gparted or a similar program.

  2. Check the filesystem with fsck.

To resize a filesystem on /dev/sda1, assuming you’ve already completed any checking and partitioning, run resize2fs either with or without a size:

sudo resize2fs /dev/sda1 100G   Resize to 100 GBsudo resize2fs /dev/sda1        Resize to the partition size

Sizes can be an absolute number of blocks, like 12345690, or a size followed by K (KB), M (MB), G (GB), T (terabytes), or s (512-byte sectors). The values are powers of two, so 1K means 1024, not 1000, and so on.

If you resize filesystems often, make your life easier with logical volume management (LVM), as explained in “Logical Volumes for Flexible Storage”, or a more modern filesystem, as in “ZFS: A Modern, Do-It-All Filesystem”.

Useful options

-f

Force the resizing operation, even if resize2fs complains.

-p

Display the progress of the operation as it runs.

e2label

stdin

stdout

- file

-- opt

--help

--version

e2label device [label]

A label is a nickname for a filesystem. The e2label command sets or prints the label of a standard Linux filesystem of type ext2, ext3, or ext4. Filesystems don’t require labels, but they’re convenient for referring to filesystems in /etc/fstab.

sudo e2label /dev/sdb1 backups        Assign a labelsudo e2label /dev/sdb1                Print a label
backups

RAID Arrays for Redundancy

mdadm

Manage RAID arrays.

RAID (Redundant Array of Independent Disks) is a technique that distributes a computer’s data across multiple disks, transparently, while acting like a single disk. Usually, RAID is for redundancy—if one disk dies, your files are still intact. Other types of RAID increase the performance of storage.

A bunch of disks in a RAID arrangement is called a RAID array. The type of RAID, called the RAID level, determines how many drive failures the array can tolerate and still guarantee the data’s safety. Some standard RAID levels are RAID-0, RAID-1, RAID-5, RAID-10, and others you can explore on the web.

Let’s create a minimal RAID-1 array using the most common RAID software for Linux, mdadm. RAID-1 adds redundancy simply by mirroring data from one drive to the others in the array. As long as one drive is still operating, the data is safe. For this example, I start with two disks, /dev/sdf and /dev/sdg, each of which has a 10 GB partition, /dev/sdf1 and /dev/sdg1. The steps I show are largely the same for other RAID levels and additional devices. For full details, visit the Linux Raid Wiki.

Warning

RAID operations can wipe out filesystems without confirmation. Practice the commands on spare drives or a virtual machine for safety.

Create a RAID Array

First, show that no RAID setup exists yet:

cat /proc/mdstat
Personalities :                No RAID types listed

Create the RAID-1 array /dev/md1, from the two partitions:

sudo mdadm --create /dev/md1 --level 1 \ 
  --raid-devices 2 /dev/sdf1 /dev/sdg1

View /proc/mdstat again. The Personalities line now shows that RAID-1 is in use, and the next line shows the new array, md1, which is being built:

cat /proc/mdstat
Personalities : [raid1]
md1 : active raid1 sdg1[1] sdf1[0]
      10474496 blocks super 1.2 [2/2] [UU]
      [=========>...........]  resync = 45.8% ...
                               finish=0.4min ...

Optionally, wait for the build (“resync”) to complete:

cat /proc/mdstat
Personalities : [raid1]
md1 : active raid1 sdg1[1] sdf1[0]
      10474496 blocks super 1.2 [2/2] [UU]

However, you don’t have to wait. The array is usable immediately. Format and mount it like any other storage device:

sudo mke2fs /dev/md1                Format the arraysudo mkdir /mnt/raid                Mount itsudo mount /dev/md1 /mnt/raiddf -h /mnt/raid                     View it
Filesystem      Size  Used Avail Use% Mounted on
/dev/md1        9.9G   24K  9.4G   1% /mnt/raid

Run lsblk to illustrate the RAID configuration:

lsblk
⋮
sdf            8:80   0    10G  0 disk
└─sdf1         8:81   0    10G  0 part
  └─md1        9:1    0    10G  0 raid1 /mnt/raid
sdg            8:96   0    10G  0 disk
└─sdg1         8:97   0    10G  0 part
  └─md1        9:1    0    10G  0 raid1 /mnt/raid

Run mdadm to see more details about the array:

sudo mdadm --detail /dev/md1
dev/md1:
  ⋮
  Creation Time : Thu Jul 20 13:15:08 2023
     Raid Level : raid1
     Array Size : 10474496 (9.99 GiB 10.73 GB)
   Raid Devices : 2
          State : clean
Working Devices : 2
  ⋮
Number  Major  Minor  RaidDevice State
  0      8      81       0       active sync /dev/sdf1
  1      8      97       1       active sync /dev/sdg1

When you’re satisfied with the array, save its configuration so it will survive reboots and mount itself. Don’t skip any steps.

  1. Save the RAID configuration to a file:

    sudo mdadm --detail --scan --verbose > /tmp/raidcat /tmp/raid
    ARRAY /dev/md1 level=raid1 num-devices=2 ...
  2. Use a text editor to append the contents of /tmp/raid to the configuration file /etc/mdadm/mdadm.conf, replacing any previous RAID configuration.

  3. Run this command to update the Linux kernel:

    sudo update-initramfs -u
  4. Reboot. Check that your RAID array survived by mounting it by hand:3

    sudo mount /dev/md1 /mnt/raid
  5. If everything worked, add this line to /etc/fstab so your RAID array mounts at boot time:

    /dev/md1  /mnt/raid  ext4  defaults  0  2
Warning

Don’t update /etc/fstab too early. If your RAID configuration has a problem and you reboot, the computer might hang. Instead, test the configuration first by rebooting and mounting the array by hand, as I have.

Replace a Device in a RAID Array

So, your RAID array is up and running. What happens when a device dies and needs replacement? First, the failure is visible in /proc/mdstat. The failed device, /dev/sdf1, is marked with (F), and the uptime indicator, which should read [UU] (two devices up), reads [U_] (first device up, second device down).

cat /proc/mdstat
Personalities : [raid1]
md1 : active raid1 sdf1[1](F) sdg1[0]
      10474496 blocks super 1.2 [2/1] [U_]

mdadm also shows the array as “degraded” and the device as “faulty”:

sudo mdadm --detail /dev/md1
/dev/md1:
   ⋮
      Raid Devices : 2
             State : clean, degraded
   Working Devices : 1
    Failed Devices : 1
   ⋮
    Number  Major  Minor   RaidDevice State
       1      8      97        -      faulty /dev/sdf1

To replace device /dev/sdf1, mark it as failed (if it isn’t already) and remove it from the RAID array:

sudo mdadm --manage /dev/md1 --fail /dev/sdf1sudo mdadm --manage /dev/md1 --remove /dev/sdf1

Shut down the computer, unplug the power cable, and physically swap the failed storage device for a new one of the same size or larger. I’ll call it by a nonexistent name /dev/NEW to clearly distinguish it in my instructions because the following commands are destructive, and you don’t want to mix up your drives. Substitute the correct device name on your system.

Boot the computer, identify a good drive in the RAID array (in our case, /dev/sdg), and copy its partition table onto the new device with the sgdisk command.

sudo sgdisk -R /dev/NEW /dev/sdg   Copy from sdg to NEWsudo sgdisk -G /dev/NEW            Randomize GUIDs

The device /dev/NEW now has a 10 GB partition, /dev/NEW1. Add it to the array:

sudo mdadm --manage /dev/md1 --add /dev/NEW1
mdadm: added /dev/NEW1

The array immediately begins rebuilding itself, mirroring data onto the new device:

cat /proc/mdstat
⋮
[==========>..........]  recovery = 51.5% ...
                         finish=0.4min ...

When mirroring is complete, the new device /dev/NEW1 has replaced the faulty device /dev/sdf1:

cat /proc/mdstat
Personalities : [raid1]
md1 : active raid1 NEW1[1] sdg1[0]
      10474496 blocks super 1.2 [2/2] [UU]

Destroy a RAID Array

Should you ever want to destroy the RAID array and use the partitions for other purposes, run these commands, assuming your device names are /dev/sdg1 and /dev/sdh1:

sudo umount /mnt/raidsudo mdadm --stop /dev/md1
mdadm: stopped /dev/md1
→ sudo mdadm --zero-superblock /dev/sdg1 /dev/sdh1

Finally, update /etc/fstab and /etc/mdadm/mdadm.conf to remove the RAID array /dev/md1, and inform the kernel that the array is gone:

sudo update-initramfs -u

Logical Volumes for Flexible Storage

pvcreate

Create a physical volume.

pvdisplay

View details of physical volumes.

pvremove

Delete a physical volume.

pvs

View other details of physical volumes.

vgcreate

Create a volume group.

vgdisplay

View details of volume groups.

vgextend

Add physical volumes to a volume group.

vgreduce

Remove physical volumes from a volume group.

vgremove

Delete a volume group.

lvcreate

Create a logical volume.

lvdisplay

View details of logical volumes.

lvresize

Resize a logical volume.

lvremove

Delete a logical volume.

Logical volume management (LVM) solves two annoying problems with disk storage:

  • Limited size. When a disk fills up, you have to delete files or replace it with a larger disk.

  • Fixed partitions. When you partition a disk, you guess how much space each partition will require, and if you’re wrong, it’s time-consuming to change.

LVM solves these problems by wrapping a layer of abstraction around physical storage. It collects together a bunch of physical disks of any sizes, called physical volumes, to simulate one big disk, which it calls a volume group. The volume group becomes a playground for creating simulated partitions, called logical volumes, that can grow and shrink on demand. Figure 4-1 shows the relationship between physical volumes (PVs), the volume group (VG) that contains them, and logical volumes (LVs) that you carve out of the total space. If the VG runs out of space, simply add another physical volume and the VG grows. If a partition (LV) is the wrong size, just change it. Existing files are preserved. Any mass storage devices can be part of a volume group, even RAID arrays created with mdadm (see “RAID Arrays for Redundancy”).

LVM concepts. Physical volumes (PV) are collected into a volume group (VG). Logical volumes (LV) are carved out of the VG.
Figure 4-1. LVM concepts. Physical volumes (PV) are collected into a volume group (VG). Logical volumes (LV) are carved out of the VG.

The most popular LVM software for Linux is called lvm2. It includes over 50 commands, which might seem like a lot, but their names follow a simple pattern: pv, vg, or lv, followed by a verb like create, remove, or display. So vgcreate creates a volume group, and pvdisplay prints information about a physical volume.

Warning

LVM operations can wipe out filesystems without confirmation. Practice the commands on spare drives or a virtual machine for safety.

Also, LVM provides no inherent redundancy. If one physical volume dies, you lose the whole volume group. For more safety, run LVM on top of RAID; see “RAID Arrays for Redundancy”.

I now present examples of using the most common lvm2 commands, using three empty 10 GB disk partitions, /dev/sdb1, /dev/sdc1, and /dev/sdd1.4 lvm2 has dozens more commands, however. For a full list, view the manpage of any lvm2 command and jump to the end or visit sourceware.org/lvm2.

Create a First Logical Volume

This sequence of steps sets up two physical volumes, groups them into a 20 GB volume group, myvg, and creates a 15 GB logical volume, stuff:

sudo pvcreate /dev/sdb1 /dev/sdc1        Create two PVs
  Physical volume "/dev/sdb1" successfully created.
  Physical volume "/dev/sdc1" successfully created.
→ sudo vgcreate myvg /dev/sdb1 /dev/sdc1   Create a VG
  Volume group "myvg" successfully created
→ sudo lvcreate -L 15G -n stuff myvg       Create the LV
  Logical volume "stuff" created.
→ sudo pvs                                 View the PVs
  PV         VG   Fmt  Attr PSize    PFree
  /dev/sdb1  myvg lvm2 a--  <10.00g      0
  /dev/sdc1  myvg lvm2 a--  <10.00g  5.34g

The logical volume stuff is usable like any other storage device. Format and mount it:

sudo mke2fs /dev/myvg/stuff            Format the LVsudo mkdir /mnt/stuff                  Mount itsudo mount /dev/myvg/stuff /mnt/stuffdf -h /mnt/stuff                       View it
Filesystem             Size Used Avail Use% Mounted on
/dev/mapper/myvg-stuff  15G  24K  1.4G   1% /mnt/stuff

When your LV is ready, add this line to /etc/fstab to mount it at boot time:

/dev/mapper/myvg-stuff  /mnt/stuff  ext4  defaults  0 2

View LVM Details

The pvdisplay, vgdisplay, and lvdisplay commands print details about physical volumes, volume groups, and logical volumes, respectively. The commands pvs, vgs, and lvs print helpful summaries of that information.

sudo pvdisplay              Show all PVssudo pvdisplay /dev/sdb1    Show selected PVssudo pvs                    Summarize PVssudo vgdisplay              Show all VGssudo vgdisplay myvg         Show selected VGssudo vgs                    Summarize VGssudo lvdisplay              Show all LVssudo lvdisplay myvg/stuff   Show selected LVssudo lvs                    Summarize LVs

Add a Logical Volume

Let’s run lvcreate again to add a 2 GB logical volume called tiny to our volume group:

sudo lvcreate -L 2G -n tiny myvg
  Logical volume "tiny" created.
→ sudo mke2fs /dev/myvg/tiny                  Formatsudo mkdir /mnt/tiny                        Mountsudo mount /dev/myvg/tiny /mnt/tinydf -h /mnt/tiny                             View
Filesystem             Size Used Avail Use% Mounted on
/dev/mapper/myvg-tiny  2.0G  24K  1.9G   1% /mnt/tiny

Add Disks to a Volume Group

The vgextend command adds physical volumes to a volume group. Suppose you want to increase the size of stuff by 10 GB (to 25 GB), but there’s only 3 GB of space left in volume group myvg. Enlarge your VG by adding a third physical volume, /dev/sdd1, increasing the VG’s total size to 30 GB:

sudo pvcreate /dev/sdd1           Create another PVsudo vgextend myvg /dev/sdd1      Grow the VG

At this point, the LVM setup looks like Figure 4-1. Run lsblk to illustrate the LVM configuration:

lsblk /dev/sdb /dev/sdc /dev/sdd
NAME           MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdb              8:16   0  10G  0 disk
└─sdb1           8:17   0  10G  0 part
  └─myvg-stuff 253:0    0  15G  0 lvm  /mnt/stuff
sdc              8:32   0  10G  0 disk
└─sdc1           8:33   0  10G  0 part
  ├─myvg-stuff 253:0    0  15G  0 lvm  /mnt/stuff
  └─myvg-tiny  253:1    0   2G  0 lvm  /mnt/tiny
sdd              8:48   0  10G  0 disk
└─sdd1           8:49   0  10G  0 part

Enlarge a Logical Volume

The lvresize command grows or shrinks a logical volume.5 Let’s enlarge the LV stuff to 25 GB:

sudo lvresize --resizefs --size 25G /dev/myvg/stuffdf -h /mnt/stuff
Filesystem             Size  Used Avail Use% Mounted on
/dev/mapper/myvg-stuff  25G  24K   24G   1% /mnt/stuff

Shrink a Logical Volume

It turns out the LV stuff doesn’t need to be so large. Shrink it to 8 GB (making sure first that it has less than 8 GB in use):

sudo lvresize --resizefs --size 8G /dev/myvg/stuff
Do you want to unmount "/mnt/stuff" ? [Y|n] y
⋮
Logical volume myvg/stuff successfully resized.
→ df -h /mnt/stuff
Filesystem              Size Used Avail Use% Mounted on
/dev/mapper/myvg-stuff  7.9G  24K  7.5G   1% /mnt/stuff

Delete a Logical Volume

The lvremove command deletes a logical volume. Let’s get rid of the LV tiny:

sudo umount /mnt/tiny            First unmount the LVsudo lvremove /dev/myvg/tiny     Remove the LV
Do you really want to remove and DISCARD
active logical volume myvg/tiny? [y/n]: y
  Logical volume "tiny" successfully removed

Reduce a Volume Group

The vgreduce command removes an unused physical volume from a volume group. The PV remains managed by lvm2, just not within the VG myvg:

sudo vgreduce myvg /dev/sdd1
  Removed "/dev/sdd1" from volume group "myvg"

Delete a Volume Group

The vgremove command removes a volume group and deletes any logical volumes it contains:

sudo vgremove myvg
Do you really want to remove volume group "myvg"
containing 1 logical volumes? [y/n]: y
Do you really want to remove and DISCARD
active logical volume myvg/stuff? [y/n]: y
  Logical volume "stuff" successfully removed
  Volume group "myvg" successfully removed

Delete a Physical Volume

The pvremove command removes physical devices from LVM:

sudo pvremove /dev/sdb1 /dev/sdc1
  Labels on physical volume "/dev/sdb1" wiped.
  Labels on physical volume "/dev/sdc1" wiped.

ZFS: A Modern, Do-It-All Filesystem

zpool

Configure a ZFS storage pool.

zfs

Configure a ZFS dataset.

Warning

ZFS operations can wipe out filesystems without confirmation. Practice the commands on spare drives or a virtual machine for safety.

ZFS (Zettabyte File System) packs advanced features like RAID, logical volume management, encryption, and compression into one convenient package. If you’re accustomed to traditional Linux filesystems like ext4, ZFS may seem like an alien world. It has its own terminology with “pools” and “vdevs.” It doesn’t use /etc/fstab or the mount command. You don’t even need to partition or format your disks explicitly.

A ZFS vdev, short for “virtual device,” is a group of physical disks that work together. They might divide the data among themselves as if they were one big disk, like a RAID-0 “disk striping” setup. They might mirror each other for redundancy, like a RAID-1 setup. They might operate as a disk cache; and there are other possibilities.

A collection of vdevs is called a pool. A pool acts like one big storage device. You can carve it up into units that are sort of like partitions, called datasets, and you can change their size limits and other attributes flexibly. Dataset names look like Linux paths without a leading slash. For example, a pool named mypool with a dataset named stuff would be named mypool/stuff. (Datasets can contain other datasets too, like mypool/stuff/important.) Add a leading slash, and you get the dataset’s default Linux mount point, like /mypool/stuff.

ZFS isn’t the only filesystem with advanced capabilities—another popular one is Btrfs—but it’s among the easiest to configure.

Note

I discuss only the minimal ZFS functionality to do interesting things. Real ZFS systems need careful configuration, tuning, and plenty of RAM; read the docs at https://oreil.ly/-t5Fu.

To demonstrate ZFS with both mirroring and striping, I use two pairs of disks, as in Figure 4-2. Each pair is a vdev with mirroring (RAID-1). ZFS then stripes across the two vdevs (RAID-0), effectively creating a RAID-10 setup. This redundant pool can tolerate one failed drive in each vdev and keep the data safe.

Our example ZFS configuration: a RAID-10 pool
Figure 4-2. Our example ZFS configuration: a RAID-10 pool

Create a ZFS Pool

Use the zpool command to construct the pool of two pairs of mirrored drives. I create a pool called mypool from four 10 GB disk devices, /dev/sdb, /dev/sdc, /dev/sdd, and /dev/sde:

sudo zpool create mypool \
  mirror /dev/sdb /dev/sdc \
  mirror /dev/sdd /dev/sde
Warning

The simple device names in my examples, like /dev/sdb, can change after a reboot. For a more robust setup, use names that are guaranteed not to change, like the symbolic links found in /dev/disk/by-id or /dev/disk/by-uuid.

Also, on real systems, be sure to set an appropriate alignment shift value with -o ashift on creation; see the docs.

Use zpool status to view the results.

zpool status
  pool: mypool
 state: ONLINE
config:
  NAME        STATE     READ WRITE CKSUM
  mypool      ONLINE       0     0     0   The pool
    mirror-0  ONLINE       0     0     0   First vdev
      sdb     ONLINE       0     0     0
      sdc     ONLINE       0     0     0
    mirror-1  ONLINE       0     0     0   Second vdev
      sdd     ONLINE       0     0     0
      sde     ONLINE       0     0     0

Create a ZFS Dataset

Traditional filesystems have partitions of fixed size that you mount in the file /etc/fstab. ZFS has datasets of arbitrary size that it mounts automatically. Create a dataset named data in pool mypool, mounted at the directory /mypool/data:

sudo zfs create -o mypool/data

Move the mount point if you like, to /mnt/stuff:

sudo zfs set mountpoint=/mnt/stuff mypool/data

View the results with either of these commands:

zfs mount
mypool           /mypool        The whole pool
mypool/data      /mnt/stuff     Your datasetzfs get mountpoint mypool/data
NAME         PROPERTY    VALUE       SOURCE
mypool/data  mountpoint  /mnt/stuff  local

Now use the dataset like any other mounted partition:

sudo cp /etc/hosts /mnt/stuffcd /mnt/stuffls
hosts

Create an Encrypted ZFS Dataset

By adding a few options, you can create a dataset that’s encrypted and requires a passphrase before mounting. Create an encrypted dataset named mypool/cryptic:

zfs create \
  -o encryption=on \
  -o keylocation=prompt \
  -o keyformat=passphrase \
  mypool/cryptic
Enter new passphrase: xxxxxxxx
Re-enter new passphrase: xxxxxxxx

Use the dataset normally. When you reboot or otherwise need to mount the dataset, run:

sudo zfs mount -l mypool/cryptic

Set Size Limits on ZFS Datasets

By default, a ZFS dataset is the same size as the pool. Limit its size by setting a quota, which you may change anytime:

sudo zfs set quota=15g mypool/datazfs list
NAME         USED  AVAIL REFER  MOUNTPOINT
mypool       312K  18.4G   25K  /mypool
mypool/data   24K  15.0G   24K  /mnt/stuff   15 GB limit

Enable Compression on ZFS Datasets

ZFS can automatically compress data as it’s written and uncompress it when read. It supports various compression algorithms; here I use gzip compression and view how effectively files are being compressed (the compression ratio):

sudo zfs set compression=gzip mypool/datacp hugefile /mnt/stuff      Store a big filezfs get compressratio       See the compression ratio
NAME           PROPERTY       VALUE  SOURCE
mypool         compressratio  122.66x  -
mypool/data    compressratio  126.12x  -

After enabling compression, only new data is compressed; existing files are not. To turn off compression:

sudo zfs set compression=off mypool/data

Snapshot a ZFS Dataset

ZFS supports snapshots: storing the state of a dataset so you can easily return to that state (roll back) later. Before performing a risky change on your files, for example, take a snapshot, and if something goes wrong, you can revert the change with a single command. Snapshots occupy very little disk space, and you can send them efficiently to other zpools or hosts (with zfs send and zfs recv). Create a snapshot of mypool/data named safe:

sudo zfs snapshot mypool/data@safe

List your snapshots:

zfs list -t snapshot
NAME               USED  AVAIL     REFER  MOUNTPOINT
mypool/data@safe     0B      -       24K  -

If you can’t list snapshots, set listsnapshots=on and try again:

sudo zpool set listsnapshots=on mypool

Try changing some files in mypool/data. Then roll back to the snapshot safe and see that your changes are gone:

sudo zfs rollback mypool/data@safe

Destroy a ZFS Dataset or Snapshot

Be careful with the zfs destroy command—it runs immediately without confirmation.

sudo zfs destroy mypool/data@safe    A snapshotsudo zfs destroy mypool/data         A dataset

Destroy a ZFS Pool

Be careful with the zpool destroy command—it runs immediately without confirmation.

sudo zpool destroy mypool

Backups and Remote Storage

rsync

Efficiently copy a set of files, even across a network.

rclone

Sync files with various cloud providers.

dd

Low-level copying of data.

growisofs

Burn a DVD or Blu-ray disc.

You can back up your precious Linux files in various ways:

  • Copy them to a remote machine.

  • Copy them to a backup medium like an external drive.

  • Burn them onto a disc.

I present a few popular Linux commands for backups, but there are others. Some users prefer cpio for its flexibility, and some long-time administrators swear by dump and restore as the only reliable way to back up and restore every type of file. See the manpages for these commands if you are interested in them.

rsync

stdin

stdout

- file

-- opt

--help

--version

rsync [options] source destination

The rsync command copies a set of files. It can make an exact copy, including file permissions and other attributes (called mirroring), or it can just copy the data. It can run over a network or on a single machine. rsync has many uses and over 50 options; I present just a few common cases relating to backups.

To mirror the directory mydir and its contents into another directory mydir2 on a single machine:

rsync -a mydir mydir2

rsync is finicky about how you specify the first directory. If you write “mydir” as in the example here, that directory is copied into mydir2, creating the subdirectory mydir2/mydir. If instead, you’d rather have only the contents of mydir copied into mydir2, append a slash onto “mydir”:

rsync  -a mydir/  mydir2

rsync can mirror a directory over a network to another host, securing the connection with SSH to prevent eavesdropping. Here I copy directory mydir to the account “smith” on remote host server.example.com, in a directory D2:

rsync -a mydir smith@server.example.com:D2

If you like rsync but also want to have incremental backups and manage them efficiently, try rsnapshot (https://oreil.ly/VNfb-).

Useful options

-o

Copy the ownership of the files. (You might need superuser privileges on the remote host.)

-g

Copy the group ownership of the files. (You might need superuser privileges on the remote host.)

-p

Copy the file permissions.

-t

Copy the file timestamps.

-r

Copy directories recursively (i.e., including their contents).

-l

Permit symbolic links to be copied (rather than the files they point to).

-D

Permit devices to be copied. (Superuser only.)

-a

Mirroring: copy all attributes of the original files. This implies all of the options -Dogptrl (think “dog patrol”).

-x

When copying a tree of files, remain within the current filesystem; do not cross over into other mounted filesystems.

-z

Compress the data for transit. Only useful for remote hosts over slow connections. Avoid compression when copying files locally (it’s wasteful).

-n

Dry-run mode: don’t actually copy. Just display what would be done.

-v

Verbose mode: print status information during the copy. Add --progress to display a numeric progress meter while files are copied.

rclone

stdin

stdout

- file

-- opt

--help

--version

rclone subcommand [options] [arguments]

The rclone command connects your Linux system to popular cloud storage providers to copy files conveniently. It works with Dropbox, Google Drive, Microsoft OneDrive, Amazon S3, and about 50 other destinations. To get started, run rclone config and follow the prompts to set up a connection with your cloud provider of choice, which rclone calls a remote. Visit rclone.org/docs for detailed instructions on configuration.

After choosing a name for your remote, such as myremote, refer to remote files with the syntax myremote:path, where path is a Linux-style file path. For example, a file photo.jpg in a remote directory Photos would be myremote:Photos/photo.jpg.

Backups are usually done with the rclone sync command, which synchronizes a local directory and a remote directory so they contain the same content, adding or deleting as necessary. It works much like the rsync --delete command. You can synchronize in either direction, from your local machine to the remote, or from the remote to your local machine. You can even set up client-side encryption, so files are transparently encrypted before they’re copied to the remote and decrypted when they’re copied back to your local system (see the docs).

Some common operations for backups include:

rclone ls remote:

List files on the remote recursively (append --max-depth 1 for no recursion).

rclone lsd remote:

List only directories on the remote.

rclone lsl remote:

Display a long listing like ls -l from the remote recursively (append --max-depth 1 for no recursion).

rclone copy myfile remote:

Copy a local file to the remote.

rclone copy remote:myfile .

Copy a remote file to your local system.

rclone move myfile remote:

Move a local file to the remote.

rclone move remote:myfile .

Move a remote file to your local system.

rclone delete remote:myfile

Delete a remote file.

rclone sync mydir remote:mydir

Synchronize local files onto the remote.

rclone sync remote:mydir mydir

Synchronize remote files onto your local system.

Run rclone help for a complete list of subcommands. Note that you can access fancier paths on the remote than my earlier examples show:

rclone copy remote:Photos/Vacation/picture.jpg .

Useful options

-n

Dry-run mode: don’t actually copy. Just display what would be done.

-i

Run interactively so you’re prompted before changes.

dd

stdin

stdout

- file

-- opt

--help

--version

dd [options]

dd is a low-level copier of bits and bytes. It can copy data from one file to another, say, from myfile to /tmp/mycopy:

dd if=myfile of=/tmp/mycopy
2+1 records in
2+1 records out
1168 bytes (1.2 kB) copied, 0.000174074 s, 6.7 MB/s

It can even convert data while copying, like changing characters to uppercase while copying from myfile to /tmp/mycopy:

dd if=myfile of=/tmp/mycopy conv=ucase

dd does much more than copy files. It can copy raw data directly from one disk device to another. Here’s a command to clone a hard disk:

sudo dd if=/dev/device1 of=/dev/device2 bs=512 \
  conv=noerror,sync          OVERWRITES /dev/device2

Or, copy an entire disk device to create an ISO file. Make sure the output file is on a different disk device and has sufficient free space.

sudo dd if=/dev/device of=disk_backup.iso
Warning

dd, when run as the superuser, can wipe out your hard drive in seconds if you’re not careful. Always double-check that the output file (the argument of=) is the one you intend. Back up your computer and keep a Linux “live” distro on hand for emergencies (see “What’s in This Book?”) before experimenting with dd as root.

For some great advice on sophisticated uses of dd, visit https://oreil.ly/R3krx. My favorite tip is backing up a disk’s master boot record (MBR), which is 512 bytes long, to a file called mbr.txt:

sudo dd if=/dev/device of=mbr.txt bs=512 count=1

Useful options

if=file

Specify an input file or device.

of=file

Specify an output file or device. Double-check that it’s the correct one!

bs=N

Copy N bytes (the “block size”) at a time. (To set different block sizes for the input and output, use ibs and obs, respectively.)

skip=N

Skip past N blocks of input (of size ibs) before starting the copy.

seek=N

Discard N blocks of output (of size obs) before starting the copy.

conv=spec

Convert the data being copied. spec can be ucase (convert to uppercase), lcase (convert to lowercase), ascii (convert to ASCII from EBCDIC), and many others listed on the manpage.

growisofs

stdin

stdout

- file

-- opt

--help

--version

growisofs [options] tracks

The growisofs command burns a writable CD, DVD, or Blu-ray disc. To burn the contents of a Linux directory onto a disc readable on Linux, Windows, and macOS systems:

  1. Locate your disc writer devices by running:

    grep "^drive name:" /proc/sys/dev/cdrom/info
    drive name:    sr1     sr0

    The available devices here are /dev/sr1 and /dev/sr0.

  2. Put the files you want to burn into a directory, say, dir. Arrange them exactly as you’d like on the disc. The directory dir itself is not copied to the disc, just its contents.

  3. Use the mkisofs command to create an ISO (disc) image file, and burn it onto a disc using growisofs, assuming your device is /dev/sr1:

    mkisofs -R -l -o $HOME/mydisk.iso dirgrowisofs -dvd-compat -Z /dev/sr1=$HOME/mydisk.isorm $HOME/mydisk.iso

To burn audio CDs, use a friendly graphical program like k3b.

1 You can mount a filesystem on a nonempty directory, but the directory’s contents become inaccessible until you unmount.

2 Notice the spelling is “umount,” not “unmount.”

3 If your RAID array mysteriously renames itself /dev/md127, you forgot to run update-initramfs in the previous step.

4 Operate on partitions rather than whole disks.

5 Old-timers may resize an LV by running lvextend, umount, fsck, resize2fs, and mount in sequence. lvresize is easier.

Get Linux Pocket Guide, 4th Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.