6

I cannot determine how to get the quota limit which is currently set on a btrfs subvolume. The btrfs wiki on quota doesn't seem to show this.

This is what I think I know:

  • set a quota: btrfs qgroup limit 21G /path
  • check used space: btrfs qgroup show /path

But how to check the already set limit?

lickdragon
  • 151
  • 2
  • 9

4 Answers4

5

Use options -r and -e:

btrfs qgroup show -pcre /path
uhrm
  • 66
  • 3
  • 1
    That’s useless, because it only lists abstract numbers (the “quota groups”) without any information about what quota group in linked to which subvolumes. Also it doesn’t work without enabling quotas, but enabling them, when they are too small for the current amount of data, will cause writes to fail. – Evi1M4chine Oct 17 '17 at 16:43
  • @Evi1M4chine, works fine on my system. [Pastebin](https://pastebin.com/cGbj9cNA). – Tim Aug 01 '18 at 17:54
5

I created a simple script that will show the quota limit for each sub-volume in the specified path and the used space too. The syntax is pretty simple:

./quota.sh path

To print the used space for all sub-volumes use the -a flag:

./quota.sh path -a

Don't forget to add execution permissions to the script.

Script:


#! /bin/sh
volumes=$(btrfs subvolume list  $1 | cut -d " " -f 9 )
snapshots=$(btrfs subvolume list -s  $1 | cut -d " " -f 14 )
regsnap=$(echo $snapshots | sed 's/ /,/g')
normalv=$(echo $volumes | sed "s/\($regsnap\)//g" )

if [ ! -z "$snapshots" ] ; then
    echo SNAPSHOTS
for p in $snapshots; do 
    quot=$(btrfs qgroup show -rF $1/$p | tail -1)
    if [ -z $2 ]; then
        (echo $quot | grep -q none) || echo $p $quot
    else
     [ "$2" == "-a" ] && echo $p $quot
    fi
done
fi

if [ ! -z "$normalv" ] ; then
    echo SUBVOLUMES
for p in $normalv; do 
    quot=$(btrfs qgroup show -rF $1/$p | tail -1)
    if [ -z $2 ]; then
        (echo $quot | grep -q none) || echo $p $quot
    else
     [ "$2" == "-a" ] && echo $p $quot
    fi
done

fi

It will print first the traditional sub-volumes and below the snapshots volumes. Sample output:

SNAPSHOTS
apple 0/258 1.32MiB 16.00KiB 20.00MiB
SUBVOLUMES
citrus/orange 0/256 1.32MiB 16.00KiB 20.00MiB
3

As we speak, btrfs is broken by design in this regard.

There is currently no function in btrfs-progs, to show which subvolume has which quota. You have to write a script (and many who fell for btrfs do), to parse the abstract quota group numbers it outputs, and list the subvolumes inside those quota groups below them. It could be added, but the btrfs developers religiously refuse to do this.

Even worse, there is not only no way to show how much of the quota a subvolume currently uses up. Which is why df only shows the total free space. It is not possible to do this at all due to how btrfs is designed at its very core. This is because subvolumes work like snapshots. Meaning, to find out how much data is in a subvolume, you’d have to scan the entire file system, and find all the files linked to that subvolume/snapshot, and add them up. Just like the du command. Which takes a lot of time. I have no idea how btrfs then knows a quota is full at all… The IRC channel could not provide me with any answer to that. (They were to busy defending their fragile over-inflated egos.) The sensible thing would be, to change the subvolume counter each time data is added or removed. Which kinda must be how btrfs knows it is full. At least I don’t know any other way. But why they would then chose to keep this available info basically a military-guarded state secret, I don’t know…

If zfs wouldn’t have such insane RAM requirements (1GB per TB … not an option on e.g. a single-board ARM computer) and the risk of data loss, due to not writing data early, due to being designed for servers with crash protection, I would recommend dumping btrfs in its favor.

Evi1M4chine
  • 161
  • 4
0

Five years later and this is still a thing? What I used to list quotas on the filesystems under /volume1. For my needs this was static and I plan on prettyfing the data downstream so pretty minimal formatting here.

#!/bin/sh

if [ "$( id -u )" -ne 0 ]
then
    echo "ERROR: ${0}: must be run by root"
    exit 1
fi

echo "path  total   used"
for path in $( find /volume1 -maxdepth 1 -mindepth 1 -type d \! -name @\* | sort )
do
    btrfs qgroup show -pcref --raw "${path}" 2>/dev/null    \
    | sed 's#$# '"${path}"'#'
done    \
| awk 'BEGIN {OFS="\t"}
    /^[0-9]/ {print $NF,$2,$4}'

For me this prints out:

path    total   used
/volume1/prj_alpha  2529345417216   9853079650304
/volume1/prj_beta   28144091136 1099511627776
/volume1/prj_delta  2261620924416   3298534883328
/volume1/prj_epsilon    565468360704    1099511627776
/volume1/prj_gamma  37339127808 107374182400
...

I know this can be made more readable but I'm doing that in a later step, not here. For this I just needed very consistent output that is easy to parse.

keithpjolley
  • 123
  • 5