This commit adds support to libfrog to enable reporting 64-bit extent counters to its users. In order to do so bulkstat ioctl is now invoked with the newly introduced XFS_BULK_IREQ_BULKSTAT_NREXT64 flag. If the ioctl call fails with -EINVAL error, the commit falls back to invoking the bulkstat ioctl without passing XFS_BULK_IREQ_BULKSTAT_NREXT64 flag. Signed-off-by: Chandan Babu R <chandan.babu@xxxxxxxxxx> --- fsr/xfs_fsr.c | 4 ++-- io/bulkstat.c | 3 ++- libfrog/bulkstat.c | 55 ++++++++++++++++++++++++++++++++++++++++++---- libxfs/xfs_fs.h | 19 +++++++++++----- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/fsr/xfs_fsr.c b/fsr/xfs_fsr.c index bb5d4a2c..1fb2e5e7 100644 --- a/fsr/xfs_fsr.c +++ b/fsr/xfs_fsr.c @@ -606,7 +606,7 @@ cmp(const void *s1, const void *s2) (bs1->bs_version == XFS_BULKSTAT_VERSION_V5 && bs2->bs_version == XFS_BULKSTAT_VERSION_V5)); - return (bs2->bs_extents - bs1->bs_extents); + return (bs2->bs_extents64 - bs1->bs_extents64); } /* @@ -670,7 +670,7 @@ fsrfs(char *mntdir, xfs_ino_t startino, int targetrange) for (p = buf, endp = (buf + buflenout); p < endp ; p++) { /* Do some obvious checks now */ if (((p->bs_mode & S_IFMT) != S_IFREG) || - (p->bs_extents < 2)) + (p->bs_extents64 < 2)) continue; ret = open_handle(&file_fd, fshandlep, p, diff --git a/io/bulkstat.c b/io/bulkstat.c index 4ae27586..8a9cf902 100644 --- a/io/bulkstat.c +++ b/io/bulkstat.c @@ -49,7 +49,7 @@ dump_bulkstat( printf("\tbs_extsize_blks = %"PRIu32"\n", bstat->bs_extsize_blks); printf("\tbs_nlink = %"PRIu32"\n", bstat->bs_nlink); - printf("\tbs_extents = %"PRIu32"\n", bstat->bs_extents); + printf("\tbs_extents32 = %"PRIu32"\n", bstat->bs_extents32); printf("\tbs_aextents = %"PRIu32"\n", bstat->bs_aextents); printf("\tbs_version = %"PRIu16"\n", bstat->bs_version); printf("\tbs_forkoff = %"PRIu16"\n", bstat->bs_forkoff); @@ -57,6 +57,7 @@ dump_bulkstat( printf("\tbs_sick = 0x%"PRIx16"\n", bstat->bs_sick); printf("\tbs_checked = 0x%"PRIx16"\n", bstat->bs_checked); printf("\tbs_mode = 0%"PRIo16"\n", bstat->bs_mode); + printf("\tbs_extents64 = %"PRIu64"\n", bstat->bs_extents64); }; static void diff --git a/libfrog/bulkstat.c b/libfrog/bulkstat.c index 195f6ea0..9de614d3 100644 --- a/libfrog/bulkstat.c +++ b/libfrog/bulkstat.c @@ -48,12 +48,13 @@ xfrog_bulkstat_single5( struct xfs_fd *xfd, uint64_t ino, unsigned int flags, + uint64_t bulkstat_flags, struct xfs_bulkstat *bulkstat) { struct xfs_bulkstat_req *req; int ret; - if (flags & ~(XFS_BULK_IREQ_SPECIAL)) + if (flags & ~(XFS_BULK_IREQ_SPECIAL | XFS_BULK_IREQ_BULKSTAT)) return -EINVAL; ret = xfrog_bulkstat_alloc_req(1, ino, &req); @@ -61,6 +62,7 @@ xfrog_bulkstat_single5( return ret; req->hdr.flags = flags; + req->hdr.bulkstat_flags = bulkstat_flags; ret = ioctl(xfd->fd, XFS_IOC_BULKSTAT, req); if (ret) { ret = -errno; @@ -73,6 +75,13 @@ xfrog_bulkstat_single5( } memcpy(bulkstat, req->bulkstat, sizeof(struct xfs_bulkstat)); + + if (!(flags & XFS_BULK_IREQ_BULKSTAT) || + !(bulkstat_flags & XFS_BULK_IREQ_BULKSTAT_NREXT64)) { + bulkstat->bs_extents64 = bulkstat->bs_extents32; + bulkstat->bs_extents32 = 0; + } + free: free(req); return ret; @@ -121,7 +130,18 @@ xfrog_bulkstat_single( if (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V1) goto try_v1; - error = xfrog_bulkstat_single5(xfd, ino, flags, bulkstat); + error = xfrog_bulkstat_single5(xfd, ino, flags | XFS_BULK_IREQ_BULKSTAT, + XFS_BULK_IREQ_BULKSTAT_NREXT64, bulkstat); + if (error == -EINVAL) { + /* + * Older versions of XFS kernel driver return -EINVAL because + * they don't recognize XFS_BULK_IREQ_BULKSTAT as a valid + * flag. Try once again without passing XFS_BULK_IREQ_BULKSTAT + * flag. + */ + error = xfrog_bulkstat_single5(xfd, ino, flags, 0, bulkstat); + } + if (error == 0 || (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V5)) return error; @@ -259,10 +279,21 @@ xfrog_bulkstat5( struct xfs_bulkstat_req *req) { int ret; + int i; ret = ioctl(xfd->fd, XFS_IOC_BULKSTAT, req); if (ret) return -errno; + + if (!(req->hdr.flags & XFS_BULK_IREQ_BULKSTAT) || + !(req->hdr.bulkstat_flags & XFS_BULK_IREQ_BULKSTAT_NREXT64)) { + for (i = 0; i < req->hdr.ocount; i++) { + req->bulkstat[i].bs_extents64 = + req->bulkstat[i].bs_extents32; + req->bulkstat[i].bs_extents32 = 0; + } + } + return 0; } @@ -308,7 +339,22 @@ xfrog_bulkstat( if (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V1) goto try_v1; + req->hdr.flags |= XFS_BULK_IREQ_BULKSTAT; + req->hdr.bulkstat_flags |= XFS_BULK_IREQ_BULKSTAT_NREXT64; + error = xfrog_bulkstat5(xfd, req); + if (error == -EINVAL) { + /* + * Older versions of XFS kernel driver return -EINVAL because + * they don't recognize XFS_BULK_IREQ_BULKSTAT as a valid + * flag. Try once again without passing XFS_BULK_IREQ_BULKSTAT + * flag. + */ + req->hdr.flags &= ~XFS_BULK_IREQ_BULKSTAT; + req->hdr.bulkstat_flags &= ~XFS_BULK_IREQ_BULKSTAT_NREXT64; + error = xfrog_bulkstat5(xfd, req); + } + if (error == 0 || (xfd->flags & XFROG_FLAG_BULKSTAT_FORCE_V5)) return error; @@ -342,6 +388,7 @@ xfrog_bulkstat_v5_to_v1( const struct xfs_bulkstat *bs5) { if (bs5->bs_aextents > UINT16_MAX || + bs5->bs_extents64 > INT32_MAX || cvt_off_fsb_to_b(xfd, bs5->bs_extsize_blks) > UINT32_MAX || cvt_off_fsb_to_b(xfd, bs5->bs_cowextsize_blks) > UINT32_MAX || time_too_big(bs5->bs_atime) || @@ -366,7 +413,7 @@ xfrog_bulkstat_v5_to_v1( bs1->bs_blocks = bs5->bs_blocks; bs1->bs_xflags = bs5->bs_xflags; bs1->bs_extsize = cvt_off_fsb_to_b(xfd, bs5->bs_extsize_blks); - bs1->bs_extents = bs5->bs_extents; + bs1->bs_extents = bs5->bs_extents64; bs1->bs_gen = bs5->bs_gen; bs1->bs_projid_lo = bs5->bs_projectid & 0xFFFF; bs1->bs_forkoff = bs5->bs_forkoff; @@ -407,7 +454,6 @@ xfrog_bulkstat_v1_to_v5( bs5->bs_blocks = bs1->bs_blocks; bs5->bs_xflags = bs1->bs_xflags; bs5->bs_extsize_blks = cvt_b_to_off_fsbt(xfd, bs1->bs_extsize); - bs5->bs_extents = bs1->bs_extents; bs5->bs_gen = bs1->bs_gen; bs5->bs_projectid = bstat_get_projid(bs1); bs5->bs_forkoff = bs1->bs_forkoff; @@ -415,6 +461,7 @@ xfrog_bulkstat_v1_to_v5( bs5->bs_checked = bs1->bs_checked; bs5->bs_cowextsize_blks = cvt_b_to_off_fsbt(xfd, bs1->bs_cowextsize); bs5->bs_aextents = bs1->bs_aextents; + bs5->bs_extents64 = bs1->bs_extents; } /* Allocate a bulkstat request. Returns zero or a negative error code. */ diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index 2594fb64..b7690691 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -394,7 +394,7 @@ struct xfs_bulkstat { uint32_t bs_extsize_blks; /* extent size hint, blocks */ uint32_t bs_nlink; /* number of links */ - uint32_t bs_extents; /* number of extents */ + uint32_t bs_extents32; /* 32-bit data fork extent counter */ uint32_t bs_aextents; /* attribute number of extents */ uint16_t bs_version; /* structure version */ uint16_t bs_forkoff; /* inode fork offset in bytes */ @@ -403,8 +403,9 @@ struct xfs_bulkstat { uint16_t bs_checked; /* checked inode metadata */ uint16_t bs_mode; /* type and mode */ uint16_t bs_pad2; /* zeroed */ + uint64_t bs_extents64; /* 64-bit data fork extent counter */ - uint64_t bs_pad[7]; /* zeroed */ + uint64_t bs_pad[6]; /* zeroed */ }; #define XFS_BULKSTAT_VERSION_V1 (1) @@ -469,7 +470,8 @@ struct xfs_bulk_ireq { uint32_t icount; /* I: count of entries in buffer */ uint32_t ocount; /* O: count of entries filled out */ uint32_t agno; /* I: see comment for IREQ_AGNO */ - uint64_t reserved[5]; /* must be zero */ + uint64_t bulkstat_flags; /* I: Bulkstat operation flags */ + uint64_t reserved[4]; /* must be zero */ }; /* @@ -492,9 +494,16 @@ struct xfs_bulk_ireq { */ #define XFS_BULK_IREQ_METADIR (1 << 2) -#define XFS_BULK_IREQ_FLAGS_ALL (XFS_BULK_IREQ_AGNO | \ +#define XFS_BULK_IREQ_BULKSTAT (1 << 3) + +#define XFS_BULK_IREQ_FLAGS_ALL (XFS_BULK_IREQ_AGNO | \ XFS_BULK_IREQ_SPECIAL | \ - XFS_BULK_IREQ_METADIR) + XFS_BULK_IREQ_METADIR | \ + XFS_BULK_IREQ_BULKSTAT) + +#define XFS_BULK_IREQ_BULKSTAT_NREXT64 (1 << 0) + +#define XFS_BULK_IREQ_BULKSTAT_FLAGS_ALL (XFS_BULK_IREQ_BULKSTAT_NREXT64) /* Operate on the root directory inode. */ #define XFS_BULK_IREQ_SPECIAL_ROOT (1) -- 2.30.2