IOCTL-XFS-BULKSTAT(2)
π¦ NAME π¦
okay so this is ioctl_xfs_bulkstat(2), bestie β a Linux system call manual page (System Calls Manual, if we're being official about it) β and it's all about how you query information for a whole batch of XFS inodes at once. no cap.
β¨ SYNOPSIS β¨
#include <xfs/xfs_fs.h>
int ioctl(int fd, XFS_IOC_BULKSTAT, struct xfs_bulkstat_req *arg);
πΈ DESCRIPTION πΈ
So the whole vibe here is: you want stat info for a group of XFS inodes, not just one lonely little guy. This ioctl uses a struct xfs_bulkstat_req to set up a bulk transfer straight from the kernel, like a little assembly line of inode facts:
struct xfs_bulkstat_req {
struct xfs_bulk_ireq hdr;
struct xfs_bulkstat bulkstat[];
};
And the xfs_bulkstat structure definition? It's coming, keep scrolling, bestie, it's right below. π
struct xfs_bulk_ireq {
uint64_t ino;
uint32_t flags;
uint32_t icount;
uint32_t ocount;
uint32_t agno;
uint64_t reserved[5];
};
So hdr.ino β you set that to the number of the first inode you want info on. Or set it to zero and you start with the very first inode in the filesystem. OR, plot twist, set it to a special value if XFS_BULK_IREQ_SPECIAL is set in the flags field. π«’ Heads up though: this is a different semantic than the lastip in the old FSBULKSTAT ioctl, so don't get it twisted. After the call goes through, this value gets set to the number of the next inode for which information could be supplied β which lowkey sets you up perfectly for the next call in your iteration loop. slay.
If the XFS_BULK_IREQ_SPECIAL flag is set in the flags field, then the ino field gets interpreted according to these special values:
XFS_BULK_IREQ_SPECIAL_ROOTβ Return stat information for the root directory inode. the root dir is the main character fr.
hdr.flags is a bit set of operational flags, and here's the whole menu:
XFS_BULK_IREQ_AGNOβ If this is set, the call will only return results for the allocation group (AG) set inhdr.agno. Ifhdr.inois set to zero, results will be returned starting with the first inode in the AG. This flag may not be set at the same time as theXFS_BULK_IREQ_SPECIALflag.XFS_BULK_IREQ_SPECIALβ If this is set, results will be returned for only the special inode specified in thehdr.inofield. This flag may not be set at the same time as theXFS_BULK_IREQ_AGNOflag.XFS_BULK_IREQ_NREXT64β If this is set, data fork extent count is returned via thebs_extents64field and0is assigned tobs_extents. Otherwise, data fork extent count is returned via thebs_extentsfield andbs_extents64is assigned a value of0. In that second case,bs_extentsis set to(2^31 - 1)if the data fork extent count is larger than2^31. This flag may be set independently of whether other flags have been set.XFS_BULK_IREQ_METADIRβ Return metadata directory tree inodes in the stat output as well. The only fields that will be populated arebs_ino,bs_gen,bs_mode,bs_sick, andbs_checked. All other fields, notablybs_blksize, will be zero. π don't come for those fields, they're literally not invited.
hdr.icount is the maximum number of records to return β and yeah, this should be the size of the array that comes after the header. keep it consistent bestie.
hdr.ocount will be set to the number of records actually returned. (the receipts. π§Ύ)
hdr.agno is the number of the allocation group (AG) for which we want results. But if the XFS_BULK_IREQ_AGNO flag is not set, this field is just ignored. it's giving decorative.
hdr.reserved must be set to zero. no notes, just zero.
bulkstat is an array of struct xfs_bulkstat, which is described right here, and the array must have at least icount elements:
struct xfs_bulkstat {
uint64_t bs_ino;
uint64_t bs_size;
uint64_t bs_blocks;
uint64_t bs_xflags;
uint64_t bs_atime;
uint64_t bs_mtime;
uint64_t bs_ctime;
uint64_t bs_btime;
uint32_t bs_gen;
uint32_t bs_uid;
uint32_t bs_gid;
uint32_t bs_projectid;
uint32_t bs_atime_nsec;
uint32_t bs_mtime_nsec;
uint32_t bs_ctime_nsec;
uint32_t bs_btime_nsec;
uint32_t bs_blksize;
uint32_t bs_rdev;
uint32_t bs_cowextsize_blks;
uint32_t bs_extsize_blks;
uint32_t bs_nlink;
uint32_t bs_extents;
uint32_t bs_aextents;
uint16_t bs_version;
uint16_t bs_forkoff;
uint16_t bs_sick;
uint16_t bs_checked;
uint16_t bs_mode;
uint16_t bs_pad2;
uint64_t bs_extents64;
uint64_t bs_pad[6];
};
okay field-by-field tour, come on, let's go πΆββοΈβ¨
bs_inois the inode number of this record.bs_sizeis the size of the file, in bytes.bs_blocksis the number of filesystem blocks allocated to this file, including metadata.bs_xflagstell us what extended flags are set on this inode. These flags are the same values as those defined in the XFS INODE FLAGS section of theioctl_xfs_fsgetxattr(2)manpage. (go peek at that one, iykyk π )bs_atimeis the last time this file was accessed, in seconds.bs_mtimeis the last time the contents of this file were modified, in seconds.bs_ctimeis the last time this inode record was modified, in seconds.bs_btimeis the time this inode record was created, in seconds.bs_genis the generation number of the inode record.bs_uidis the user id.bs_gidis the group id.bs_projectidis the the project id. (yes, that double "the" is in the original, we're leaving it, it's iconic π)bs_atime_nsecis the nanoseconds component of the last time this file was accessed.bs_mtime_nsecis the nanoseconds component of the last time the contents of this file were modified.bs_ctime_nsecis the nanoseconds component of the last time this inode record was modified.bs_btime_nsecis the nanoseconds component of the time this inode record was created.bs_blksizeis the size of a data block for this file, in units of bytes.bs_rdevis the encoded device id if this is a special file.bs_cowextsize_blksis the Copy on Write extent size hint for this file, in units of data blocks.bs_extsize_blksis the extent size hint for this file, in units of data blocks.bs_nlinkis the number of hard links to this inode.bs_extentsis the number of storage mappings associated with this file's data.bs_aextentsis the number of storage mappings associated with this file's extended attributes.bs_versionis the version of this data structure. This will be set toXFS_BULKSTAT_VERSION_V5by the kernel. β¨bs_forkoffis the offset of the attribute fork in the inode record, in bytes.- The fields
bs_sickandbs_checkedindicate the relative health of various allocation group metadata. Please see the section XFS INODE METADATA HEALTH REPORTING for more information. π©Ί (that's right, we're getting a whole health check section, stay tuned) bs_modeis the file type and mode.bs_pad[7]is zeroed.
π« RETURN VALUE π«
On error, -1 is returned, and errno is set to indicate the error. classic.
π©Ί XFS INODE METADATA HEALTH REPORTING π©Ί
The online filesystem checking utility scans inode metadata and records what it finds in the kernel incore state. So here's the scheme that lets userspace read the incore health status of an inode β it's giving doctor's chart:
- If a given sick flag is set in
bs_sick, then that piece of metadata has been observed to be damaged. The same bit should be set inbs_checked. π - If a given sick flag is set in
bs_checkedbut is not set inbs_sick, then that piece of metadata has been checked and is not faulty. healthy queen π - If a given sick flag is not set in
bs_checked, then no conclusion can be made. shrug, the data simply isn't there.
The following flags apply to these fields:
XFS_BS_SICK_INODEβ The inode's record itself.XFS_BS_SICK_BMBTDβ File data extent mappings.XFS_BS_SICK_BMBTAβ Extended attribute extent mappings.XFS_BS_SICK_BMBTCβ Copy on Write staging extent mappings.XFS_BS_SICK_DIRβ Directory information.XFS_BS_SICK_XATTRβ Extended attribute data.XFS_BS_SICK_SYMLINKβ Symbolic link target.XFS_BS_SICK_PARENTβ Parent pointers.XFS_BS_SICK_DIRTREEβ Directory is the source of corruption in the directory tree.
π¨ ERRORS π¨
Error codes can be one of, but are not limited to, the following β so don't assume the list is closed, bestie:
EFAULTβ The kernel was not able to copy into the userspace buffer.EFSBADCRCβ Metadata checksum validation failed while performing the query.EFSCORRUPTEDβ Metadata corruption was encountered while performing the query.EINVALβ One of the arguments was not valid.EIOβ An I/O error was encountered while performing the query.ENOMEMβ There was insufficient memory to perform the query.
π CONFORMING TO π
This API is specific to XFS filesystem on the Linux kernel. no portability tea here, it's a Linux-XFS exclusive π
π SEE ALSO π
ioctl(2), ioctl_xfs_fsgetxattr(2)
okay that's the whole page, you ate that π«Ά this lil gem comes from the XFS manual collection and it's dated 2019-05-23 β so yeah, it's been serving accurate inode facts since then, no cap. go forth and bulkstat, bestie πβ¨π
π¦ where this page comes from
- alpine 3.22: xfsprogs-doc 6.14.0-r0 Β· LGPL-2.1-or-later
- alpine 3.23: xfsprogs-doc 6.17.0-r0 Β· LGPL-2.1-or-later
- alpine 3.24: xfsprogs-doc 7.0.1-r0 Β· LGPL-2.1-or-later
- arch rolling: xfsprogs 7.2.0-1
- arch rolling: xfsprogs 7.2.1-1 Β· GPL-2.0-only AND LGPL-2.1-only
- centos-stream 10: xfsprogs-devel 6.16.0-1.el10 Β· GPL-1.0-or-later AND LGPL-2.1-or-later
- fedora 43: xfsprogs-devel 6.15.0-3.fc43 Β· GPL-1.0-or-later AND LGPL-2.1-or-later
- fedora 43: xfsprogs-devel 6.15.0-3.fc43 Β· GPL-1.0-or-later AND LGPL-2.1-or-later
- fedora 44: xfsprogs-devel 6.18.0-2.fc44 Β· GPL-1.0-or-later AND LGPL-2.1-or-later
- fedora 44: xfsprogs-devel 6.18.0-2.fc44 Β· GPL-1.0-or-later AND LGPL-2.1-or-later
- fedora 44: xfsprogs-devel 7.1.1-1.fc44 Β· GPL-1.0-or-later AND LGPL-2.1-or-later
- fedora 44: xfsprogs-devel 7.1.1-1.fc44 Β· GPL-1.0-or-later AND LGPL-2.1-or-later
- nixos 26.05: xfsprogs 6.19.0
- nixpkgs unstable: xfsprogs 7.2.1
- opensuse-leap 16.0: xfsprogs 6.19.0-160000.3.1 Β· GPL-2.0-or-later
- opensuse-leap 16.0: xfsprogs 6.19.0-160000.3.1 Β· GPL-2.0-or-later
- opensuse-leap 16.0: xfsprogs 6.19.0-160000.3.1 Β· GPL-2.0-or-later
- opensuse-leap 16.0: xfsprogs 6.19.0-160000.3.1 Β· GPL-2.0-or-later
- ubuntu resolute: xfslibs-dev 6.18.0-3 Β· GPL-2.0-only
- ubuntu stonking: xfslibs-dev 6.19.0-1 Β· GPL-2.0-only
- π the page's license: GPL-2.0+
- Copyright (c) 2019, Oracle. All rights reserved
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms