lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 21 Jun 2018 11:46:17 -0600
From:   Andreas Dilger <adilger@...ger.ca>
To:     Arnd Bergmann <arnd@...db.de>
Cc:     Theodore Ts'o <tytso@....edu>, Jan Kara <jack@...e.com>,
        y2038@...ts.linaro.org,
        Ext4 Developers List <linux-ext4@...r.kernel.org>,
        Tahsin Erdogan <tahsin@...gle.com>, Jan Kara <jack@...e.cz>,
        Deepa Dinamani <deepa.kernel@...il.com>,
        Linux Kernel Mailing List <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH 6/6] [RFC] ext4: super: extend timestamps to 40 bits

On Jun 20, 2018, at 9:33 AM, Arnd Bergmann <arnd@...db.de> wrote:
> 
> The inode timestamps use 34 bits in ext4, but the various timestamps in
> the superblock are limited to 32 bits. If every user accesses these as
> 'unsigned', then this is good until year 2106, but it seems better to
> extend this a bit further in the process of removing the deprecated
> get_seconds() function.
> 
> This adds another byte for each timestamp in the superblock, making
> them long enough to store timestamps beyond what is in the inodes,
> which seems good enough here (in ocfs2, they are already 64-bit wide,
> which is appropriate for a new layout).
> 
> I did not modify e2fsprogs, which obviously needs the same change to
> actually interpret future timestamps correctly.
> 
> Signed-off-by: Arnd Bergmann <arnd@...db.de>

Patch looks functionally correct, some minor comments below that I
think would improve it.

> ---
> fs/ext4/ext4.h  |  9 ++++++++-
> fs/ext4/super.c | 35 ++++++++++++++++++++++++++---------
> fs/ext4/sysfs.c | 18 ++++++++++++++++--
> 3 files changed, 50 insertions(+), 12 deletions(-)
> 
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 6b4f4369a08c..cac1464383e4 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -1294,7 +1294,14 @@ struct ext4_super_block {
> 	__le32	s_lpf_ino;		/* Location of the lost+found inode */
> 	__le32	s_prj_quota_inum;	/* inode for tracking project quota */
> 	__le32	s_checksum_seed;	/* crc32c(uuid) if csum_seed set */
> -	__le32	s_reserved[98];		/* Padding to the end of the block */
> +	__u8	s_wtime_hi;
> +	__u8	s_mtime_hi;
> +	__u8	s_mkfs_time_hi;
> +	__u8	s_lastcheck_hi;
> +	__u8	s_first_error_time_hi;
> +	__u8	s_last_error_time_hi;
> +	__u8	s_pad[2];
> +	__le32	s_reserved[96];		/* Padding to the end of the block */
> 	__le32	s_checksum;		/* crc32c(superblock) */
> };
> 
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 0c4c2201b3aa..2063d4e5ed08 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -312,6 +312,20 @@ void ext4_itable_unused_set(struct super_block *sb,
> 		bg->bg_itable_unused_hi = cpu_to_le16(count >> 16);
> }
> 
> +static void ext4_update_tstamp(__le32 *lo, __u8 *hi)

Would it be better to wrap this in a macro, something like:

#define ext4_update_tstamp(es, tstamp) \
	__ext4_update_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)
#define ext4_get_tstamp(es, tstamp) \
	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)

So that it can be used in the callers more easily:

	ext4_update_tstamp(es, s_last_error_time);
	time = ext4_get_tstamp(es, s_last_error_time);

> +{
> +	time64_t now = ktime_get_real_seconds();
> +
> +	now = clamp_val(now, 0, 0xffffffffffull);

Long strings of "0xfff..." are hard to get correct.  This looks right,
but it may be easier to be sure it is correct with something like:

	/* timestamps have a 32-bit low field and 8-bit high field */
	now = clamp_val(now, 0, (1ULL << 40) - 1);

> +
> +	*lo = cpu_to_le32(lower_32_bits(now));
> +	*hi = upper_32_bits(now);
> +}
> +
> +static time64_t ext4_get_tstamp(__le32 *lo, __u8 *hi)
> +{
> +	return ((time64_t)(*hi) << 32) + le32_to_cpu(*lo);
> +}
> 
> static void __save_error_info(struct super_block *sb, const char *func,
> 			    unsigned int line)
> @@ -322,11 +336,12 @@ static void __save_error_info(struct super_block *sb, const char *func,
> 	if (bdev_read_only(sb->s_bdev))
> 		return;
> 	es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
> -	es->s_last_error_time = cpu_to_le32(get_seconds());
> +	ext4_update_tstamp(&es->s_last_error_time, &es->s_last_error_time_hi);
> 	strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
> 	es->s_last_error_line = cpu_to_le32(line);
> 	if (!es->s_first_error_time) {
> 		es->s_first_error_time = es->s_last_error_time;
> +		es->s_first_error_time_hi = es->s_last_error_time_hi;

> 		strncpy(es->s_first_error_func, func,
> 			sizeof(es->s_first_error_func));
> 		es->s_first_error_line = cpu_to_le32(line);
> @@ -2163,8 +2178,8 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
> 			 "warning: maximal mount count reached, "
> 			 "running e2fsck is recommended");
> 	else if (le32_to_cpu(es->s_checkinterval) &&
> -		(le32_to_cpu(es->s_lastcheck) +
> -			le32_to_cpu(es->s_checkinterval) <= get_seconds()))
> +		 (ext4_get_tstamp(&es->s_lastcheck, &es->s_lastcheck_hi) +
> +		  le32_to_cpu(es->s_checkinterval) <= ktime_get_real_seconds()))
> 		ext4_msg(sb, KERN_WARNING,
> 			 "warning: checktime reached, "
> 			 "running e2fsck is recommended");
> @@ -2173,7 +2188,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
> 	if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
> 		es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT);
> 	le16_add_cpu(&es->s_mnt_count, 1);
> -	es->s_mtime = cpu_to_le32(get_seconds());
> +	ext4_update_tstamp(&es->s_mtime, &es->s_mtime_hi);
> 	ext4_update_dynamic_rev(sb);
> 	if (sbi->s_journal)
> 		ext4_set_feature_journal_needs_recovery(sb);
> @@ -2839,8 +2854,9 @@ static void print_daily_error_info(struct timer_list *t)
> 		ext4_msg(sb, KERN_NOTICE, "error count since last fsck: %u",
> 			 le32_to_cpu(es->s_error_count));
> 	if (es->s_first_error_time) {
> -		printk(KERN_NOTICE "EXT4-fs (%s): initial error at time %u: %.*s:%d",
> -		       sb->s_id, le32_to_cpu(es->s_first_error_time),
> +		printk(KERN_NOTICE "EXT4-fs (%s): initial error at time %llu: %.*s:%d",
> +		       sb->s_id,
> +		       ext4_get_tstamp(&es->s_first_error_time, &es->s_first_error_time_hi),
> 		       (int) sizeof(es->s_first_error_func),
> 		       es->s_first_error_func,
> 		       le32_to_cpu(es->s_first_error_line));
> @@ -2853,8 +2869,9 @@ static void print_daily_error_info(struct timer_list *t)
> 		printk(KERN_CONT "\n");
> 	}
> 	if (es->s_last_error_time) {
> -		printk(KERN_NOTICE "EXT4-fs (%s): last error at time %u: %.*s:%d",
> -		       sb->s_id, le32_to_cpu(es->s_last_error_time),
> +		printk(KERN_NOTICE "EXT4-fs (%s): last error at time %llu: %.*s:%d",
> +		       sb->s_id,
> +		       ext4_get_tstamp(&es->s_last_error_time, &es->s_last_error_time_hi),
> 		       (int) sizeof(es->s_last_error_func),
> 		       es->s_last_error_func,
> 		       le32_to_cpu(es->s_last_error_line));
> @@ -4747,7 +4764,7 @@ static int ext4_commit_super(struct super_block *sb, int sync)
> 	 * to complain and force a full file system check.
> 	 */
> 	if (!(sb->s_flags & SB_RDONLY))
> -		es->s_wtime = cpu_to_le32(get_seconds());
> +		ext4_update_tstamp(&es->s_wtime, &es->s_wtime_hi);
> 	if (sb->s_bdev->bd_part)
> 		es->s_kbytes_written =
> 			cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
> diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
> index b970a200f20c..fe58aa905cbe 100644
> --- a/fs/ext4/sysfs.c
> +++ b/fs/ext4/sysfs.c
> @@ -25,6 +25,8 @@ typedef enum {
> 	attr_reserved_clusters,
> 	attr_inode_readahead,
> 	attr_trigger_test_error,
> +	attr_first_error_time,
> +	attr_last_error_time,
> 	attr_feature,
> 	attr_pointer_ui,
> 	attr_pointer_atomic,
> @@ -182,8 +184,8 @@ EXT4_RW_ATTR_SBI_UI(warning_ratelimit_burst, s_warning_ratelimit_state.burst);
> EXT4_RW_ATTR_SBI_UI(msg_ratelimit_interval_ms, s_msg_ratelimit_state.interval);
> EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst);
> EXT4_RO_ATTR_ES_UI(errors_count, s_error_count);
> -EXT4_RO_ATTR_ES_UI(first_error_time, s_first_error_time);
> -EXT4_RO_ATTR_ES_UI(last_error_time, s_last_error_time);
> +EXT4_ATTR(first_error_time, 0444, first_error_time);
> +EXT4_ATTR(last_error_time, 0444, last_error_time);
> 
> static unsigned int old_bump_val = 128;
> EXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val);
> @@ -249,6 +251,12 @@ static void *calc_ptr(struct ext4_attr *a, struct ext4_sb_info *sbi)
> 	return NULL;
> }
> 
> +static ssize_t print_time(char *buf, __le32 lo, __u8 hi)

It would probably be more consistent to name this "print_tstamp()"
since it isn't strictly a "time" as one would expect.

> +{
> +	return snprintf(buf, PAGE_SIZE, "%lld",
> +			((time64_t)hi << 32) + le32_to_cpu(lo));
> +}

Similarly, wrap this with:

#define print_tstamp(buf, es, tstamp) \
	__print_tstamp(buf, &(es)->tstamp, &(es)->tstamp ## _hi)

> @@ -287,6 +295,12 @@ static ssize_t ext4_attr_show(struct kobject *kobj,
> 				atomic_read((atomic_t *) ptr));
> 	case attr_feature:
> 		return snprintf(buf, PAGE_SIZE, "supported\n");
> +	case attr_first_error_time:
> +		return print_time(buf, sbi->s_es->s_first_error_time,
> +				       sbi->s_es->s_first_error_time_hi);
> +	case attr_last_error_time:
> +		return print_time(buf, sbi->s_es->s_last_error_time,
> +				       sbi->s_es->s_last_error_time_hi);
> 	}
> 
> 	return 0;
> --
> 2.9.0
> 


Cheers, Andreas






Download attachment "signature.asc" of type "application/pgp-signature" (874 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ