Add qgroup/quota btrfs commands info for man page. Arne, please could you be so kindly to take care of these info for the man page from now onwards ? I extract the text both from your pdf and your email. May be something was wrong because I am not familiar with the qgroup/quota commands. After merging this patch you can see this text in the man page doing: make man/btrfs.8.in man man/btrfs.8.in Don''t hesitate to contact me for further information. Comments are welcome. BR G.Baroncelli Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it> --- btrfs.c | 79 ++++++++++++++++++++++++++++++++++++- btrfs_cmds.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 198 insertions(+), 5 deletions(-) diff --git a/btrfs.c b/btrfs.c index d7ece5b..3c72d0a 100644 --- a/btrfs.c +++ b/btrfs.c @@ -184,6 +184,82 @@ * the filesystem. Can be mixed with the \Bdevid\b filter to select * chunks in a given address range on a specific device. * + * \h Subvolume Quota concept + * + * \BSubvolume Quota Groups\b + * + * The basic notion of the Subvolume Quota feature is the quota group, short + * qgroup. Qgroups are notated as <level>/<id>, e.g. the qgroup 3/2 is a qgroup + * of level 3. For level 0 the leading \I0/\i can be omitted. Qgroups of level + * 0 get created automatically when a subvolume/snapshot gets created. The ID + * of the qgroup corresponds to the ID of the subvolume, so 0/5 is the qgroup + * for the root subvolume. For the \Ibtrfs qgroup\i command, the path to the + * subvolume can also be used instead of 0/<ID>. For all higher levels, the ID + * can be choosen freely. + * Each qgroup can contain a set of lower level qgroups, thus creating a + * hierarchy of qgroups. + * + * + * /- {0/1} ------->[ 1 ] + * / + * /- {1/1} ->-+ /-->[ 2 ] + * / \\\\ / + * {2/1}->-+ + {0/2} ->-+ + * \\\\ / \\\\ + * \\\\- {1/2} ->-+ +-->[ 3 ] + * \\\\ / + * \\\\- {0/3} ->-+ + * \\\\ + * \\\\-->[ 4 ] + * + * + * At the bottom of the figure above some extents are depicted showing which + * qgroups reference which extents. It is important to understand the notion + * of referenced versus exclusive. + * In the example qgroup 0/2 references extents 2 and 3, while 1/2 references + * extents 2-4. 2/1 references all extents. + * On the other hand, extent 1 is exclusive to 0/1, extent 2 is exclusive to + * 0/2, while extent 3 is neither exclusive to 0/2 nor to 0/3. + * But because both references can be reached from 1/2, extent 3 is exclusive + * to 1/2. + * All extents are exclusive to 2/1. So exclusive doesn''t mean there''s no other + * way to reach the extent, but it does mean that if you delete all subvolumes + * contained in a qgroup, the extent will get deleted. Exclusive of a qgroup + * conveys the useful information how much space will be freed in case all + * subvolumes of the qgroup get deleted. + * All data extents are accounted this way. Metadata that belong to a specific + * subvolume (i.e. its fs tree) are also accounted. Checksums and extent + * allocation information are not accounted. + * + * In turn the referenced count of a qgroup can be limited. All writes beyond + * that limit will lead to a \IQuota Exceeded\i error. + * + * \BQuota Inheritance\b + * + * If a subvolume should be part of a qgroup, it has to be added to the qgroup + * at creation time. To add it at a later time, it would be necessary to at + * least rescan the full subvolume for a proper accounting. + * A snapshot references the exact amount of space as its source, and both + * source and destination now have an exclusive count of 0 (4k to be precise, + * as the roots of the trees are not shared). Regarding the qgroups of higher + * levels, if the qgroup contains both the source and the destination, nothing + * changes. If the qgroup contains only the source, it might lose some + * exclusive. But how much? The tempting answer is, \Bsubtract all exclusive + * of the source from the qgroup\b, but that''s wrong, or at + * least not enough. There could have been an extent that''s referenced from the + * source and another subvolume from that qgroup. This extent would have been + * exclusive to the qgroup, but not to the source subvolume. With the creation + * of the snapshot the qgroup would also lose this extent from its exclusive + * set. + * So how can this problem be solved? In the instant the snapshot gets cre- + * ated we already have to know the correct exclusive count. We need to have a + * second qgroup that contains all the subvolumes as the first qgroup, except + * the subvolume we want to snapshot. The moment we create the snapshot, the + * exclusive count from the second qgroup needs to be copied to the first + * qgroup, as it represents the correct value. The second qgroup is called a + * tracking qgroup. + * It is only there in case a snapshot is needed. + * * \h EXIT STATUS * \Bbtrfs\b returns a zero exist status if it succeeds. Non zero is returned in * case of failure. @@ -204,9 +280,6 @@ ****/ - - - typedef int (*CommandFunction)(int argc, char **argv); struct Command { diff --git a/btrfs_cmds.c b/btrfs_cmds.c index 967917e..a071853 100644 --- a/btrfs_cmds.c +++ b/btrfs_cmds.c @@ -419,7 +419,7 @@ int do_subvol_list(int argc, char **argv) /**** man: btrfs subvolume snapshot * - * \Bbtrfs\b \Bsubvolume snapshot\b\I [-r] <source> [<dest>/]<name>\i + * \Bbtrfs\b \Bsubvolume snapshot\b\I [-r] [-i <qid>] [-c <cspec>] [-x <cspec>] <source> [<dest>/]<name>\i * * Create a writable/readonly snapshot of the subvolume <source> with * the name <name> in the <dest> directory. @@ -428,6 +428,17 @@ int do_subvol_list(int argc, char **argv) * name \I<name>\i in the \I<dest>\i directory. If \I<source>\i is not a * subvolume, \Bbtrfs\b returns an error. If \I-r\i is given, the snapshot * will be readonly. + * + * With the creation of a snapshot + * a qgroup gets created automatically. With -i this qgroup can be + * added to a higher level qgroup <qid> at creation time. This option can be + * given multiple times. + * -c and -x copy the values from one qgroup to another at creation time. + * In some usecases this is necessary to keep the values consistent. + * The copy spec <cspec> + * consists of two qgroupid separated by '':'', giving <srcid>:<dstid>. -c + * copies the ''referenced'' value, -x copies the ''exclusive'' value. These + * options can be given multiple times. ****/ int do_clone(int argc, char **argv) @@ -646,13 +657,24 @@ int do_delete_subvolume(int argc, char **argv) /**** man: btrfs subvolume create * - * \Bbtrfs\b \Bsubvolume create\b\I [<dest>/]<name>\i + * \Bbtrfs\b \Bsubvolume create\b\I [-i <qid>] [-c <cspec>] [-x <cspec>] [<dest>/]<name>\i * * Create a subvolume in <dest> (or the current directory if * not passed). * * Create a subvolume in \I<dest>\i (or in the current directory if * \I<dest>\i is omitted). + * + * With the creation of a subvolume + * a qgroup gets created automatically. With -i this qgroup can be + * added to a higher level qgroup <qid> at creation time. This option can be + * given multiple times. + * -c and -x copy the values from one qgroup to another at creation time. + * In some usecases this is necessary to keep the values consistent. + * The copy spec <cspec> + * consists of two qgroupid separated by '':'', giving <srcid>:<dstid>. -c + * copies the ''referenced'' value, -x copies the ''exclusive'' value. These + * options can be given multiple times. ****/ int do_create_subvol(int argc, char **argv) @@ -1922,6 +1944,14 @@ int do_get_default_subvol(int nargs, char **argv) return 0; } +/**** man: btrfs filesystem df + * + * \Bbtrfs\b \Bfilesystem df\b \I<path>\i + * + * Show space usage information for the mount point \I<path>\i. + * + * Show space usage information for the mount point \I<path>\i. + ****/ int do_df_filesystem(int nargs, char **argv) { struct btrfs_ioctl_space_args *sargs; @@ -2170,16 +2200,43 @@ int quota_ctl(int cmd, int nargs, char **argv) return 0; } +/**** man: btrfs quota enable + * + * \Bbtrfs\b \Bquota enable\b \I<path>\i + * + * Enable subvolume quota support for a filesystem. + * + * Enable subvolume quota support for a filesystem. It creates the quota + * tree. + ****/ int do_quota_enable(int nargs, char **argv) { return quota_ctl(BTRFS_QUOTA_CTL_ENABLE, nargs, argv); } +/**** man: btrfs quota disable + * + * \Bbtrfs\b \Bquota disable\b \I<path>\i + * + * Disable subvolume quota support for a filesystem. + * + * Disable subvolume quota support for a filesystem. It removes the quota + * tree and with it all configuration information. + ****/ int do_quota_disable(int nargs, char **argv) { return quota_ctl(BTRFS_QUOTA_CTL_DISABLE, nargs, argv); } +/**** man: btrfs quota rescan + * + * \Bbtrfs\b \Bquota rescan\b \I<path>\i + * + * Rescan the subvolume for a changed quota setting. + * + * Triggers a full re-init of quota information, doing a full fs rescan. + * (Kernel side currently does not implement it yet.) + ****/ int do_quota_rescan(int nargs, char **argv) { return quota_ctl(BTRFS_QUOTA_CTL_RESCAN, nargs, argv); @@ -2220,11 +2277,29 @@ int qgroup_assign(int assign, int nargs, char **argv) return 0; } +/**** man: btrfs qgroup assign + * + * \Bbtrfs\b \Bqgroup assign\b \I<src-id> <dst-id> <path>\i + * + * Assign a subvol to a quota group. + * + * Assigns the lower level qgroup <src-id> to the higher level + * qgroup <dst-id> in the + * btrfs found in <path>. It is used to build qgroup hierarchies. + ****/ int do_qgroup_assign(int nargs, char **argv) { return qgroup_assign(1, nargs, argv); } +/**** man: btrfs qgroup remove + * + * \Bbtrfs\b \Bqgroup remove\b \I<src-id> <dst-id> <path>\i + * + * Remove a subvol from a quota group. + * + * Remove the qgroup <src-id> from the qgroup <dst-id>. + ****/ int do_qgroup_remove(int nargs, char **argv) { return qgroup_assign(0, nargs, argv); @@ -2257,11 +2332,29 @@ int qgroup_create(int create, int nargs, char **argv) return 0; } +/**** man: btrfs qgroup create + * + * \Bbtrfs\b \Bqgroup create\b \I<qgroupid> <path>\i + * + * Create a subvolume quota group. + * + * Creates a qgroup with id <qgroupid> for the btrfs found in <path>. + * It will not be part of any hierarchy. + ****/ int do_qgroup_create(int nargs, char **argv) { return qgroup_create(1, nargs, argv); } +/**** man: btrfs qgroup destroy + * + * \Bbtrfs\b \Bqgroup destroy\b \I<qgroupid> <path>\i + * + * Destroy a subvolume quota group. + * + * Removes the qgroup <qgroupid> from the btrfs found in <path>. It will also + * be removed from any higher-level qgroups. + ****/ int do_qgroup_destroy(int nargs, char **argv) { return qgroup_create(0, nargs, argv); @@ -2361,6 +2454,15 @@ done: return ret; } +/**** man: btrfs qgroup show + * + * \Bbtrfs\b \Bqgroup show\b \I<path>\i + * + * Show all subvolume quota groups. + * + * Lists all configured qgroup together with the current exclusive and + * referenced values. + ****/ int do_qgroup_show(int nargs, char **argv) { int ret=0, fd; @@ -2422,6 +2524,24 @@ static int parse_limit(const char *p, unsigned long long *s) return 1; } + +/**** man: btrfs qgroup limit + * + * \Bbtrfs\b \Bqgroup limit\b [-c] [-e] \I<size>|none {<qgroupid> <path>|<subvolume>}\i + * + * Limit the size of a subvolume quota group. + * + * Impose a limit of <size> for the amount of referenced space onto the + * qgroup <qgroupid> in btrfs <path-to-btrfs> or onto the qgroup referenced + * by <path-to-subvol>. A size of none removes the limit. + * + * \B-c\b referenced + * + * \B-e\b exclusive + * + * \Isize\i may be in the form nnnn{K|M|G|T}, where K means Kilobytes, M + * means Megabytes.... + ****/ int do_qgroup_limit(int argc, char **argv) { int ret=0, fd, e; -- gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijack@inwind.it> Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512