import xfsprogs-5.0.0-10.el8

c8 imports/c8/xfsprogs-5.0.0-10.el8
CentOS Sources 3 years ago committed by MSVSphere Packaging Team
commit 369f7b1d9e

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/xfsprogs-5.0.0.tar.xz

@ -0,0 +1 @@
1a3d7ce8ebf75e001463162e4a44c0f5bf0beab7 SOURCES/xfsprogs-5.0.0.tar.xz

@ -0,0 +1,74 @@
Index: xfsprogs-4.19.0/mkfs/xfs_mkfs.c
===================================================================
--- xfsprogs-4.19.0.orig/mkfs/xfs_mkfs.c
+++ xfsprogs-4.19.0/mkfs/xfs_mkfs.c
@@ -1973,15 +1973,15 @@ _("Directory ftype field always enabled
usage();
}
- } else {
+ } else { /* !crcs_enabled */
/*
- * The kernel doesn't currently support crc=0,finobt=1
- * filesystems. If crcs are not enabled and the user has not
- * explicitly turned finobt on, then silently turn it off to
- * avoid an unnecessary warning.
+ * The kernel doesn't support crc=0,finobt=1 filesystems.
+ * If crcs are not enabled and the user has not explicitly
+ * turned finobt on, then silently turn it off to avoid an
+ * unnecessary warning.
* If the user explicitly tried to use crc=0,finobt=1,
* then issue an error.
- * The same is also for sparse inodes.
+ * The same is also true for sparse inodes and reflink.
*/
if (cli->sb_feat.finobt && cli_opt_set(&mopts, M_FINOBT)) {
fprintf(stderr,
@@ -2004,7 +2004,7 @@ _("rmapbt not supported without CRC supp
}
cli->sb_feat.rmapbt = false;
- if (cli->sb_feat.reflink) {
+ if (cli->sb_feat.reflink && cli_opt_set(&mopts, M_REFLINK)) {
fprintf(stderr,
_("reflink not supported without CRC support\n"));
usage();
@@ -3788,7 +3788,7 @@ main(
.finobt = true,
.spinodes = true,
.rmapbt = false,
- .reflink = false,
+ .reflink = true,
.parent_pointers = false,
.nodalign = false,
.nortalign = false,
Index: xfsprogs-4.19.0/man/man8/mkfs.xfs.8
===================================================================
--- xfsprogs-4.19.0.orig/man/man8/mkfs.xfs.8
+++ xfsprogs-4.19.0/man/man8/mkfs.xfs.8
@@ -229,9 +229,9 @@ mapping will be changed to the new block
enables the creation of per-file snapshots and deduplication. It is only
available for the data forks of regular files.
.IP
-By default,
+By default in Red Hat Enterprise Linux 8,
.B mkfs.xfs
-will not create reference count btrees and therefore will not enable the
+will create reference count btrees and therefore will enable the
reflink feature. This feature is only available for filesystems created with
the (default)
.B \-m crc=1
@@ -239,6 +239,13 @@ option set. When the option
.B \-m crc=0
is used, the reference count btree feature is not supported and reflink is
disabled.
+.IP
+Note: the filesystem DAX mount option (
+.B \-o dax
+) is incompatible with
+reflink-enabled XFS filesystems. To use filesystem DAX with XFS, specify the
+.B \-m reflink=0
+option to mkfs.xfs to disable the reflink feature.
.RE
.TP
.BI \-d " data_section_options"

@ -0,0 +1,106 @@
From b192e77cc38473964c718bd035502b702c6a6e34 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Tue, 21 May 2019 11:03:43 -0500
Subject: [PATCH] libxfs: create current_time helper and sync
xfs_trans_ichgtime
Make xfs_trans_ichgtime() almost match kernelspace by creating a
new current_time() helper to match the kernel utility.
This reduces still more cosmetic change. We may want to sync the
creation flag over to the kernel even though it's not used today.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/include/xfs_inode.h b/include/xfs_inode.h
index 52d79f3..76f9ac7 100644
--- a/include/xfs_inode.h
+++ b/include/xfs_inode.h
@@ -16,6 +16,16 @@ struct xfs_mount;
struct xfs_inode_log_item;
struct xfs_dir_ops;
+/*
+ * These are not actually used, they are only for userspace build
+ * compatibility in code that looks at i_state
+ */
+#define I_DIRTY_TIME 0
+#define I_DIRTY_TIME_EXPIRED 0
+
+#define IS_I_VERSION(inode) (0)
+#define inode_maybe_inc_iversion(inode,flags) (0)
+
/*
* Inode interface. This fakes up a "VFS inode" to make the xfs_inode appear
* similar to the kernel which now is used tohold certain parts of the on-disk
@@ -25,6 +35,7 @@ struct inode {
mode_t i_mode;
uint32_t i_nlink;
xfs_dev_t i_rdev; /* This actually holds xfs_dev_t */
+ unsigned long i_state; /* Not actually used in userspace */
uint32_t i_generation;
uint64_t i_version;
struct timespec i_atime;
@@ -150,6 +161,9 @@ extern void libxfs_trans_ichgtime(struct xfs_trans *,
struct xfs_inode *, int);
extern int libxfs_iflush_int (struct xfs_inode *, struct xfs_buf *);
+#define timespec64 timespec
+extern struct timespec64 current_time(struct inode *inode);
+
/* Inode Cache Interfaces */
extern bool libxfs_inode_verify_forks(struct xfs_inode *ip);
extern int libxfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
diff --git a/libxfs/util.c b/libxfs/util.c
index 9fe9a36..951f7cf 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -136,11 +136,21 @@ xfs_log_calc_unit_res(
return unit_bytes;
}
+struct timespec64
+current_time(struct inode *inode)
+{
+ struct timespec64 tv;
+ struct timeval stv;
+
+ gettimeofday(&stv, (struct timezone *)0);
+ tv.tv_sec = stv.tv_sec;
+ tv.tv_nsec = stv.tv_usec * 1000;
+
+ return tv;
+}
+
/*
* Change the requested timestamp in the given inode.
- *
- * This was once shared with the kernel, but has diverged to the point
- * where it's no longer worth the hassle of maintaining common code.
*/
void
libxfs_trans_ichgtime(
@@ -148,12 +158,14 @@ libxfs_trans_ichgtime(
struct xfs_inode *ip,
int flags)
{
- struct timespec tv;
- struct timeval stv;
+ struct inode *inode = VFS_I(ip);
+ struct timespec64 tv;
+
+ ASSERT(tp);
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+
+ tv = current_time(inode);
- gettimeofday(&stv, (struct timezone *)0);
- tv.tv_sec = stv.tv_sec;
- tv.tv_nsec = stv.tv_usec * 1000;
if (flags & XFS_ICHGTIME_MOD)
VFS_I(ip)->i_mtime = tv;
if (flags & XFS_ICHGTIME_CHG)

@ -0,0 +1,60 @@
From 9c726ef0d2d829ae83756d3817f271e9c2c8777a Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Wed, 10 Jul 2019 11:35:07 -0400
Subject: [PATCH] mkfs: don't use xfs_verify_fsbno() before m_sb is fully set
up
Commit 8da5298 mkfs: validate start and end of aligned logs stopped
open-coding log end block checks, and used xfs_verify_fsbno() instead.
It also used xfs_verify_fsbno() to validate the log start. This
seemed to make sense, but then xfs/306 started failing on 4k sector
filesystems, which leads to a log striep unite being set on a single
AG filesystem.
As it turns out, if xfs_verify_fsbno() is testing a block in the
last AG, it needs to have mp->m_sb.sb_dblocks set, which isn't done
until later. With sb_dblocks unset we can't know how many blocks
are in the last AG, and hence can't validate it.
To fix all this, go back to open-coding the checks; note that this
/does/ rely on m_sb.sb_agblklog being set, but that /is/ already
done in the early call to start_superblock_setup().
Fixes: 8da5298 ("mkfs: validate start and end of aligned logs")
Reported-by: Dave Chinner <david@fromorbit.com>
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
mkfs/xfs_mkfs.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 468b8fde..4e576a5c 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -3040,7 +3040,7 @@ align_internal_log(
cfg->logstart = ((cfg->logstart + (sunit - 1)) / sunit) * sunit;
/* If our log start overlaps the next AG's metadata, fail. */
- if (!xfs_verify_fsbno(mp, cfg->logstart)) {
+ if (XFS_FSB_TO_AGBNO(mp, cfg->logstart) <= XFS_AGFL_BLOCK(mp)) {
fprintf(stderr,
_("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n"
"within an allocation group.\n"),
@@ -3051,10 +3051,9 @@ _("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n"
/* round up/down the log size now */
align_log_size(cfg, sunit);
- /* check the aligned log still fits in an AG. */
+ /* check the aligned log still starts and ends in the same AG. */
logend = cfg->logstart + cfg->logblocks - 1;
- if (XFS_FSB_TO_AGNO(mp, cfg->logstart) != XFS_FSB_TO_AGNO(mp, logend) ||
- !xfs_verify_fsbno(mp, logend)) {
+ if (XFS_FSB_TO_AGNO(mp, cfg->logstart) != XFS_FSB_TO_AGNO(mp, logend)) {
fprintf(stderr,
_("Due to stripe alignment, the internal log size (%lld) is too large.\n"
"Must fit within an allocation group.\n"),
--
2.17.0

@ -0,0 +1,52 @@
From 8da52988ad210958f21c178620bb1e44f1188cd0 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 25 Jun 2019 17:04:42 -0400
Subject: [PATCH] mkfs: validate start and end of aligned logs
Validate that the start and end of the log stay within a single AG if
we adjust either end to align to stripe units.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
mkfs/xfs_mkfs.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index ddb25ecc..468b8fde 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -3033,15 +3033,28 @@ align_internal_log(
struct xfs_mount *mp,
int sunit)
{
+ uint64_t logend;
+
/* round up log start if necessary */
if ((cfg->logstart % sunit) != 0)
cfg->logstart = ((cfg->logstart + (sunit - 1)) / sunit) * sunit;
+ /* If our log start overlaps the next AG's metadata, fail. */
+ if (!xfs_verify_fsbno(mp, cfg->logstart)) {
+ fprintf(stderr,
+_("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n"
+ "within an allocation group.\n"),
+ (long long) cfg->logstart);
+ usage();
+ }
+
/* round up/down the log size now */
align_log_size(cfg, sunit);
/* check the aligned log still fits in an AG. */
- if (cfg->logblocks > cfg->agsize - XFS_FSB_TO_AGBNO(mp, cfg->logstart)) {
+ logend = cfg->logstart + cfg->logblocks - 1;
+ if (XFS_FSB_TO_AGNO(mp, cfg->logstart) != XFS_FSB_TO_AGNO(mp, logend) ||
+ !xfs_verify_fsbno(mp, logend)) {
fprintf(stderr,
_("Due to stripe alignment, the internal log size (%lld) is too large.\n"
"Must fit within an allocation group.\n"),
--
2.17.0

@ -0,0 +1,42 @@
From 59cf967983f6aaff4ce33a50135ae57032ebd8f2 Mon Sep 17 00:00:00 2001
From: Allison Collins <allison.henderson@oracle.com>
Date: Wed, 10 Jul 2019 11:38:04 -0400
Subject: [PATCH] xfsprogs: Fix uninitialized cfg->lsunit
While investigating another mkfs bug, noticed that cfg->lsunit is sometimes
left uninitialized when it should not. This is because calc_stripe_factors
in some cases needs cfg->loginternal to be set first. This is done in
validate_logdev. So move calc_stripe_factors below validate_logdev while
parsing configs.
Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
mkfs/xfs_mkfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 79377b12..65cf1e0f 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -4007,7 +4007,6 @@ main(
cfg.rtblocks = calc_dev_size(cli.rtsize, &cfg, &ropts, R_SIZE, "rt");
validate_rtextsize(&cfg, &cli, &ft);
- calc_stripe_factors(&cfg, &cli, &ft);
/*
* Open and validate the device configurations
@@ -4017,6 +4016,7 @@ main(
validate_datadev(&cfg, &cli);
validate_logdev(&cfg, &cli, &logfile);
validate_rtdev(&cfg, &cli, &rtfile);
+ calc_stripe_factors(&cfg, &cli, &ft);
/*
* At this point when know exactly what size all the devices are,
--
2.17.0

@ -0,0 +1,81 @@
From bf6d4cf988176ad7efd0089830bfbf200a5e0196 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:27 -0500
Subject: [PATCH] libfrog: convert cvttime to return time64_t
Change the cvttime function to return 64-bit time values so that we can
put them to use with the bigtime feature.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/include/convert.h b/include/convert.h
index 0489a1d..2b427df 100644
--- a/include/convert.h
+++ b/include/convert.h
@@ -16,7 +16,7 @@ extern uint16_t cvt_u16(char *s, int base);
extern long long cvtnum(size_t blocksize, size_t sectorsize, char *s);
extern void cvtstr(double value, char *str, size_t sz);
-extern unsigned long cvttime(char *s);
+extern time64_t cvttime(char *s);
extern uid_t uid_from_string(char *user);
extern gid_t gid_from_string(char *group);
diff --git a/libfrog/convert.c b/libfrog/convert.c
index ed4cae7..209b874 100644
--- a/libfrog/convert.c
+++ b/libfrog/convert.c
@@ -267,14 +267,14 @@ cvtstr(
#define DAYS_TO_SECONDS(d) ((d) * HOURS_TO_SECONDS(24))
#define WEEKS_TO_SECONDS(w) ((w) * DAYS_TO_SECONDS(7))
-unsigned long
+time64_t
cvttime(
char *s)
{
- unsigned long i;
+ time64_t i;
char *sp;
- i = strtoul(s, &sp, 0);
+ i = strtoll(s, &sp, 0);
if (i == 0 && sp == s)
return 0;
if (*sp == '\0')
diff --git a/quota/edit.c b/quota/edit.c
index 01d358f..b3cad02 100644
--- a/quota/edit.c
+++ b/quota/edit.c
@@ -419,13 +419,13 @@ restore_f(
static void
set_timer(
- uint32_t id,
- uint type,
- uint mask,
- char *dev,
- uint value)
+ uint32_t id,
+ uint type,
+ uint mask,
+ char *dev,
+ time64_t value)
{
- fs_disk_quota_t d;
+ struct fs_disk_quota d;
memset(&d, 0, sizeof(d));
@@ -476,7 +476,7 @@ timer_f(
int argc,
char **argv)
{
- uint value;
+ time64_t value;
char *name = NULL;
uint32_t id = 0;
int c, flags = 0, type = 0, mask = 0;

@ -0,0 +1,61 @@
From 0160c1490d4b49889c9ed01a39f760cba762eac5 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:28 -0500
Subject: [PATCH] libfrog: list the bigtime feature when reporting geometry
When we're reporting on a filesystem's geometry, report if the bigtime
feature is enabled on this filesystem.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libfrog/fsgeom.c b/libfrog/fsgeom.c
index 8879d16..ddacd59 100644
--- a/libfrog/fsgeom.c
+++ b/libfrog/fsgeom.c
@@ -25,6 +25,7 @@ xfs_report_geom(
int spinodes;
int rmapbt_enabled;
int reflink_enabled;
+ int bigtime_enabled;
isint = geo->logstart > 0;
lazycount = geo->flags & XFS_FSOP_GEOM_FLAGS_LAZYSB ? 1 : 0;
@@ -40,12 +41,13 @@ xfs_report_geom(
spinodes = geo->flags & XFS_FSOP_GEOM_FLAGS_SPINODES ? 1 : 0;
rmapbt_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_RMAPBT ? 1 : 0;
reflink_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_REFLINK ? 1 : 0;
+ bigtime_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_BIGTIME ? 1 : 0;
printf(_(
"meta-data=%-22s isize=%-6d agcount=%u, agsize=%u blks\n"
" =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n"
" =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u\n"
-" =%-22s reflink=%u\n"
+" =%-22s reflink=%-4u bigtime=%u\n"
"data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
" =%-22s sunit=%-6u swidth=%u blks\n"
"naming =version %-14u bsize=%-6u ascii-ci=%d, ftype=%d\n"
@@ -55,7 +57,7 @@ xfs_report_geom(
mntpoint, geo->inodesize, geo->agcount, geo->agblocks,
"", geo->sectsize, attrversion, projid32bit,
"", crcs_enabled, finobt_enabled, spinodes, rmapbt_enabled,
- "", reflink_enabled,
+ "", reflink_enabled, bigtime_enabled,
"", geo->blocksize, (unsigned long long)geo->datablocks,
geo->imaxpct,
"", geo->sunit, geo->swidth,
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 00f367e..a0452c2 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -115,6 +115,7 @@
#define xfs_calc_dquots_per_chunk libxfs_calc_dquots_per_chunk
#define xfs_dquot_verify libxfs_dquot_verify
#define xfs_dqblk_repair libxfs_dqblk_repair
+#define xfs_dquot_from_disk_ts libxfs_dquot_from_disk_ts
#define xfs_symlink_blocks libxfs_symlink_blocks
#define xfs_symlink_hdr_ok libxfs_symlink_hdr_ok

@ -0,0 +1,89 @@
From ec24f6fa05f695af02b4e0fca5bc27cb1cab49b7 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 12:05:32 -0500
Subject: [PATCH] libxfs: create a real struct timespec64
Create a real struct timespec64 that supports 64-bit seconds counts.
The C library struct timespec doesn't support this on 32-bit
architectures and we cannot lose the upper bits in the incore inode.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/include/libxfs.h b/include/libxfs.h
index 731561c..2bdef70 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -36,8 +36,6 @@ extern uint32_t crc32c_le(uint32_t crc, unsigned char const *p, size_t len);
#include "xfs_cksum.h"
-#define timespec64 timespec
-
/*
* This mirrors the kernel include for xfs_buf.h - it's implicitly included in
* every files via a similar include in the kernel xfs_linux.h.
diff --git a/include/xfs_inode.h b/include/xfs_inode.h
index e03d1cb..ddd48be 100644
--- a/include/xfs_inode.h
+++ b/include/xfs_inode.h
@@ -32,15 +32,15 @@ struct xfs_dir_ops;
* metadata.
*/
struct inode {
- mode_t i_mode;
- uint32_t i_nlink;
- xfs_dev_t i_rdev; /* This actually holds xfs_dev_t */
- unsigned long i_state; /* Not actually used in userspace */
- uint32_t i_generation;
- uint64_t i_version;
- struct timespec i_atime;
- struct timespec i_mtime;
- struct timespec i_ctime;
+ mode_t i_mode;
+ uint32_t i_nlink;
+ xfs_dev_t i_rdev; /* This actually holds xfs_dev_t */
+ unsigned long i_state; /* Not actually used in userspace */
+ uint32_t i_generation;
+ uint64_t i_version;
+ struct timespec64 i_atime;
+ struct timespec64 i_mtime;
+ struct timespec64 i_ctime;
};
typedef struct xfs_inode {
diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
index 8232f89..b45d07e 100644
--- a/libxfs/libxfs_priv.h
+++ b/libxfs/libxfs_priv.h
@@ -62,8 +62,6 @@ extern kmem_zone_t *xfs_buf_zone;
extern kmem_zone_t *xfs_inode_zone;
extern kmem_zone_t *xfs_trans_zone;
-#define timespec64 timespec
-
/* CRC stuff, buffer API dependent on it */
#define crc32c(c,p,l) crc32c_le((c),(unsigned char const *)(p),(l))
diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index c8a3b12..fbc9031 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -686,6 +686,14 @@ struct xfs_extent_data {
#define XFS_IOC_CLONE_RANGE _IOW (0x94, 13, struct xfs_clone_args)
#define XFS_IOC_FILE_EXTENT_SAME _IOWR(0x94, 54, struct xfs_extent_data)
+/* 64-bit seconds counter that works independently of the C library time_t. */
+typedef long long int time64_t;
+
+struct timespec64 {
+ time64_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+
#ifndef HAVE_BBMACROS
/*
* Block I/O parameterization. A basic block (BB) is the lowest size of

@ -0,0 +1,53 @@
From c0e580154e1469f1bcef132b1a7585409f66e1e5 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 14:52:31 -0500
Subject: [PATCH] libxfs: refactor NSEC_PER_SEC
Clean up all the open-coded and duplicate definitions of time unit
conversion factors.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
NOTE: scrub is not present in rhel8, so that hunk is omitted
diff --git a/include/platform_defs.h.in b/include/platform_defs.h.in
index d111ec6..0b7214e 100644
--- a/include/platform_defs.h.in
+++ b/include/platform_defs.h.in
@@ -77,4 +77,7 @@ typedef unsigned short umode_t;
# define ASSERT(EX) ((void) 0)
#endif
+#define NSEC_PER_SEC (1000000000ULL)
+#define NSEC_PER_USEC (1000ULL)
+
#endif /* __XFS_PLATFORM_DEFS_H__ */
diff --git a/repair/dinode.c b/repair/dinode.c
index 77f78f1..8fa5f88 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -2216,7 +2216,7 @@ check_nsec(
struct xfs_timestamp *t,
int *dirty)
{
- if (be32_to_cpu(t->t_nsec) < 1000000000)
+ if (be32_to_cpu(t->t_nsec) < NSEC_PER_SEC)
return;
do_warn(
diff --git a/scrub/progress.c b/scrub/progress.c
index d0afe90..2058f59 100644
--- a/scrub/progress.c
+++ b/scrub/progress.c
@@ -110,7 +110,6 @@ progress_report(
fflush(pt.fp);
}
-#define NSEC_PER_SEC (1000000000)
static void *
progress_report_thread(void *arg)
{

@ -0,0 +1,139 @@
From 9eb0d6eb9066daa621e710139c8c8d50fedbabcf Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:27 -0500
Subject: [PATCH] mkfs: enable the inode btree counter feature
Teach mkfs how to enable the inode btree counter feature.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/man/man8/mkfs.xfs.8 b/man/man8/mkfs.xfs.8
index 9d6f315..45b150f 100644
--- a/man/man8/mkfs.xfs.8
+++ b/man/man8/mkfs.xfs.8
@@ -188,6 +188,21 @@ option set. When the option
.B \-m crc=0
is used, the free inode btree feature is not supported and is disabled.
.TP
+.BI inobtcount= value
+This option causes the filesystem to record the number of blocks used by
+the inode btree and the free inode btree.
+This can be used to reduce mount times when the free inode btree is enabled.
+.IP
+By default,
+.B mkfs.xfs
+will not enable this option.
+This feature is only available for filesystems created with the (default)
+.B \-m finobt=1
+option set.
+When the option
+.B \-m finobt=0
+is used, the inode btree counter feature is not supported and is disabled.
+.TP
.BI uuid= value
Use the given value as the filesystem UUID for the newly created filesystem.
The default is to generate a random UUID.
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 16819d8..87f15f4 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -117,6 +117,7 @@ enum {
M_UUID,
M_RMAPBT,
M_REFLINK,
+ M_INOBTCNT,
M_MAX_OPTS,
};
@@ -651,6 +652,7 @@ static struct opt_params mopts = {
[M_UUID] = "uuid",
[M_RMAPBT] = "rmapbt",
[M_REFLINK] = "reflink",
+ [M_INOBTCNT] = "inobtcount",
},
.subopt_params = {
{ .index = M_CRC,
@@ -681,6 +683,12 @@ static struct opt_params mopts = {
.maxval = 1,
.defaultval = 1,
},
+ { .index = M_INOBTCNT,
+ .conflicts = { { NULL, LAST_CONFLICT } },
+ .minval = 0,
+ .maxval = 1,
+ .defaultval = 1,
+ },
},
};
@@ -731,6 +739,7 @@ struct sb_feat_args {
bool spinodes; /* XFS_SB_FEAT_INCOMPAT_SPINODES */
bool rmapbt; /* XFS_SB_FEAT_RO_COMPAT_RMAPBT */
bool reflink; /* XFS_SB_FEAT_RO_COMPAT_REFLINK */
+ bool inobtcnt; /* XFS_SB_FEAT_RO_COMPAT_INOBTCNT */
bool nodalign;
bool nortalign;
};
@@ -853,7 +862,8 @@ usage( void )
{
fprintf(stderr, _("Usage: %s\n\
/* blocksize */ [-b size=num]\n\
-/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
+/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,\n\
+ inobtcnt=0|1]\n\
/* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
(sunit=value,swidth=value|su=num,sw=num|noalign),\n\
sectsize=num\n\
@@ -1607,6 +1617,9 @@ meta_opts_parser(
case M_REFLINK:
cli->sb_feat.reflink = getnum(value, opts, subopt);
break;
+ case M_INOBTCNT:
+ cli->sb_feat.inobtcnt = getnum(value, opts, subopt);
+ break;
default:
return -EINVAL;
}
@@ -2037,6 +2050,22 @@ _("reflink not supported without CRC support\n"));
usage();
}
cli->sb_feat.reflink = false;
+
+ if (cli->sb_feat.inobtcnt && cli_opt_set(&mopts, M_INOBTCNT)) {
+ fprintf(stderr,
+_("inode btree counters not supported without CRC support\n"));
+ usage();
+ }
+ cli->sb_feat.inobtcnt = false;
+ }
+
+ if (!cli->sb_feat.finobt) {
+ if (cli->sb_feat.inobtcnt && cli_opt_set(&mopts, M_INOBTCNT)) {
+ fprintf(stderr,
+_("inode btree counters not supported without finobt support\n"));
+ usage();
+ }
+ cli->sb_feat.inobtcnt = false;
}
if ((cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) &&
@@ -3002,6 +3031,8 @@ sb_set_features(
sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT;
if (fp->reflink)
sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK;
+ if (fp->inobtcnt)
+ sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_INOBTCNT;
/*
* Sparse inode chunk support has two main inode alignment requirements.
@@ -3917,6 +3948,7 @@ main(
.spinodes = true,
.rmapbt = false,
.reflink = true,
+ .inobtcnt = false,
.parent_pointers = false,
.nodalign = false,
.nortalign = false,

@ -0,0 +1,130 @@
From e9601810beb7d5b36a5fbd03c593cf63f685bfff Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:28 -0500
Subject: [PATCH] mkfs: format bigtime filesystems
Allow formatting with large timestamps.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/man/man8/mkfs.xfs.8 b/man/man8/mkfs.xfs.8
index 45b150f..0a115cb 100644
--- a/man/man8/mkfs.xfs.8
+++ b/man/man8/mkfs.xfs.8
@@ -154,6 +154,22 @@ valid
are:
.RS 1.2i
.TP
+.BI bigtime= value
+This option enables filesystems that can handle inode timestamps from December
+1901 to July 2486, and quota timer expirations from January 1970 to July 2486.
+The value is either 0 to disable the feature, or 1 to enable large timestamps.
+.IP
+If this feature is not enabled, the filesystem can only handle timestamps from
+December 1901 to January 2038, and quota timers from January 1970 to February
+2106.
+.IP
+By default,
+.B mkfs.xfs
+will not enable this feature.
+If the option
+.B \-m crc=0
+is used, the large timestamp feature is not supported and is disabled.
+.TP
.BI crc= value
This is used to create a filesystem which maintains and checks CRC information
in all metadata objects on disk. The value is either 0 to disable the feature,
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 87f15f4..b74a00b 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -118,6 +118,7 @@ enum {
M_RMAPBT,
M_REFLINK,
M_INOBTCNT,
+ M_BIGTIME,
M_MAX_OPTS,
};
@@ -653,6 +654,7 @@ static struct opt_params mopts = {
[M_RMAPBT] = "rmapbt",
[M_REFLINK] = "reflink",
[M_INOBTCNT] = "inobtcount",
+ [M_BIGTIME] = "bigtime",
},
.subopt_params = {
{ .index = M_CRC,
@@ -689,6 +691,12 @@ static struct opt_params mopts = {
.maxval = 1,
.defaultval = 1,
},
+ { .index = M_BIGTIME,
+ .conflicts = { { NULL, LAST_CONFLICT } },
+ .minval = 0,
+ .maxval = 1,
+ .defaultval = 1,
+ },
},
};
@@ -740,6 +748,7 @@ struct sb_feat_args {
bool rmapbt; /* XFS_SB_FEAT_RO_COMPAT_RMAPBT */
bool reflink; /* XFS_SB_FEAT_RO_COMPAT_REFLINK */
bool inobtcnt; /* XFS_SB_FEAT_RO_COMPAT_INOBTCNT */
+ bool bigtime; /* XFS_SB_FEAT_INCOMPAT_BIGTIME */
bool nodalign;
bool nortalign;
};
@@ -863,7 +872,7 @@ usage( void )
fprintf(stderr, _("Usage: %s\n\
/* blocksize */ [-b size=num]\n\
/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,\n\
- inobtcnt=0|1]\n\
+ inobtcnt=0|1,bigtime=0|1]\n\
/* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
(sunit=value,swidth=value|su=num,sw=num|noalign),\n\
sectsize=num\n\
@@ -1620,6 +1629,9 @@ meta_opts_parser(
case M_INOBTCNT:
cli->sb_feat.inobtcnt = getnum(value, opts, subopt);
break;
+ case M_BIGTIME:
+ cli->sb_feat.bigtime = getnum(value, opts, subopt);
+ break;
default:
return -EINVAL;
}
@@ -2057,6 +2069,13 @@ _("inode btree counters not supported without CRC support\n"));
usage();
}
cli->sb_feat.inobtcnt = false;
+
+ if (cli->sb_feat.bigtime && cli_opt_set(&mopts, M_BIGTIME)) {
+ fprintf(stderr,
+_("timestamps later than 2038 not supported without CRC support\n"));
+ usage();
+ }
+ cli->sb_feat.bigtime = false;
}
if (!cli->sb_feat.finobt) {
@@ -3033,6 +3052,8 @@ sb_set_features(
sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK;
if (fp->inobtcnt)
sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_INOBTCNT;
+ if (fp->bigtime)
+ sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_BIGTIME;
/*
* Sparse inode chunk support has two main inode alignment requirements.
@@ -3952,6 +3973,7 @@ main(
.parent_pointers = false,
.nodalign = false,
.nortalign = false,
+ .bigtime = false,
},
};

@ -0,0 +1,32 @@
From cac80700d88a32c1835cb37f982e98ddd73021e5 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:28 -0500
Subject: [PATCH] xfs: enable big timestamps
Source kernel commit: 29887a22713192509cfc6068ea3b200cdb8856da
Enable the big timestamp feature.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Gao Xiang <hsiangkao@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 4848de8..722c9de 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -471,7 +471,8 @@ xfs_sb_has_ro_compat_feature(
#define XFS_SB_FEAT_INCOMPAT_ALL \
(XFS_SB_FEAT_INCOMPAT_FTYPE| \
XFS_SB_FEAT_INCOMPAT_SPINODES| \
- XFS_SB_FEAT_INCOMPAT_META_UUID)
+ XFS_SB_FEAT_INCOMPAT_META_UUID| \
+ XFS_SB_FEAT_INCOMPAT_BIGTIME)
#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL
static inline bool

@ -0,0 +1,28 @@
From 46da703382fa31bb02049a4131602f8a40002dbb Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:27 -0500
Subject: [PATCH] xfs: enable new inode btree counters feature
Source kernel commit: b896a39faa5a2f97dadfb347928466afb12cc63a
Enable the new inode btree counters feature.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 9ba65e5..4848de8 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -453,7 +453,8 @@ xfs_sb_has_compat_feature(
#define XFS_SB_FEAT_RO_COMPAT_ALL \
(XFS_SB_FEAT_RO_COMPAT_FINOBT | \
XFS_SB_FEAT_RO_COMPAT_RMAPBT | \
- XFS_SB_FEAT_RO_COMPAT_REFLINK)
+ XFS_SB_FEAT_RO_COMPAT_REFLINK| \
+ XFS_SB_FEAT_RO_COMPAT_INOBTCNT)
#define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL
static inline bool
xfs_sb_has_ro_compat_feature(

@ -0,0 +1,74 @@
From 18e3b8c234fac67c6c96e9ff34f0ab4598220fa1 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 15:11:09 -0500
Subject: [PATCH] xfs: explicitly define inode timestamp range
Source kernel commit: 876fdc7c4f366a709ac272ef3336ae7dce58f2af
Formally define the inode timestamp ranges that existing filesystems
support, and switch the vfs timetamp ranges to use it.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Gao Xiang <hsiangkao@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
NOTE: we hvae no xfs_compat.h so S32_MAX etc went in xfs_fs.h
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 7f7b03a..5712aa0 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -839,11 +839,33 @@ typedef struct xfs_agfl {
ASSERT(xfs_daddr_to_agno(mp, d) == \
xfs_daddr_to_agno(mp, (d) + (len) - 1)))
+/*
+ * XFS Timestamps
+ * ==============
+ *
+ * Traditional ondisk inode timestamps consist of signed 32-bit counters for
+ * seconds and nanoseconds; time zero is the Unix epoch, Jan 1 00:00:00 UTC
+ * 1970, which means that the timestamp epoch is the same as the Unix epoch.
+ * Therefore, the ondisk min and max defined here can be used directly to
+ * constrain the incore timestamps on a Unix system.
+ */
typedef struct xfs_timestamp {
__be32 t_sec; /* timestamp seconds */
__be32 t_nsec; /* timestamp nanoseconds */
} xfs_timestamp_t;
+/*
+ * Smallest possible ondisk seconds value with traditional timestamps. This
+ * corresponds exactly with the incore timestamp Dec 13 20:45:52 UTC 1901.
+ */
+#define XFS_LEGACY_TIME_MIN ((int64_t)S32_MIN)
+
+/*
+ * Largest possible ondisk seconds value with traditional timestamps. This
+ * corresponds exactly with the incore timestamp Jan 19 03:14:07 UTC 2038.
+ */
+#define XFS_LEGACY_TIME_MAX ((int64_t)S32_MAX)
+
/*
* On-disk inode structure.
*
diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index fbc9031..4fa9852 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -694,6 +694,10 @@ struct timespec64 {
long tv_nsec; /* nanoseconds */
};
+#define U32_MAX ((uint32_t)~0U)
+#define S32_MAX ((int32_t)(U32_MAX >> 1))
+#define S32_MIN ((int32_t)(-S32_MAX - 1))
+
#ifndef HAVE_BBMACROS
/*
* Block I/O parameterization. A basic block (BB) is the lowest size of

@ -0,0 +1,94 @@
From acaa814953273827f380262ba900f0d50a95bee2 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 15:13:50 -0500
Subject: [PATCH] xfs: move xfs_log_dinode_to_disk to the log recovery code
Source kernel commit: 88947ea0ba713c9b74b212755b3b58242f0e7a56
Move this function to xfs_inode_item_recover.c since there's only one
caller of it.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Gao Xiang <hsiangkao@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
index 975f097..f80ce10 100644
--- a/libxfs/xfs_inode_buf.c
+++ b/libxfs/xfs_inode_buf.c
@@ -318,58 +318,6 @@ xfs_inode_to_disk(
}
}
-void
-xfs_log_dinode_to_disk(
- struct xfs_log_dinode *from,
- struct xfs_dinode *to)
-{
- to->di_magic = cpu_to_be16(from->di_magic);
- to->di_mode = cpu_to_be16(from->di_mode);
- to->di_version = from->di_version;
- to->di_format = from->di_format;
- to->di_onlink = 0;
- to->di_uid = cpu_to_be32(from->di_uid);
- to->di_gid = cpu_to_be32(from->di_gid);
- to->di_nlink = cpu_to_be32(from->di_nlink);
- to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
- to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
- memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
-
- to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec);
- to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec);
- to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec);
- to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec);
- to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec);
- to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec);
-
- to->di_size = cpu_to_be64(from->di_size);
- to->di_nblocks = cpu_to_be64(from->di_nblocks);
- to->di_extsize = cpu_to_be32(from->di_extsize);
- to->di_nextents = cpu_to_be32(from->di_nextents);
- to->di_anextents = cpu_to_be16(from->di_anextents);
- to->di_forkoff = from->di_forkoff;
- to->di_aformat = from->di_aformat;
- to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
- to->di_dmstate = cpu_to_be16(from->di_dmstate);
- to->di_flags = cpu_to_be16(from->di_flags);
- to->di_gen = cpu_to_be32(from->di_gen);
-
- if (from->di_version == 3) {
- to->di_changecount = cpu_to_be64(from->di_changecount);
- to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec);
- to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec);
- to->di_flags2 = cpu_to_be64(from->di_flags2);
- to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
- to->di_ino = cpu_to_be64(from->di_ino);
- to->di_lsn = cpu_to_be64(from->di_lsn);
- memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
- uuid_copy(&to->di_uuid, &from->di_uuid);
- to->di_flushiter = 0;
- } else {
- to->di_flushiter = cpu_to_be16(from->di_flushiter);
- }
-}
-
static xfs_failaddr_t
xfs_dinode_verify_fork(
struct xfs_dinode *dip,
diff --git a/libxfs/xfs_inode_buf.h b/libxfs/xfs_inode_buf.h
index c9ac69c..0343368 100644
--- a/libxfs/xfs_inode_buf.h
+++ b/libxfs/xfs_inode_buf.h
@@ -59,8 +59,6 @@ void xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *);
void xfs_inode_to_disk(struct xfs_inode *ip, struct xfs_dinode *to,
xfs_lsn_t lsn);
void xfs_inode_from_disk(struct xfs_inode *ip, struct xfs_dinode *from);
-void xfs_log_dinode_to_disk(struct xfs_log_dinode *from,
- struct xfs_dinode *to);
bool xfs_dinode_good_version(struct xfs_mount *mp, __u8 version);

@ -0,0 +1,101 @@
From fc3e21db4a30d0d81158938cabba0fb59fc57ad8 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Wed, 11 Nov 2020 13:48:47 -0500
Subject: [PATCH] xfs: redefine xfs_ictimestamp_t
Source kernel commit: 30e05599219f3c15bd5f24190af0e33cdb4a00e5
Redefine xfs_ictimestamp_t as a uint64_t typedef in preparation for the
bigtime functionality. Preserve the legacy structure format so that we
can let the compiler take care of the masking and shifting.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Gao Xiang <hsiangkao@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_log_format.h b/libxfs/xfs_log_format.h
index e5f97c6..8dc0df0 100644
--- a/libxfs/xfs_log_format.h
+++ b/libxfs/xfs_log_format.h
@@ -368,10 +368,13 @@ static inline int xfs_ilog_fdata(int w)
* directly mirrors the xfs_dinode structure as it must contain all the same
* information.
*/
-typedef struct xfs_ictimestamp {
+typedef uint64_t xfs_ictimestamp_t;
+
+/* Legacy timestamp encoding format. */
+struct xfs_legacy_ictimestamp {
int32_t t_sec; /* timestamp seconds */
int32_t t_nsec; /* timestamp nanoseconds */
-} xfs_ictimestamp_t;
+};
/*
* Define the format of the inode core that is logged. This structure must be
diff --git a/logprint/log_misc.c b/logprint/log_misc.c
index c325f04..4fad82b 100644
--- a/logprint/log_misc.c
+++ b/logprint/log_misc.c
@@ -446,8 +446,10 @@ xlog_print_trans_inode_core(
(int)ip->di_format);
printf(_("nlink %hd uid %d gid %d\n"),
ip->di_nlink, ip->di_uid, ip->di_gid);
- printf(_("atime 0x%x mtime 0x%x ctime 0x%x\n"),
- ip->di_atime.t_sec, ip->di_mtime.t_sec, ip->di_ctime.t_sec);
+ printf(_("atime 0x%llx mtime 0x%llx ctime 0x%llx\n"),
+ xlog_extract_dinode_ts(ip->di_atime),
+ xlog_extract_dinode_ts(ip->di_mtime),
+ xlog_extract_dinode_ts(ip->di_ctime));
printf(_("size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n"),
(unsigned long long)ip->di_size, (unsigned long long)ip->di_nblocks,
ip->di_extsize, ip->di_nextents);
@@ -739,6 +741,16 @@ xlog_print_trans_icreate(
******************************************************************************
*/
+time64_t
+xlog_extract_dinode_ts(
+ const xfs_ictimestamp_t its)
+{
+ struct xfs_legacy_ictimestamp *lits;
+
+ lits = (struct xfs_legacy_ictimestamp *)&its;
+ return (time64_t)lits->t_sec;
+}
+
void
xlog_print_lseek(struct xlog *log, int fd, xfs_daddr_t blkno, int whence)
{
diff --git a/logprint/log_print_all.c b/logprint/log_print_all.c
index eafffe2..3ca01b1 100644
--- a/logprint/log_print_all.c
+++ b/logprint/log_print_all.c
@@ -249,8 +249,10 @@ xlog_recover_print_inode_core(
printf(_(" uid:%d gid:%d nlink:%d projid:0x%04x%04x\n"),
di->di_uid, di->di_gid, di->di_nlink,
di->di_projid_hi, di->di_projid_lo);
- printf(_(" atime:%d mtime:%d ctime:%d\n"),
- di->di_atime.t_sec, di->di_mtime.t_sec, di->di_ctime.t_sec);
+ printf(_(" atime:%lld mtime:%lld ctime:%lld\n"),
+ xlog_extract_dinode_ts(di->di_atime),
+ xlog_extract_dinode_ts(di->di_mtime),
+ xlog_extract_dinode_ts(di->di_ctime));
printf(_(" flushiter:%d\n"), di->di_flushiter);
printf(_(" size:0x%llx nblks:0x%llx exsize:%d "
"nextents:%d anextents:%d\n"), (unsigned long long)
diff --git a/logprint/logprint.h b/logprint/logprint.h
index 98ac0d4..0061d5a 100644
--- a/logprint/logprint.h
+++ b/logprint/logprint.h
@@ -18,6 +18,7 @@ extern int print_no_data;
extern int print_no_print;
/* exports */
+extern time64_t xlog_extract_dinode_ts(const xfs_ictimestamp_t);
extern void xlog_print_lseek(struct xlog *, int, xfs_daddr_t, int);
extern void xfs_log_copy(struct xlog *, int, char *);

@ -0,0 +1,196 @@
From a252aadfc977473e0851acf0d529c930c6e8e181 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 16:29:40 -0500
Subject: [PATCH] xfs: redefine xfs_timestamp_t
Source kernel commit: 5a0bb066f60fa02f453d7721844eae59f505c06e
Redefine xfs_timestamp_t as a __be64 typedef in preparation for the
bigtime functionality. Preserve the legacy structure format so that we
can let the compiler take care of masking and shifting.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Gao Xiang <hsiangkao@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/db/field.c b/db/field.c
index 66fa37e..4a45c66 100644
--- a/db/field.c
+++ b/db/field.c
@@ -350,7 +350,7 @@ const ftattr_t ftattrtab[] = {
{ FLDT_TIME, "time", fp_time, NULL, SI(bitsz(int32_t)), FTARG_SIGNED,
NULL, NULL },
{ FLDT_TIMESTAMP, "timestamp", NULL, (char *)timestamp_flds,
- SI(bitsz(xfs_timestamp_t)), 0, NULL, timestamp_flds },
+ SI(bitsz(struct xfs_legacy_timestamp)), 0, NULL, timestamp_flds },
{ FLDT_UINT1, "uint1", fp_num, "%u", SI(1), 0, NULL, NULL },
{ FLDT_UINT16D, "uint16d", fp_num, "%u", SI(bitsz(uint16_t)), 0, NULL,
NULL },
diff --git a/db/inode.c b/db/inode.c
index 697f7fe..b308538 100644
--- a/db/inode.c
+++ b/db/inode.c
@@ -176,7 +176,7 @@ const field_t inode_v3_flds[] = {
};
-#define TOFF(f) bitize(offsetof(xfs_timestamp_t, t_ ## f))
+#define TOFF(f) bitize(offsetof(struct xfs_legacy_timestamp, t_ ## f))
const field_t timestamp_flds[] = {
{ "sec", FLDT_TIME, OI(TOFF(sec)), C1, 0, TYP_NONE },
{ "nsec", FLDT_NSEC, OI(TOFF(nsec)), C1, 0, TYP_NONE },
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 8858341..371f5cd 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -847,12 +847,16 @@ typedef struct xfs_agfl {
* seconds and nanoseconds; time zero is the Unix epoch, Jan 1 00:00:00 UTC
* 1970, which means that the timestamp epoch is the same as the Unix epoch.
* Therefore, the ondisk min and max defined here can be used directly to
- * constrain the incore timestamps on a Unix system.
+ * constrain the incore timestamps on a Unix system. Note that we actually
+ * encode a __be64 value on disk.
*/
-typedef struct xfs_timestamp {
+typedef __be64 xfs_timestamp_t;
+
+/* Legacy timestamp encoding format. */
+struct xfs_legacy_timestamp {
__be32 t_sec; /* timestamp seconds */
__be32 t_nsec; /* timestamp nanoseconds */
-} xfs_timestamp_t;
+};
/*
* Smallest possible ondisk seconds value with traditional timestamps. This
diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
index f80ce10..d8831a1 100644
--- a/libxfs/xfs_inode_buf.c
+++ b/libxfs/xfs_inode_buf.c
@@ -195,6 +195,21 @@ xfs_imap_to_bp(
return 0;
}
+/* Convert an ondisk timestamp to an incore timestamp. */
+struct timespec64
+xfs_inode_from_disk_ts(
+ const xfs_timestamp_t ts)
+{
+ struct timespec64 tv;
+ struct xfs_legacy_timestamp *lts;
+
+ lts = (struct xfs_legacy_timestamp *)&ts;
+ tv.tv_sec = (int)be32_to_cpu(lts->t_sec);
+ tv.tv_nsec = (int)be32_to_cpu(lts->t_nsec);
+
+ return tv;
+}
+
void
xfs_inode_from_disk(
struct xfs_inode *ip,
@@ -231,12 +246,10 @@ xfs_inode_from_disk(
* a time before epoch is converted to a time long after epoch
* on 64 bit systems.
*/
- inode->i_atime.tv_sec = (int)be32_to_cpu(from->di_atime.t_sec);
- inode->i_atime.tv_nsec = (int)be32_to_cpu(from->di_atime.t_nsec);
- inode->i_mtime.tv_sec = (int)be32_to_cpu(from->di_mtime.t_sec);
- inode->i_mtime.tv_nsec = (int)be32_to_cpu(from->di_mtime.t_nsec);
- inode->i_ctime.tv_sec = (int)be32_to_cpu(from->di_ctime.t_sec);
- inode->i_ctime.tv_nsec = (int)be32_to_cpu(from->di_ctime.t_nsec);
+ inode->i_atime = xfs_inode_from_disk_ts(from->di_atime);
+ inode->i_mtime = xfs_inode_from_disk_ts(from->di_mtime);
+ inode->i_ctime = xfs_inode_from_disk_ts(from->di_ctime);
+
inode->i_generation = be32_to_cpu(from->di_gen);
inode->i_mode = be16_to_cpu(from->di_mode);
@@ -254,13 +267,27 @@ xfs_inode_from_disk(
if (to->di_version == 3) {
inode_set_iversion_queried(inode,
be64_to_cpu(from->di_changecount));
- to->di_crtime.tv_sec = be32_to_cpu(from->di_crtime.t_sec);
- to->di_crtime.tv_nsec = be32_to_cpu(from->di_crtime.t_nsec);
+ to->di_crtime = xfs_inode_from_disk_ts(from->di_crtime);
to->di_flags2 = be64_to_cpu(from->di_flags2);
to->di_cowextsize = be32_to_cpu(from->di_cowextsize);
}
}
+/* Convert an incore timestamp to an ondisk timestamp. */
+static inline xfs_timestamp_t
+xfs_inode_to_disk_ts(
+ const struct timespec64 tv)
+{
+ struct xfs_legacy_timestamp *lts;
+ xfs_timestamp_t ts;
+
+ lts = (struct xfs_legacy_timestamp *)&ts;
+ lts->t_sec = cpu_to_be32(tv.tv_sec);
+ lts->t_nsec = cpu_to_be32(tv.tv_nsec);
+
+ return ts;
+}
+
void
xfs_inode_to_disk(
struct xfs_inode *ip,
@@ -281,12 +308,9 @@ xfs_inode_to_disk(
to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
memset(to->di_pad, 0, sizeof(to->di_pad));
- to->di_atime.t_sec = cpu_to_be32(inode->i_atime.tv_sec);
- to->di_atime.t_nsec = cpu_to_be32(inode->i_atime.tv_nsec);
- to->di_mtime.t_sec = cpu_to_be32(inode->i_mtime.tv_sec);
- to->di_mtime.t_nsec = cpu_to_be32(inode->i_mtime.tv_nsec);
- to->di_ctime.t_sec = cpu_to_be32(inode->i_ctime.tv_sec);
- to->di_ctime.t_nsec = cpu_to_be32(inode->i_ctime.tv_nsec);
+ to->di_atime = xfs_inode_to_disk_ts(inode->i_atime);
+ to->di_mtime = xfs_inode_to_disk_ts(inode->i_mtime);
+ to->di_ctime = xfs_inode_to_disk_ts(inode->i_ctime);
to->di_nlink = cpu_to_be32(inode->i_nlink);
to->di_gen = cpu_to_be32(inode->i_generation);
to->di_mode = cpu_to_be16(inode->i_mode);
@@ -304,8 +328,7 @@ xfs_inode_to_disk(
if (from->di_version == 3) {
to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
- to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.tv_sec);
- to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.tv_nsec);
+ to->di_crtime = xfs_inode_to_disk_ts(from->di_crtime);
to->di_flags2 = cpu_to_be64(from->di_flags2);
to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
to->di_ino = cpu_to_be64(ip->i_ino);
diff --git a/libxfs/xfs_inode_buf.h b/libxfs/xfs_inode_buf.h
index 0343368..6147f42 100644
--- a/libxfs/xfs_inode_buf.h
+++ b/libxfs/xfs_inode_buf.h
@@ -76,4 +76,6 @@ xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
uint32_t cowextsize, uint16_t mode, uint16_t flags,
uint64_t flags2);
+struct timespec64 xfs_inode_from_disk_ts(const xfs_timestamp_t ts);
+
#endif /* __XFS_INODE_BUF_H__ */
diff --git a/repair/dinode.c b/repair/dinode.c
index 8fa5f88..0c40f2a 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -2213,9 +2213,12 @@ static void
check_nsec(
const char *name,
xfs_ino_t lino,
- struct xfs_timestamp *t,
+ xfs_timestamp_t *ts,
int *dirty)
{
+ struct xfs_legacy_timestamp *t;
+
+ t = (struct xfs_legacy_timestamp *)ts;
if (be32_to_cpu(t->t_nsec) < NSEC_PER_SEC)
return;

@ -0,0 +1,49 @@
From abc0f20536e3bc1505f575f452c55585c34f6e06 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 15:11:43 -0500
Subject: [PATCH] xfs: refactor default quota grace period setting code
Source kernel commit: ccc8e771aa7a80eb047fc263780816ca76dd02a6
Refactor the code that sets the default quota grace period into a helper
function so that we can override the ondisk behavior later.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index c67bd61..8858341 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1190,6 +1190,11 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
* been reached, and therefore no expiration has been set. Therefore, the
* ondisk min and max defined here can be used directly to constrain the incore
* quota expiration timestamps on a Unix system.
+ *
+ * The grace period for each quota type is stored in the root dquot (id = 0)
+ * and is applied to a non-root dquot when it exceeds the soft or hard limits.
+ * The length of quota grace periods are unsigned 32-bit quantities measured in
+ * units of seconds. A value of zero means to use the default period.
*/
/*
@@ -1204,6 +1209,14 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
*/
#define XFS_DQ_LEGACY_EXPIRY_MAX ((int64_t)U32_MAX)
+/*
+ * Default quota grace periods, ranging from zero (use the compiled defaults)
+ * to ~136 years. These are applied to a non-root dquot that has exceeded
+ * either limit.
+ */
+#define XFS_DQ_GRACE_MIN ((int64_t)0)
+#define XFS_DQ_GRACE_MAX ((int64_t)U32_MAX)
+
/*
* This is the main portion of the on-disk representation of quota
* information for a user. This is the q_core of the xfs_dquot_t that

@ -0,0 +1,54 @@
From 94c5482a7e0cbb6fd289745a4b5f49a133a4f5e8 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 15:11:09 -0500
Subject: [PATCH] xfs: refactor quota expiration timer modification
Source kernel commit: 11d8a9190275855f79d62093d789e962cc7228fb
Define explicit limits on the range of quota grace period expiration
timeouts and refactor the code that modifies the timeouts into helpers
that clamp the values appropriately. Note that we'll refactor the
default grace period timer separately.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 5712aa0..c67bd61 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1180,6 +1180,30 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
#define XFS_DQUOT_MAGIC 0x4451 /* 'DQ' */
#define XFS_DQUOT_VERSION (uint8_t)0x01 /* latest version number */
+/*
+ * XFS Quota Timers
+ * ================
+ *
+ * Traditional quota grace period expiration timers are an unsigned 32-bit
+ * seconds counter; time zero is the Unix epoch, Jan 1 00:00:01 UTC 1970.
+ * Note that an expiration value of zero means that the quota limit has not
+ * been reached, and therefore no expiration has been set. Therefore, the
+ * ondisk min and max defined here can be used directly to constrain the incore
+ * quota expiration timestamps on a Unix system.
+ */
+
+/*
+ * Smallest possible ondisk quota expiration value with traditional timestamps.
+ * This corresponds exactly with the incore expiration Jan 1 00:00:01 UTC 1970.
+ */
+#define XFS_DQ_LEGACY_EXPIRY_MIN ((int64_t)1)
+
+/*
+ * Largest possible ondisk quota expiration value with traditional timestamps.
+ * This corresponds exactly with the incore expiration Feb 7 06:28:15 UTC 2106.
+ */
+#define XFS_DQ_LEGACY_EXPIRY_MAX ((int64_t)U32_MAX)
+
/*
* This is the main portion of the on-disk representation of quota
* information for a user. This is the q_core of the xfs_dquot_t that

@ -0,0 +1,58 @@
From 68879320b482e73e6ce202a8e680c8ab7e6a2af4 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 15:12:50 -0500
Subject: [PATCH] xfs: refactor quota timestamp coding
Source kernel commit: 9f99c8fe551a056c0929dff13cbce62b6b150156
Refactor quota timestamp encoding and decoding into helper functions so
that we can add extra behavior in the next patch.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_dquot_buf.c b/libxfs/xfs_dquot_buf.c
index 324f528..963f8ea 100644
--- a/libxfs/xfs_dquot_buf.c
+++ b/libxfs/xfs_dquot_buf.c
@@ -286,3 +286,21 @@ const struct xfs_buf_ops xfs_dquot_buf_ra_ops = {
.verify_read = xfs_dquot_buf_readahead_verify,
.verify_write = xfs_dquot_buf_write_verify,
};
+
+/* Convert an on-disk timer value into an incore timer value. */
+time64_t
+xfs_dquot_from_disk_ts(
+ struct xfs_disk_dquot *ddq,
+ __be32 dtimer)
+{
+ return be32_to_cpu(dtimer);
+}
+
+/* Convert an incore timer value into an on-disk timer value. */
+__be32
+xfs_dquot_to_disk_ts(
+ struct xfs_dquot *dqp,
+ time64_t timer)
+{
+ return cpu_to_be32(timer);
+}
diff --git a/libxfs/xfs_quota_defs.h b/libxfs/xfs_quota_defs.h
index c69dba4..2f61cd3 100644
--- a/libxfs/xfs_quota_defs.h
+++ b/libxfs/xfs_quota_defs.h
@@ -149,4 +149,9 @@ extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
extern int xfs_dqblk_repair(struct xfs_mount *mp, struct xfs_dqblk *dqb,
xfs_dqid_t id, uint type);
+struct xfs_dquot;
+time64_t xfs_dquot_from_disk_ts(struct xfs_disk_dquot *ddq,
+ __be32 dtimer);
+__be32 xfs_dquot_to_disk_ts(struct xfs_dquot *ddq, time64_t timer);
+
#endif /* __XFS_QUOTA_H__ */

@ -0,0 +1,159 @@
From 177c81e25b763c90f9815b1f4055d9d5c515a845 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 15:11:09 -0500
Subject: [PATCH] xfs: store inode btree block counts in AGI header
Source kernel commit: 2a39946c984464e4aac82c556ba9915589be7323
Add a btree block usage counters for both inode btrees to the AGI header
so that we don't have to walk the entire finobt at mount time to create
the per-AG reservations.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
NOTE: kernel routines are not used to initialize AGIs in this
version, so I added to the open-coded function in xfs_mkfs.c
diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index a7d1a0d..850d6e3 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -258,6 +258,11 @@ xfs_agiblock_init(
}
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
+ if (xfs_sb_version_hasinobtcounts(&mp->m_sb)) {
+ agi->agi_iblocks = cpu_to_be32(1);
+ if (xfs_sb_version_hasfinobt(&mp->m_sb))
+ agi->agi_fblocks = cpu_to_be32(1);
+ }
}
typedef void (*aghdr_init_work_f)(struct xfs_mount *mp, struct xfs_buf *bp,
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 23eca3b..7f7b03a 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -449,6 +449,7 @@ xfs_sb_has_compat_feature(
#define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */
#define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */
#define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */
+#define XFS_SB_FEAT_RO_COMPAT_INOBTCNT (1 << 3) /* inobt block counts */
#define XFS_SB_FEAT_RO_COMPAT_ALL \
(XFS_SB_FEAT_RO_COMPAT_FINOBT | \
XFS_SB_FEAT_RO_COMPAT_RMAPBT | \
@@ -546,6 +547,17 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
(sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK);
}
+/*
+ * Inode btree block counter. We record the number of inobt and finobt blocks
+ * in the AGI header so that we can skip the finobt walk at mount time when
+ * setting up per-AG reservations.
+ */
+static inline bool xfs_sb_version_hasinobtcounts(struct xfs_sb *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
+ (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_INOBTCNT);
+}
+
/*
* end of superblock version macros
*/
@@ -750,6 +762,9 @@ typedef struct xfs_agi {
__be32 agi_free_root; /* root of the free inode btree */
__be32 agi_free_level;/* levels in free inode btree */
+ __be32 agi_iblocks; /* inobt blocks used */
+ __be32 agi_fblocks; /* finobt blocks used */
+
/* structure must be padded to 64 bit alignment */
} xfs_agi_t;
@@ -770,7 +785,8 @@ typedef struct xfs_agi {
#define XFS_AGI_ALL_BITS_R1 ((1 << XFS_AGI_NUM_BITS_R1) - 1)
#define XFS_AGI_FREE_ROOT (1 << 11)
#define XFS_AGI_FREE_LEVEL (1 << 12)
-#define XFS_AGI_NUM_BITS_R2 13
+#define XFS_AGI_IBLOCKS (1 << 13) /* both inobt/finobt block counters */
+#define XFS_AGI_NUM_BITS_R2 14
/* disk block (xfs_daddr_t) in the AG */
#define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index a600c03..9d380f9 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -2451,6 +2451,7 @@ xfs_ialloc_log_agi(
offsetof(xfs_agi_t, agi_unlinked),
offsetof(xfs_agi_t, agi_free_root),
offsetof(xfs_agi_t, agi_free_level),
+ offsetof(xfs_agi_t, agi_iblocks),
sizeof(xfs_agi_t)
};
#ifdef DEBUG
diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
index 716a81f..9db87e9 100644
--- a/libxfs/xfs_ialloc_btree.c
+++ b/libxfs/xfs_ialloc_btree.c
@@ -68,6 +68,25 @@ xfs_finobt_set_root(
XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL);
}
+/* Update the inode btree block counter for this btree. */
+static inline void
+xfs_inobt_mod_blockcount(
+ struct xfs_btree_cur *cur,
+ int howmuch)
+{
+ struct xfs_buf *agbp = cur->bc_private.a.agbp;
+ struct xfs_agi *agi = agbp->b_addr;
+
+ if (!xfs_sb_version_hasinobtcounts(&cur->bc_mp->m_sb))
+ return;
+
+ if (cur->bc_btnum == XFS_BTNUM_FINO)
+ be32_add_cpu(&agi->agi_fblocks, howmuch);
+ else if (cur->bc_btnum == XFS_BTNUM_INO)
+ be32_add_cpu(&agi->agi_iblocks, howmuch);
+ xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_IBLOCKS);
+}
+
STATIC int
__xfs_inobt_alloc_block(
struct xfs_btree_cur *cur,
@@ -103,6 +122,7 @@ __xfs_inobt_alloc_block(
new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno));
*stat = 1;
+ xfs_inobt_mod_blockcount(cur, 1);
return 0;
}
@@ -135,6 +155,7 @@ __xfs_inobt_free_block(
struct xfs_buf *bp,
enum xfs_ag_resv_type resv)
{
+ xfs_inobt_mod_blockcount(cur, -1);
return xfs_free_extent(cur->bc_tp,
XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp)), 1,
&XFS_RMAP_OINFO_INOBT, resv);
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 16819d8..992224d 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -3588,6 +3588,11 @@ initialise_ag_headers(
platform_uuid_copy(&agi->agi_uuid, &sbp->sb_uuid);
for (c = 0; c < XFS_AGI_UNLINKED_BUCKETS; c++)
agi->agi_unlinked[c] = cpu_to_be32(NULLAGINO);
+ if (xfs_sb_version_hasinobtcounts(&mp->m_sb)) {
+ agi->agi_iblocks = cpu_to_be32(1);
+ if (xfs_sb_version_hasfinobt(&mp->m_sb))
+ agi->agi_fblocks = cpu_to_be32(1);
+ }
libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
/*

@ -0,0 +1,61 @@
From eb2c6897f36d560f84ed5124b246f2759c470f11 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 10 Nov 2020 15:11:09 -0500
Subject: [PATCH] xfs: use the finobt block counts to speed up mount times
Source kernel commit: 1ac35f061af011442eeb731632f6daae991ecf7c
Now that we have reliable finobt block counts, use them to speed up the
per-AG block reservation calculations at mount time.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
index 9db87e9..b1adc80 100644
--- a/libxfs/xfs_ialloc_btree.c
+++ b/libxfs/xfs_ialloc_btree.c
@@ -593,6 +593,28 @@ xfs_inobt_count_blocks(
return error;
}
+/* Read finobt block count from AGI header. */
+static int
+xfs_finobt_read_blocks(
+ struct xfs_mount *mp,
+ struct xfs_trans *tp,
+ xfs_agnumber_t agno,
+ xfs_extlen_t *tree_blocks)
+{
+ struct xfs_buf *agbp;
+ struct xfs_agi *agi;
+ int error;
+
+ error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+ if (error)
+ return error;
+
+ agi = agbp->b_addr;
+ *tree_blocks = be32_to_cpu(agi->agi_fblocks);
+ xfs_trans_brelse(tp, agbp);
+ return 0;
+}
+
/*
* Figure out how many blocks to reserve and how many are used by this btree.
*/
@@ -610,7 +632,11 @@ xfs_finobt_calc_reserves(
if (!xfs_sb_version_hasfinobt(&mp->m_sb))
return 0;
- error = xfs_inobt_count_blocks(mp, tp, agno, XFS_BTNUM_FINO, &tree_len);
+ if (xfs_sb_version_hasinobtcounts(&mp->m_sb))
+ error = xfs_finobt_read_blocks(mp, tp, agno, &tree_len);
+ else
+ error = xfs_inobt_count_blocks(mp, tp, agno, XFS_BTNUM_FINO,
+ &tree_len);
if (error)
return error;

@ -0,0 +1,371 @@
From e7e3beb95efd751f227a0ced4c83fc5b88582e2e Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Wed, 11 Nov 2020 20:08:14 -0500
Subject: [PATCH] xfs: widen ondisk inode timestamps to deal with y2038+
Source kernel commit: f93e5436f0ee5a85eaa3a86d2614d215873fb18b
Redesign the ondisk inode timestamps to be a simple unsigned 64-bit
counter of nanoseconds since 14 Dec 1901 (i.e. the minimum time in the
32-bit unix time epoch). This enables us to handle dates up to 2486,
which solves the y2038 problem.
sandeen: update xfs_flags2diflags2() as well, to match
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Gao Xiang <hsiangkao@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
NOTE: xfs_trans_inode.c was not brought over in this version, so code
landed in trans.c
We also do not have the pre-computed geometry, so that needs to be
explicitly added to libxfs_ialloc rather than inheriting from igeo.
diff --git a/include/xfs_inode.h b/include/xfs_inode.h
index ddd48be..25f2eac 100644
--- a/include/xfs_inode.h
+++ b/include/xfs_inode.h
@@ -146,6 +146,11 @@ static inline bool xfs_is_reflink_inode(struct xfs_inode *ip)
return ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK;
}
+static inline bool xfs_inode_has_bigtime(struct xfs_inode *ip)
+{
+ return ip->i_d.di_flags2 & XFS_DIFLAG2_BIGTIME;
+}
+
typedef struct cred {
uid_t cr_uid;
gid_t cr_gid;
diff --git a/libxfs/trans.c b/libxfs/trans.c
index db90624..54e4dd6 100644
--- a/libxfs/trans.c
+++ b/libxfs/trans.c
@@ -415,6 +415,17 @@ xfs_trans_log_inode(
tp->t_flags |= XFS_TRANS_DIRTY;
set_bit(XFS_LI_DIRTY, &ip->i_itemp->ili_item.li_flags);
+ /*
+ * If we're updating the inode core or the timestamps and it's possible
+ * to upgrade this inode to bigtime format, do so now.
+ */
+ if ((flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) &&
+ xfs_sb_version_hasbigtime(&ip->i_mount->m_sb) &&
+ !xfs_inode_has_bigtime(ip)) {
+ ip->i_d.di_flags2 |= XFS_DIFLAG2_BIGTIME;
+ flags |= XFS_ILOG_CORE;
+ }
+
/*
* Always OR in the bits from the ili_last_fields field.
* This is to coordinate with the xfs_iflush() and xfs_iflush_done()
diff --git a/libxfs/util.c b/libxfs/util.c
index 9383bb8..7a8729f 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -222,7 +222,8 @@ xfs_flags2diflags2(
unsigned int xflags)
{
uint64_t di_flags2 =
- (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK);
+ (ip->i_d.di_flags2 & (XFS_DIFLAG2_REFLINK |
+ XFS_DIFLAG2_BIGTIME));
if (xflags & FS_XFLAG_DAX)
di_flags2 |= XFS_DIFLAG2_DAX;
@@ -317,8 +318,14 @@ libxfs_ialloc(
ASSERT(ip->i_d.di_ino == ino);
ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid));
VFS_I(ip)->i_version = 1;
- ip->i_d.di_flags2 = pip ? 0 : xfs_flags2diflags2(ip,
- fsx->fsx_xflags);
+ if (pip) {
+ ip->i_d.di_flags2 = 0;
+ if (xfs_sb_version_hasbigtime(&ip->i_mount->m_sb))
+ ip->i_d.di_flags2 |= XFS_DIFLAG2_BIGTIME;
+ } else {
+ ip->i_d.di_flags2 = xfs_flags2diflags2(ip, fsx->fsx_xflags);
+ }
+
ip->i_d.di_crtime.tv_sec = (int32_t)VFS_I(ip)->i_mtime.tv_sec;
ip->i_d.di_crtime.tv_nsec = (int32_t)VFS_I(ip)->i_mtime.tv_nsec;
ip->i_d.di_cowextsize = pip ? 0 : fsx->fsx_cowextsize;
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 371f5cd..b1f6219 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -466,6 +466,7 @@ xfs_sb_has_ro_compat_feature(
#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */
#define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */
#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */
+#define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */
#define XFS_SB_FEAT_INCOMPAT_ALL \
(XFS_SB_FEAT_INCOMPAT_FTYPE| \
XFS_SB_FEAT_INCOMPAT_SPINODES| \
@@ -580,6 +581,12 @@ xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino)
#define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \
XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno))
+static inline bool xfs_sb_version_hasbigtime(struct xfs_sb *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
+ (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_BIGTIME);
+}
+
/*
* File system sector to basic block conversions.
*/
@@ -849,6 +856,13 @@ typedef struct xfs_agfl {
* Therefore, the ondisk min and max defined here can be used directly to
* constrain the incore timestamps on a Unix system. Note that we actually
* encode a __be64 value on disk.
+ *
+ * When the bigtime feature is enabled, ondisk inode timestamps become an
+ * unsigned 64-bit nanoseconds counter. This means that the bigtime inode
+ * timestamp epoch is the start of the classic timestamp range, which is
+ * Dec 31 20:45:52 UTC 1901. Because the epochs are not the same, callers
+ * /must/ use the bigtime conversion functions when encoding and decoding raw
+ * timestamps.
*/
typedef __be64 xfs_timestamp_t;
@@ -870,6 +884,50 @@ struct xfs_legacy_timestamp {
*/
#define XFS_LEGACY_TIME_MAX ((int64_t)S32_MAX)
+/*
+ * Smallest possible ondisk seconds value with bigtime timestamps. This
+ * corresponds (after conversion to a Unix timestamp) with the traditional
+ * minimum timestamp of Dec 13 20:45:52 UTC 1901.
+ */
+#define XFS_BIGTIME_TIME_MIN ((int64_t)0)
+
+/*
+ * Largest supported ondisk seconds value with bigtime timestamps. This
+ * corresponds (after conversion to a Unix timestamp) with an incore timestamp
+ * of Jul 2 20:20:24 UTC 2486.
+ *
+ * We round down the ondisk limit so that the bigtime quota and inode max
+ * timestamps will be the same.
+ */
+#define XFS_BIGTIME_TIME_MAX ((int64_t)((-1ULL / NSEC_PER_SEC) & ~0x3ULL))
+
+/*
+ * Bigtime epoch is set exactly to the minimum time value that a traditional
+ * 32-bit timestamp can represent when using the Unix epoch as a reference.
+ * Hence the Unix epoch is at a fixed offset into the supported bigtime
+ * timestamp range.
+ *
+ * The bigtime epoch also matches the minimum value an on-disk 32-bit XFS
+ * timestamp can represent so we will not lose any fidelity in converting
+ * to/from unix and bigtime timestamps.
+ *
+ * The following conversion factor converts a seconds counter from the Unix
+ * epoch to the bigtime epoch.
+ */
+#define XFS_BIGTIME_EPOCH_OFFSET (-(int64_t)S32_MIN)
+
+/* Convert a timestamp from the Unix epoch to the bigtime epoch. */
+static inline uint64_t xfs_unix_to_bigtime(time64_t unix_seconds)
+{
+ return (uint64_t)unix_seconds + XFS_BIGTIME_EPOCH_OFFSET;
+}
+
+/* Convert a timestamp from the bigtime epoch to the Unix epoch. */
+static inline time64_t xfs_bigtime_to_unix(uint64_t ondisk_seconds)
+{
+ return (time64_t)ondisk_seconds - XFS_BIGTIME_EPOCH_OFFSET;
+}
+
/*
* On-disk inode structure.
*
@@ -1096,12 +1154,22 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
#define XFS_DIFLAG2_DAX_BIT 0 /* use DAX for this inode */
#define XFS_DIFLAG2_REFLINK_BIT 1 /* file's blocks may be shared */
#define XFS_DIFLAG2_COWEXTSIZE_BIT 2 /* copy on write extent size hint */
+#define XFS_DIFLAG2_BIGTIME_BIT 3 /* big timestamps */
+
#define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT)
#define XFS_DIFLAG2_REFLINK (1 << XFS_DIFLAG2_REFLINK_BIT)
#define XFS_DIFLAG2_COWEXTSIZE (1 << XFS_DIFLAG2_COWEXTSIZE_BIT)
+#define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT)
#define XFS_DIFLAG2_ANY \
- (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE)
+ (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \
+ XFS_DIFLAG2_BIGTIME)
+
+static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
+{
+ return dip->di_version >= 3 &&
+ (dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_BIGTIME));
+}
/*
* Inode number format:
diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index 4fa9852..714dba1 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -231,6 +231,7 @@ typedef struct xfs_fsop_resblks {
#define XFS_FSOP_GEOM_FLAGS_SPINODES 0x40000 /* sparse inode chunks */
#define XFS_FSOP_GEOM_FLAGS_RMAPBT 0x80000 /* reverse mapping btree */
#define XFS_FSOP_GEOM_FLAGS_REFLINK 0x100000 /* files can share blocks */
+#define XFS_FSOP_GEOM_FLAGS_BIGTIME 0x200000 /* 64-bit nsec timestamps */
/*
* Minimum and maximum sizes need for growth checks.
diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
index d8831a1..8cd16bf 100644
--- a/libxfs/xfs_inode_buf.c
+++ b/libxfs/xfs_inode_buf.c
@@ -195,14 +195,29 @@ xfs_imap_to_bp(
return 0;
}
+static inline struct timespec64 xfs_inode_decode_bigtime(uint64_t ts)
+{
+ struct timespec64 tv;
+ uint32_t n;
+
+ tv.tv_sec = xfs_bigtime_to_unix(div_u64_rem(ts, NSEC_PER_SEC, &n));
+ tv.tv_nsec = n;
+
+ return tv;
+}
+
/* Convert an ondisk timestamp to an incore timestamp. */
struct timespec64
xfs_inode_from_disk_ts(
+ struct xfs_dinode *dip,
const xfs_timestamp_t ts)
{
struct timespec64 tv;
struct xfs_legacy_timestamp *lts;
+ if (xfs_dinode_has_bigtime(dip))
+ return xfs_inode_decode_bigtime(be64_to_cpu(ts));
+
lts = (struct xfs_legacy_timestamp *)&ts;
tv.tv_sec = (int)be32_to_cpu(lts->t_sec);
tv.tv_nsec = (int)be32_to_cpu(lts->t_nsec);
@@ -246,9 +261,9 @@ xfs_inode_from_disk(
* a time before epoch is converted to a time long after epoch
* on 64 bit systems.
*/
- inode->i_atime = xfs_inode_from_disk_ts(from->di_atime);
- inode->i_mtime = xfs_inode_from_disk_ts(from->di_mtime);
- inode->i_ctime = xfs_inode_from_disk_ts(from->di_ctime);
+ inode->i_atime = xfs_inode_from_disk_ts(from, from->di_atime);
+ inode->i_mtime = xfs_inode_from_disk_ts(from, from->di_mtime);
+ inode->i_ctime = xfs_inode_from_disk_ts(from, from->di_ctime);
inode->i_generation = be32_to_cpu(from->di_gen);
inode->i_mode = be16_to_cpu(from->di_mode);
@@ -267,7 +282,7 @@ xfs_inode_from_disk(
if (to->di_version == 3) {
inode_set_iversion_queried(inode,
be64_to_cpu(from->di_changecount));
- to->di_crtime = xfs_inode_from_disk_ts(from->di_crtime);
+ to->di_crtime = xfs_inode_from_disk_ts(from, from->di_crtime);
to->di_flags2 = be64_to_cpu(from->di_flags2);
to->di_cowextsize = be32_to_cpu(from->di_cowextsize);
}
@@ -276,11 +291,15 @@ xfs_inode_from_disk(
/* Convert an incore timestamp to an ondisk timestamp. */
static inline xfs_timestamp_t
xfs_inode_to_disk_ts(
+ struct xfs_inode *ip,
const struct timespec64 tv)
{
struct xfs_legacy_timestamp *lts;
xfs_timestamp_t ts;
+ if (xfs_inode_has_bigtime(ip))
+ return cpu_to_be64(xfs_inode_encode_bigtime(tv));
+
lts = (struct xfs_legacy_timestamp *)&ts;
lts->t_sec = cpu_to_be32(tv.tv_sec);
lts->t_nsec = cpu_to_be32(tv.tv_nsec);
@@ -308,9 +327,9 @@ xfs_inode_to_disk(
to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
memset(to->di_pad, 0, sizeof(to->di_pad));
- to->di_atime = xfs_inode_to_disk_ts(inode->i_atime);
- to->di_mtime = xfs_inode_to_disk_ts(inode->i_mtime);
- to->di_ctime = xfs_inode_to_disk_ts(inode->i_ctime);
+ to->di_atime = xfs_inode_to_disk_ts(ip, inode->i_atime);
+ to->di_mtime = xfs_inode_to_disk_ts(ip, inode->i_mtime);
+ to->di_ctime = xfs_inode_to_disk_ts(ip, inode->i_ctime);
to->di_nlink = cpu_to_be32(inode->i_nlink);
to->di_gen = cpu_to_be32(inode->i_generation);
to->di_mode = cpu_to_be16(inode->i_mode);
@@ -328,7 +347,7 @@ xfs_inode_to_disk(
if (from->di_version == 3) {
to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
- to->di_crtime = xfs_inode_to_disk_ts(from->di_crtime);
+ to->di_crtime = xfs_inode_to_disk_ts(ip, from->di_crtime);
to->di_flags2 = cpu_to_be64(from->di_flags2);
to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
to->di_ino = cpu_to_be64(ip->i_ino);
@@ -547,6 +566,11 @@ xfs_dinode_verify(
if (fa)
return fa;
+ /* bigtime iflag can only happen on bigtime filesystems */
+ if (xfs_dinode_has_bigtime(dip) &&
+ !xfs_sb_version_hasbigtime(&mp->m_sb))
+ return __this_address;
+
return NULL;
}
diff --git a/libxfs/xfs_inode_buf.h b/libxfs/xfs_inode_buf.h
index 6147f42..2b91e60 100644
--- a/libxfs/xfs_inode_buf.h
+++ b/libxfs/xfs_inode_buf.h
@@ -40,6 +40,11 @@ struct xfs_icdinode {
struct timespec64 di_crtime; /* time created */
};
+static inline bool xfs_icdinode_has_bigtime(const struct xfs_icdinode *icd)
+{
+ return icd->di_flags2 & XFS_DIFLAG2_BIGTIME;
+}
+
/*
* Inode location information. Stored in the inode and passed to
* xfs_imap_to_bp() to get a buffer and dinode for a given inode.
@@ -76,6 +81,12 @@ xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
uint32_t cowextsize, uint16_t mode, uint16_t flags,
uint64_t flags2);
-struct timespec64 xfs_inode_from_disk_ts(const xfs_timestamp_t ts);
+static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
+{
+ return xfs_unix_to_bigtime(tv.tv_sec) * NSEC_PER_SEC + tv.tv_nsec;
+}
+
+struct timespec64 xfs_inode_from_disk_ts(struct xfs_dinode *dip,
+ const xfs_timestamp_t ts);
#endif /* __XFS_INODE_BUF_H__ */
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index cee77a6..d11545b 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -1124,6 +1124,8 @@ xfs_fs_geometry(
geo->flags |= XFS_FSOP_GEOM_FLAGS_RMAPBT;
if (xfs_sb_version_hasreflink(sbp))
geo->flags |= XFS_FSOP_GEOM_FLAGS_REFLINK;
+ if (xfs_sb_version_hasbigtime(sbp))
+ geo->flags |= XFS_FSOP_GEOM_FLAGS_BIGTIME;
if (xfs_sb_version_hassector(sbp))
geo->logsectsize = sbp->sb_logsectsize;
else

@ -0,0 +1,170 @@
From 06963ef0d4ff9a6736f699d1ca8ef5a0c194799b Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Thu, 12 Nov 2020 16:49:42 -0500
Subject: [PATCH] xfs: widen ondisk quota expiration timestamps to handle
y2038+
Source kernel commit: 4ea1ff3b49681af45a4a8c14baf7f0b3d11aa74a
Enable the bigtime feature for quota timers. We decrease the accuracy
of the timers to ~4s in exchange for being able to set timers up to the
bigtime maximum.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
NOTE: Again, slightly different macro names due to lack of the
quota type/flags split.
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index 8651d6a..beb2328 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -202,4 +202,8 @@ extern xfs_mount_t *libxfs_mount (xfs_mount_t *, xfs_sb_t *,
extern void libxfs_umount (xfs_mount_t *);
extern void libxfs_rtmount_destroy (xfs_mount_t *);
+/* Dummy xfs_dquot so that libxfs compiles. */
+struct xfs_dquot {
+ int q_type;
+};
#endif /* __XFS_MOUNT_H__ */
diff --git a/libxfs/xfs_dquot_buf.c b/libxfs/xfs_dquot_buf.c
index 963f8ea..db93dda 100644
--- a/libxfs/xfs_dquot_buf.c
+++ b/libxfs/xfs_dquot_buf.c
@@ -69,6 +69,13 @@ xfs_dquot_verify(
ddq_type != XFS_DQ_GROUP)
return __this_address;
+ if ((ddq->d_flags & XFS_DQ_BIGTIME) &&
+ !xfs_sb_version_hasbigtime(&mp->m_sb))
+ return __this_address;
+
+ if ((ddq->d_flags & XFS_DQ_BIGTIME) && !ddq->d_id)
+ return __this_address;
+
if (id != -1 && id != be32_to_cpu(ddq->d_id))
return __this_address;
@@ -293,7 +300,12 @@ xfs_dquot_from_disk_ts(
struct xfs_disk_dquot *ddq,
__be32 dtimer)
{
- return be32_to_cpu(dtimer);
+ uint32_t t = be32_to_cpu(dtimer);
+
+ if (t != 0 && (ddq->d_flags & XFS_DQ_BIGTIME))
+ return xfs_dq_bigtime_to_unix(t);
+
+ return t;
}
/* Convert an incore timer value into an on-disk timer value. */
@@ -302,5 +314,10 @@ xfs_dquot_to_disk_ts(
struct xfs_dquot *dqp,
time64_t timer)
{
- return cpu_to_be32(timer);
+ uint32_t t = timer;
+
+ if (timer != 0 && (dqp->q_type & XFS_DQ_BIGTIME))
+ t = xfs_dq_unix_to_bigtime(timer);
+
+ return cpu_to_be32(t);
}
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index b1f6219..9ba65e5 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1263,6 +1263,10 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
* ondisk min and max defined here can be used directly to constrain the incore
* quota expiration timestamps on a Unix system.
*
+ * When bigtime is enabled, we trade two bits of precision to expand the
+ * expiration timeout range to match that of big inode timestamps. The min and
+ * max recorded here are the on-disk limits, not a Unix timestamp.
+ *
* The grace period for each quota type is stored in the root dquot (id = 0)
* and is applied to a non-root dquot when it exceeds the soft or hard limits.
* The length of quota grace periods are unsigned 32-bit quantities measured in
@@ -1281,6 +1285,48 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
*/
#define XFS_DQ_LEGACY_EXPIRY_MAX ((int64_t)U32_MAX)
+/*
+ * Smallest possible ondisk quota expiration value with bigtime timestamps.
+ * This corresponds (after conversion to a Unix timestamp) with the incore
+ * expiration of Jan 1 00:00:04 UTC 1970.
+ */
+#define XFS_DQ_BIGTIME_EXPIRY_MIN (XFS_DQ_LEGACY_EXPIRY_MIN)
+
+/*
+ * Largest supported ondisk quota expiration value with bigtime timestamps.
+ * This corresponds (after conversion to a Unix timestamp) with an incore
+ * expiration of Jul 2 20:20:24 UTC 2486.
+ *
+ * The ondisk field supports values up to -1U, which corresponds to an incore
+ * expiration in 2514. This is beyond the maximum the bigtime inode timestamp,
+ * so we cap the maximum bigtime quota expiration to the max inode timestamp.
+ */
+#define XFS_DQ_BIGTIME_EXPIRY_MAX ((int64_t)4074815106U)
+
+/*
+ * The following conversion factors assist in converting a quota expiration
+ * timestamp between the incore and ondisk formats.
+ */
+#define XFS_DQ_BIGTIME_SHIFT (2)
+#define XFS_DQ_BIGTIME_SLACK ((int64_t)(1ULL << XFS_DQ_BIGTIME_SHIFT) - 1)
+
+/* Convert an incore quota expiration timestamp to an ondisk bigtime value. */
+static inline uint32_t xfs_dq_unix_to_bigtime(time64_t unix_seconds)
+{
+ /*
+ * Round the expiration timestamp up to the nearest bigtime timestamp
+ * that we can store, to give users the most time to fix problems.
+ */
+ return ((uint64_t)unix_seconds + XFS_DQ_BIGTIME_SLACK) >>
+ XFS_DQ_BIGTIME_SHIFT;
+}
+
+/* Convert an ondisk bigtime quota expiration value to an incore timestamp. */
+static inline time64_t xfs_dq_bigtime_to_unix(uint32_t ondisk_seconds)
+{
+ return (time64_t)ondisk_seconds << XFS_DQ_BIGTIME_SHIFT;
+}
+
/*
* Default quota grace periods, ranging from zero (use the compiled defaults)
* to ~136 years. These are applied to a non-root dquot that has exceeded
diff --git a/libxfs/xfs_quota_defs.h b/libxfs/xfs_quota_defs.h
index 2f61cd3..70d89cc 100644
--- a/libxfs/xfs_quota_defs.h
+++ b/libxfs/xfs_quota_defs.h
@@ -28,17 +28,20 @@ typedef uint16_t xfs_qwarncnt_t;
#define XFS_DQ_GROUP 0x0004 /* a group quota */
#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */
#define XFS_DQ_FREEING 0x0010 /* dquot is being torn down */
+#define XFS_DQ_BIGTIME 0x0080 /* large expiry timestamps */
#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
-#define XFS_DQTYPE_ANY (XFS_DQ_ALLTYPES)
+#define XFS_DQTYPE_ANY (XFS_DQ_ALLTYPES | \
+ XFS_DQ_BIGTIME)
#define XFS_DQ_FLAGS \
{ XFS_DQ_USER, "USER" }, \
{ XFS_DQ_PROJ, "PROJ" }, \
{ XFS_DQ_GROUP, "GROUP" }, \
{ XFS_DQ_DIRTY, "DIRTY" }, \
- { XFS_DQ_FREEING, "FREEING" }
+ { XFS_DQ_FREEING, "FREEING" }, \
+ { XFS_DQ_BIGTIME, "BIGTIME" }
/*
* We have the possibility of all three quota types being active at once, and

@ -0,0 +1,122 @@
From a9a32fcb9176c82aed6d85f209e7279b76c8b55f Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:28 -0500
Subject: [PATCH] xfs_db: refactor quota timer printing
Introduce type-specific printing functions to xfs_db to print a quota
timer instead of printing a raw int32 value. This is needed to stay
ahead of changes that we're going to make to the quota timer format in
the following patches.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/db/dquot.c b/db/dquot.c
index dd9e83f..5c82456 100644
--- a/db/dquot.c
+++ b/db/dquot.c
@@ -60,8 +60,8 @@ const field_t disk_dquot_flds[] = {
TYP_NONE },
{ "bcount", FLDT_QCNT, OI(DOFF(bcount)), C1, 0, TYP_NONE },
{ "icount", FLDT_QCNT, OI(DOFF(icount)), C1, 0, TYP_NONE },
- { "itimer", FLDT_INT32D, OI(DOFF(itimer)), C1, 0, TYP_NONE },
- { "btimer", FLDT_INT32D, OI(DOFF(btimer)), C1, 0, TYP_NONE },
+ { "itimer", FLDT_QTIMER, OI(DOFF(itimer)), C1, 0, TYP_NONE },
+ { "btimer", FLDT_QTIMER, OI(DOFF(btimer)), C1, 0, TYP_NONE },
{ "iwarns", FLDT_QWARNCNT, OI(DOFF(iwarns)), C1, 0, TYP_NONE },
{ "bwarns", FLDT_QWARNCNT, OI(DOFF(bwarns)), C1, 0, TYP_NONE },
{ "pad0", FLDT_UINT32X, OI(DOFF(pad0)), C1, FLD_SKIPALL, TYP_NONE },
@@ -70,7 +70,7 @@ const field_t disk_dquot_flds[] = {
{ "rtb_softlimit", FLDT_QCNT, OI(DOFF(rtb_softlimit)), C1, 0,
TYP_NONE },
{ "rtbcount", FLDT_QCNT, OI(DOFF(rtbcount)), C1, 0, TYP_NONE },
- { "rtbtimer", FLDT_INT32D, OI(DOFF(rtbtimer)), C1, 0, TYP_NONE },
+ { "rtbtimer", FLDT_QTIMER, OI(DOFF(rtbtimer)), C1, 0, TYP_NONE },
{ "rtbwarns", FLDT_QWARNCNT, OI(DOFF(rtbwarns)), C1, 0, TYP_NONE },
{ "pad", FLDT_UINT16X, OI(DOFF(pad)), C1, FLD_SKIPALL, TYP_NONE },
{ NULL }
diff --git a/db/field.c b/db/field.c
index a187a72..770acda 100644
--- a/db/field.c
+++ b/db/field.c
@@ -351,6 +351,8 @@ const ftattr_t ftattrtab[] = {
FTARG_SIGNED, NULL, NULL },
{ FLDT_TIMESTAMP, "timestamp", NULL, (char *)timestamp_flds,
SI(bitsz(xfs_timestamp_t)), 0, NULL, timestamp_flds },
+ { FLDT_QTIMER, "qtimer", fp_qtimer, NULL, SI(bitsz(uint32_t)), 0,
+ NULL, NULL },
{ FLDT_UINT1, "uint1", fp_num, "%u", SI(1), 0, NULL, NULL },
{ FLDT_UINT16D, "uint16d", fp_num, "%u", SI(bitsz(uint16_t)), 0, NULL,
NULL },
diff --git a/db/field.h b/db/field.h
index 1506537..387c189 100644
--- a/db/field.h
+++ b/db/field.h
@@ -170,6 +170,7 @@ typedef enum fldt {
FLDT_TIME,
FLDT_TIMESTAMP,
+ FLDT_QTIMER,
FLDT_UINT1,
FLDT_UINT16D,
FLDT_UINT16O,
diff --git a/db/fprint.c b/db/fprint.c
index 6e72bf0..72ed55f 100644
--- a/db/fprint.c
+++ b/db/fprint.c
@@ -180,6 +180,40 @@ fp_nsec(
return 1;
}
+int
+fp_qtimer(
+ void *obj,
+ int bit,
+ int count,
+ char *fmtstr,
+ int size,
+ int arg,
+ int base,
+ int array)
+{
+ uint32_t sec;
+ __be32 *t;
+ int bitpos;
+ int i;
+
+ ASSERT(bitoffs(bit) == 0);
+ for (i = 0, bitpos = bit;
+ i < count && !seenint();
+ i++, bitpos += size) {
+ if (array)
+ dbprintf("%d:", i + base);
+
+ t = obj + byteize(bitpos);
+ sec = be32_to_cpu(*t);
+
+ dbprintf("%u", sec);
+
+ if (i < count - 1)
+ dbprintf(" ");
+ }
+ return 1;
+}
+
/*ARGSUSED*/
int
fp_uuid(
diff --git a/db/fprint.h b/db/fprint.h
index bfeed15..a1ea935 100644
--- a/db/fprint.h
+++ b/db/fprint.h
@@ -17,6 +17,8 @@ extern int fp_time(void *obj, int bit, int count, char *fmtstr, int size,
int arg, int base, int array);
extern int fp_nsec(void *obj, int bit, int count, char *fmtstr, int size,
int arg, int base, int array);
+extern int fp_qtimer(void *obj, int bit, int count, char *fmtstr, int size,
+ int arg, int base, int array);
extern int fp_uuid(void *obj, int bit, int count, char *fmtstr, int size,
int arg, int base, int array);
extern int fp_crc(void *obj, int bit, int count, char *fmtstr, int size,

@ -0,0 +1,176 @@
From 300422226c423222e78d82d54b09d0ae27c7d4af Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:27 -0500
Subject: [PATCH] xfs_db: refactor timestamp printing
Introduce type-specific printing functions to xfs_db to print an
xfs_timestamp instead of open-coding the timestamp decoding. This is
needed to stay ahead of changes that we're going to make to
xfs_timestamp_t in the following patches.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/db/field.c b/db/field.c
index 4a45c66..a187a72 100644
--- a/db/field.c
+++ b/db/field.c
@@ -334,8 +334,8 @@ const ftattr_t ftattrtab[] = {
FTARG_SIGNED, NULL, NULL },
{ FLDT_INT8D, "int8d", fp_num, "%d", SI(bitsz(int8_t)), FTARG_SIGNED,
NULL, NULL },
- { FLDT_NSEC, "nsec", fp_num, "%09d", SI(bitsz(int32_t)), FTARG_SIGNED,
- NULL, NULL },
+ { FLDT_NSEC, "nsec", fp_nsec, NULL, SI(bitsz(xfs_timestamp_t)),
+ FTARG_SIGNED, NULL, NULL },
{ FLDT_QCNT, "qcnt", fp_num, "%llu", SI(bitsz(xfs_qcnt_t)), 0, NULL,
NULL },
{ FLDT_QWARNCNT, "qwarncnt", fp_num, "%u", SI(bitsz(xfs_qwarncnt_t)), 0,
@@ -347,10 +347,10 @@ const ftattr_t ftattrtab[] = {
{ FLDT_SYMLINK_CRC, "symlink", NULL, (char *)symlink_crc_flds,
symlink_size, FTARG_SIZE, NULL, symlink_crc_flds },
- { FLDT_TIME, "time", fp_time, NULL, SI(bitsz(int32_t)), FTARG_SIGNED,
- NULL, NULL },
+ { FLDT_TIME, "time", fp_time, NULL, SI(bitsz(xfs_timestamp_t)),
+ FTARG_SIGNED, NULL, NULL },
{ FLDT_TIMESTAMP, "timestamp", NULL, (char *)timestamp_flds,
- SI(bitsz(struct xfs_legacy_timestamp)), 0, NULL, timestamp_flds },
+ SI(bitsz(xfs_timestamp_t)), 0, NULL, timestamp_flds },
{ FLDT_UINT1, "uint1", fp_num, "%u", SI(1), 0, NULL, NULL },
{ FLDT_UINT16D, "uint16d", fp_num, "%u", SI(bitsz(uint16_t)), 0, NULL,
NULL },
diff --git a/db/fprint.c b/db/fprint.c
index c9d07e1..6e72bf0 100644
--- a/db/fprint.c
+++ b/db/fprint.c
@@ -112,22 +112,21 @@ fp_sarray(
return 1;
}
-/*ARGSUSED*/
int
fp_time(
- void *obj,
- int bit,
- int count,
- char *fmtstr,
- int size,
- int arg,
- int base,
- int array)
+ void *obj,
+ int bit,
+ int count,
+ char *fmtstr,
+ int size,
+ int arg,
+ int base,
+ int array)
{
- int bitpos;
- char *c;
- int i;
- time_t t;
+ struct timespec64 tv;
+ xfs_timestamp_t *ts;
+ int bitpos;
+ int i;
ASSERT(bitoffs(bit) == 0);
for (i = 0, bitpos = bit;
@@ -135,10 +134,46 @@ fp_time(
i++, bitpos += size) {
if (array)
dbprintf("%d:", i + base);
- t = (time_t)getbitval((char *)obj + byteize(bitpos), 0,
- sizeof(int32_t) * 8, BVSIGNED);
- c = ctime(&t);
- dbprintf("%24.24s", c);
+
+ ts = obj + byteize(bitpos);
+ tv = libxfs_inode_from_disk_ts(obj, *ts);
+
+ dbprintf("%24.24s", tv.tv_sec);
+
+ if (i < count - 1)
+ dbprintf(" ");
+ }
+ return 1;
+}
+
+int
+fp_nsec(
+ void *obj,
+ int bit,
+ int count,
+ char *fmtstr,
+ int size,
+ int arg,
+ int base,
+ int array)
+{
+ struct timespec64 tv;
+ xfs_timestamp_t *ts;
+ int bitpos;
+ int i;
+
+ ASSERT(bitoffs(bit) == 0);
+ for (i = 0, bitpos = bit;
+ i < count && !seenint();
+ i++, bitpos += size) {
+ if (array)
+ dbprintf("%d:", i + base);
+
+ ts = obj + byteize(bitpos);
+ tv = libxfs_inode_from_disk_ts(obj, *ts);
+
+ dbprintf("%u", tv.tv_nsec);
+
if (i < count - 1)
dbprintf(" ");
}
diff --git a/db/fprint.h b/db/fprint.h
index c958dca..bfeed15 100644
--- a/db/fprint.h
+++ b/db/fprint.h
@@ -15,6 +15,8 @@ extern int fp_sarray(void *obj, int bit, int count, char *fmtstr, int size,
int arg, int base, int array);
extern int fp_time(void *obj, int bit, int count, char *fmtstr, int size,
int arg, int base, int array);
+extern int fp_nsec(void *obj, int bit, int count, char *fmtstr, int size,
+ int arg, int base, int array);
extern int fp_uuid(void *obj, int bit, int count, char *fmtstr, int size,
int arg, int base, int array);
extern int fp_crc(void *obj, int bit, int count, char *fmtstr, int size,
diff --git a/db/inode.c b/db/inode.c
index b308538..bbfee74 100644
--- a/db/inode.c
+++ b/db/inode.c
@@ -176,10 +176,9 @@ const field_t inode_v3_flds[] = {
};
-#define TOFF(f) bitize(offsetof(struct xfs_legacy_timestamp, t_ ## f))
const field_t timestamp_flds[] = {
- { "sec", FLDT_TIME, OI(TOFF(sec)), C1, 0, TYP_NONE },
- { "nsec", FLDT_NSEC, OI(TOFF(nsec)), C1, 0, TYP_NONE },
+ { "sec", FLDT_TIME, OI(0), C1, 0, TYP_NONE },
+ { "nsec", FLDT_NSEC, OI(0), C1, 0, TYP_NONE },
{ NULL }
};
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index f4f7626..00f367e 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -89,6 +89,7 @@
#define xfs_da_get_buf libxfs_da_get_buf
#define xfs_inode_from_disk libxfs_inode_from_disk
+#define xfs_inode_from_disk_ts libxfs_inode_from_disk_ts
#define xfs_inode_to_disk libxfs_inode_to_disk
#define xfs_dinode_calc_crc libxfs_dinode_calc_crc
#define xfs_idata_realloc libxfs_idata_realloc

@ -0,0 +1,122 @@
From 344f38a9e5d0f938dae337c8c769853e6368d480 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:28 -0500
Subject: [PATCH] xfs_db: report bigtime format timestamps
Report the large format timestamps in a human-readable manner if it is
possible to do so without loss of information.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/db/fprint.c b/db/fprint.c
index 72ed55f..65accfd 100644
--- a/db/fprint.c
+++ b/db/fprint.c
@@ -112,6 +112,35 @@ fp_sarray(
return 1;
}
+static void
+fp_time64(
+ time64_t sec)
+{
+ time_t tt = sec;
+ time64_t tt_sec = tt;
+ char *c;
+
+ /*
+ * Stupid time_t shenanigans -- POSIX.1-2017 only requires that this
+ * type represent a time in seconds. Since we have no idea if our
+ * time64_t filesystem timestamps can actually be represented by the C
+ * library, we resort to converting the input value from time64_t to
+ * time_t and back to time64_t to check for information loss. If so,
+ * we print the raw value; otherwise we print a human-readable value.
+ */
+ if (tt_sec != sec)
+ goto raw;
+
+ c = ctime(&tt);
+ if (!c)
+ goto raw;
+
+ dbprintf("%24.24s", c);
+ return;
+raw:
+ dbprintf("%lld", sec);
+}
+
int
fp_time(
void *obj,
@@ -138,7 +167,7 @@ fp_time(
ts = obj + byteize(bitpos);
tv = libxfs_inode_from_disk_ts(obj, *ts);
- dbprintf("%24.24s", tv.tv_sec);
+ fp_time64(tv.tv_sec);
if (i < count - 1)
dbprintf(" ");
@@ -191,7 +220,8 @@ fp_qtimer(
int base,
int array)
{
- uint32_t sec;
+ struct xfs_disk_dquot *ddq = obj;
+ time64_t sec;
__be32 *t;
int bitpos;
int i;
@@ -204,9 +234,16 @@ fp_qtimer(
dbprintf("%d:", i + base);
t = obj + byteize(bitpos);
- sec = be32_to_cpu(*t);
+ sec = libxfs_dquot_from_disk_ts(ddq, *t);
- dbprintf("%u", sec);
+ /*
+ * Display the raw value if it's the default grace expiration
+ * period (root dquot) or if the quota has not expired.
+ */
+ if (ddq->d_id == 0 || sec == 0)
+ dbprintf("%lld", sec);
+ else
+ fp_time64(sec);
if (i < count - 1)
dbprintf(" ");
diff --git a/db/inode.c b/db/inode.c
index bbfee74..37c7dc0 100644
--- a/db/inode.c
+++ b/db/inode.c
@@ -172,10 +172,12 @@ const field_t inode_v3_flds[] = {
{ "cowextsz", FLDT_UINT1,
OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_COWEXTSIZE_BIT-1), C1,
0, TYP_NONE },
+ { "bigtime", FLDT_UINT1,
+ OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_BIGTIME_BIT - 1), C1,
+ 0, TYP_NONE },
{ NULL }
};
-
const field_t timestamp_flds[] = {
{ "sec", FLDT_TIME, OI(0), C1, 0, TYP_NONE },
{ "nsec", FLDT_NSEC, OI(0), C1, 0, TYP_NONE },
diff --git a/db/sb.c b/db/sb.c
index d63fc71..109fdc3 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -689,6 +689,8 @@ version_string(
strcat(s, ",REFLINK");
if (xfs_sb_version_hasinobtcounts(sbp))
strcat(s, ",INOBTCNT");
+ if (xfs_sb_version_hasbigtime(sbp))
+ strcat(s, ",BIGTIME");
return s;
}

@ -0,0 +1,39 @@
From 13b8917251601e06660ed6ebe6bdeafa4c431ca3 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:27 -0500
Subject: [PATCH] xfs_db: support displaying inode btree block counts in AGI
header
Fix up xfs_db to support displaying the btree block counts.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/db/agi.c b/db/agi.c
index bf21b2d..cfb4f7b 100644
--- a/db/agi.c
+++ b/db/agi.c
@@ -48,6 +48,8 @@ const field_t agi_flds[] = {
{ "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE },
{ "free_root", FLDT_AGBLOCK, OI(OFF(free_root)), C1, 0, TYP_FINOBT },
{ "free_level", FLDT_UINT32D, OI(OFF(free_level)), C1, 0, TYP_NONE },
+ { "ino_blocks", FLDT_UINT32D, OI(OFF(iblocks)), C1, 0, TYP_NONE },
+ { "fino_blocks", FLDT_UINT32D, OI(OFF(fblocks)), C1, 0, TYP_NONE },
{ NULL }
};
diff --git a/db/sb.c b/db/sb.c
index 5059b26..d63fc71 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -687,6 +687,8 @@ version_string(
strcat(s, ",RMAPBT");
if (xfs_sb_version_hasreflink(sbp))
strcat(s, ",REFLINK");
+ if (xfs_sb_version_hasinobtcounts(sbp))
+ strcat(s, ",INOBTCNT");
return s;
}

@ -0,0 +1,245 @@
From 4893718570dac172f639cc5e8687e782c4f759ee Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:28 -0500
Subject: [PATCH] xfs_db: support printing time limits
Support printing the minimum and maxium timestamp limits on this
filesystem.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/db/Makefile b/db/Makefile
index 8fecfc1..68ab659 100644
--- a/db/Makefile
+++ b/db/Makefile
@@ -14,7 +14,7 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \
io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \
sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h \
fuzz.h
-CFILES = $(HFILES:.h=.c) btdump.c info.c
+CFILES = $(HFILES:.h=.c) btdump.c info.c timelimit.c
LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh
LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBFROG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD)
diff --git a/db/command.c b/db/command.c
index c7c5234..73b06a7 100644
--- a/db/command.c
+++ b/db/command.c
@@ -139,4 +139,5 @@ init_commands(void)
write_init();
dquot_init();
fuzz_init();
+ timelimit_init();
}
diff --git a/db/command.h b/db/command.h
index eacfd46..1a9b4d2 100644
--- a/db/command.h
+++ b/db/command.h
@@ -30,3 +30,4 @@ extern void init_commands(void);
extern void btdump_init(void);
extern void info_init(void);
+extern void timelimit_init(void);
diff --git a/db/timelimit.c b/db/timelimit.c
new file mode 100644
index 0000000..53a0a39
--- /dev/null
+++ b/db/timelimit.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#include "libxfs.h"
+#include "command.h"
+#include "output.h"
+#include "init.h"
+
+enum show_what {
+ SHOW_AUTO,
+ SHOW_CLASSIC,
+ SHOW_BIGTIME,
+};
+
+
+enum print_how {
+ PRINT_RAW,
+ PRINT_PRETTY,
+ PRINT_COMPACT,
+};
+
+static void
+show_limit(
+ const char *tag,
+ int64_t limit,
+ enum print_how how)
+{
+ if (how == PRINT_COMPACT) {
+ dbprintf("%" PRId64 " ", limit);
+ return;
+ }
+
+ if (how == PRINT_PRETTY && limit <= LONG_MAX && limit >= LONG_MIN) {
+ time_t tt = limit;
+ char *c;
+
+ c = ctime(&tt);
+ if (c) {
+ dbprintf("%s = %24.24s\n", tag, c);
+ return;
+ }
+ }
+
+ dbprintf("%s = %" PRId64 "\n", tag, limit);
+}
+
+static void
+show_limits(
+ enum show_what whatkind,
+ enum print_how how)
+{
+ enum print_how grace_how = how;
+
+ switch (whatkind) {
+ case SHOW_AUTO:
+ /* should never get here */
+ break;
+ case SHOW_CLASSIC:
+ show_limit("time.min", XFS_LEGACY_TIME_MIN, how);
+ show_limit("time.max", XFS_LEGACY_TIME_MAX, how);
+ show_limit("dqtimer.min", XFS_DQ_LEGACY_EXPIRY_MIN, how);
+ show_limit("dqtimer.max", XFS_DQ_LEGACY_EXPIRY_MAX, how);
+ break;
+ case SHOW_BIGTIME:
+ show_limit("time.min",
+ xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MIN), how);
+ show_limit("time.max",
+ xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MAX), how);
+ show_limit("dqtimer.min",
+ xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MIN),
+ how);
+ show_limit("dqtimer.max",
+ xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MAX),
+ how);
+ break;
+ }
+
+ /* grace periods are always integers */
+ if (grace_how != PRINT_COMPACT)
+ grace_how = PRINT_RAW;
+ show_limit("dqgrace.min", XFS_DQ_GRACE_MIN, grace_how);
+ show_limit("dqgrace.min", XFS_DQ_GRACE_MAX, grace_how);
+
+ if (how == PRINT_COMPACT)
+ dbprintf("\n");
+}
+
+static int
+timelimit_f(
+ int argc,
+ char **argv)
+{
+ enum show_what whatkind = SHOW_AUTO;
+ enum print_how how = PRINT_RAW;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp("--classic", argv[i]))
+ whatkind = SHOW_CLASSIC;
+ else if (!strcmp("--bigtime", argv[i]))
+ whatkind = SHOW_BIGTIME;
+ else if (!strcmp("--pretty", argv[i]))
+ how = PRINT_PRETTY;
+ else if (!strcmp("--compact", argv[i]))
+ how = PRINT_COMPACT;
+ else {
+ dbprintf(_("%s: bad option for timelimit command\n"),
+ argv[i]);
+ return 1;
+ }
+ }
+
+ if (whatkind == SHOW_AUTO) {
+ if (xfs_sb_version_hasbigtime(&mp->m_sb))
+ whatkind = SHOW_BIGTIME;
+ else
+ whatkind = SHOW_CLASSIC;
+ }
+
+ show_limits(whatkind, how);
+ return 0;
+}
+
+static void
+timelimit_help(void)
+{
+ dbprintf(_(
+"\n"
+" Print the minimum and maximum supported values for inode timestamps,\n"
+" disk quota expiration timers, and disk quota grace periods supported\n"
+" by this filesystem.\n"
+"\n"
+" Options:\n"
+" --classic -- Force printing of the classic time limits.\n"
+" --bigtime -- Force printing of the bigtime limits.\n"
+" --pretty -- Pretty-print the time limits.\n"
+" --compact -- Print the limits in a single line.\n"
+"\n"
+));
+
+}
+
+static const cmdinfo_t timelimit_cmd = {
+ .name = "timelimit",
+ .cfunc = timelimit_f,
+ .argmin = 0,
+ .argmax = -1,
+ .canpush = 0,
+ .args = N_("[--classic|--bigtime] [--pretty]"),
+ .oneline = N_("display timestamp limits"),
+ .help = timelimit_help,
+};
+
+void
+timelimit_init(void)
+{
+ add_command(&timelimit_cmd);
+}
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index a1ee351..f46e936 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -785,6 +785,29 @@ The possible data types are:
.BR rtsummary ", " sb ", " symlink " and " text .
See the TYPES section below for more information on these data types.
.TP
+.BI "timelimit [" OPTIONS ]
+Print the minimum and maximum supported values for inode timestamps,
+quota expiration timers, and quota grace periods supported by this
+filesystem.
+Options include:
+.RS 1.0i
+.TP 0.4i
+.B \--bigtime
+Print the time limits of an XFS filesystem with the
+.B bigtime
+feature enabled.
+.TP 0.4i
+.B \--classic
+Print the time limits of a classic XFS filesystem.
+.TP 0.4i
+.B \--compact
+Print all limits as raw values on a single line.
+.TP 0.4i
+.B \--pretty
+Print the timestamps in the current locale's date and time format instead of
+raw seconds since the Unix epoch.
+.RE
+.TP
.BI "uuid [" uuid " | " generate " | " rewrite " | " restore ]
Set the filesystem universally unique identifier (UUID).
The filesystem UUID can be used by

@ -0,0 +1,199 @@
From 219285adf56da85171fa90f42714341484750856 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:27 -0500
Subject: [PATCH] xfs_quota: convert time_to_string to use time64_t
Rework the time_to_string helper to be capable of dealing with 64-bit
timestamps.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/quota/quota.c b/quota/quota.c
index 9545cc4..8ba0995 100644
--- a/quota/quota.c
+++ b/quota/quota.c
@@ -48,6 +48,7 @@ quota_mount(
uint flags)
{
fs_disk_quota_t d;
+ time64_t timer;
char *dev = mount->fs_name;
char c[8], h[8], s[8];
uint qflags;
@@ -100,6 +101,7 @@ quota_mount(
}
if (form & XFS_BLOCK_QUOTA) {
+ timer = d.d_btimer;
qflags = (flags & HUMAN_FLAG);
if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
qflags |= LIMIT_FLAG;
@@ -111,16 +113,17 @@ quota_mount(
bbs_to_string(d.d_blk_softlimit, s, sizeof(s)),
bbs_to_string(d.d_blk_hardlimit, h, sizeof(h)),
d.d_bwarns,
- time_to_string(d.d_btimer, qflags));
+ time_to_string(timer, qflags));
else
fprintf(fp, " %10llu %10llu %10llu %02d %9s ",
(unsigned long long)d.d_bcount >> 1,
(unsigned long long)d.d_blk_softlimit >> 1,
(unsigned long long)d.d_blk_hardlimit >> 1,
d.d_bwarns,
- time_to_string(d.d_btimer, qflags));
+ time_to_string(timer, qflags));
}
if (form & XFS_INODE_QUOTA) {
+ timer = d.d_itimer;
qflags = (flags & HUMAN_FLAG);
if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
qflags |= LIMIT_FLAG;
@@ -132,16 +135,17 @@ quota_mount(
num_to_string(d.d_ino_softlimit, s, sizeof(s)),
num_to_string(d.d_ino_hardlimit, h, sizeof(h)),
d.d_iwarns,
- time_to_string(d.d_itimer, qflags));
+ time_to_string(timer, qflags));
else
fprintf(fp, " %10llu %10llu %10llu %02d %9s ",
(unsigned long long)d.d_icount,
(unsigned long long)d.d_ino_softlimit,
(unsigned long long)d.d_ino_hardlimit,
d.d_iwarns,
- time_to_string(d.d_itimer, qflags));
+ time_to_string(timer, qflags));
}
if (form & XFS_RTBLOCK_QUOTA) {
+ timer = d.d_rtbtimer;
qflags = (flags & HUMAN_FLAG);
if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
qflags |= LIMIT_FLAG;
@@ -153,14 +157,14 @@ quota_mount(
bbs_to_string(d.d_rtb_softlimit, s, sizeof(s)),
bbs_to_string(d.d_rtb_hardlimit, h, sizeof(h)),
d.d_rtbwarns,
- time_to_string(d.d_rtbtimer, qflags));
+ time_to_string(timer, qflags));
else
fprintf(fp, " %10llu %10llu %10llu %02d %9s ",
(unsigned long long)d.d_rtbcount >> 1,
(unsigned long long)d.d_rtb_softlimit >> 1,
(unsigned long long)d.d_rtb_hardlimit >> 1,
d.d_rtbwarns,
- time_to_string(d.d_rtbtimer, qflags));
+ time_to_string(timer, qflags));
}
fprintf(fp, "%s\n", mount->fs_dir);
return 1;
diff --git a/quota/quota.h b/quota/quota.h
index b7f259e..13ae450 100644
--- a/quota/quota.h
+++ b/quota/quota.h
@@ -40,7 +40,7 @@ enum {
*/
extern char *type_to_string(uint __type);
extern char *form_to_string(uint __form);
-extern char *time_to_string(time_t __time, uint __flags);
+extern char *time_to_string(time64_t __time, uint __flags);
extern char *bbs_to_string(uint64_t __v, char *__c, uint __size);
extern char *num_to_string(uint64_t __v, char *__c, uint __size);
extern char *pct_to_string(uint64_t __v, uint64_t __t, char *__c, uint __s);
diff --git a/quota/report.c b/quota/report.c
index e6def91..2d5024e 100644
--- a/quota/report.c
+++ b/quota/report.c
@@ -330,6 +330,7 @@ report_mount(
uint flags)
{
fs_disk_quota_t d;
+ time64_t timer;
char *dev = mount->fs_name;
char c[8], h[8], s[8];
uint qflags;
@@ -397,6 +398,7 @@ report_mount(
}
if (form & XFS_BLOCK_QUOTA) {
+ timer = d.d_btimer;
qflags = (flags & HUMAN_FLAG);
if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
qflags |= LIMIT_FLAG;
@@ -408,16 +410,17 @@ report_mount(
bbs_to_string(d.d_blk_softlimit, s, sizeof(s)),
bbs_to_string(d.d_blk_hardlimit, h, sizeof(h)),
d.d_bwarns,
- time_to_string(d.d_btimer, qflags));
+ time_to_string(timer, qflags));
else
fprintf(fp, " %10llu %10llu %10llu %02d %9s",
(unsigned long long)d.d_bcount >> 1,
(unsigned long long)d.d_blk_softlimit >> 1,
(unsigned long long)d.d_blk_hardlimit >> 1,
d.d_bwarns,
- time_to_string(d.d_btimer, qflags));
+ time_to_string(timer, qflags));
}
if (form & XFS_INODE_QUOTA) {
+ timer = d.d_itimer;
qflags = (flags & HUMAN_FLAG);
if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
qflags |= LIMIT_FLAG;
@@ -429,16 +432,17 @@ report_mount(
num_to_string(d.d_ino_softlimit, s, sizeof(s)),
num_to_string(d.d_ino_hardlimit, h, sizeof(h)),
d.d_iwarns,
- time_to_string(d.d_itimer, qflags));
+ time_to_string(timer, qflags));
else
fprintf(fp, " %10llu %10llu %10llu %02d %9s",
(unsigned long long)d.d_icount,
(unsigned long long)d.d_ino_softlimit,
(unsigned long long)d.d_ino_hardlimit,
d.d_iwarns,
- time_to_string(d.d_itimer, qflags));
+ time_to_string(timer, qflags));
}
if (form & XFS_RTBLOCK_QUOTA) {
+ timer = d.d_rtbtimer;
qflags = (flags & HUMAN_FLAG);
if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
qflags |= LIMIT_FLAG;
@@ -450,14 +454,14 @@ report_mount(
bbs_to_string(d.d_rtb_softlimit, s, sizeof(s)),
bbs_to_string(d.d_rtb_hardlimit, h, sizeof(h)),
d.d_rtbwarns,
- time_to_string(d.d_rtbtimer, qflags));
+ time_to_string(timer, qflags));
else
fprintf(fp, " %10llu %10llu %10llu %02d %9s",
(unsigned long long)d.d_rtbcount >> 1,
(unsigned long long)d.d_rtb_softlimit >> 1,
(unsigned long long)d.d_rtb_hardlimit >> 1,
d.d_rtbwarns,
- time_to_string(d.d_rtbtimer, qflags));
+ time_to_string(timer, qflags));
}
fputc('\n', fp);
return 1;
diff --git a/quota/util.c b/quota/util.c
index 50470ab..361d2a8 100644
--- a/quota/util.c
+++ b/quota/util.c
@@ -18,11 +18,12 @@
char *
time_to_string(
- time_t origin,
+ time64_t origin,
uint flags)
{
static char timestamp[32];
- time_t now, timer;
+ time64_t timer;
+ time_t now;
uint days, hours, minutes, seconds;
if (flags & ABSOLUTE_FLAG) {

@ -0,0 +1,35 @@
From 0d7b09ac95e4cde766a534fdb7ea8dd46451ad53 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Fri, 4 Dec 2020 12:17:12 -0500
Subject: [PATCH] xfs_quota: document how the default quota is stored
Nowhere in the man page is the default quota described; what it
does or where it is stored. Add some brief information about this.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
man/man8/xfs_quota.8 | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/man/man8/xfs_quota.8 b/man/man8/xfs_quota.8
index dd0479cd..6ead7ee9 100644
--- a/man/man8/xfs_quota.8
+++ b/man/man8/xfs_quota.8
@@ -178,6 +178,12 @@ to a file on
where the user's quota has not been exceeded.
Then after rectifying the quota situation, the file can be moved back to the
filesystem it belongs on.
+.SS Default Quotas
+The XFS quota subsystem allows a default quota to be enforced
+for any user, group or project which does not have a quota limit
+explicitly set.
+These limits are stored in and displayed as ID 0's limits, although they
+do not actually limit ID 0.
.SH USER COMMANDS
.TP
.B print
--
2.29.2

@ -0,0 +1,236 @@
From f3eb31d9c005558ce975e2806f8dc73b0ecbd7f7 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:28 -0500
Subject: [PATCH] xfs_quota: support editing and reporting quotas with bigtime
Enhance xfs_quota to detect and report grace period expirations past
2038.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/include/xqm.h b/include/xqm.h
index 8ab1907..573441d 100644
--- a/include/xqm.h
+++ b/include/xqm.h
@@ -47,7 +47,10 @@ typedef struct fs_disk_quota {
__s32 d_btimer; /* similar to above; for disk blocks */
__u16 d_iwarns; /* # warnings issued wrt num inodes */
__u16 d_bwarns; /* # warnings issued wrt disk blocks */
- __s32 d_padding2; /* padding2 - for future use */
+ __s8 d_itimer_hi; /* upper 8 bits of timer values */
+ __s8 d_btimer_hi;
+ __s8 d_rtbtimer_hi;
+ __s8 d_padding2; /* padding2 - for future use */
__u64 d_rtb_hardlimit;/* absolute limit on realtime blks */
__u64 d_rtb_softlimit;/* preferred limit on RT disk blks */
__u64 d_rtbcount; /* # realtime blocks owned */
@@ -93,6 +96,21 @@ typedef struct fs_disk_quota {
#define FS_DQ_RTBWARNS (1<<11)
#define FS_DQ_WARNS_MASK (FS_DQ_BWARNS | FS_DQ_IWARNS | FS_DQ_RTBWARNS)
+/*
+ * Accounting values. These can only be set for filesystem with
+ * non-transactional quotas that require quotacheck(8) in userspace.
+ */
+#define FS_DQ_BCOUNT (1<<12)
+#define FS_DQ_ICOUNT (1<<13)
+#define FS_DQ_RTBCOUNT (1<<14)
+#define FS_DQ_ACCT_MASK (FS_DQ_BCOUNT | FS_DQ_ICOUNT | FS_DQ_RTBCOUNT)
+
+/*
+ * Quota expiration timestamps are 40-bit signed integers, with the upper 8
+ * bits encoded in the _hi fields.
+ */
+#define FS_DQ_BIGTIME (1<<15)
+
/*
* Various flags related to quotactl(2). Only relevant to XFS filesystems.
*/
diff --git a/quota/edit.c b/quota/edit.c
index b3cad02..1a3b2d9 100644
--- a/quota/edit.c
+++ b/quota/edit.c
@@ -417,6 +417,53 @@ restore_f(
return 0;
}
+time64_t
+decode_timer(
+ const struct fs_disk_quota *d,
+ __s32 timer_lo,
+ __s8 timer_hi)
+{
+ if (d->d_fieldmask & FS_DQ_BIGTIME)
+ return (uint32_t)timer_lo | (int64_t)timer_hi << 32;
+ return timer_lo;
+}
+
+static inline void
+encode_timer(
+ const struct fs_disk_quota *d,
+ __s32 *timer_lo,
+ __s8 *timer_hi,
+ time64_t timer)
+{
+ *timer_lo = timer;
+ if (d->d_fieldmask & FS_DQ_BIGTIME)
+ *timer_hi = timer >> 32;
+ else
+ *timer_hi = 0;
+}
+
+static inline bool want_bigtime(time64_t timer)
+{
+ return timer > INT32_MAX || timer < INT32_MIN;
+}
+
+static void
+encode_timers(
+ struct fs_disk_quota *d,
+ time64_t btimer,
+ time64_t itimer,
+ time64_t rtbtimer)
+{
+ d->d_fieldmask &= ~FS_DQ_BIGTIME;
+ if (want_bigtime(btimer) || want_bigtime(itimer) ||
+ want_bigtime(rtbtimer))
+ d->d_fieldmask |= FS_DQ_BIGTIME;
+
+ encode_timer(d, &d->d_btimer, &d->d_btimer_hi, btimer);
+ encode_timer(d, &d->d_itimer, &d->d_itimer_hi, itimer);
+ encode_timer(d, &d->d_rtbtimer, &d->d_rtbtimer_hi, rtbtimer);
+}
+
static void
set_timer(
uint32_t id,
@@ -426,6 +473,7 @@ set_timer(
time64_t value)
{
struct fs_disk_quota d;
+ time64_t btimer, itimer, rtbtimer;
memset(&d, 0, sizeof(d));
@@ -446,23 +494,28 @@ set_timer(
time(&now);
+ btimer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
+ itimer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
+ rtbtimer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
+
/* Only set grace time if user is already past soft limit */
if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
- d.d_btimer = now + value;
+ btimer = now + value;
if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
- d.d_itimer = now + value;
+ itimer = now + value;
if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
- d.d_rtbtimer = now + value;
+ rtbtimer = now + value;
} else {
- d.d_btimer = value;
- d.d_itimer = value;
- d.d_rtbtimer = value;
+ btimer = value;
+ itimer = value;
+ rtbtimer = value;
}
d.d_version = FS_DQUOT_VERSION;
d.d_flags = type;
d.d_fieldmask = mask;
d.d_id = id;
+ encode_timers(&d, btimer, itimer, rtbtimer);
if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
exitcode = 1;
diff --git a/quota/quota.c b/quota/quota.c
index 8ba0995..0747ced 100644
--- a/quota/quota.c
+++ b/quota/quota.c
@@ -101,7 +101,7 @@ quota_mount(
}
if (form & XFS_BLOCK_QUOTA) {
- timer = d.d_btimer;
+ timer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
qflags = (flags & HUMAN_FLAG);
if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
qflags |= LIMIT_FLAG;
@@ -123,7 +123,7 @@ quota_mount(
time_to_string(timer, qflags));
}
if (form & XFS_INODE_QUOTA) {
- timer = d.d_itimer;
+ timer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
qflags = (flags & HUMAN_FLAG);
if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
qflags |= LIMIT_FLAG;
@@ -145,7 +145,7 @@ quota_mount(
time_to_string(timer, qflags));
}
if (form & XFS_RTBLOCK_QUOTA) {
- timer = d.d_rtbtimer;
+ timer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
qflags = (flags & HUMAN_FLAG);
if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
qflags |= LIMIT_FLAG;
diff --git a/quota/quota.h b/quota/quota.h
index 13ae450..74eb146 100644
--- a/quota/quota.h
+++ b/quota/quota.h
@@ -3,6 +3,8 @@
* Copyright (c) 2005 Silicon Graphics, Inc.
* All Rights Reserved.
*/
+#ifndef XFS_QUOTA_QUOTA_H_
+#define XFS_QUOTA_QUOTA_H_
#include "xqm.h"
#include "path.h"
@@ -73,3 +75,8 @@ extern char *uid_to_name(uint32_t __uid);
extern char *gid_to_name(uint32_t __gid);
extern char *prid_to_name(uint32_t __prid);
extern bool isdigits_only(const char *);
+
+time64_t decode_timer(const struct fs_disk_quota *d, __s32 timer_lo,
+ __s8 timer_hi);
+
+#endif /* XFS_QUOTA_QUOTA_H_ */
diff --git a/quota/report.c b/quota/report.c
index 2d5024e..6ac5549 100644
--- a/quota/report.c
+++ b/quota/report.c
@@ -398,7 +398,7 @@ report_mount(
}
if (form & XFS_BLOCK_QUOTA) {
- timer = d.d_btimer;
+ timer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
qflags = (flags & HUMAN_FLAG);
if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
qflags |= LIMIT_FLAG;
@@ -420,7 +420,7 @@ report_mount(
time_to_string(timer, qflags));
}
if (form & XFS_INODE_QUOTA) {
- timer = d.d_itimer;
+ timer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
qflags = (flags & HUMAN_FLAG);
if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
qflags |= LIMIT_FLAG;
@@ -442,7 +442,7 @@ report_mount(
time_to_string(timer, qflags));
}
if (form & XFS_RTBLOCK_QUOTA) {
- timer = d.d_rtbtimer;
+ timer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
qflags = (flags & HUMAN_FLAG);
if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
qflags |= LIMIT_FLAG;

@ -0,0 +1,92 @@
xfs_repair: Use proper min/max values in compute_level_geometry
When compute_level_geometry was added it exclusively uses
m_alloc_mnr/m_alloc_mxr but the rmap btree should be using
m_rmap_mnr/m_rmap_mxr. Pass those in directly to fix the
problem.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
diff --git a/repair/phase5.c b/repair/phase5.c
index 0b8a55ff..dff342c8 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -355,12 +355,12 @@ compute_level_geometry(
struct bt_stat_level *lptr,
uint64_t nr_this_level,
int slack,
- bool leaf)
+ uint maxrecs,
+ uint minrecs)
{
- unsigned int maxrecs = mp->m_alloc_mxr[!leaf];
unsigned int desired_npb;
- desired_npb = max(mp->m_alloc_mnr[!leaf], maxrecs - slack);
+ desired_npb = max(minrecs, maxrecs - slack);
lptr->num_recs_tot = nr_this_level;
lptr->num_blocks = max(1ULL, nr_this_level / desired_npb);
@@ -410,7 +410,8 @@ calculate_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno,
* of the tree and set up the cursor for the leaf level
* (note that the same code is duplicated further down)
*/
- compute_level_geometry(mp, lptr, num_extents, 2, true);
+ compute_level_geometry(mp, lptr, num_extents, 2,
+ mp->m_alloc_mxr[0], mp->m_alloc_mnr[0]);
level = 1;
#ifdef XR_BLD_FREE_TRACE
@@ -429,7 +430,8 @@ calculate_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno,
lptr = &btree_curs->level[level];
compute_level_geometry(mp, lptr,
- p_lptr->num_blocks, 0, false);
+ p_lptr->num_blocks, 0,
+ mp->m_alloc_mxr[1], mp->m_alloc_mnr[1]);
#ifdef XR_BLD_FREE_TRACE
fprintf(stderr, "%s %d %d %d %d %d\n", __func__,
level,
@@ -509,7 +511,8 @@ calculate_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno,
* of the number of extents changing
*/
old_blocks = btree_curs->level[0].num_blocks;
- compute_level_geometry(mp, &btree_curs->level[0], num_extents, 2, true);
+ compute_level_geometry(mp, &btree_curs->level[0], num_extents, 2,
+ mp->m_alloc_mxr[0], mp->m_alloc_mnr[0]);
extra_blocks = 0;
if (old_blocks != btree_curs->level[0].num_blocks) {
@@ -578,7 +581,8 @@ calculate_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno,
lptr = &btree_curs->level[level++];
compute_level_geometry(mp, lptr,
- p_lptr->num_blocks, 0, false);
+ p_lptr->num_blocks, 0,
+ mp->m_alloc_mxr[1], mp->m_alloc_mnr[1]);
}
ASSERT(level < XFS_BTREE_MAXLEVELS);
ASSERT(lptr->num_blocks == 1);
@@ -1399,7 +1403,8 @@ init_rmapbt_cursor(
* metadata AG entries without too many splits.
*/
compute_level_geometry(mp, lptr, num_recs,
- num_recs > mp->m_rmap_mxr[0] ? 10 : 0, true);
+ num_recs > mp->m_rmap_mxr[0] ? 10 : 0,
+ mp->m_rmap_mxr[0], mp->m_rmap_mnr[0]);
blocks_allocated = lptr->num_blocks;
level = 1;
@@ -1408,7 +1413,8 @@ init_rmapbt_cursor(
lptr = &btree_curs->level[level++];
compute_level_geometry(mp, lptr,
- p_lptr->num_blocks, 0, false);
+ p_lptr->num_blocks, 0,
+ mp->m_rmap_mxr[1], mp->m_rmap_mnr[1]);
blocks_allocated += lptr->num_blocks;
}
ASSERT(level < XFS_BTREE_MAXLEVELS);

@ -0,0 +1,98 @@
From 62c713cb0c7791717c0b2a663ff0cc72842fe6c7 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:27 -0500
Subject: [PATCH] xfs_repair: check inode btree block counters in AGI
Make sure that both inode btree block counters in the AGI are correct.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/repair/scan.c b/repair/scan.c
index 5b76212..086a3cd 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -1933,6 +1933,12 @@ _("invalid inode count, inode chunk %d/%u, count %d ninodes %d\n"),
return suspect;
}
+struct ino_priv {
+ struct aghdr_cnts *agcnts;
+ uint32_t ino_blocks;
+ uint32_t fino_blocks;
+};
+
/*
* this one walks the inode btrees sucking the info there into
* the incore avl tree. We try and rescue corrupted btree records
@@ -1961,7 +1967,8 @@ scan_inobt(
void *priv,
const struct xfs_buf_ops *ops)
{
- struct aghdr_cnts *agcnts = priv;
+ struct ino_priv *ipriv = priv;
+ struct aghdr_cnts *agcnts = ipriv->agcnts;
char *name;
int i;
int numrecs;
@@ -1977,10 +1984,12 @@ scan_inobt(
case XFS_FIBT_MAGIC:
case XFS_FIBT_CRC_MAGIC:
name = "fino";
+ ipriv->fino_blocks++;
break;
case XFS_IBT_MAGIC:
case XFS_IBT_CRC_MAGIC:
name = "ino";
+ ipriv->ino_blocks++;
break;
default:
name = "(unknown)";
@@ -2320,6 +2329,9 @@ validate_agi(
xfs_agnumber_t agno,
struct aghdr_cnts *agcnts)
{
+ struct ino_priv priv = {
+ .agcnts = agcnts,
+ };
xfs_agblock_t bno;
int i;
uint32_t magic;
@@ -2329,7 +2341,7 @@ validate_agi(
magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_IBT_CRC_MAGIC
: XFS_IBT_MAGIC;
scan_sbtree(bno, be32_to_cpu(agi->agi_level),
- agno, 0, scan_inobt, 1, magic, agcnts,
+ agno, 0, scan_inobt, 1, magic, &priv,
&xfs_inobt_buf_ops);
} else {
do_warn(_("bad agbno %u for inobt root, agno %d\n"),
@@ -2342,7 +2354,7 @@ validate_agi(
magic = xfs_sb_version_hascrc(&mp->m_sb) ?
XFS_FIBT_CRC_MAGIC : XFS_FIBT_MAGIC;
scan_sbtree(bno, be32_to_cpu(agi->agi_free_level),
- agno, 0, scan_inobt, 1, magic, agcnts,
+ agno, 0, scan_inobt, 1, magic, &priv,
&xfs_inobt_buf_ops);
} else {
do_warn(_("bad agbno %u for finobt root, agno %d\n"),
@@ -2350,6 +2362,17 @@ validate_agi(
}
}
+ if (xfs_sb_version_hasinobtcounts(&mp->m_sb)) {
+ if (be32_to_cpu(agi->agi_iblocks) != priv.ino_blocks)
+ do_warn(_("bad inobt block count %u, saw %u\n"),
+ be32_to_cpu(agi->agi_iblocks),
+ priv.ino_blocks);
+ if (be32_to_cpu(agi->agi_fblocks) != priv.fino_blocks)
+ do_warn(_("bad finobt block count %u, saw %u\n"),
+ be32_to_cpu(agi->agi_fblocks),
+ priv.fino_blocks);
+ }
+
if (be32_to_cpu(agi->agi_count) != agcnts->agicount) {
do_warn(_("agi_count %u, counted %u in ag %u\n"),
be32_to_cpu(agi->agi_count), agcnts->agicount, agno);

@ -0,0 +1,29 @@
From 086250dc5707ee6fcfb1ee8499e7af092904a7a6 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:27 -0500
Subject: [PATCH] xfs_repair: regenerate inode btree block counters in AGI
Reset both inode btree block counters in the AGI when rebuilding the
metadata indexes.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/repair/phase5.c b/repair/phase5.c
index ad9394d..a37d672 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -1126,6 +1126,11 @@ build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs,
agi->agi_free_level = cpu_to_be32(finobt_curs->num_levels);
}
+ if (xfs_sb_version_hasinobtcounts(&mp->m_sb)) {
+ agi->agi_iblocks = cpu_to_be32(btree_curs->num_tot_blocks);
+ agi->agi_fblocks = cpu_to_be32(finobt_curs->num_tot_blocks);
+ }
+
libxfs_writebuf(agi_buf, 0);
}

@ -0,0 +1,81 @@
From 37c7dda1c20bfd2cc73679275bab2dd43e0ad9b8 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 20 Nov 2020 17:03:28 -0500
Subject: [PATCH] xfs_repair: support bigtime timestamp checking
Make sure that inodes don't have the bigtime flag set when the feature
is disabled, and don't check for overflows in the nanoseconds when
bigtime is enabled because that is no longer possible. Also make sure
that quotas don't have bigtime set erroneously.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
NOTE: we do not have quota repair in this version of xfsprogs
diff --git a/repair/dinode.c b/repair/dinode.c
index 0c40f2a..561603b 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -2213,11 +2213,15 @@ static void
check_nsec(
const char *name,
xfs_ino_t lino,
+ struct xfs_dinode *dip,
xfs_timestamp_t *ts,
int *dirty)
{
struct xfs_legacy_timestamp *t;
+ if (xfs_dinode_has_bigtime(dip))
+ return;
+
t = (struct xfs_legacy_timestamp *)ts;
if (be32_to_cpu(t->t_nsec) < NSEC_PER_SEC)
return;
@@ -2625,6 +2629,27 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"),
flags2 &= ~XFS_DIFLAG2_COWEXTSIZE;
}
+ if (xfs_dinode_has_bigtime(dino) &&
+ !xfs_sb_version_hasbigtime(&mp->m_sb)) {
+ if (!uncertain) {
+ do_warn(
+ _("inode %" PRIu64 " is marked bigtime but file system does not support large timestamps\n"),
+ lino);
+ }
+ flags2 &= ~XFS_DIFLAG2_BIGTIME;
+
+ if (no_modify) {
+ do_warn(_("would zero timestamps.\n"));
+ } else {
+ do_warn(_("zeroing timestamps.\n"));
+ dino->di_atime = 0;
+ dino->di_mtime = 0;
+ dino->di_ctime = 0;
+ dino->di_crtime = 0;
+ *dirty = 1;
+ }
+ }
+
if (!verify_mode && flags2 != be64_to_cpu(dino->di_flags2)) {
if (!no_modify) {
do_warn(_("fixing bad flags2.\n"));
@@ -2752,11 +2777,11 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "),
}
/* nsec fields cannot be larger than 1 billion */
- check_nsec("atime", lino, &dino->di_atime, dirty);
- check_nsec("mtime", lino, &dino->di_mtime, dirty);
- check_nsec("ctime", lino, &dino->di_ctime, dirty);
+ check_nsec("atime", lino, dino, &dino->di_atime, dirty);
+ check_nsec("mtime", lino, dino, &dino->di_mtime, dirty);
+ check_nsec("ctime", lino, dino, &dino->di_ctime, dirty);
if (dino->di_version >= 3)
- check_nsec("crtime", lino, &dino->di_crtime, dirty);
+ check_nsec("crtime", lino, dino, &dino->di_crtime, dirty);
/*
* general size/consistency checks:

@ -0,0 +1,38 @@
From 2c40c5a72b3cd0c4599bc84a7a8b09a496d46db3 Mon Sep 17 00:00:00 2001
From: Zorro Lang <zlang@redhat.com>
Date: Fri, 12 Feb 2021 17:23:05 -0500
Subject: [PATCH] mkfs: fix wrong inobtcount usage error output
When mkfs fails, it shows:
...
/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,\n\
inobtcnt=0|1,bigtime=0|1]\n\
...
The "inobtcnt=0|1" is wrong usage, it must be inobtcount, there's not
an alias. To avoid misadvice, fix it.
Signed-off-by: Zorro Lang <zlang@redhat.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
mkfs/xfs_mkfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 0c66255a..964299d3 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -928,7 +928,7 @@ usage( void )
fprintf(stderr, _("Usage: %s\n\
/* blocksize */ [-b size=num]\n\
/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,\n\
- inobtcnt=0|1,bigtime=0|1]\n\
+ inobtcount=0|1,bigtime=0|1]\n\
/* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
(sunit=value,swidth=value|su=num,sw=num|noalign),\n\
sectsize=num\n\
--
2.27.0

@ -0,0 +1,53 @@
From dcad5c60c59bfcdf4e27dc552b94591eced0a452 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <djwong@kernel.org>
Date: Thu, 15 Apr 2021 15:44:10 -0400
Subject: [PATCH] libfrog: report inobtcount in geometry
Report the inode btree counter feature in fs feature reports.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
libfrog/fsgeom.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libfrog/fsgeom.c b/libfrog/fsgeom.c
index 14507668..4f1a1842 100644
--- a/libfrog/fsgeom.c
+++ b/libfrog/fsgeom.c
@@ -29,6 +29,7 @@ xfs_report_geom(
int rmapbt_enabled;
int reflink_enabled;
int bigtime_enabled;
+ int inobtcount;
isint = geo->logstart > 0;
lazycount = geo->flags & XFS_FSOP_GEOM_FLAGS_LAZYSB ? 1 : 0;
@@ -45,12 +46,13 @@ xfs_report_geom(
rmapbt_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_RMAPBT ? 1 : 0;
reflink_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_REFLINK ? 1 : 0;
bigtime_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_BIGTIME ? 1 : 0;
+ inobtcount = geo->flags & XFS_FSOP_GEOM_FLAGS_INOBTCNT ? 1 : 0;
printf(_(
"meta-data=%-22s isize=%-6d agcount=%u, agsize=%u blks\n"
" =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n"
" =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u\n"
-" =%-22s reflink=%-4u bigtime=%u\n"
+" =%-22s reflink=%-4u bigtime=%u inobtcount=%u\n"
"data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
" =%-22s sunit=%-6u swidth=%u blks\n"
"naming =version %-14u bsize=%-6u ascii-ci=%d, ftype=%d\n"
@@ -60,7 +62,7 @@ xfs_report_geom(
mntpoint, geo->inodesize, geo->agcount, geo->agblocks,
"", geo->sectsize, attrversion, projid32bit,
"", crcs_enabled, finobt_enabled, spinodes, rmapbt_enabled,
- "", reflink_enabled, bigtime_enabled,
+ "", reflink_enabled, bigtime_enabled, inobtcount,
"", geo->blocksize, (unsigned long long)geo->datablocks,
geo->imaxpct,
"", geo->sunit, geo->swidth,
--
2.27.0

@ -0,0 +1,29 @@
From d625f74125863304d111f5c6a0817a115f8e502d Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <djwong@kernel.org>
Date: Fri, 7 May 2021 10:42:17 -0400
Subject: [PATCH] libxfs: copy crtime correctly now that it's timespec64
The incore i_mtime and di_crtime are both timespec64 now, which means
that tv_sec is a 64-bit value. Don't cast that to int32_t when we're
creating an inode, because we'll end up truncating the creation time
incorrectly, should an xfsprogs of this vintage make it to 2039. :P
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/util.c b/libxfs/util.c
index 7a8729f..fd4906f 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -326,8 +326,7 @@ libxfs_ialloc(
ip->i_d.di_flags2 = xfs_flags2diflags2(ip, fsx->fsx_xflags);
}
- ip->i_d.di_crtime.tv_sec = (int32_t)VFS_I(ip)->i_mtime.tv_sec;
- ip->i_d.di_crtime.tv_nsec = (int32_t)VFS_I(ip)->i_mtime.tv_nsec;
+ ip->i_d.di_crtime = VFS_I(ip)->i_mtime; /* struct copy */
ip->i_d.di_cowextsize = pip ? 0 : fsx->fsx_cowextsize;
}

@ -0,0 +1,42 @@
From bdeb014153934e1d98787a9609a7532baf6a5c37 Mon Sep 17 00:00:00 2001
From: Zorro Lang <zlang@redhat.com>
Date: Tue, 6 Apr 2021 16:56:32 -0400
Subject: [PATCH] libxfs: expose inobtcount in xfs geometry
Source kernel commit: bc41fa5321f93ecbabec177f888451cfc17ad66d
As xfs supports the feature of inode btree block counters now, expose
this feature flag in xfs geometry, for userspace can check if the
inobtcnt is enabled or not.
Signed-off-by: Zorro Lang <zlang@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index 714dba1..4e4a22e 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -232,6 +232,7 @@ typedef struct xfs_fsop_resblks {
#define XFS_FSOP_GEOM_FLAGS_RMAPBT 0x80000 /* reverse mapping btree */
#define XFS_FSOP_GEOM_FLAGS_REFLINK 0x100000 /* files can share blocks */
#define XFS_FSOP_GEOM_FLAGS_BIGTIME 0x200000 /* 64-bit nsec timestamps */
+#define XFS_FSOP_GEOM_FLAGS_INOBTCNT 0x400000 /* inobt btree counter */
/*
* Minimum and maximum sizes need for growth checks.
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index d11545b..6249e9a 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -1126,6 +1126,8 @@ xfs_fs_geometry(
geo->flags |= XFS_FSOP_GEOM_FLAGS_REFLINK;
if (xfs_sb_version_hasbigtime(sbp))
geo->flags |= XFS_FSOP_GEOM_FLAGS_BIGTIME;
+ if (xfs_sb_version_hasinobtcounts(sbp))
+ geo->flags |= XFS_FSOP_GEOM_FLAGS_INOBTCNT;
if (xfs_sb_version_hassector(sbp))
geo->logsectsize = sbp->sb_logsectsize;
else

@ -0,0 +1,29 @@
From 5b9782c9317b7ac0ff942dffb667bad8502f0932 Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@lst.de>
Date: Wed, 30 Jun 2021 18:29:41 -0400
Subject: [PATCH] xfs: remove the unused xfs_icdinode_has_bigtime helper
Source kernel commit: 55f773380e922d3b975a7acb24331c76611cce30
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_inode_buf.h b/libxfs/xfs_inode_buf.h
index 2b91e60..8d6737b 100644
--- a/libxfs/xfs_inode_buf.h
+++ b/libxfs/xfs_inode_buf.h
@@ -40,11 +40,6 @@ struct xfs_icdinode {
struct timespec64 di_crtime; /* time created */
};
-static inline bool xfs_icdinode_has_bigtime(const struct xfs_icdinode *icd)
-{
- return icd->di_flags2 & XFS_DIFLAG2_BIGTIME;
-}
-
/*
* Inode location information. Stored in the inode and passed to
* xfs_imap_to_bp() to get a buffer and dinode for a given inode.

@ -0,0 +1,46 @@
From 59301887102cc0415c8350a5e9562fe4beb083b6 Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@lst.de>
Date: Wed, 30 Jun 2021 18:38:58 -0400
Subject: [PATCH] xfs: rename struct xfs_legacy_ictimestamp
Source kernel commit: 732de7dbdbd30df40a6d260a8da6fc5262039439
Rename struct xfs_legacy_ictimestamp to struct xfs_log_legacy_timestamp
as it is a type used for logging timestamps with no relationship to the
in-core inode.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_log_format.h b/libxfs/xfs_log_format.h
index 85ac52c..bc26894 100644
--- a/libxfs/xfs_log_format.h
+++ b/libxfs/xfs_log_format.h
@@ -371,7 +371,7 @@ static inline int xfs_ilog_fdata(int w)
typedef uint64_t xfs_log_timestamp_t;
/* Legacy timestamp encoding format. */
-struct xfs_legacy_ictimestamp {
+struct xfs_log_legacy_timestamp {
int32_t t_sec; /* timestamp seconds */
int32_t t_nsec; /* timestamp nanoseconds */
};
diff --git a/logprint/log_misc.c b/logprint/log_misc.c
index f4fd7a8..4889e65 100644
--- a/logprint/log_misc.c
+++ b/logprint/log_misc.c
@@ -745,9 +745,9 @@ time64_t
xlog_extract_dinode_ts(
const xfs_log_timestamp_t its)
{
- struct xfs_legacy_ictimestamp *lits;
+ struct xfs_log_legacy_timestamp *lits;
- lits = (struct xfs_legacy_ictimestamp *)&its;
+ lits = (struct xfs_log_legacy_timestamp *)&its;
return (time64_t)lits->t_sec;
}

@ -0,0 +1,77 @@
From 27bb0efa5e615a9162f5bc3e228bdb7c337faa4c Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@lst.de>
Date: Wed, 30 Jun 2021 18:38:58 -0400
Subject: [PATCH] xfs: rename xfs_ictimestamp_t
Source kernel commit: 6fc277c7c935c7e1fdee23e82da988d9d3cb6bef
Rename xfs_ictimestamp_t to xfs_log_timestamp_t as it is a type used
for logging timestamps with no relationship to the in-core inode.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_log_format.h b/libxfs/xfs_log_format.h
index 8dc0df0..85ac52c 100644
--- a/libxfs/xfs_log_format.h
+++ b/libxfs/xfs_log_format.h
@@ -368,7 +368,7 @@ static inline int xfs_ilog_fdata(int w)
* directly mirrors the xfs_dinode structure as it must contain all the same
* information.
*/
-typedef uint64_t xfs_ictimestamp_t;
+typedef uint64_t xfs_log_timestamp_t;
/* Legacy timestamp encoding format. */
struct xfs_legacy_ictimestamp {
@@ -393,9 +393,9 @@ struct xfs_log_dinode {
uint16_t di_projid_hi; /* higher part of owner's project id */
uint8_t di_pad[6]; /* unused, zeroed space */
uint16_t di_flushiter; /* incremented on flush */
- xfs_ictimestamp_t di_atime; /* time last accessed */
- xfs_ictimestamp_t di_mtime; /* time last modified */
- xfs_ictimestamp_t di_ctime; /* time created/inode modified */
+ xfs_log_timestamp_t di_atime; /* time last accessed */
+ xfs_log_timestamp_t di_mtime; /* time last modified */
+ xfs_log_timestamp_t di_ctime; /* time created/inode modified */
xfs_fsize_t di_size; /* number of bytes in file */
xfs_rfsblock_t di_nblocks; /* # of direct & btree blocks used */
xfs_extlen_t di_extsize; /* basic/minimum extent size for file */
@@ -420,7 +420,7 @@ struct xfs_log_dinode {
uint8_t di_pad2[12]; /* more padding for future expansion */
/* fields only written to during inode creation */
- xfs_ictimestamp_t di_crtime; /* time created */
+ xfs_log_timestamp_t di_crtime; /* time created */
xfs_ino_t di_ino; /* inode number */
uuid_t di_uuid; /* UUID of the filesystem */
diff --git a/logprint/log_misc.c b/logprint/log_misc.c
index 4fad82b..f4fd7a8 100644
--- a/logprint/log_misc.c
+++ b/logprint/log_misc.c
@@ -743,7 +743,7 @@ xlog_print_trans_icreate(
time64_t
xlog_extract_dinode_ts(
- const xfs_ictimestamp_t its)
+ const xfs_log_timestamp_t its)
{
struct xfs_legacy_ictimestamp *lits;
diff --git a/logprint/logprint.h b/logprint/logprint.h
index 0061d5a..fe3831d 100644
--- a/logprint/logprint.h
+++ b/logprint/logprint.h
@@ -18,7 +18,7 @@ extern int print_no_data;
extern int print_no_print;
/* exports */
-extern time64_t xlog_extract_dinode_ts(const xfs_ictimestamp_t);
+extern time64_t xlog_extract_dinode_ts(const xfs_log_timestamp_t);
extern void xlog_print_lseek(struct xlog *, int, xfs_daddr_t, int);
extern void xfs_log_copy(struct xlog *, int, char *);

@ -0,0 +1,70 @@
From 7e8275f8939988f18f9a4a596381ca215fde2270 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Mon, 4 Nov 2019 15:35:49 -0500
Subject: [PATCH] xfs_growfs: allow mounted device node as argument
Up until:
b97815a0 xfs_growfs: ensure target path is an active xfs mountpoint
xfs_growfs actually accepted a mounted block device name as the
primary argument, because it could be found in the mount table.
It turns out that Ansible was making use of this undocumented behavior,
and it's trivial to allow it, so put it back in place and document
it this time.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
growfs/xfs_growfs.c | 3 +++
man/man8/xfs_growfs.8 | 10 +++++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/growfs/xfs_growfs.c b/growfs/xfs_growfs.c
index eab15984..6c62833b 100644
--- a/growfs/xfs_growfs.c
+++ b/growfs/xfs_growfs.c
@@ -141,6 +141,9 @@ main(int argc, char **argv)
}
fs = fs_table_lookup_mount(rpath);
+ if (!fs)
+ fs = fs_table_lookup_blkdev(rpath);
+
if (!fs) {
fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"),
progname, argv[optind]);
diff --git a/man/man8/xfs_growfs.8 b/man/man8/xfs_growfs.8
index 7e6a387c..60a88189 100644
--- a/man/man8/xfs_growfs.8
+++ b/man/man8/xfs_growfs.8
@@ -35,7 +35,12 @@ xfs_growfs \- expand an XFS filesystem
.B \-R
.I size
]
+[
.I mount-point
+|
+.I block-device
+]
+
.br
.B xfs_growfs \-V
.SH DESCRIPTION
@@ -45,7 +50,10 @@ expands an existing XFS filesystem (see
The
.I mount-point
argument is the pathname of the directory where the filesystem
-is mounted. The filesystem must be mounted to be grown (see
+is mounted. The
+.I block-device
+argument is the device name of a mounted XFS filesystem.
+The filesystem must be mounted to be grown (see
.BR mount (8)).
The existing contents of the filesystem are undisturbed, and the added space
becomes available for additional file storage.
--
2.17.0

@ -0,0 +1,109 @@
From 7e8a6edb4d1ba0079152eb477abbbc1dfb1ebb7e Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
Date: Fri, 13 Dec 2019 16:21:26 -0500
Subject: [PATCH] mkfs: Break block discard into chunks of 2 GB
Some users are not happy about the BLKDISCARD taking too long and at the
same time not being informed about that - so they think that the command
actually hung.
This commit changes code so that progress reporting is possible and also
typing the ^C will cancel the ongoing BLKDISCARD.
Signed-off-by: Pavel Reichl <preichl@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
mkfs/xfs_mkfs.c | 50 ++++++++++++++++++++++++++++++++++++-------------
1 file changed, 37 insertions(+), 13 deletions(-)
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 18338a61..4bfdebf6 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -1240,17 +1240,40 @@ done:
}
static void
-discard_blocks(dev_t dev, uint64_t nsectors)
+discard_blocks(dev_t dev, uint64_t nsectors, int quiet)
{
- int fd;
+ int fd;
+ uint64_t offset = 0;
+ /* Discard the device 2G at a time */
+ const uint64_t step = 2ULL << 30;
+ const uint64_t count = BBTOB(nsectors);
- /*
- * We intentionally ignore errors from the discard ioctl. It is
- * not necessary for the mkfs functionality but just an optimization.
- */
fd = libxfs_device_to_fd(dev);
- if (fd > 0)
- platform_discard_blocks(fd, 0, nsectors << 9);
+ if (fd <= 0)
+ return;
+ if (!quiet) {
+ printf("Discarding blocks...");
+ fflush(stdout);
+ }
+
+ /* The block discarding happens in smaller batches so it can be
+ * interrupted prematurely
+ */
+ while (offset < count) {
+ uint64_t tmp_step = min(step, count - offset);
+
+ /*
+ * We intentionally ignore errors from the discard ioctl. It is
+ * not necessary for the mkfs functionality but just an
+ * optimization. However we should stop on error.
+ */
+ if (platform_discard_blocks(fd, offset, tmp_step))
+ return;
+
+ offset += tmp_step;
+ }
+ if (!quiet)
+ printf("Done.\n");
}
static __attribute__((noreturn)) void
@@ -2507,18 +2530,19 @@ open_devices(
static void
discard_devices(
- struct libxfs_xinit *xi)
+ struct libxfs_xinit *xi,
+ int quiet)
{
/*
* This function has to be called after libxfs has been initialized.
*/
if (!xi->disfile)
- discard_blocks(xi->ddev, xi->dsize);
+ discard_blocks(xi->ddev, xi->dsize, quiet);
if (xi->rtdev && !xi->risfile)
- discard_blocks(xi->rtdev, xi->rtsize);
+ discard_blocks(xi->rtdev, xi->rtsize, quiet);
if (xi->logdev && xi->logdev != xi->ddev && !xi->lisfile)
- discard_blocks(xi->logdev, xi->logBBsize);
+ discard_blocks(xi->logdev, xi->logBBsize, quiet);
}
static void
@@ -3749,7 +3773,7 @@ main(
* All values have been validated, discard the old device layout.
*/
if (discard && !dry_run)
- discard_devices(&xi);
+ discard_devices(&xi, quiet);
/*
* we need the libxfs buffer cache from here on in.
--
2.17.0

@ -0,0 +1,56 @@
From 2383d7c5cf20efcff75cb29ca3e02cfbe1bf2209 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Tue, 17 Dec 2019 16:52:39 -0500
Subject: [PATCH] mkfs: tidy up discard notifications
Only notify user of discard operations if the first one succeeds,
and be sure to print a trailing newline if we stop early.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
mkfs/xfs_mkfs.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 4bfdebf6..606f79da 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -1251,10 +1251,6 @@ discard_blocks(dev_t dev, uint64_t nsectors, int quiet)
fd = libxfs_device_to_fd(dev);
if (fd <= 0)
return;
- if (!quiet) {
- printf("Discarding blocks...");
- fflush(stdout);
- }
/* The block discarding happens in smaller batches so it can be
* interrupted prematurely
@@ -1267,12 +1263,20 @@ discard_blocks(dev_t dev, uint64_t nsectors, int quiet)
* not necessary for the mkfs functionality but just an
* optimization. However we should stop on error.
*/
- if (platform_discard_blocks(fd, offset, tmp_step))
+ if (platform_discard_blocks(fd, offset, tmp_step) == 0) {
+ if (offset == 0 && !quiet) {
+ printf("Discarding blocks...");
+ fflush(stdout);
+ }
+ } else {
+ if (offset > 0 && !quiet)
+ printf("\n");
return;
+ }
offset += tmp_step;
}
- if (!quiet)
+ if (offset > 0 && !quiet)
printf("Done.\n");
}
--
2.17.0

@ -0,0 +1,112 @@
From 9d6023a856a1c4f84415dff59b0d5459cc8768db Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Thu, 27 Feb 2020 15:05:48 -0500
Subject: [PATCH] libxfs: use FALLOC_FL_ZERO_RANGE in libxfs_device_zero
I had a request from someone who cared about mkfs speed over
a slower network block device to look into using faster zeroing
methods, particularly for the log, during mkfs.
Using FALLOC_FL_ZERO_RANGE is faster in this case than writing
a bunch of zeros across a wire.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
include/builddefs.in | 3 +++
include/linux.h | 22 ++++++++++++++++++++++
libxfs/rdwr.c | 15 +++++++++++----
3 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/include/builddefs.in b/include/builddefs.in
index 4700b52..1dd27f7 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -144,6 +144,9 @@ endif
ifeq ($(HAVE_GETFSMAP),yes)
PCFLAGS+= -DHAVE_GETFSMAP
endif
+ifeq ($(HAVE_FALLOCATE),yes)
+PCFLAGS += -DHAVE_FALLOCATE
+endif
LIBICU_LIBS = @libicu_LIBS@
LIBICU_CFLAGS = @libicu_CFLAGS@
diff --git a/include/linux.h b/include/linux.h
index 8f3c32b..57726bb 100644
--- a/include/linux.h
+++ b/include/linux.h
@@ -20,6 +20,10 @@
#include <stdio.h>
#include <asm/types.h>
#include <mntent.h>
+#include <fcntl.h>
+#if defined(HAVE_FALLOCATE)
+#include <linux/falloc.h>
+#endif
#ifdef OVERRIDE_SYSTEM_FSXATTR
# define fsxattr sys_fsxattr
#endif
@@ -164,6 +168,24 @@ static inline void platform_mntent_close(struct mntent_cursor * cursor)
endmntent(cursor->mtabp);
}
+#if defined(FALLOC_FL_ZERO_RANGE)
+static inline int
+platform_zero_range(
+ int fd,
+ xfs_off_t start,
+ size_t len)
+{
+ int ret;
+
+ ret = fallocate(fd, FALLOC_FL_ZERO_RANGE, start, len);
+ if (!ret)
+ return 0;
+ return -errno;
+}
+#else
+#define platform_zero_range(fd, s, l) (-EOPNOTSUPP)
+#endif
+
/*
* Check whether we have to define FS_IOC_FS[GS]ETXATTR ourselves. These
* are a copy of the definitions moved to linux/uapi/fs.h in the 4.5 kernel,
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index 0d9d720..e2d9d79 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -61,8 +61,18 @@ libxfs_device_zero(struct xfs_buftarg *btp, xfs_daddr_t start, uint len)
{
xfs_off_t start_offset, end_offset, offset;
ssize_t zsize, bytes;
+ size_t len_bytes;
char *z;
- int fd;
+ int error, fd;
+
+ fd = libxfs_device_to_fd(btp->dev);
+ start_offset = LIBXFS_BBTOOFF64(start);
+
+ /* try to use special zeroing methods, fall back to writes if needed */
+ len_bytes = LIBXFS_BBTOOFF64(len);
+ error = platform_zero_range(fd, start_offset, len_bytes);
+ if (!error)
+ return 0;
zsize = min(BDSTRAT_SIZE, BBTOB(len));
if ((z = memalign(libxfs_device_alignment(), zsize)) == NULL) {
@@ -73,9 +83,6 @@ libxfs_device_zero(struct xfs_buftarg *btp, xfs_daddr_t start, uint len)
}
memset(z, 0, zsize);
- fd = libxfs_device_to_fd(btp->dev);
- start_offset = LIBXFS_BBTOOFF64(start);
-
if ((lseek(fd, start_offset, SEEK_SET)) < 0) {
fprintf(stderr, _("%s: %s seek to offset %llu failed: %s\n"),
progname, __FUNCTION__,
--
2.9.5

@ -0,0 +1,123 @@
From cb49e9a41477791af390a397c97da28da31fb81d Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@lst.de>
Date: Wed, 22 Jan 2020 11:29:44 -0500
Subject: [PATCH] xfs: use a struct timespec64 for the in-core crtime
Source kernel commit: 8d2d878db897d7501aaa2f72e10bb28295bb5498
struct xfs_icdinode is purely an in-memory data structure, so don't use
a log on-disk structure for it. This simplifies the code a bit, and
also reduces our include hell slightly.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
[darrick: fix a minor indenting problem in xfs_trans_ichgtime]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/include/libxfs.h b/include/libxfs.h
index 2bdef70..731561c 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -36,6 +36,8 @@ extern uint32_t crc32c_le(uint32_t crc, unsigned char const *p, size_t len);
#include "xfs_cksum.h"
+#define timespec64 timespec
+
/*
* This mirrors the kernel include for xfs_buf.h - it's implicitly included in
* every files via a similar include in the kernel xfs_linux.h.
diff --git a/include/xfs_inode.h b/include/xfs_inode.h
index 76f9ac7..e03d1cb 100644
--- a/include/xfs_inode.h
+++ b/include/xfs_inode.h
@@ -161,7 +161,6 @@ extern void libxfs_trans_ichgtime(struct xfs_trans *,
struct xfs_inode *, int);
extern int libxfs_iflush_int (struct xfs_inode *, struct xfs_buf *);
-#define timespec64 timespec
extern struct timespec64 current_time(struct inode *inode);
/* Inode Cache Interfaces */
diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
index b45d07e..8232f89 100644
--- a/libxfs/libxfs_priv.h
+++ b/libxfs/libxfs_priv.h
@@ -62,6 +62,8 @@ extern kmem_zone_t *xfs_buf_zone;
extern kmem_zone_t *xfs_inode_zone;
extern kmem_zone_t *xfs_trans_zone;
+#define timespec64 timespec
+
/* CRC stuff, buffer API dependent on it */
#define crc32c(c,p,l) crc32c_le((c),(unsigned char const *)(p),(l))
diff --git a/libxfs/util.c b/libxfs/util.c
index 951f7cf..9383bb8 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -170,10 +170,8 @@ libxfs_trans_ichgtime(
VFS_I(ip)->i_mtime = tv;
if (flags & XFS_ICHGTIME_CHG)
VFS_I(ip)->i_ctime = tv;
- if (flags & XFS_ICHGTIME_CREATE) {
- ip->i_d.di_crtime.t_sec = (int32_t)tv.tv_sec;
- ip->i_d.di_crtime.t_nsec = (int32_t)tv.tv_nsec;
- }
+ if (flags & XFS_ICHGTIME_CREATE)
+ ip->i_d.di_crtime = tv;
}
STATIC uint16_t
@@ -321,8 +319,8 @@ libxfs_ialloc(
VFS_I(ip)->i_version = 1;
ip->i_d.di_flags2 = pip ? 0 : xfs_flags2diflags2(ip,
fsx->fsx_xflags);
- ip->i_d.di_crtime.t_sec = (int32_t)VFS_I(ip)->i_mtime.tv_sec;
- ip->i_d.di_crtime.t_nsec = (int32_t)VFS_I(ip)->i_mtime.tv_nsec;
+ ip->i_d.di_crtime.tv_sec = (int32_t)VFS_I(ip)->i_mtime.tv_sec;
+ ip->i_d.di_crtime.tv_nsec = (int32_t)VFS_I(ip)->i_mtime.tv_nsec;
ip->i_d.di_cowextsize = pip ? 0 : fsx->fsx_cowextsize;
}
diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
index 503990f..975f097 100644
--- a/libxfs/xfs_inode_buf.c
+++ b/libxfs/xfs_inode_buf.c
@@ -254,8 +254,8 @@ xfs_inode_from_disk(
if (to->di_version == 3) {
inode_set_iversion_queried(inode,
be64_to_cpu(from->di_changecount));
- to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec);
- to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec);
+ to->di_crtime.tv_sec = be32_to_cpu(from->di_crtime.t_sec);
+ to->di_crtime.tv_nsec = be32_to_cpu(from->di_crtime.t_nsec);
to->di_flags2 = be64_to_cpu(from->di_flags2);
to->di_cowextsize = be32_to_cpu(from->di_cowextsize);
}
@@ -304,8 +304,8 @@ xfs_inode_to_disk(
if (from->di_version == 3) {
to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
- to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec);
- to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec);
+ to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.tv_sec);
+ to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.tv_nsec);
to->di_flags2 = cpu_to_be64(from->di_flags2);
to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
to->di_ino = cpu_to_be64(ip->i_ino);
diff --git a/libxfs/xfs_inode_buf.h b/libxfs/xfs_inode_buf.h
index ab0f841..c9ac69c 100644
--- a/libxfs/xfs_inode_buf.h
+++ b/libxfs/xfs_inode_buf.h
@@ -37,7 +37,7 @@ struct xfs_icdinode {
uint64_t di_flags2; /* more random flags */
uint32_t di_cowextsize; /* basic cow extent size for file */
- xfs_ictimestamp_t di_crtime; /* time created */
+ struct timespec64 di_crtime; /* time created */
};
/*

@ -0,0 +1,227 @@
From 36dc471cc9bb17868b79cf8dea8151b207387539 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Tue, 26 May 2020 14:36:26 -0400
Subject: [PATCH] xfs_quota: allow individual timer extension
The only grace period which can be set via xfs_quota today is for id 0,
i.e. the default grace period for all users. However, setting an
individual grace period is useful; for example:
Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
Alice uses 150 inodes, and enters a short grace period
Alice really needs to use those 150 inodes past the grace period
The administrator extends Alice's grace period until next Monday
vfs quota users such as ext4 can do this today, with setquota -T
xfs_quota can now accept an optional user id or name (symmetric with
how warn limits are specified), in which case that user's grace period
is extended to expire the given amount of time from now().
To maintain compatibility with old command lines, if none of
[-d|id|name] are specified, default limits are set as before.
(kernelspace requires updates to enable all this as well.)
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
man/man8/xfs_quota.8 | 36 +++++++++++++++++--
quota/edit.c | 83 +++++++++++++++++++++++++++++++++++++-------
2 files changed, 104 insertions(+), 15 deletions(-)
Index: xfsprogs-5.0.0/man/man8/xfs_quota.8
===================================================================
--- xfsprogs-5.0.0.orig/man/man8/xfs_quota.8
+++ xfsprogs-5.0.0/man/man8/xfs_quota.8
@@ -460,14 +460,46 @@ must be specified.
.B \-bir
]
.I value
+[
+.B -d
+|
+.I id
+|
+.I name
+]
.br
Allows the quota enforcement timeout (i.e. the amount of time allowed
to pass before the soft limits are enforced as the hard limits) to
be modified. The current timeout setting can be displayed using the
.B state
-command. The value argument is a number of seconds, but units of
-\&'minutes', 'hours', 'days', and 'weeks' are also understood
+command.
+.br
+When setting the default timer via the
+.B \-d
+option, or for
+.B id
+0, or if no argument is given after
+.I value
+the
+.I value
+argument is a number of seconds indicating the relative amount of time after
+soft limits are exceeded, before hard limits are enforced.
+.br
+When setting any other individual timer by
+.I id
+or
+.I name,
+the
+.I value
+is the number of seconds from now, at which time the hard limits will be enforced.
+This allows extending the grace time of an individual user who has exceeded soft
+limits.
+.br
+For
+.I value,
+units of \&'minutes', 'hours', 'days', and 'weeks' are also understood
(as are their abbreviations 'm', 'h', 'd', and 'w').
+.br
.HP
.B warn
[
Index: xfsprogs-5.0.0/quota/edit.c
===================================================================
--- xfsprogs-5.0.0.orig/quota/edit.c
+++ xfsprogs-5.0.0/quota/edit.c
@@ -419,6 +419,7 @@ restore_f(
static void
set_timer(
+ uint32_t id,
uint type,
uint mask,
char *dev,
@@ -427,14 +428,43 @@ set_timer(
fs_disk_quota_t d;
memset(&d, 0, sizeof(d));
+
+ /*
+ * If id is specified we are extending grace time by value
+ * Otherwise we are setting the default grace time
+ */
+ if (id) {
+ time_t now;
+
+ /* Get quota to find out whether user is past soft limits */
+ if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
+ exitcode = 1;
+ fprintf(stderr, _("%s: cannot get quota: %s\n"),
+ progname, strerror(errno));
+ return;
+ }
+
+ time(&now);
+
+ /* Only set grace time if user is already past soft limit */
+ if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
+ d.d_btimer = now + value;
+ if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
+ d.d_itimer = now + value;
+ if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
+ d.d_rtbtimer = now + value;
+ } else {
+ d.d_btimer = value;
+ d.d_itimer = value;
+ d.d_rtbtimer = value;
+ }
+
d.d_version = FS_DQUOT_VERSION;
d.d_flags = type;
d.d_fieldmask = mask;
- d.d_itimer = value;
- d.d_btimer = value;
- d.d_rtbtimer = value;
+ d.d_id = id;
- if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) {
+ if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
exitcode = 1;
fprintf(stderr, _("%s: cannot set timer: %s\n"),
progname, strerror(errno));
@@ -447,10 +477,15 @@ timer_f(
char **argv)
{
uint value;
- int c, type = 0, mask = 0;
+ char *name = NULL;
+ uint32_t id = 0;
+ int c, flags = 0, type = 0, mask = 0;
- while ((c = getopt(argc, argv, "bgipru")) != EOF) {
+ while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
switch (c) {
+ case 'd':
+ flags |= DEFAULTS_FLAG;
+ break;
case 'b':
mask |= FS_DQ_BTIMER;
break;
@@ -474,23 +509,45 @@ timer_f(
}
}
- if (argc != optind + 1)
+ /*
+ * Older versions of the command did not accept -d|id|name,
+ * so in that case we assume we're setting default timer,
+ * and the last arg is the timer value.
+ *
+ * Otherwise, if the defaults flag is set, we expect 1 more arg for
+ * timer value ; if not, 2 more args: 1 for value, one for id/name.
+ */
+ if (!(flags & DEFAULTS_FLAG) && (argc == optind + 1)) {
+ value = cvttime(argv[optind++]);
+ } else if (flags & DEFAULTS_FLAG) {
+ if (argc != optind + 1)
+ return command_usage(&timer_cmd);
+ value = cvttime(argv[optind++]);
+ } else if (argc == optind + 2) {
+ value = cvttime(argv[optind++]);
+ name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
+ } else
return command_usage(&timer_cmd);
- value = cvttime(argv[optind++]);
+ /* if none of -bir specified, set them all */
if (!mask)
mask = FS_DQ_TIMER_MASK;
if (!type) {
type = XFS_USER_QUOTA;
} else if (type != XFS_GROUP_QUOTA &&
- type != XFS_PROJ_QUOTA &&
- type != XFS_USER_QUOTA) {
+ type != XFS_PROJ_QUOTA &&
+ type != XFS_USER_QUOTA) {
return command_usage(&timer_cmd);
}
- set_timer(type, mask, fs_path->fs_name, value);
+ if (name)
+ id = id_from_string(name, type);
+
+ if (id >= 0)
+ set_timer(id, type, mask, fs_path->fs_name, value);
+
return 0;
}
@@ -616,9 +673,9 @@ edit_init(void)
timer_cmd.name = "timer";
timer_cmd.cfunc = timer_f;
- timer_cmd.argmin = 2;
+ timer_cmd.argmin = 1;
timer_cmd.argmax = -1;
- timer_cmd.args = _("[-bir] [-g|-p|-u] value");
+ timer_cmd.args = _("[-bir] [-g|-p|-u] value [-d|id|name]");
timer_cmd.oneline = _("set quota enforcement timeouts");
timer_cmd.help = timer_help;
timer_cmd.flags = CMD_FLAG_FOREIGN_OK;

@ -0,0 +1,69 @@
From eaa5b0b79bcf2eb36f7a5e1a5b7171ad5ced7bac Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 10 Jul 2020 15:33:36 -0400
Subject: [PATCH] xfs_quota: fix unsigned int id comparisons
Fix compiler warnings about unsigned int comparisons by replacing them
with an explicit check for the one possible invalid value (-1U).
id_from_string sets exitcode to nonzero when it sees this value, so the
call sites don't have to do that.
Coverity-id: 1463855, 1463856, 1463857
Fixes: 67a73d6139d0 ("xfs_quota: refactor code to generate id from name")
Fixes: 36dc471cc9bb ("xfs_quota: allow individual timer extension")
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
quota/edit.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
Index: xfsprogs-5.0.0/quota/edit.c
===================================================================
--- xfsprogs-5.0.0.orig/quota/edit.c
+++ xfsprogs-5.0.0/quota/edit.c
@@ -307,11 +307,11 @@ limit_f(
id = id_from_string(name, type);
- if (id >= 0)
- set_limits(id, type, mask, fs_path->fs_name,
- &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
- else
- exitcode = -1;
+ if (id == -1)
+ return 0;
+
+ set_limits(id, type, mask, fs_path->fs_name,
+ &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
return 0;
}
@@ -545,9 +545,10 @@ timer_f(
if (name)
id = id_from_string(name, type);
- if (id >= 0)
- set_timer(id, type, mask, fs_path->fs_name, value);
+ if (id == -1)
+ return 0;
+ set_timer(id, type, mask, fs_path->fs_name, value);
return 0;
}
@@ -642,11 +643,10 @@ warn_f(
}
id = id_from_string(name, type);
- if (id >= 0)
- set_warnings(id, type, mask, fs_path->fs_name, value);
- else
- exitcode = -1;
+ if (id == -1)
+ return 0;
+ set_warnings(id, type, mask, fs_path->fs_name, value);
return 0;
}

@ -0,0 +1,271 @@
From 67a73d6139d0336eb7ced05bd78a26b57f408187 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Tue, 26 May 2020 14:36:04 -0400
Subject: [PATCH] xfs_quota: refactor code to generate id from name
There's boilerplate for setting limits and warnings, where we have
a case statement for each of the 3 quota types, and from there call
3 different functions to configure each of the 3 types, each of which
calls its own version of id to string function...
Refactor this so that the main function can call a generic id to string
conversion routine, and then call a common action. This save a lot of
LOC.
I was looking at allowing xfs to bump out individual grace periods like
setquota can do, and this refactoring allows us to add new actions like
that without copying all the boilerplate again.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
quota/edit.c | 194 +++++++++++++--------------------------------------
1 file changed, 49 insertions(+), 145 deletions(-)
Index: xfsprogs-5.0.0/quota/edit.c
===================================================================
--- xfsprogs-5.0.0.orig/quota/edit.c
+++ xfsprogs-5.0.0/quota/edit.c
@@ -101,6 +101,40 @@ warn_help(void)
"\n"));
}
+static uint32_t
+id_from_string(
+ char *name,
+ int type)
+{
+ uint32_t id = -1;
+ const char *type_name = "unknown type";
+
+ switch (type) {
+ case XFS_USER_QUOTA:
+ type_name = "user";
+ id = uid_from_string(name);
+ break;
+ case XFS_GROUP_QUOTA:
+ type_name = "group";
+ id = gid_from_string(name);
+ break;
+ case XFS_PROJ_QUOTA:
+ type_name = "project";
+ id = prid_from_string(name);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ if (id == -1) {
+ fprintf(stderr, _("%s: invalid %s name: %s\n"),
+ type_name, progname, name);
+ exitcode = 1;
+ }
+ return id;
+}
+
static void
set_limits(
uint32_t id,
@@ -135,75 +169,6 @@ set_limits(
}
}
-static void
-set_user_limits(
- char *name,
- uint type,
- uint mask,
- uint64_t *bsoft,
- uint64_t *bhard,
- uint64_t *isoft,
- uint64_t *ihard,
- uint64_t *rtbsoft,
- uint64_t *rtbhard)
-{
- uid_t uid = uid_from_string(name);
-
- if (uid == -1) {
- exitcode = 1;
- fprintf(stderr, _("%s: invalid user name: %s\n"),
- progname, name);
- } else
- set_limits(uid, type, mask, fs_path->fs_name,
- bsoft, bhard, isoft, ihard, rtbsoft, rtbhard);
-}
-
-static void
-set_group_limits(
- char *name,
- uint type,
- uint mask,
- uint64_t *bsoft,
- uint64_t *bhard,
- uint64_t *isoft,
- uint64_t *ihard,
- uint64_t *rtbsoft,
- uint64_t *rtbhard)
-{
- gid_t gid = gid_from_string(name);
-
- if (gid == -1) {
- exitcode = 1;
- fprintf(stderr, _("%s: invalid group name: %s\n"),
- progname, name);
- } else
- set_limits(gid, type, mask, fs_path->fs_name,
- bsoft, bhard, isoft, ihard, rtbsoft, rtbhard);
-}
-
-static void
-set_project_limits(
- char *name,
- uint type,
- uint mask,
- uint64_t *bsoft,
- uint64_t *bhard,
- uint64_t *isoft,
- uint64_t *ihard,
- uint64_t *rtbsoft,
- uint64_t *rtbhard)
-{
- prid_t prid = prid_from_string(name);
-
- if (prid == -1) {
- exitcode = 1;
- fprintf(stderr, _("%s: invalid project name: %s\n"),
- progname, name);
- } else
- set_limits(prid, type, mask, fs_path->fs_name,
- bsoft, bhard, isoft, ihard, rtbsoft, rtbhard);
-}
-
/* extract number of blocks from an ascii string */
static int
extractb(
@@ -258,6 +223,7 @@ limit_f(
char **argv)
{
char *name;
+ uint32_t id;
uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard;
int c, type = 0, mask = 0, flags = 0;
uint bsize, ssize, endoptions;
@@ -339,20 +305,13 @@ limit_f(
return command_usage(&limit_cmd);
}
- switch (type) {
- case XFS_USER_QUOTA:
- set_user_limits(name, type, mask,
- &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
- break;
- case XFS_GROUP_QUOTA:
- set_group_limits(name, type, mask,
- &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
- break;
- case XFS_PROJ_QUOTA:
- set_project_limits(name, type, mask,
- &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
- break;
- }
+
+ id = id_from_string(name, type);
+ if (id >= 0)
+ set_limits(id, type, mask, fs_path->fs_name,
+ &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard);
+ else
+ exitcode = -1;
return 0;
}
@@ -561,63 +520,13 @@ set_warnings(
}
}
-static void
-set_user_warnings(
- char *name,
- uint type,
- uint mask,
- uint value)
-{
- uid_t uid = uid_from_string(name);
-
- if (uid == -1) {
- exitcode = 1;
- fprintf(stderr, _("%s: invalid user name: %s\n"),
- progname, name);
- } else
- set_warnings(uid, type, mask, fs_path->fs_name, value);
-}
-
-static void
-set_group_warnings(
- char *name,
- uint type,
- uint mask,
- uint value)
-{
- gid_t gid = gid_from_string(name);
-
- if (gid == -1) {
- exitcode = 1;
- fprintf(stderr, _("%s: invalid group name: %s\n"),
- progname, name);
- } else
- set_warnings(gid, type, mask, fs_path->fs_name, value);
-}
-
-static void
-set_project_warnings(
- char *name,
- uint type,
- uint mask,
- uint value)
-{
- prid_t prid = prid_from_string(name);
-
- if (prid == -1) {
- exitcode = 1;
- fprintf(stderr, _("%s: invalid project name: %s\n"),
- progname, name);
- } else
- set_warnings(prid, type, mask, fs_path->fs_name, value);
-}
-
static int
warn_f(
int argc,
char **argv)
{
char *name;
+ uint32_t id;
uint value;
int c, flags = 0, type = 0, mask = 0;
@@ -675,17 +584,12 @@ warn_f(
return command_usage(&warn_cmd);
}
- switch (type) {
- case XFS_USER_QUOTA:
- set_user_warnings(name, type, mask, value);
- break;
- case XFS_GROUP_QUOTA:
- set_group_warnings(name, type, mask, value);
- break;
- case XFS_PROJ_QUOTA:
- set_project_warnings(name, type, mask, value);
- break;
- }
+ id = id_from_string(name, type);
+ if (id >= 0)
+ set_warnings(id, type, mask, fs_path->fs_name, value);
+ else
+ exitcode = -1;
+
return 0;
}

@ -0,0 +1,54 @@
From cae4fd291266c32441c6a7fcca49929fe11c391c Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 10 Jul 2020 15:35:44 -0400
Subject: [PATCH] xfs_repair: check for AG btree records that would wrap around
For AG btree types, make sure that each record's length is not so huge
that integer wraparound would happen.
Found via xfs/358 fuzzing recs[1].blockcount = ones.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
repair/scan.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/repair/scan.c b/repair/scan.c
index 5c8d8b23..1ddb5763 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -684,7 +684,8 @@ _("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
b, i, name, agno, bno);
continue;
}
- if (len == 0 || !verify_agbno(mp, agno, end - 1)) {
+ if (len == 0 || end <= b ||
+ !verify_agbno(mp, agno, end - 1)) {
do_warn(
_("invalid length %u in record %u of %s btree block %u/%u\n"),
len, i, name, agno, bno);
@@ -1066,7 +1067,8 @@ _("%s rmap btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
b, i, name, agno, bno);
continue;
}
- if (len == 0 || !verify_agbno(mp, agno, end - 1)) {
+ if (len == 0 || end <= b ||
+ !verify_agbno(mp, agno, end - 1)) {
do_warn(
_("invalid length %u in record %u of %s btree block %u/%u\n"),
len, i, name, agno, bno);
@@ -1353,7 +1355,8 @@ _("leftover CoW extent has invalid startblock in record %u of %s btree block %u/
b, i, name, agno, bno);
continue;
}
- if (len == 0 || !verify_agbno(mp, agno, end - 1)) {
+ if (len == 0 || end <= agb ||
+ !verify_agbno(mp, agno, end - 1)) {
do_warn(
_("invalid length %u in record %u of %s btree block %u/%u\n"),
len, i, name, agno, bno);
--
2.29.2

@ -0,0 +1,124 @@
From 320cc3b263542e692c4978fb327efa591892ab37 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 10 Jul 2020 15:35:45 -0400
Subject: [PATCH] xfs_repair: complain about bad interior btree pointers
Actually complain about garbage btree node pointers, don't just silently
ignore them.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
libxfs/libxfs_api_defs.h | 1 +
repair/scan.c | 55 +++++++++++++++++++++++++++++-----------
2 files changed, 41 insertions(+), 15 deletions(-)
Index: xfsprogs-5.0.0/libxfs/libxfs_api_defs.h
===================================================================
--- xfsprogs-5.0.0.orig/libxfs/libxfs_api_defs.h
+++ xfsprogs-5.0.0/libxfs/libxfs_api_defs.h
@@ -118,6 +118,7 @@
#define xfs_symlink_blocks libxfs_symlink_blocks
#define xfs_symlink_hdr_ok libxfs_symlink_hdr_ok
+#define xfs_verify_agbno libxfs_verify_agbno
#define xfs_verify_cksum libxfs_verify_cksum
#define xfs_dinode_verify libxfs_dinode_verify
Index: xfsprogs-5.0.0/repair/scan.c
===================================================================
--- xfsprogs-5.0.0.orig/repair/scan.c
+++ xfsprogs-5.0.0/repair/scan.c
@@ -743,6 +743,14 @@ _("%s freespace btree block claimed (sta
for (i = 0; i < numrecs; i++) {
xfs_agblock_t agbno = be32_to_cpu(pp[i]);
+ if (!libxfs_verify_agbno(mp, agno, agbno)) {
+ do_warn(
+ _("bad btree pointer (%u) in %sbt block %u/%u\n"),
+ agbno, name, agno, bno);
+ suspect++;
+ return;
+ }
+
/*
* XXX - put sibling detection right here.
* we know our sibling chain is good. So as we go,
@@ -752,10 +760,8 @@ _("%s freespace btree block claimed (sta
* pointer mismatch, try and extract as much data
* as possible.
*/
- if (agbno != 0 && verify_agbno(mp, agno, agbno)) {
- scan_sbtree(agbno, level, agno, suspect, scan_allocbt,
- 0, magic, priv, ops);
- }
+ scan_sbtree(agbno, level, agno, suspect, scan_allocbt, 0,
+ magic, priv, ops);
}
}
@@ -1196,10 +1202,16 @@ advance:
continue;
}
- if (agbno != 0 && verify_agbno(mp, agno, agbno)) {
- scan_sbtree(agbno, level, agno, suspect, scan_rmapbt, 0,
- magic, priv, ops);
+ if (!libxfs_verify_agbno(mp, agno, agbno)) {
+ do_warn(
+ _("bad btree pointer (%u) in %sbt block %u/%u\n"),
+ agbno, name, agno, bno);
+ suspect++;
+ return;
}
+
+ scan_sbtree(agbno, level, agno, suspect, scan_rmapbt, 0, magic,
+ priv, ops);
}
out:
@@ -1416,10 +1428,16 @@ _("extent (%u/%u) len %u claimed, state
for (i = 0; i < numrecs; i++) {
xfs_agblock_t agbno = be32_to_cpu(pp[i]);
- if (agbno != 0 && verify_agbno(mp, agno, agbno)) {
- scan_sbtree(agbno, level, agno, suspect, scan_refcbt, 0,
- magic, priv, ops);
+ if (!libxfs_verify_agbno(mp, agno, agbno)) {
+ do_warn(
+ _("bad btree pointer (%u) in %sbt block %u/%u\n"),
+ agbno, name, agno, bno);
+ suspect++;
+ return;
}
+
+ scan_sbtree(agbno, level, agno, suspect, scan_refcbt, 0, magic,
+ priv, ops);
}
out:
if (suspect)
@@ -2083,11 +2101,18 @@ _("inode btree block claimed (state %d),
}
for (i = 0; i < numrecs; i++) {
- if (be32_to_cpu(pp[i]) != 0 && verify_agbno(mp, agno,
- be32_to_cpu(pp[i])))
- scan_sbtree(be32_to_cpu(pp[i]), level, agno,
- suspect, scan_inobt, 0, magic, priv,
- ops);
+ xfs_agblock_t agbno = be32_to_cpu(pp[i]);
+
+ if (!libxfs_verify_agbno(mp, agno, agbno)) {
+ do_warn(
+ _("bad btree pointer (%u) in %sbt block %u/%u\n"),
+ agbno, name, agno, bno);
+ suspect++;
+ return;
+ }
+
+ scan_sbtree(be32_to_cpu(pp[i]), level, agno, suspect,
+ scan_inobt, 0, magic, priv, ops);
}
}

@ -0,0 +1,209 @@
From dcd6c2e1490ba5c59c14ca8ea843ca36048888b8 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 10 Jul 2020 15:35:45 -0400
Subject: [PATCH] xfs_repair: convert to libxfs_verify_agbno
Convert the homegrown verify_agbno callers to use the libxfs function,
as needed. In some places we drop the "bno != 0" checks because those
conditionals are checking btree roots; btree roots should never be
zero if the corresponding feature bit is set; and repair skips the if
clause entirely if the feature bit is disabled.
In effect, this strengthens repair to validate that AG btree pointers
neither point to the AG headers nor past the end of the AG.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
libxfs/libxfs_api_defs.h | 1 +
repair/dinode.c | 11 -----------
repair/dinode.h | 5 -----
repair/scan.c | 36 +++++++++++++++++++++++-------------
4 files changed, 24 insertions(+), 29 deletions(-)
Index: xfsprogs-5.0.0/libxfs/libxfs_api_defs.h
===================================================================
--- xfsprogs-5.0.0.orig/libxfs/libxfs_api_defs.h
+++ xfsprogs-5.0.0/libxfs/libxfs_api_defs.h
@@ -121,6 +121,7 @@
#define xfs_verify_agbno libxfs_verify_agbno
#define xfs_verify_cksum libxfs_verify_cksum
#define xfs_dinode_verify libxfs_dinode_verify
+#define xfs_ag_block_count libxfs_ag_block_count
#define xfs_alloc_ag_max_usable libxfs_alloc_ag_max_usable
#define xfs_allocbt_maxrecs libxfs_allocbt_maxrecs
Index: xfsprogs-5.0.0/repair/dinode.c
===================================================================
--- xfsprogs-5.0.0.orig/repair/dinode.c
+++ xfsprogs-5.0.0/repair/dinode.c
@@ -284,17 +284,6 @@ verify_dfsbno_range(xfs_mount_t *mp,
return (XR_DFSBNORANGE_VALID);
}
-int
-verify_agbno(xfs_mount_t *mp,
- xfs_agnumber_t agno,
- xfs_agblock_t agbno)
-{
- xfs_sb_t *sbp = &mp->m_sb;;
-
- /* range check ag #, ag block. range-checking offset is pointless */
- return verify_ag_bno(sbp, agno, agbno) == 0;
-}
-
static int
process_rt_rec(
xfs_mount_t *mp,
Index: xfsprogs-5.0.0/repair/dinode.h
===================================================================
--- xfsprogs-5.0.0.orig/repair/dinode.h
+++ xfsprogs-5.0.0/repair/dinode.h
@@ -10,11 +10,6 @@ struct blkmap;
struct prefetch_args;
int
-verify_agbno(xfs_mount_t *mp,
- xfs_agnumber_t agno,
- xfs_agblock_t agbno);
-
-int
verify_dfsbno(xfs_mount_t *mp,
xfs_fsblock_t fsbno);
Index: xfsprogs-5.0.0/repair/scan.c
===================================================================
--- xfsprogs-5.0.0.orig/repair/scan.c
+++ xfsprogs-5.0.0/repair/scan.c
@@ -642,14 +642,14 @@ _("%s freespace btree block claimed (sta
len = be32_to_cpu(rp[i].ar_blockcount);
end = b + len;
- if (b == 0 || !verify_agbno(mp, agno, b)) {
+ if (!libxfs_verify_agbno(mp, agno, b)) {
do_warn(
_("invalid start block %u in record %u of %s btree block %u/%u\n"),
b, i, name, agno, bno);
continue;
}
if (len == 0 || end <= b ||
- !verify_agbno(mp, agno, end - 1)) {
+ !libxfs_verify_agbno(mp, agno, end - 1)) {
do_warn(
_("invalid length %u in record %u of %s btree block %u/%u\n"),
len, i, name, agno, bno);
@@ -914,6 +914,16 @@ rmap_in_order(
return offset > lastoffset;
}
+static inline bool
+verify_rmap_agbno(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_agblock_t agbno)
+{
+ return agbno < libxfs_ag_block_count(mp, agno);
+}
+
+
static void
scan_rmapbt(
struct xfs_btree_block *block,
@@ -1031,14 +1041,14 @@ _("%s rmap btree block claimed (state %d
end = key.rm_startblock + key.rm_blockcount;
/* Make sure agbno & len make sense. */
- if (!verify_agbno(mp, agno, b)) {
+ if (!verify_rmap_agbno(mp, agno, b)) {
do_warn(
_("invalid start block %u in record %u of %s btree block %u/%u\n"),
b, i, name, agno, bno);
continue;
}
if (len == 0 || end <= b ||
- !verify_agbno(mp, agno, end - 1)) {
+ !verify_rmap_agbno(mp, agno, end - 1)) {
do_warn(
_("invalid length %u in record %u of %s btree block %u/%u\n"),
len, i, name, agno, bno);
@@ -1325,14 +1335,14 @@ _("leftover CoW extent has invalid start
}
end = agb + len;
- if (!verify_agbno(mp, agno, agb)) {
+ if (!libxfs_verify_agbno(mp, agno, agb)) {
do_warn(
_("invalid start block %u in record %u of %s btree block %u/%u\n"),
b, i, name, agno, bno);
continue;
}
if (len == 0 || end <= agb ||
- !verify_agbno(mp, agno, end - 1)) {
+ !libxfs_verify_agbno(mp, agno, end - 1)) {
do_warn(
_("invalid length %u in record %u of %s btree block %u/%u\n"),
len, i, name, agno, bno);
@@ -2145,7 +2155,7 @@ scan_agfl(
{
struct agfl_state *as = priv;
- if (verify_agbno(mp, as->agno, bno))
+ if (libxfs_verify_agbno(mp, as->agno, bno))
set_bmap(as->agno, bno, XR_E_FREE);
else
do_warn(_("bad agbno %u in agfl, agno %d\n"),
@@ -2217,7 +2227,7 @@ validate_agf(
uint32_t magic;
bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]);
- if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(mp, agno, bno)) {
magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTB_CRC_MAGIC
: XFS_ABTB_MAGIC;
scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
@@ -2229,7 +2239,7 @@ validate_agf(
}
bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]);
- if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(mp, agno, bno)) {
magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTC_CRC_MAGIC
: XFS_ABTC_MAGIC;
scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
@@ -2249,7 +2259,7 @@ validate_agf(
priv.last_rec.rm_owner = XFS_RMAP_OWN_UNKNOWN;
priv.nr_blocks = 0;
bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]);
- if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(mp, agno, bno)) {
scan_sbtree(bno,
be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]),
agno, 0, scan_rmapbt, 1, XFS_RMAP_CRC_MAGIC,
@@ -2267,7 +2277,7 @@ validate_agf(
if (xfs_sb_version_hasreflink(&mp->m_sb)) {
bno = be32_to_cpu(agf->agf_refcount_root);
- if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(mp, agno, bno)) {
struct refc_priv priv;
memset(&priv, 0, sizeof(priv));
@@ -2315,7 +2325,7 @@ validate_agi(
uint32_t magic;
bno = be32_to_cpu(agi->agi_root);
- if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(mp, agno, bno)) {
magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_IBT_CRC_MAGIC
: XFS_IBT_MAGIC;
scan_sbtree(bno, be32_to_cpu(agi->agi_level),
@@ -2328,7 +2338,7 @@ validate_agi(
if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
bno = be32_to_cpu(agi->agi_free_root);
- if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ if (libxfs_verify_agbno(mp, agno, bno)) {
magic = xfs_sb_version_hascrc(&mp->m_sb) ?
XFS_FIBT_CRC_MAGIC : XFS_FIBT_MAGIC;
scan_sbtree(bno, be32_to_cpu(agi->agi_free_level),

@ -0,0 +1,290 @@
From 6df28d12d7760701c9d11e659e374665c5ffd0b9 Mon Sep 17 00:00:00 2001
From: Gao Xiang <hsiangkao@redhat.com>
Date: Fri, 10 Jul 2020 15:32:36 -0400
Subject: [PATCH] xfs_repair: fix rebuilding btree block less than minrecs
In production, we found that sometimes xfs_repair phase 5
rebuilds freespace node block with pointers less than minrecs
and if we trigger xfs_repair again it would report such
the following message:
bad btree nrecs (39, min=40, max=80) in btbno block 0/7882
The background is that xfs_repair starts to rebuild AGFL
after the freespace btree is settled in phase 5 so we may
need to leave necessary room in advance for each btree
leaves in order to avoid freespace btree split and then
result in AGFL rebuild fails. The old mathematics uses
ceil(num_extents / maxrecs) to decide the number of node
blocks. That would be fine without leaving extra space
since minrecs = maxrecs / 2 but if some slack was decreased
from maxrecs, the result would be larger than what is
expected and cause num_recs_pb less than minrecs, i.e:
num_extents = 79, adj_maxrecs = 80 - 2 (slack) = 78
so we'd get
num_blocks = ceil(79 / 78) = 2,
num_recs_pb = 79 / 2 = 39, which is less than
minrecs = 80 / 2 = 40
OTOH, btree bulk loading code behaves in a different way.
As in xfs_btree_bload_level_geometry it wrote
num_blocks = floor(num_extents / maxrecs)
which will never go below minrecs. And when it goes above
maxrecs, just increment num_blocks and recalculate so we
can get the reasonable results.
Later, btree bulk loader will replace the current repair code.
But we may still want to look for a backportable solution
for stable versions. Hence, keep the same logic to avoid
the freespace as well as rmap btree minrecs underflow for now.
Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: Dave Chinner <dchinner@redhat.com>
Cc: Eric Sandeen <sandeen@sandeen.net>
Fixes: 9851fd79bfb1 ("repair: AGFL rebuild fails if btree split required")
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
repair/phase5.c | 152 ++++++++++++++++++++----------------------------
1 file changed, 63 insertions(+), 89 deletions(-)
Index: xfsprogs-5.0.0/repair/phase5.c
===================================================================
--- xfsprogs-5.0.0.orig/repair/phase5.c
+++ xfsprogs-5.0.0/repair/phase5.c
@@ -346,11 +346,32 @@ finish_cursor(bt_status_t *curs)
* failure at runtime. Hence leave a couple of records slack space in
* each block to allow immediate modification of the tree without
* requiring splits to be done.
- *
- * XXX(hch): any reason we don't just look at mp->m_alloc_mxr?
*/
-#define XR_ALLOC_BLOCK_MAXRECS(mp, level) \
- (libxfs_allocbt_maxrecs((mp), (mp)->m_sb.sb_blocksize, (level) == 0) - 2)
+static void
+compute_level_geometry(
+ struct xfs_mount *mp,
+ struct bt_stat_level *lptr,
+ uint64_t nr_this_level,
+ int slack,
+ bool leaf)
+{
+ unsigned int maxrecs = mp->m_alloc_mxr[!leaf];
+ unsigned int desired_npb;
+
+ desired_npb = max(mp->m_alloc_mnr[!leaf], maxrecs - slack);
+ lptr->num_recs_tot = nr_this_level;
+ lptr->num_blocks = max(1ULL, nr_this_level / desired_npb);
+
+ lptr->num_recs_pb = nr_this_level / lptr->num_blocks;
+ lptr->modulo = nr_this_level % lptr->num_blocks;
+ if (lptr->num_recs_pb > maxrecs ||
+ (lptr->num_recs_pb == maxrecs && lptr->modulo)) {
+ lptr->num_blocks++;
+
+ lptr->num_recs_pb = nr_this_level / lptr->num_blocks;
+ lptr->modulo = nr_this_level % lptr->num_blocks;
+ }
+}
/*
* this calculates a freespace cursor for an ag.
@@ -368,6 +389,7 @@ calculate_freespace_cursor(xfs_mount_t *
int i;
int extents_used;
int extra_blocks;
+ uint64_t old_blocks;
bt_stat_level_t *lptr;
bt_stat_level_t *p_lptr;
extent_tree_node_t *ext_ptr;
@@ -386,10 +408,7 @@ calculate_freespace_cursor(xfs_mount_t *
* of the tree and set up the cursor for the leaf level
* (note that the same code is duplicated further down)
*/
- lptr->num_blocks = howmany(num_extents, XR_ALLOC_BLOCK_MAXRECS(mp, 0));
- lptr->num_recs_pb = num_extents / lptr->num_blocks;
- lptr->modulo = num_extents % lptr->num_blocks;
- lptr->num_recs_tot = num_extents;
+ compute_level_geometry(mp, lptr, num_extents, 2, true);
level = 1;
#ifdef XR_BLD_FREE_TRACE
@@ -403,30 +422,23 @@ calculate_freespace_cursor(xfs_mount_t *
* if we need more levels, set them up. # of records
* per level is the # of blocks in the level below it
*/
- if (lptr->num_blocks > 1) {
- for (; btree_curs->level[level - 1].num_blocks > 1
- && level < XFS_BTREE_MAXLEVELS;
- level++) {
- lptr = &btree_curs->level[level];
- p_lptr = &btree_curs->level[level - 1];
- lptr->num_blocks = howmany(p_lptr->num_blocks,
- XR_ALLOC_BLOCK_MAXRECS(mp, level));
- lptr->modulo = p_lptr->num_blocks
- % lptr->num_blocks;
- lptr->num_recs_pb = p_lptr->num_blocks
- / lptr->num_blocks;
- lptr->num_recs_tot = p_lptr->num_blocks;
+ while (lptr->num_blocks > 1) {
+ p_lptr = lptr;
+ lptr = &btree_curs->level[level];
+
+ compute_level_geometry(mp, lptr,
+ p_lptr->num_blocks, 0, false);
#ifdef XR_BLD_FREE_TRACE
- fprintf(stderr, "%s %d %d %d %d %d\n", __func__,
- level,
- lptr->num_blocks,
- lptr->num_recs_pb,
- lptr->modulo,
- lptr->num_recs_tot);
+ fprintf(stderr, "%s %d %d %d %d %d\n", __func__,
+ level,
+ lptr->num_blocks,
+ lptr->num_recs_pb,
+ lptr->modulo,
+ lptr->num_recs_tot);
#endif
- }
+ level++;
}
-
+ ASSERT(level < XFS_BTREE_MAXLEVELS);
ASSERT(lptr->num_blocks == 1);
btree_curs->num_levels = level;
@@ -494,8 +506,11 @@ calculate_freespace_cursor(xfs_mount_t *
* see if the number of leaf blocks will change as a result
* of the number of extents changing
*/
- if (howmany(num_extents, XR_ALLOC_BLOCK_MAXRECS(mp, 0))
- != btree_curs->level[0].num_blocks) {
+ old_blocks = btree_curs->level[0].num_blocks;
+ compute_level_geometry(mp, &btree_curs->level[0], num_extents, 2, true);
+ extra_blocks = 0;
+
+ if (old_blocks != btree_curs->level[0].num_blocks) {
/*
* yes -- recalculate the cursor. If the number of
* excess (overallocated) blocks is < xfs_agfl_size/2, we're ok.
@@ -551,31 +566,19 @@ calculate_freespace_cursor(xfs_mount_t *
}
lptr = &btree_curs->level[0];
- lptr->num_blocks = howmany(num_extents,
- XR_ALLOC_BLOCK_MAXRECS(mp, 0));
- lptr->num_recs_pb = num_extents / lptr->num_blocks;
- lptr->modulo = num_extents % lptr->num_blocks;
- lptr->num_recs_tot = num_extents;
level = 1;
/*
* if we need more levels, set them up
*/
- if (lptr->num_blocks > 1) {
- for (level = 1; btree_curs->level[level-1].num_blocks
- > 1 && level < XFS_BTREE_MAXLEVELS;
- level++) {
- lptr = &btree_curs->level[level];
- p_lptr = &btree_curs->level[level-1];
- lptr->num_blocks = howmany(p_lptr->num_blocks,
- XR_ALLOC_BLOCK_MAXRECS(mp, level));
- lptr->modulo = p_lptr->num_blocks
- % lptr->num_blocks;
- lptr->num_recs_pb = p_lptr->num_blocks
- / lptr->num_blocks;
- lptr->num_recs_tot = p_lptr->num_blocks;
- }
+ while (lptr->num_blocks > 1) {
+ p_lptr = lptr;
+ lptr = &btree_curs->level[level++];
+
+ compute_level_geometry(mp, lptr,
+ p_lptr->num_blocks, 0, false);
}
+ ASSERT(level < XFS_BTREE_MAXLEVELS);
ASSERT(lptr->num_blocks == 1);
btree_curs->num_levels = level;
@@ -589,22 +592,6 @@ calculate_freespace_cursor(xfs_mount_t *
ASSERT(blocks_allocated_total >= blocks_needed);
extra_blocks = blocks_allocated_total - blocks_needed;
- } else {
- if (extents_used > 0) {
- /*
- * reset the leaf level geometry to account
- * for consumed extents. we can leave the
- * rest of the cursor alone since the number
- * of leaf blocks hasn't changed.
- */
- lptr = &btree_curs->level[0];
-
- lptr->num_recs_pb = num_extents / lptr->num_blocks;
- lptr->modulo = num_extents % lptr->num_blocks;
- lptr->num_recs_tot = num_extents;
- }
-
- extra_blocks = 0;
}
btree_curs->num_tot_blocks = blocks_allocated_pt;
@@ -1335,7 +1322,6 @@ init_rmapbt_cursor(
struct bt_stat_level *lptr;
struct bt_stat_level *p_lptr;
xfs_extlen_t blocks_allocated;
- int maxrecs;
if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) {
memset(btree_curs, 0, sizeof(struct bt_status));
@@ -1371,32 +1357,20 @@ init_rmapbt_cursor(
* Leave enough slack in the rmapbt that we can insert the
* metadata AG entries without too many splits.
*/
- maxrecs = mp->m_rmap_mxr[0];
- if (num_recs > maxrecs)
- maxrecs -= 10;
- blocks_allocated = lptr->num_blocks = howmany(num_recs, maxrecs);
-
- lptr->modulo = num_recs % lptr->num_blocks;
- lptr->num_recs_pb = num_recs / lptr->num_blocks;
- lptr->num_recs_tot = num_recs;
+ compute_level_geometry(mp, lptr, num_recs,
+ num_recs > mp->m_rmap_mxr[0] ? 10 : 0, true);
+ blocks_allocated = lptr->num_blocks;
level = 1;
- if (lptr->num_blocks > 1) {
- for (; btree_curs->level[level-1].num_blocks > 1
- && level < XFS_BTREE_MAXLEVELS;
- level++) {
- lptr = &btree_curs->level[level];
- p_lptr = &btree_curs->level[level - 1];
- lptr->num_blocks = howmany(p_lptr->num_blocks,
- mp->m_rmap_mxr[1]);
- lptr->modulo = p_lptr->num_blocks % lptr->num_blocks;
- lptr->num_recs_pb = p_lptr->num_blocks
- / lptr->num_blocks;
- lptr->num_recs_tot = p_lptr->num_blocks;
-
- blocks_allocated += lptr->num_blocks;
- }
+ while (lptr->num_blocks > 1) {
+ p_lptr = lptr;
+ lptr = &btree_curs->level[level++];
+
+ compute_level_geometry(mp, lptr,
+ p_lptr->num_blocks, 0, false);
+ blocks_allocated += lptr->num_blocks;
}
+ ASSERT(level < XFS_BTREE_MAXLEVELS);
ASSERT(lptr->num_blocks == 1);
btree_curs->num_levels = level;

@ -0,0 +1,88 @@
From 08280b4b6efd317c673c6718a27d77e702d0480d Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 10 Jul 2020 15:35:45 -0400
Subject: [PATCH] xfs_repair: tag inobt vs finobt errors properly
Amend the generic inode btree block scanner function to tag correctly
which tree it's complaining about. Previously, dubious finobt headers
would be attributed to the "inode btree", which is at best ambiguous
and misleading at worst.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
repair/scan.c | 36 ++++++++++++++++++++++++++----------
1 file changed, 26 insertions(+), 10 deletions(-)
Index: xfsprogs-5.0.0/repair/scan.c
===================================================================
--- xfsprogs-5.0.0.orig/repair/scan.c
+++ xfsprogs-5.0.0/repair/scan.c
@@ -1934,6 +1934,7 @@ scan_inobt(
const struct xfs_buf_ops *ops)
{
struct aghdr_cnts *agcnts = priv;
+ char *name;
int i;
int numrecs;
int state;
@@ -1944,17 +1945,32 @@ scan_inobt(
hdr_errors = 0;
+ switch (magic) {
+ case XFS_FIBT_MAGIC:
+ case XFS_FIBT_CRC_MAGIC:
+ name = "fino";
+ break;
+ case XFS_IBT_MAGIC:
+ case XFS_IBT_CRC_MAGIC:
+ name = "ino";
+ break;
+ default:
+ name = "(unknown)";
+ assert(0);
+ break;
+ }
+
if (be32_to_cpu(block->bb_magic) != magic) {
- do_warn(_("bad magic # %#x in inobt block %d/%d\n"),
- be32_to_cpu(block->bb_magic), agno, bno);
+ do_warn(_("bad magic # %#x in %sbt block %d/%d\n"),
+ be32_to_cpu(block->bb_magic), name, agno, bno);
hdr_errors++;
bad_ino_btree = 1;
if (suspect)
return;
}
if (be16_to_cpu(block->bb_level) != level) {
- do_warn(_("expected level %d got %d in inobt block %d/%d\n"),
- level, be16_to_cpu(block->bb_level), agno, bno);
+ do_warn(_("expected level %d got %d in %sbt block %d/%d\n"),
+ level, be16_to_cpu(block->bb_level), name, agno, bno);
hdr_errors++;
bad_ino_btree = 1;
if (suspect)
@@ -1976,8 +1992,8 @@ scan_inobt(
default:
set_bmap(agno, bno, XR_E_MULT);
do_warn(
-_("inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
- state, agno, bno, suspect);
+_("%sbt btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
+ name, state, agno, bno, suspect);
}
numrecs = be16_to_cpu(block->bb_numrecs);
@@ -1999,8 +2015,8 @@ _("inode btree block claimed (state %d),
if (hdr_errors) {
bad_ino_btree = 1;
- do_warn(_("dubious inode btree block header %d/%d\n"),
- agno, bno);
+ do_warn(_("dubious %sbt btree block header %d/%d\n"),
+ name, agno, bno);
suspect++;
}

@ -0,0 +1,31 @@
From 7b4a7b3f6bce91be45b54fc68e169cb756dc8c74 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Mon, 24 Aug 2020 12:47:47 -0400
Subject: [PATCH] xfs_db: short circuit type_f if type is unchanged
There's no reason to go through the type change code if the
type has not been changed.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
db/type.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/db/type.c b/db/type.c
index 3cb1e868..572ac6d6 100644
--- a/db/type.c
+++ b/db/type.c
@@ -216,6 +216,8 @@ type_f(
tt = findtyp(argv[1]);
if (tt == NULL) {
dbprintf(_("no such type %s\n"), argv[1]);
+ } else if (iocur_top->typ == tt) {
+ return 0;
} else {
if (iocur_top->typ == NULL)
dbprintf(_("no current object\n"));
--
2.29.2

@ -0,0 +1,76 @@
From ca42fa70929e88781e7daeee4cf4588adb834661 Mon Sep 17 00:00:00 2001
From: Bill O'Donnell <billodo@redhat.com>
Date: Mon, 24 Aug 2020 13:23:23 -0400
Subject: [PATCH] xfs_quota: command error message improvement
Make the error messages for rudimentary xfs_quota commands
(off, enable, disable) more user friendly, instead of the
terse sys error outputs.
Signed-off-by: Bill O'Donnell <billodo@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
quota/state.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/quota/state.c b/quota/state.c
index 8f9718f1..7a595fc6 100644
--- a/quota/state.c
+++ b/quota/state.c
@@ -306,8 +306,16 @@ enable_enforcement(
return;
}
dir = mount->fs_name;
- if (xfsquotactl(XFS_QUOTAON, dir, type, 0, (void *)&qflags) < 0)
- perror("XFS_QUOTAON");
+ if (xfsquotactl(XFS_QUOTAON, dir, type, 0, (void *)&qflags) < 0) {
+ if (errno == EEXIST)
+ fprintf(stderr,
+ _("Quota enforcement already enabled.\n"));
+ else if (errno == EINVAL || errno == ENOSYS)
+ fprintf(stderr,
+ _("Can't enable enforcement when quota off.\n"));
+ else
+ perror("XFS_QUOTAON");
+ }
else if (flags & VERBOSE_FLAG)
state_quotafile_mount(stdout, type, mount, flags);
}
@@ -328,8 +336,16 @@ disable_enforcement(
return;
}
dir = mount->fs_name;
- if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0)
- perror("XFS_QUOTAOFF");
+ if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0) {
+ if (errno == EEXIST)
+ fprintf(stderr,
+ _("Quota enforcement already disabled.\n"));
+ else if (errno == EINVAL || errno == ENOSYS)
+ fprintf(stderr,
+ _("Can't disable enforcement when quota off.\n"));
+ else
+ perror("XFS_QUOTAOFF");
+ }
else if (flags & VERBOSE_FLAG)
state_quotafile_mount(stdout, type, mount, flags);
}
@@ -350,8 +366,12 @@ quotaoff(
return;
}
dir = mount->fs_name;
- if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0)
- perror("XFS_QUOTAOFF");
+ if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0) {
+ if (errno == EEXIST || errno == ENOSYS)
+ fprintf(stderr, _("Quota already off.\n"));
+ else
+ perror("XFS_QUOTAOFF");
+ }
else if (flags & VERBOSE_FLAG)
state_quotafile_mount(stdout, type, mount, flags);
}
--
2.31.1

@ -0,0 +1,52 @@
From 387a96e12a937c1b2ee29a0f2c52245d6a283078 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Mon, 24 Aug 2020 13:23:32 -0400
Subject: [PATCH] xfs_quota: display warning limits when printing quota type
information
We should dump the default warning limits when we're printing quota
information.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
quota/state.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/quota/state.c b/quota/state.c
index 7a595fc6..1627181d 100644
--- a/quota/state.c
+++ b/quota/state.c
@@ -130,6 +130,16 @@ state_timelimit(
time_to_string(timelimit, VERBOSE_FLAG | ABSOLUTE_FLAG));
}
+static void
+state_warnlimit(
+ FILE *fp,
+ uint form,
+ uint16_t warnlimit)
+{
+ fprintf(fp, _("%s max warnings: %u\n"),
+ form_to_string(form), warnlimit);
+}
+
/*
* fs_quota_stat holds a subset of fs_quota_statv; this copies
* the smaller into the larger, leaving any not-present fields
@@ -218,7 +228,11 @@ state_quotafile_mount(
sv.qs_flags & XFS_QUOTA_PDQ_ENFD);
state_timelimit(fp, XFS_BLOCK_QUOTA, sv.qs_btimelimit);
+ state_warnlimit(fp, XFS_BLOCK_QUOTA, sv.qs_bwarnlimit);
+
state_timelimit(fp, XFS_INODE_QUOTA, sv.qs_itimelimit);
+ state_warnlimit(fp, XFS_INODE_QUOTA, sv.qs_iwarnlimit);
+
state_timelimit(fp, XFS_RTBLOCK_QUOTA, sv.qs_rtbtimelimit);
}
--
2.31.1

@ -0,0 +1,141 @@
From d8a9454608ff97e98fb7de0da28f8d40804d2296 Mon Sep 17 00:00:00 2001
From: Bill O'Donnell <billodo@redhat.com>
Date: Mon, 24 Aug 2020 13:23:43 -0400
Subject: [PATCH] xfs_quota: state command should report ugp grace times
Since grace periods are now supported for three quota types (ugp),
modify xfs_quota state command to report times for all three.
Add a helper function for stat reporting.
Signed-off-by: Bill O'Donnell <billodo@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
quota/state.c | 96 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 67 insertions(+), 29 deletions(-)
diff --git a/quota/state.c b/quota/state.c
index 1627181d..19d34ed0 100644
--- a/quota/state.c
+++ b/quota/state.c
@@ -191,49 +191,87 @@ state_stat_to_statv(
}
static void
-state_quotafile_mount(
+state_quotafile_stat(
FILE *fp,
uint type,
- struct fs_path *mount,
+ struct fs_path *mount,
+ struct fs_quota_statv *sv,
+ struct fs_quota_stat *s,
uint flags)
{
- struct fs_quota_stat s;
- struct fs_quota_statv sv;
+ bool accounting, enforcing;
+ struct fs_qfilestatv *qsv;
char *dev = mount->fs_name;
- sv.qs_version = FS_QSTATV_VERSION1;
-
- if (xfsquotactl(XFS_GETQSTATV, dev, type, 0, (void *)&sv) < 0) {
- if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, (void *)&s) < 0) {
+ if (xfsquotactl(XFS_GETQSTATV, dev, type, 0, (void *)sv) < 0) {
+ if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, (void *)s) < 0) {
if (flags & VERBOSE_FLAG)
fprintf(fp,
_("%s quota are not enabled on %s\n"),
type_to_string(type), dev);
return;
}
- state_stat_to_statv(&s, &sv);
+ state_stat_to_statv(s, sv);
+ }
+
+ switch(type) {
+ case XFS_USER_QUOTA:
+ qsv = &sv->qs_uquota;
+ accounting = sv->qs_flags & XFS_QUOTA_UDQ_ACCT;
+ enforcing = sv->qs_flags & XFS_QUOTA_UDQ_ENFD;
+ break;
+ case XFS_GROUP_QUOTA:
+ qsv = &sv->qs_gquota;
+ accounting = sv->qs_flags & XFS_QUOTA_GDQ_ACCT;
+ enforcing = sv->qs_flags & XFS_QUOTA_GDQ_ENFD;
+ break;
+ case XFS_PROJ_QUOTA:
+ qsv = &sv->qs_pquota;
+ accounting = sv->qs_flags & XFS_QUOTA_PDQ_ACCT;
+ enforcing = sv->qs_flags & XFS_QUOTA_PDQ_ENFD;
+ break;
+ default:
+ return;
}
- if (type & XFS_USER_QUOTA)
- state_qfilestat(fp, mount, XFS_USER_QUOTA, &sv.qs_uquota,
- sv.qs_flags & XFS_QUOTA_UDQ_ACCT,
- sv.qs_flags & XFS_QUOTA_UDQ_ENFD);
- if (type & XFS_GROUP_QUOTA)
- state_qfilestat(fp, mount, XFS_GROUP_QUOTA, &sv.qs_gquota,
- sv.qs_flags & XFS_QUOTA_GDQ_ACCT,
- sv.qs_flags & XFS_QUOTA_GDQ_ENFD);
- if (type & XFS_PROJ_QUOTA)
- state_qfilestat(fp, mount, XFS_PROJ_QUOTA, &sv.qs_pquota,
- sv.qs_flags & XFS_QUOTA_PDQ_ACCT,
- sv.qs_flags & XFS_QUOTA_PDQ_ENFD);
-
- state_timelimit(fp, XFS_BLOCK_QUOTA, sv.qs_btimelimit);
- state_warnlimit(fp, XFS_BLOCK_QUOTA, sv.qs_bwarnlimit);
-
- state_timelimit(fp, XFS_INODE_QUOTA, sv.qs_itimelimit);
- state_warnlimit(fp, XFS_INODE_QUOTA, sv.qs_iwarnlimit);
-
- state_timelimit(fp, XFS_RTBLOCK_QUOTA, sv.qs_rtbtimelimit);
+
+ state_qfilestat(fp, mount, type, qsv, accounting, enforcing);
+
+ state_timelimit(fp, XFS_BLOCK_QUOTA, sv->qs_btimelimit);
+ state_warnlimit(fp, XFS_BLOCK_QUOTA, sv->qs_bwarnlimit);
+
+ state_timelimit(fp, XFS_INODE_QUOTA, sv->qs_itimelimit);
+ state_warnlimit(fp, XFS_INODE_QUOTA, sv->qs_iwarnlimit);
+
+ state_timelimit(fp, XFS_RTBLOCK_QUOTA, sv->qs_rtbtimelimit);
+}
+
+static void
+state_quotafile_mount(
+ FILE *fp,
+ uint type,
+ struct fs_path *mount,
+ uint flags)
+{
+ struct fs_quota_stat s;
+ struct fs_quota_statv sv;
+
+ sv.qs_version = FS_QSTATV_VERSION1;
+
+ if (type & XFS_USER_QUOTA) {
+ state_quotafile_stat(fp, XFS_USER_QUOTA, mount,
+ &sv, &s, flags);
+ }
+
+ if (type & XFS_GROUP_QUOTA) {
+ state_quotafile_stat(fp, XFS_GROUP_QUOTA, mount,
+ &sv, &s, flags);
+ }
+
+ if (type & XFS_PROJ_QUOTA) {
+ state_quotafile_stat(fp, XFS_PROJ_QUOTA, mount,
+ &sv, &s, flags);
+ }
}
static void
--
2.31.1

@ -0,0 +1,76 @@
From 97a4059660b27a9b0e3d8cdde5dbef8712685865 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
Date: Mon, 28 Sep 2020 17:31:18 -0400
Subject: [PATCH] mkfs.xfs: fix ASSERT on too-small device with stripe geometry
When a too-small device is created with stripe geometry, we hit an
assert in align_ag_geometry():
mkfs.xfs: xfs_mkfs.c:2834: align_ag_geometry: Assertion `cfg->agcount != 0' failed.
This is because align_ag_geometry() finds that the size of the last
(only) AG is too small, and attempts to trim it off. Obviously 0
AGs is invalid, and we hit the ASSERT.
Reported-by: Zdenek Kabelac <zkabelac@redhat.com>
Suggested-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Pavel Reichl <preichl@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
include/xfs_multidisk.h | 14 +++++++-------
mkfs/xfs_mkfs.c | 6 +++---
2 files changed, 10 insertions(+), 10 deletions(-)
Index: xfsprogs-5.0.0/include/xfs_multidisk.h
===================================================================
--- xfsprogs-5.0.0.orig/include/xfs_multidisk.h
+++ xfsprogs-5.0.0/include/xfs_multidisk.h
@@ -14,7 +14,6 @@
#define XFS_DFL_BLOCKSIZE_LOG 12 /* 4096 byte blocks */
#define XFS_DINODE_DFL_LOG 8 /* 256 byte inodes */
#define XFS_DINODE_DFL_CRC_LOG 9 /* 512 byte inodes for CRCs */
-#define XFS_MIN_DATA_BLOCKS 100
#define XFS_MIN_INODE_PERBLOCK 2 /* min inodes per block */
#define XFS_DFL_IMAXIMUM_PCT 25 /* max % of space for inodes */
#define XFS_MIN_REC_DIRSIZE 12 /* 4096 byte dirblocks (V2) */
@@ -25,13 +24,14 @@
* accept w/o warnings
*/
-#define XFS_AG_BYTES(bblog) ((long long)BBSIZE << (bblog))
-#define XFS_AG_MIN_BYTES ((XFS_AG_BYTES(15))) /* 16 MB */
-#define XFS_AG_MAX_BYTES ((XFS_AG_BYTES(31))) /* 1 TB */
-#define XFS_AG_MIN_BLOCKS(blog) (XFS_AG_MIN_BYTES >> (blog))
-#define XFS_AG_MAX_BLOCKS(blog) ((XFS_AG_MAX_BYTES - 1) >> (blog))
+#define XFS_AG_BYTES(bblog) ((long long)BBSIZE << (bblog))
+#define XFS_MIN_DATA_BLOCKS(cfg) (XFS_AG_MIN_BLOCKS((cfg)->blocklog))
+#define XFS_AG_MIN_BYTES ((XFS_AG_BYTES(15))) /* 16 MB */
+#define XFS_AG_MAX_BYTES ((XFS_AG_BYTES(31))) /* 1 TB */
+#define XFS_AG_MIN_BLOCKS(blog) (XFS_AG_MIN_BYTES >> (blog))
+#define XFS_AG_MAX_BLOCKS(blog) ((XFS_AG_MAX_BYTES - 1) >> (blog))
-#define XFS_MAX_AGNUMBER ((xfs_agnumber_t)(NULLAGNUMBER - 1))
+#define XFS_MAX_AGNUMBER ((xfs_agnumber_t)(NULLAGNUMBER - 1))
/*
* These values define what we consider a "multi-disk" filesystem. That is, a
Index: xfsprogs-5.0.0/mkfs/xfs_mkfs.c
===================================================================
--- xfsprogs-5.0.0.orig/mkfs/xfs_mkfs.c
+++ xfsprogs-5.0.0/mkfs/xfs_mkfs.c
@@ -2581,10 +2581,10 @@ _("size %s specified for data subvolume
cfg->dblocks = DTOBT(xi->dsize, cfg->blocklog);
}
- if (cfg->dblocks < XFS_MIN_DATA_BLOCKS) {
+ if (cfg->dblocks < XFS_MIN_DATA_BLOCKS(cfg)) {
fprintf(stderr,
-_("size %lld of data subvolume is too small, minimum %d blocks\n"),
- (long long)cfg->dblocks, XFS_MIN_DATA_BLOCKS);
+_("size %lld of data subvolume is too small, minimum %lld blocks\n"),
+ (long long)cfg->dblocks, XFS_MIN_DATA_BLOCKS(cfg));
usage();
}

@ -0,0 +1,101 @@
From bce109af5ea0b0d6547d8cd0500560f32532e6bd Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Fri, 4 Sep 2020 16:05:20 -0400
Subject: [PATCH] xfs: drop the type parameter from xfs_dquot_verify
Source kernel commit: f9751c4ad3d17fa93773c187732f10c8a49940e3
xfs_qm_reset_dqcounts (aka quotacheck) is the only xfs_dqblk_verify
caller that actually knows the specific quota type that it's looking
for. Since everything else just pass in type==0 (including the buffer
verifier), drop the parameter and open-code the check like
xfs_dquot_from_disk already does.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
diff --git a/libxfs/xfs_dquot_buf.c b/libxfs/xfs_dquot_buf.c
index 5e31938..a3e8ba1 100644
--- a/libxfs/xfs_dquot_buf.c
+++ b/libxfs/xfs_dquot_buf.c
@@ -37,8 +37,7 @@ xfs_failaddr_t
xfs_dquot_verify(
struct xfs_mount *mp,
xfs_disk_dquot_t *ddq,
- xfs_dqid_t id,
- uint type) /* used only during quotacheck */
+ xfs_dqid_t id) /* used only during quotacheck */
{
/*
* We can encounter an uninitialized dquot buffer for 2 reasons:
@@ -60,8 +59,6 @@ xfs_dquot_verify(
if (ddq->d_version != XFS_DQUOT_VERSION)
return __this_address;
- if (type && ddq->d_flags != type)
- return __this_address;
if (ddq->d_flags != XFS_DQ_USER &&
ddq->d_flags != XFS_DQ_PROJ &&
ddq->d_flags != XFS_DQ_GROUP)
@@ -95,14 +92,13 @@ xfs_failaddr_t
xfs_dqblk_verify(
struct xfs_mount *mp,
struct xfs_dqblk *dqb,
- xfs_dqid_t id,
- uint type) /* used only during quotacheck */
+ xfs_dqid_t id) /* used only during quotacheck */
{
if (xfs_sb_version_hascrc(&mp->m_sb) &&
!uuid_equal(&dqb->dd_uuid, &mp->m_sb.sb_meta_uuid))
return __this_address;
- return xfs_dquot_verify(mp, &dqb->dd_diskdq, id, type);
+ return xfs_dquot_verify(mp, &dqb->dd_diskdq, id);
}
/*
@@ -207,7 +203,7 @@ xfs_dquot_buf_verify(
if (i == 0)
id = be32_to_cpu(ddq->d_id);
- fa = xfs_dqblk_verify(mp, &dqb[i], id + i, 0);
+ fa = xfs_dqblk_verify(mp, &dqb[i], id + i);
if (fa) {
if (!readahead)
xfs_buf_verifier_error(bp, -EFSCORRUPTED,
diff --git a/libxfs/xfs_quota_defs.h b/libxfs/xfs_quota_defs.h
index d3f2977..afe1ea0 100644
--- a/libxfs/xfs_quota_defs.h
+++ b/libxfs/xfs_quota_defs.h
@@ -140,9 +140,9 @@ typedef uint16_t xfs_qwarncnt_t;
#define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS)
extern xfs_failaddr_t xfs_dquot_verify(struct xfs_mount *mp,
- struct xfs_disk_dquot *ddq, xfs_dqid_t id, uint type);
+ struct xfs_disk_dquot *ddq, xfs_dqid_t id);
extern xfs_failaddr_t xfs_dqblk_verify(struct xfs_mount *mp,
- struct xfs_dqblk *dqb, xfs_dqid_t id, uint type);
+ struct xfs_dqblk *dqb, xfs_dqid_t id);
extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
extern int xfs_dqblk_repair(struct xfs_mount *mp, struct xfs_dqblk *dqb,
xfs_dqid_t id, uint type);
diff --git a/repair/dinode.c b/repair/dinode.c
index 04c2dd5..77f78f1 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -1233,8 +1233,10 @@ _("cannot read inode %" PRIu64 ", file block %" PRIu64 ", disk block %" PRIu64 "
goto bad;
}
}
- if (libxfs_dquot_verify(mp, &dqb->dd_diskdq, dqid,
- quota_type) != NULL) {
+ if (libxfs_dquot_verify(mp, &dqb->dd_diskdq, dqid)
+ != NULL ||
+ (dqb->dd_diskdq.d_flags & XFS_DQ_ALLTYPES)
+ != quota_type) {
do_warn(_("%s: Corrupt quota for id %u. "),
quota_string, dqid);
bad_dqb = 1;

@ -0,0 +1,98 @@
From 28518f7782310951019d6d28f2a6e9f9fc6e4a1c Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 15 Sep 2020 15:50:35 -0400
Subject: [PATCH] xfs: improve ondisk dquot flags checking
Source kernel commit: a990f7a84edc9941956ea3c1dfb89733c80f9ad0
Create an XFS_DQTYPE_ANY mask for ondisk dquots flags, and use that to
ensure that we never accept any garbage flags when we're loading dquots.
While we're at it, restructure the quota type flag checking to use the
proper masking.
Note that I plan to add y2038 support soon, which will require a new
xfs_dqtype_t flag for extended timestamp support, hence all the work to
make the type masking work correctly.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
---
NOTES: I did not backport the type-vs-flags split, so some of the
naming convenstions are different here.
diff --git a/db/check.c b/db/check.c
index c3dae20..27f6639 100644
--- a/db/check.c
+++ b/db/check.c
@@ -3452,7 +3452,7 @@ process_quota(
error++;
continue;
}
- if (dqb->dd_diskdq.d_flags != exp_flags) {
+ if (dqb->dd_diskdq.d_flags & ~XFS_DQTYPE_ANY) {
if (scicb)
dbprintf(_("bad flags %#x for %s dqblk "
"%lld entry %d id %u\n"),
@@ -3461,6 +3461,17 @@ process_quota(
error++;
continue;
}
+ if ((dqb->dd_diskdq.d_flags & XFS_DQ_ALLTYPES)
+ != exp_flags) {
+ if (scicb)
+ dbprintf(_("wrong type %#x for %s dqblk "
+ "%lld entry %d id %u\n"),
+ dqb->dd_diskdq.d_flags &
+ XFS_DQ_ALLTYPES, s,
+ (xfs_fileoff_t)qbno, i, dqid);
+ error++;
+ continue;
+ }
if (be32_to_cpu(dqb->dd_diskdq.d_id) != dqid) {
if (scicb)
dbprintf(_("bad id %u for %s dqblk %lld "
diff --git a/libxfs/xfs_dquot_buf.c b/libxfs/xfs_dquot_buf.c
index a3e8ba1..324f528 100644
--- a/libxfs/xfs_dquot_buf.c
+++ b/libxfs/xfs_dquot_buf.c
@@ -39,6 +39,8 @@ xfs_dquot_verify(
xfs_disk_dquot_t *ddq,
xfs_dqid_t id) /* used only during quotacheck */
{
+ __u8 ddq_type;
+
/*
* We can encounter an uninitialized dquot buffer for 2 reasons:
* 1. If we crash while deleting the quotainode(s), and those blks got
@@ -59,9 +61,12 @@ xfs_dquot_verify(
if (ddq->d_version != XFS_DQUOT_VERSION)
return __this_address;
- if (ddq->d_flags != XFS_DQ_USER &&
- ddq->d_flags != XFS_DQ_PROJ &&
- ddq->d_flags != XFS_DQ_GROUP)
+ if (ddq->d_flags & ~XFS_DQTYPE_ANY)
+ return __this_address;
+ ddq_type = ddq->d_flags & XFS_DQ_ALLTYPES;
+ if (ddq_type != XFS_DQ_USER &&
+ ddq_type != XFS_DQ_PROJ &&
+ ddq_type != XFS_DQ_GROUP)
return __this_address;
if (id != -1 && id != be32_to_cpu(ddq->d_id))
diff --git a/libxfs/xfs_quota_defs.h b/libxfs/xfs_quota_defs.h
index afe1ea0..c69dba4 100644
--- a/libxfs/xfs_quota_defs.h
+++ b/libxfs/xfs_quota_defs.h
@@ -31,6 +31,8 @@ typedef uint16_t xfs_qwarncnt_t;
#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
+#define XFS_DQTYPE_ANY (XFS_DQ_ALLTYPES)
+
#define XFS_DQ_FLAGS \
{ XFS_DQ_USER, "USER" }, \
{ XFS_DQ_PROJ, "PROJ" }, \

@ -0,0 +1,387 @@
Summary: Utilities for managing the XFS filesystem
Name: xfsprogs
Version: 5.0.0
Release: 10%{?dist}
License: GPL+ and LGPLv2+
Group: System Environment/Base
URL: https://xfs.wiki.kernel.org
Source0: http://kernel.org/pub/linux/utils/fs/xfs/xfsprogs/%{name}-%{version}.tar.xz
BuildRequires: gcc
BuildRequires: libtool, gettext, libattr-devel, libuuid-devel
BuildRequires: readline-devel, libblkid-devel >= 2.17-0.1.git5e51568
BuildRequires: lvm2-devel, libicu-devel >= 4.6
Provides: xfs-cmds
Obsoletes: xfs-cmds <= %{version}
Provides: xfsprogs-qa-devel
Obsoletes: xfsprogs-qa-devel <= %{version}
Conflicts: xfsdump < 3.0.1
# reflink is not yet default upstream, but we enabled it as such
Patch0: xfsprogs-4.17.0-reflink-default.patch
Patch1: xfsprogs-5.1.0-mkfs-validate-start-and-end-of-aligned-logs.patch
Patch2: xfsprogs-5.1.0-mkfs-don-t-use-xfs_verify_fsbno-before-m_sb-is-fully.patch
Patch3: xfsprogs-5.1.0-xfsprogs-Fix-uninitialized-cfg-lsunit.patch
Patch4: xfsprogs-5.3.0-xfs_growfs-allow-mounted-device-node-as-argument.patch
Patch5: xfsprogs-5.5.0-libxfs-use-FALLOC_FL_ZERO_RANGE-in-libxfs_device_zer.patch
Patch6: xfsprogs-5.4.0-mkfs-Break-block-discard-into-chunks-of-2-GB.patch
Patch7: xfsprogs-5.4.0-mkfs-tidy-up-discard-notifications.patch
Patch8: xfsprogs-5.7.0-xfs_quota-refactor-code-to-generate-id-from-name.patch
Patch9: xfsprogs-5.7.0-xfs_quota-allow-individual-timer-extension.patch
Patch10: xfsprogs-5.7.0-xfs_quota-fix-unsigned-int-id-comparisons.patch
Patch11: xfsprogs-5.7.0-xfs_repair-check-for-AG-btree-records-that-would-wra.patch
Patch12: xfsprogs-5.7.0-xfs_repair-tag-inobt-vs-finobt-errors-properly.patch
Patch13: xfsprogs-5.7.0-xfs_repair-complain-about-bad-interior-btree-pointer.patch
Patch14: xfsprogs-5.7.0-xfs_repair-convert-to-libxfs_verify_agbno.patch
Patch15: xfsprogs-5.9.0-mkfs.xfs-fix-ASSERT-on-too-small-device-with-stripe.patch
Patch16: xfsprogs-5.7.0-xfs_repair-fix-rebuilding-btree-block-less-than-minr.patch
Patch17: xfsprogs-5.10.0-xfs_quota-document-how-the-default-quota-is-stored.patch
Patch18: xfsprogs-5.8.0-xfs_db-short-circuit-type_f-if-type-is-unchanged.patch
Patch19: xfsprogs-5.10.0-xfs_repair-Use-proper-min-max-values-in-compute_level_geometry.patch
Patch20: xfsprogs-5.8.0-xfs_quota-command-error-message-improvement.patch
Patch21: xfsprogs-5.8.0-xfs_quota-display-warning-limits-when-printing-quota.patch
Patch22: xfsprogs-5.8.0-xfs_quota-state-command-should-report-ugp-grace-time.patch
Patch23: xfsprogs-5.1.0-libxfs-create-current_time-helper-and-sync-xfs_trans.patch
Patch24: xfsprogs-5.5.0-xfs-use-a-struct-timespec64-for-the-in-core-crtime.patch
Patch25: xfsprogs-5.9.0-xfs-drop-the-type-parameter-from-xfs_dquot_verify.patch
Patch26: xfsprogs-5.9.0-xfs-improve-ondisk-dquot-flags-checking.patch
Patch27: xfsprogs-5.10.0-libxfs-create-a-real-struct-timespec64.patch
Patch28: xfsprogs-5.10.0-libxfs-refactor-NSEC_PER_SEC.patch
Patch29: xfsprogs-5.10.0-xfs-store-inode-btree-block-counts-in-AGI-header.patch
Patch30: xfsprogs-5.10.0-xfs-use-the-finobt-block-counts-to-speed-up-mount-ti.patch
Patch31: xfsprogs-5.10.0-xfs-explicitly-define-inode-timestamp-range.patch
Patch32: xfsprogs-5.10.0-xfs-refactor-quota-expiration-timer-modification.patch
Patch33: xfsprogs-5.10.0-xfs-refactor-default-quota-grace-period-setting-code.patch
Patch34: xfsprogs-5.10.0-xfs-refactor-quota-timestamp-coding.patch
Patch35: xfsprogs-5.10.0-xfs-move-xfs_log_dinode_to_disk-to-the-log-recovery-.patch
Patch36: xfsprogs-5.10.0-xfs-redefine-xfs_timestamp_t.patch
Patch37: xfsprogs-5.10.0-xfs-redefine-xfs_ictimestamp_t.patch
Patch38: xfsprogs-5.10.0-xfs-widen-ondisk-inode-timestamps-to-deal-with-y2038.patch
Patch39: xfsprogs-5.10.0-xfs-widen-ondisk-quota-expiration-timestamps-to-hand.patch
Patch40: xfsprogs-5.10.0-xfs_db-support-displaying-inode-btree-block-counts-i.patch
Patch41: xfsprogs-5.10.0-xfs_repair-check-inode-btree-block-counters-in-AGI.patch
Patch42: xfsprogs-5.10.0-xfs_repair-regenerate-inode-btree-block-counters-in-.patch
Patch43: xfsprogs-5.10.0-xfs-enable-new-inode-btree-counters-feature.patch
Patch44: xfsprogs-5.10.0-mkfs-enable-the-inode-btree-counter-feature.patch
Patch45: xfsprogs-5.10.0-libfrog-convert-cvttime-to-return-time64_t.patch
Patch46: xfsprogs-5.10.0-xfs_quota-convert-time_to_string-to-use-time64_t.patch
Patch47: xfsprogs-5.10.0-xfs_db-refactor-timestamp-printing.patch
Patch48: xfsprogs-5.10.0-xfs_db-refactor-quota-timer-printing.patch
Patch49: xfsprogs-5.10.0-libfrog-list-the-bigtime-feature-when-reporting-geom.patch
Patch50: xfsprogs-5.10.0-xfs_db-report-bigtime-format-timestamps.patch
Patch51: xfsprogs-5.10.0-xfs_db-support-printing-time-limits.patch
Patch52: xfsprogs-5.10.0-xfs_quota-support-editing-and-reporting-quotas-with-.patch
Patch53: xfsprogs-5.10.0-xfs_repair-support-bigtime-timestamp-checking.patch
Patch54: xfsprogs-5.10.0-xfs-enable-big-timestamps.patch
Patch55: xfsprogs-5.10.0-mkfs-format-bigtime-filesystems.patch
Patch56: xfsprogs-5.12.0-libxfs-copy-crtime-correctly-now-that-it-s-timespec6.patch
Patch57: xfsprogs-5.13.0-xfs-remove-the-unused-xfs_icdinode_has_bigtime-helpe.patch
Patch58: xfsprogs-5.13.0-xfs-rename-xfs_ictimestamp_t.patch
Patch59: xfsprogs-5.13.0-xfs-rename-struct-xfs_legacy_ictimestamp.patch
Patch60: xfsprogs-5.11.0-mkfs-fix-wrong-inobtcount-usage-error-output.patch
Patch61: xfsprogs-5.12.0-libxfs-expose-inobtcount-in-xfs-geometry.patch
Patch62: xfsprogs-5.12.0-libfrog-report-inobtcount-in-geometry.patch
%description
A set of commands to use the XFS filesystem, including mkfs.xfs.
XFS is a high performance journaling filesystem which originated
on the SGI IRIX platform. It is completely multi-threaded, can
support large files and large filesystems, extended attributes,
variable block sizes, is extent based, and makes extensive use of
Btrees (directories, extents, free space) to aid both performance
and scalability.
This implementation is on-disk compatible with the IRIX version
of XFS.
%package devel
Summary: XFS filesystem-specific headers
Group: Development/Libraries
Requires: xfsprogs = %{version}-%{release}, libuuid-devel
%description devel
xfsprogs-devel contains the header files needed to develop XFS
filesystem-specific programs.
You should install xfsprogs-devel if you want to develop XFS
filesystem-specific programs, If you install xfsprogs-devel, you'll
also want to install xfsprogs.
%prep
%setup -q
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1
%patch23 -p1
%patch24 -p1
%patch25 -p1
%patch26 -p1
%patch27 -p1
%patch28 -p1
%patch29 -p1
%patch30 -p1
%patch31 -p1
%patch32 -p1
%patch33 -p1
%patch34 -p1
%patch35 -p1
%patch36 -p1
%patch37 -p1
%patch38 -p1
%patch39 -p1
%patch40 -p1
%patch41 -p1
%patch42 -p1
%patch43 -p1
%patch44 -p1
%patch45 -p1
%patch46 -p1
%patch47 -p1
%patch48 -p1
%patch49 -p1
%patch50 -p1
%patch51 -p1
%patch52 -p1
%patch53 -p1
%patch54 -p1
%patch55 -p1
%patch56 -p1
%patch57 -p1
%patch58 -p1
%patch59 -p1
%patch60 -p1
%patch61 -p1
%patch62 -p1
%build
export tagname=CC
%configure \
--enable-readline=yes \
--enable-blkid=yes \
--enable-lto=no \
--enable-scrub=no
# NOTE scrub manpages manually removed below as well
make V=1 %{?_smp_mflags}
%install
make DIST_ROOT=$RPM_BUILD_ROOT install install-dev \
PKG_ROOT_SBIN_DIR=%{_sbindir} PKG_ROOT_LIB_DIR=%{_libdir}
# nuke .la files, etc
rm -f $RPM_BUILD_ROOT/{%{_lib}/*.{la,a,so},%{_libdir}/*.{la,a}}
# remove non-versioned docs location
rm -rf $RPM_BUILD_ROOT/%{_datadir}/doc/xfsprogs/
# Remove scrub manpages
rm -rf $RPM_BUILD_ROOT/%{_mandir}/man8/xfs_scrub*
%find_lang %{name}
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%files -f %{name}.lang
%doc doc/CHANGES README
%{_libdir}/*.so.*
%{_mandir}/man5/*
%{_mandir}/man8/*
%{_sbindir}/*
%files devel
%{_mandir}/man2/*
%{_mandir}/man3/*
%dir %{_includedir}/xfs
%{_includedir}/xfs/handle.h
%{_includedir}/xfs/jdm.h
%{_includedir}/xfs/linux.h
%{_includedir}/xfs/xfs.h
%{_includedir}/xfs/xfs_arch.h
%{_includedir}/xfs/xfs_fs.h
%{_includedir}/xfs/xfs_types.h
%{_includedir}/xfs/xfs_format.h
%{_includedir}/xfs/xfs_da_format.h
%{_includedir}/xfs/xfs_log_format.h
%{_includedir}/xfs/xqm.h
%{_libdir}/*.so
%changelog
* Thu Dec 09 2021 Bill O'Donnell <bodonnel@redhat.com> 5.0.0-10
- xfsprogs: enable bigtime and inode btree counter features in RHEL8 (#2024201))
* Thu Jul 08 2021 Bill O'Donnell <bodonnel@redhat.com> 5.0.0-9
- xfs_quota: state command should report ugp grace time (#1949743)
* Thu Jan 07 2021 Bill O'Donnell <billodo@redhat.com> 5.0.0-8
- xfs_repair: Use proper min/max values in compute_level_geometry (#1910384)
* Mon Dec 14 2020 Bill O'Donnell <billodo@redhat.com> 5.0.0-7
- xfs_quota: document how the default quota is stored (#1850188)
- xfs_db: skip type change if type_f unchanged (#1867474)
* Wed Dec 09 2020 Bill O'Donnell <billodo@redhat.com> 5.0.0-6
- xfs_repair: improve AG btree ptr validation (libxfs_verify_agbno) (#1887288)
- mkfs.xfs: fix ASSERT on too-small device with stripe geometry (#1887401)
- xfs_repair: fix rebuilding btree block less than minrecs (#1759452)
* Wed Dec 02 2020 Bill O'Donnell <billodo@redhat.com> 5.0.0-5
- xfs_quota: allow individual timer extension (#1899204)
* Wed Jun 03 2020 Eric Sandeen <sandeen@redhat.com> 5.0.0-4
- mkfs.xfs: inform user about discard, and make interruptable (#1836414)
* Mon Apr 20 2020 Eric Sandeen <sandeen@redhat.com> 5.0.0-3
- mkfs.xfs: use faster log zeroing on supported devices (#1755046)
* Sat Dec 14 2019 Eric Sandeen <sandeen@redhat.com> 5.0.0-2
- mkfs.xfs: validate log stripe unit alignment (#1632596)
- xfs_growfs: allow mounted device node as argument (#1765217)
* Tue May 21 2019 Eric Sandeen <sandeen@redhat.com> 5.0.0-1
- New upstream version (#1712147)
- mkfs.xfs: validate extent size hint parameters (#1683007)
- mkfs.xfs: null-terminate symlinks created via protofile (#1640503)
- xfs_repair: allow '/' in attribute names (#1667354)
- xfs_info: allow device name as parameter (#1679840)
- xfs_quota: fix project inheritance flag handling (#1664105)
- xfs_metadump: handle symlinks correctly (#1693074)
- xfs_db: fix finobt record decoding with sparse inodes (#1690245)
* Mon Feb 04 2019 Eric Sandeen <sandeen@redhat.com> 4.19.0-2
- xfs_repair: initialize non-leaf finobt blocks with correct magic (#1670153)
* Tue Nov 27 2018 Eric Sandeen <sandeen@redhat.com> 4.19.0-1
- New upstream release (#1652248)
- Note reflink default in mkfs.xfs manpage (#1641698)
- Fix xfs_db sign extension in agi freecount (#1640090)
- Fix xfs_repair hang on large filesystem (#1630674)
* Tue Sep 25 2018 Eric Sandeen <sandeen@redhat.com> 4.18.0-3
- Remove experimental xfs_scrub utility (#1623301)
* Wed Sep 19 2018 Eric Sandeen <sandeen@redhat.com> 4.18.0-2
- Fix annobin checks (#1630641)
* Tue Aug 28 2018 Eric Sandeen <sandeen@redhat.com> 4.18.0-1
- New upstream release (#1623695)
* Mon Aug 13 2018 Eric Sandeen <sandeen@redhat.com> 4.17.0-4
- Disable reflink automatically if crcs are disabled (#1600610)
* Wed Aug 01 2018 Charalampos Stratakis <cstratak@redhat.com> - 4.17.0-3
- Rebuild for platform-python
* Thu Jun 28 2018 Eric Sandeen <sandeen@redhat.com> 4.17.0-2
- Default mkfs to reflink enabled (#1494028)
* Thu Jun 28 2018 Eric Sandeen <sandeen@redhat.com> 4.17.0-1
- New upstream release
- Clean up spec file
* Mon Feb 26 2018 Eric Sandeen <sandeen@redhat.com> 4.15.1-1
- New upstream release
- Update Polish translation
* Mon Feb 26 2018 Eric Sandeen <sandeen@redhat.com> 4.15.0-2
- BuildRequires: gcc
* Sat Feb 24 2018 Eric Sandeen <sandeen@redhat.com> 4.15.0-1
- New upstream release
- Adds new xfs_scrub utility and services
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 4.14.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Mon Nov 27 2017 Eric Sandeen <sandeen@redhat.com> 4.14.0-1
- New upstream release
* Wed Sep 27 2017 Eric Sandeen <sandeen@redhat.com> 4.13.1-1
- New upstream release
- Trim ancient changelog
* Thu Aug 03 2017 Fedora Release Engineering <releng@fedoraproject.org> - 4.12.0-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
* Sun Jul 30 2017 Florian Weimer <fweimer@redhat.com> - 4.12.0-3
- Rebuild with binutils fix for ppc64le (#1475636)
* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 4.12.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
* Mon Jul 24 2017 Eric Sandeen <sandeen@redhat.com> 4.12.0-1
- New upstream release
* Fri May 05 2017 Eric Sandeen <sandeen@redhat.com> 4.11.0-1
- New upstream release
* Sun Feb 26 2017 Eric Sandeen <sandeen@redhat.com> 4.10.0-1
- New upstream release
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 4.9.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
* Thu Jan 12 2017 Igor Gnatenko <ignatenko@redhat.com> - 4.9.0-2
- Rebuild for readline 7.x
* Thu Jan 05 2017 Eric Sandeen <sandeen@redhat.com> 4.9.0-1
- New upstream release
* Tue Oct 18 2016 Eric Sandeen <sandeen@redhat.com> 4.8.0-1
- New upstream release
* Tue Sep 06 2016 Eric Sandeen <sandeen@redhat.com> 4.7.0-2
- Add libattr-devel build dependency to fix xfs_fsr
* Sun Sep 04 2016 Eric Sandeen <sandeen@redhat.com> 4.7.0-1
- New upstream release
* Tue Mar 15 2016 Eric Sandeen <sandeen@redhat.com> 4.5.0-1
- New upstream release
* Thu Mar 10 2016 Eric Sandeen <sandeen@redhat.com> 4.3.0-3
- Fix build w/ new kernels which have [sg]etxattr promotion
* Fri Feb 05 2016 Fedora Release Engineering <releng@fedoraproject.org> - 4.3.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
* Mon Nov 30 2015 Eric Sandeen <sandeen@redhat.com> 4.3.0-1
- New upstream release
* Wed Sep 09 2015 Eric Sandeen <sandeen@redhat.com> 4.2.0-1
- New upstream release
* Thu Jul 30 2015 Eric Sandeen <sandeen@redhat.com> 3.2.4-1
- New upstream release
- Addresses CVE-2012-2150 for xfs_metadump
* Fri Jun 19 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.2.3-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
* Wed Jun 10 2015 Eric Sandeen <sandeen@redhat.com> 3.2.3-1
- New upstream release
Loading…
Cancel
Save