diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2021-04-28 22:51:42 -0400 |
---|---|---|
committer | Stijn Tintel <stijn@linux-ipv6.be> | 2021-05-24 15:37:06 +0300 |
commit | f9c6ee7f2a25267a7612c619271efb705266dff1 (patch) | |
tree | 3e799f24faa7a25256add394352439a63ade45c8 | |
parent | 4ee89ed16074175477c21ff051c521b90e7373c8 (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>
-rw-r--r-- | fs/bcachefs/bcachefs.h | 23 | ||||
-rw-r--r-- | fs/bcachefs/fs.c | 4 | ||||
-rw-r--r-- | fs/bcachefs/super-io.c | 10 |
3 files changed, 25 insertions, 12 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h index f2d2c7bbc29b..24aa2cc7d965 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) */ @@ -873,19 +875,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 4e5da2a0b359..3161760050c9 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -1551,7 +1551,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 11d7167b0129..74a75ced031e 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -367,9 +367,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]); |