summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-04-28 22:51:42 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:02 -0400
commit595c1e9bab7fd5512250d0e297e50a549af59b1f (patch)
treea66d69cfe31dd911c0ca62d426b44b02ac63a93c
parent4f6dad46cb4b6db75758bc790a74d7f0f04e450b (diff)
bcachefs: Fix time handling
There were some overflows in the time conversion functions - fix this by converting tv_sec and tv_nsec separately. Also, set sb->time_min and sb->time_max. Fixes xfstest generic/258. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/bcachefs.h23
-rw-r--r--fs/bcachefs/fs.c4
-rw-r--r--fs/bcachefs/super-io.c10
3 files changed, 25 insertions, 12 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index 323705f352de..c47e69931b8a 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -605,11 +605,13 @@ struct bch_fs {
u64 time_base_lo;
u32 time_base_hi;
- u32 time_precision;
+ unsigned time_units_per_sec;
+ unsigned nsec_per_time_unit;
u64 features;
u64 compat;
} sb;
+
struct bch_sb_handle disk_sb;
unsigned short block_bits; /* ilog2(block_size) */
@@ -872,19 +874,22 @@ static inline unsigned block_bytes(const struct bch_fs *c)
return c->opts.block_size << 9;
}
-static inline struct timespec64 bch2_time_to_timespec(struct bch_fs *c, u64 time)
+static inline struct timespec64 bch2_time_to_timespec(struct bch_fs *c, s64 time)
{
- return ns_to_timespec64(time * c->sb.time_precision + c->sb.time_base_lo);
+ struct timespec64 t;
+ s32 rem;
+
+ time += c->sb.time_base_lo;
+
+ t.tv_sec = div_s64_rem(time, c->sb.time_units_per_sec, &rem);
+ t.tv_nsec = rem * c->sb.nsec_per_time_unit;
+ return t;
}
static inline s64 timespec_to_bch2_time(struct bch_fs *c, struct timespec64 ts)
{
- s64 ns = timespec64_to_ns(&ts) - c->sb.time_base_lo;
-
- if (c->sb.time_precision == 1)
- return ns;
-
- return div_s64(ns, c->sb.time_precision);
+ return (ts.tv_sec * c->sb.time_units_per_sec +
+ (int) ts.tv_nsec / c->sb.nsec_per_time_unit) - c->sb.time_base_lo;
}
static inline s64 bch2_current_time(struct bch_fs *c)
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 67e9a354ad37..b00f35201132 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -1565,7 +1565,9 @@ got_sb:
#endif
sb->s_xattr = bch2_xattr_handlers;
sb->s_magic = BCACHEFS_STATFS_MAGIC;
- sb->s_time_gran = c->sb.time_precision;
+ sb->s_time_gran = c->sb.nsec_per_time_unit;
+ sb->s_time_min = div_s64(S64_MIN, c->sb.time_units_per_sec) + 1;
+ sb->s_time_max = div_s64(S64_MAX, c->sb.time_units_per_sec);
c->vfs_sb = sb;
strlcpy(sb->s_id, c->name, sizeof(sb->s_id));
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index e0de6f0c0cb4..4c7cea4cfc2b 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -373,9 +373,15 @@ static void bch2_sb_update(struct bch_fs *c)
c->sb.clean = BCH_SB_CLEAN(src);
c->sb.encryption_type = BCH_SB_ENCRYPTION_TYPE(src);
c->sb.encoded_extent_max= 1 << BCH_SB_ENCODED_EXTENT_MAX_BITS(src);
- c->sb.time_base_lo = le64_to_cpu(src->time_base_lo);
+
+ c->sb.nsec_per_time_unit = le32_to_cpu(src->time_precision);
+ c->sb.time_units_per_sec = NSEC_PER_SEC / c->sb.nsec_per_time_unit;
+
+ /* XXX this is wrong, we need a 96 or 128 bit integer type */
+ c->sb.time_base_lo = div_u64(le64_to_cpu(src->time_base_lo),
+ c->sb.nsec_per_time_unit);
c->sb.time_base_hi = le32_to_cpu(src->time_base_hi);
- c->sb.time_precision = le32_to_cpu(src->time_precision);
+
c->sb.features = le64_to_cpu(src->features[0]);
c->sb.compat = le64_to_cpu(src->compat[0]);