Commit 595c1e9b authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet
Browse files

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: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 4f6dad46
Loading
Loading
Loading
Loading
+14 −9
Original line number Diff line number Diff line
@@ -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)
+3 −1
Original line number Diff line number Diff line
@@ -1565,7 +1565,9 @@ static struct dentry *bch2_mount(struct file_system_type *fs_type,
#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));

+8 −2
Original line number Diff line number Diff line
@@ -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]);