[[Internal_Inodes]]
= Internal Inodes

XFS allocates several inodes when a filesystem is created. These are internal
and not accessible from the standard directory structure. These inodes are only
accessible from the superblock.

[[Metadata_Directories]]
== Metadata Directory Tree

If the +XFS_SB_FEAT_INCOMPAT_METADIR+ feature is enabled, the +sb_metadirino+
field in the superblock points to the root of a directory tree containing
metadata files.  This directory tree is completely internal to the filesystem
and must not be exposed to user programs.

When this feature is enabled, metadata files should be found by walking the
metadata directory tree.  The superblock fields that formerly pointed to (some)
of those inodes have been deallocated and may be reused by future features.

.Metadata Directory Paths
[options="header"]
|=====
| Metadata File                                  | Location
| xref:Quota_Inodes[User Quota]                  | /quota/user
| xref:Quota_Inodes[Group Quota]                 | /quota/group
| xref:Quota_Inodes[Project Quota]               | /quota/project
| xref:Real-Time_Bitmap_Inode[Realtime Bitmap]   | /rtgroups/*.bitmap
| xref:Real-Time_Summary_Inode[Realtime Summary] | /rtgroups/*.summary
| xref:Real_time_Reverse_Mapping_Btree[Realtime Reverse Mapping B+tree] | /rtgroups/*.rmap
| xref:Real_time_Refcount_Btree[Realtime Reference Count+tree] | /rtgroups/*.refcount
|=====

Metadata files are flagged by the +XFS_DIFLAG2_METADATA+ flag in the
+di_flags2+ field.  Metadata files must have the following properties:

* Must be either a directory or a regular file.
* chmod 0000
* User and group IDs set to zero.
* The +XFS_DIFLAG_IMMUTABLE+, +XFS_DIFLAG_SYNC+, +XFS_DIFLAG_NOATIME+, +XFS_DIFLAG_NODUMP+, and +XFS_DIFLAG_NODEFRAG+ flags must all be set in +di_flags+.
* For a directory, the +XFS_DIFLAG_NOSYMLINKS+ flag must also be set.
* The +XFS_DIFLAG2_METADATA+ flag must be set in +di_flags2+.
* The +XFS_DIFLAG2_DAX+ flag must not be set.

=== Metadata Directory Example

This example shows a metadta directory from a freshly formatted root
filesystem:

----
xfs_db> sb 0
xfs_db> p
magicnum = 0x58465342
blocksize = 4096
dblocks = 5192704
rblocks = 0
rextents = 0
uuid = cbf2ceef-658e-46b0-8f96-785661c37976
logstart = 4194311
rootino = 128
rbmino = 130
rsumino = 131
...
meta_uuid = 00000000-0000-0000-0000-000000000000
metadirino = 129
...
----

Notice how the listing includes the root of the metadata directory tree
(+metadirino+).

----
xfs_db> path -m /
xfs_db> ls
8          129                directory      0x0000002e   1 . (good)
10         129                directory      0x0000172e   2 .. (good)
12         33685632           directory      0x2d18ab4c   8 rtgroups (good)
----

Here we use the +path+ and +ls+ commands to display the root directory of
the metadata directory.  We can navigate the directory the old way, too:

----
xfs_db> p
core.magic = 0x494e
core.mode = 040000
core.version = 3
core.format = 1 (local)
core.onlink = 0
core.uid = 0
core.gid = 0
...
v3.flags2 = 0x8000000000000018
v3.cowextsize = 0
v3.crtime.sec = Wed Aug  7 10:22:36 2024
v3.crtime.nsec = 273744000
v3.inumber = 129
v3.uuid = 7e55b909-8728-4d69-a1fa-891427314eea
v3.reflink = 0
v3.cowextsz = 0
v3.dax = 0
v3.bigtime = 1
v3.nrext64 = 1
v3.metadata = 1
u3.sfdir3.hdr.count = 1
u3.sfdir3.hdr.i8count = 0
u3.sfdir3.hdr.parent.i4 = 129
u3.sfdir3.list[0].namelen = 8
u3.sfdir3.list[0].offset = 0x60
u3.sfdir3.list[0].name = "rtgroups"
u3.sfdir3.list[0].inumber.i4 = 33685632
u3.sfdir3.list[0].filetype = 2
----

The root of the metadata directory is a short format directory, and looks just
like any other directory.  The only difference is that the metadata flag is
set, and the directory can only be viewed in the XFS debugger.

----
xfs_db> path -m /rtgroups/0.rmap
btdump
u3.rtrmapbt.recs[1] = [startblock,blockcount,owner,offset,extentflag,attrfork,bmbtblock]
1:[0,1,-3,0,0,0,0]
----

Observe that we can use the xfs_db +path+ command to navigate the metadata
directory tree to the user quota file and display its contents.

[[Quota_Inodes]]
== Quota Inodes

Prior to version 5 filesystems, two inodes can be allocated for quota
management.  The first inode will be used for user quotas.  The second inode
will be used for group quotas or project quotas, depending on mount options.
Group and project quotas are mutually exclusive features in these environments.

In version 5 or later filesystems, each quota type is allocated its own inode,
making it possible to use group and project quota management simultaneously.

* Project quota's primary purpose is to track and monitor disk usage for
directories. For this to occur, the directory inode must have the
+XFS_DIFLAG_PROJINHERIT+ flag set so all inodes created underneath the directory
inherit the project ID.

* Inodes and blocks owned by ID zero do not have enforced quotas, but only quota
accounting.

* Extended attributes do not contribute towards the ID's quota.

* To access each ID's quota information in the file, seek to the ID offset
multiplied by the size of +xfs_dqblk_t+ (136 bytes).

.Quota inode layout
image::images/76.png[]

Quota information is stored in the data extents of the reserved quota
inodes as an array of the +xfs_dqblk+ structures, where there is one array
element for each ID in the system:

[source, c]
----
struct xfs_disk_dquot {
     __be16                d_magic;
     __u8                  d_version;
     __u8                  d_flags;
     __be32                d_id;
     __be64                d_blk_hardlimit;
     __be64                d_blk_softlimit;
     __be64                d_ino_hardlimit;
     __be64                d_ino_softlimit;
     __be64                d_bcount;
     __be64                d_icount;
     __be32                d_itimer;
     __be32                d_btimer;
     __be16                d_iwarns;
     __be16                d_bwarns;
     __be32                d_pad0;
     __be64                d_rtb_hardlimit;
     __be64                d_rtb_softlimit;
     __be64                d_rtbcount;
     __be32                d_rtbtimer;
     __be16                d_rtbwarns;
     __be16                d_pad;
};
struct xfs_dqblk {
     struct xfs_disk_dquot dd_diskdq;
     char                  dd_fill[4];

     /* version 5 filesystem fields begin here */
     __be32                dd_crc;
     __be64                dd_lsn;
     uuid_t                dd_uuid;
};
----

*d_magic*::
Specifies the signature where these two bytes are 0x4451 (+XFS_DQUOT_MAGIC+),
or ``DQ'' in ASCII.

*d_version*::
The structure version, currently this is 1 (+XFS_DQUOT_VERSION+).

*d_flags*::
Specifies which type of ID the structure applies to:

[source, c]
----
#define XFS_DQ_USER  0x0001
#define XFS_DQ_PROJ  0x0002
#define XFS_DQ_GROUP 0x0004
----

*d_id*::
The ID for the quota structure. This will be a uid, gid or projid based on the
value of +d_flags+.

*d_blk_hardlimit*::
The hard limit for the number of filesystem blocks the ID can own. The
ID will not be able to use more space than this limit. If it is attempted,
+ENOSPC+ will be returned.

*d_blk_softlimit*::
The soft limit for the number of filesystem blocks the ID can own.
The ID can temporarily use more space than by +d_blk_softlimit+ up to
+d_blk_hardlimit+. If the space is not freed by the time limit specified by ID
zero's +d_btimer+ value, the ID will be denied more space until the total
blocks owned goes below +d_blk_softlimit+.

*d_ino_hardlimit*::
The hard limit for the number of inodes the ID can own. The ID will
not be able to create or own any more inodes if +d_icount+ reaches this value.

*d_ino_softlimit*::
The soft limit for the number of inodes the ID can own. The ID can
temporarily create or own more inodes than specified by +d_ino_softlimit+ up to
+d_ino_hardlimit+. If the inode count is not reduced by the time limit specified
by ID zero's +d_itimer+ value, the ID will be denied from creating or owning more
inodes until the count goes below +d_ino_softlimit+.

*d_bcount*::
How many filesystem blocks are actually owned by the ID.

*d_icount*::
How many inodes are actually owned by the ID.

*d_itimer*::
Specifies the time when the ID's +d_icount+ exceeded +d_ino_softlimit+. The soft
limit will turn into a hard limit after the elapsed time exceeds ID zero's
+d_itimer+ value. When d_icount goes back below +d_ino_softlimit+, +d_itimer+
is reset back to zero.

If the +XFS_SB_FEAT_INCOMPAT_BIGTIME+ feature is enabled, the 32 bits used by
the timestamp field are interpreted as the upper 32 bits of an 34-bit unsigned
seconds counter.  See the section about xref:Quota_Timers[quota expiration
timers] for more details.

*d_btimer*::
Specifies the time when the ID's +d_bcount+ exceeded +d_blk_softlimit+. The soft
limit will turn into a hard limit after the elapsed time exceeds ID zero's
+d_btimer+ value. When d_bcount goes back below +d_blk_softlimit+, +d_btimer+
is reset back to zero.

*d_iwarns*::
*d_bwarns*::
*d_rtbwarns*::
Specifies how many times a warning has been issued. Currently not used.

*d_rtb_hardlimit*::
The hard limit for the number of real-time blocks the ID can own. The
ID cannot own more space on the real-time subvolume beyond this limit.

*d_rtb_softlimit*::
The soft limit for the number of real-time blocks the ID can own. The
ID can temporarily own more space than specified by +d_rtb_softlimit+ up to
+d_rtb_hardlimit+. If +d_rtbcount+ is not reduced by the time limit specified
by ID zero's +d_rtbtimer value+, the ID will be denied from owning more space
until the count goes below +d_rtb_softlimit+.

*d_rtbcount*::
How many real-time blocks are currently owned by the ID.

*d_rtbtimer*::
Specifies the time when the ID's +d_rtbcount+ exceeded +d_rtb_softlimit+. The
soft limit will turn into a hard limit after the elapsed time exceeds ID zero's
+d_rtbtimer+ value. When +d_rtbcount+ goes back below +d_rtb_softlimit+,
+d_rtbtimer+ is reset back to zero.

*dd_uuid*::
The UUID of this block, which must match either +sb_uuid+ or +sb_meta_uuid+
depending on which features are set.

*dd_lsn*::
Log sequence number of the last DQ block write.

*dd_crc*::
Checksum of the DQ block.

[[Real-time_Inodes]]
== Real-time Inodes

There are two inodes allocated to managing the real-time device's space, the
xref:Real-Time_Bitmap_Inode[Bitmap Inode] and the
xref:Real-Time_Summary_Inode[Summary Inode].

Each realtime group can allocate one inode to managing a
xref:Real_time_Reverse_Mapping_Btree[reverse-index of space] usage, and
a second one to manage xref:Real_time_Refcount_Btree[reference counts] of space
usage.
