From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.parknet.co.jp (mail.parknet.co.jp [210.171.160.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0362B3B8BC6 for ; Tue, 24 Mar 2026 07:25:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.171.160.6 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774337170; cv=none; b=o4INc6ePV2EJTCRtrcmc0U1fg4QDxdptuOrPFacGXq9jQq9RciJOXh3oCBwAQO6qD3z0nnrf2lo2+d6ADE3I6WqQyzuaTyRS+h644bTFUC/2xaK5lIVzdrgosHFqzK7jCII9w7WO/GnityVLhuPAgMiyWclizIexfnMQfqzlBYw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774337170; c=relaxed/simple; bh=siMwtFd9xz9a6zfBGfVyF87wCMRqHUtfa/4aP9iU8FM=; h=From:To:Cc:Subject:In-Reply-To:References:Date:Message-ID: MIME-Version:Content-Type; b=VQjif12gvfQkt3hREJxsFBI4Zz9FOm7hKK3CJu7Hkq9TvL7Q4n4cVZpV7kvSjB6joFmpxIOmKoF/PZWoULtM8VNXgYTeQn4CV7Y1T0eDtbhM3ToDIk8fa1zAgXNZeNyqyrPgFFcoomVsVJbQ7yvH87iksAkwtsm8Gs7DQD3ziY8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=mail.parknet.co.jp; spf=pass smtp.mailfrom=parknet.co.jp; dkim=pass (2048-bit key) header.d=parknet.co.jp header.i=@parknet.co.jp header.b=Ua2ScZrV; dkim=permerror (0-bit key) header.d=parknet.co.jp header.i=@parknet.co.jp header.b=sQtJs+eS; arc=none smtp.client-ip=210.171.160.6 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=mail.parknet.co.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=parknet.co.jp Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=parknet.co.jp header.i=@parknet.co.jp header.b="Ua2ScZrV"; dkim=permerror (0-bit key) header.d=parknet.co.jp header.i=@parknet.co.jp header.b="sQtJs+eS" Received: from ibmpc.myhome.or.jp (server.parknet.ne.jp [210.171.168.39]) by mail.parknet.co.jp (Postfix) with ESMTPSA id 8088126F765E; Tue, 24 Mar 2026 16:19:51 +0900 (JST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=parknet.co.jp; s=20250114; t=1774336791; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=GKYCbt7+DsHz/UsPxjcClQhC2XQ0NG0eDSGgUETZnsQ=; b=Ua2ScZrVVOrAyZi2BjxWzdybuZWPtzdFKjTBxXf1VS+5L7YFumbxKCWe5hHbi3iUxGE3tj SJF/flVY7WC4FMR7w+8R8yYO1R5mRn7FeyxBgKHOqgGlAcLDiUdFfTejLP4IHIbOfJGXU5 gBIS9OsyIfTqX1QxIigC0ihszu51ohGxo6vNkgOSFCxCE8hjVQfCVpd02YQoBFhKNnf7J4 SoR4PsRkMGNntF30iYMHzrASl/vQtt48rh9j9BMxU81JM4L2oI2gZe90qS48+olaAn4uj+ y31M6+05/MBwPw1Y46liuD1NX5p69crmfUrWv4b5BtKKdgodo1WRKnRbNm/Ryg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=parknet.co.jp; s=20250114-ed25519; t=1774336791; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=GKYCbt7+DsHz/UsPxjcClQhC2XQ0NG0eDSGgUETZnsQ=; b=sQtJs+eS3sTDfUZ+mUH++5YbiH/gwsjXrDeigDj1QSwcWnoJFJkI3dU9kPY3ZePnYzgAAR MUe3+TdnQtmVbACQ== Received: from devron.myhome.or.jp (devron.myhome.or.jp [192.168.0.3]) by ibmpc.myhome.or.jp (Postfix) with ESMTPS id 0C203E0057A; Tue, 24 Mar 2026 16:19:51 +0900 (JST) Received: by devron.myhome.or.jp (Postfix, from userid 1000) id 01EEF22001B7; Tue, 24 Mar 2026 16:19:50 +0900 (JST) From: OGAWA Hirofumi To: Christian Brauner Cc: aviv.daum@gmail.com, linux-kernel@vger.kernel.org Subject: Re: [PATCH v2] fat: add KUnit tests for timestamp conversion helpers In-Reply-To: <87h5qgsbei.fsf@mail.parknet.co.jp> References: <20260315144212.24325-1-aviv.daum@gmail.com> <20260315222404.9678-1-aviv.daum@gmail.com> <87h5qgsbei.fsf@mail.parknet.co.jp> Date: Tue, 24 Mar 2026 16:19:50 +0900 Message-ID: <87ecl9zobt.fsf@mail.parknet.co.jp> User-Agent: Gnus/5.13 (Gnus v5.13) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain Hi, Christian Ping? IIRC, you requested me to send FAT patches (fs/*) to you. Thanks. OGAWA Hirofumi writes: > aviv.daum@gmail.com writes: > >> From: avivdaum >> >> Extend fat_test with coverage for FAT timestamp edge cases that are not >> currently exercised. >> >> Add tests for fat_time_unix2fat() clamping at the UTC boundaries and >> when time_offset pushes an otherwise valid timestamp outside the FAT >> date range. Also cover the NULL time_cs path used by existing callers, >> and verify fat_truncate_atime() truncation across timezone offsets. >> >> Signed-off-by: avivdaum > > Looks good. Thanks. > > Acked-by: OGAWA Hirofumi > >> v2: >> - Compare __le16 values directly in unix2fat tests >> >> --- >> fs/fat/fat_test.c | 181 ++++++++++++++++++++++++++++++++++++++++++++-- >> 1 file changed, 173 insertions(+), 8 deletions(-) >> >> diff --git a/fs/fat/fat_test.c b/fs/fat/fat_test.c >> index 1f0062659..5c97a7fcc 100644 >> --- a/fs/fat/fat_test.c >> +++ b/fs/fat/fat_test.c >> @@ -29,6 +29,22 @@ struct fat_timestamp_testcase { >> int time_offset; >> }; >> >> +struct fat_unix2fat_clamp_testcase { >> + const char *name; >> + struct timespec64 ts; >> + __le16 time; >> + __le16 date; >> + u8 cs; >> + int time_offset; >> +}; >> + >> +struct fat_truncate_atime_testcase { >> + const char *name; >> + struct timespec64 ts; >> + struct timespec64 expected; >> + int time_offset; >> +}; >> + >> static struct fat_timestamp_testcase time_test_cases[] = { >> { >> .name = "Earliest possible UTC (1980-01-01 00:00:00)", >> @@ -120,13 +136,92 @@ static struct fat_timestamp_testcase time_test_cases[] = { >> }, >> }; >> >> +static struct fat_unix2fat_clamp_testcase unix2fat_clamp_test_cases[] = { >> + { >> + .name = "Clamp to earliest FAT date for 1979-12-31 23:59:59 UTC", >> + .ts = {.tv_sec = 315532799LL, .tv_nsec = 0L}, >> + .time = cpu_to_le16(0), >> + .date = cpu_to_le16(33), >> + .cs = 0, >> + .time_offset = 0, >> + }, >> + { >> + .name = "Clamp after time_offset=-60 pushes 1980-01-01 00:30 UTC below 1980", >> + .ts = {.tv_sec = 315534600LL, .tv_nsec = 0L}, >> + .time = cpu_to_le16(0), >> + .date = cpu_to_le16(33), >> + .cs = 0, >> + .time_offset = -60, >> + }, >> + { >> + .name = "Clamp to latest FAT date for 2108-01-01 00:00:00 UTC", >> + .ts = {.tv_sec = 4354819200LL, .tv_nsec = 0L}, >> + .time = cpu_to_le16(49021), >> + .date = cpu_to_le16(65439), >> + .cs = 199, >> + .time_offset = 0, >> + }, >> + { >> + .name = "Clamp after time_offset=60 pushes 2107-12-31 23:30 UTC beyond 2107", >> + .ts = {.tv_sec = 4354817400LL, .tv_nsec = 0L}, >> + .time = cpu_to_le16(49021), >> + .date = cpu_to_le16(65439), >> + .cs = 199, >> + .time_offset = 60, >> + }, >> +}; >> + >> +static struct fat_truncate_atime_testcase truncate_atime_test_cases[] = { >> + { >> + .name = "UTC atime truncates to 2004-02-29 00:00:00", >> + .ts = {.tv_sec = 1078058096LL, .tv_nsec = 789000000L}, >> + .expected = {.tv_sec = 1078012800LL, .tv_nsec = 0L}, >> + .time_offset = 0, >> + }, >> + { >> + .name = "time_offset=-60 truncates 2004-02-29 00:30 UTC to previous local midnight", >> + .ts = {.tv_sec = 1078014645LL, .tv_nsec = 123000000L}, >> + .expected = {.tv_sec = 1077930000LL, .tv_nsec = 0L}, >> + .time_offset = -60, >> + }, >> + { >> + .name = "time_offset=60 truncates 2004-02-29 23:30 UTC to next local midnight", >> + .ts = {.tv_sec = 1078097445LL, .tv_nsec = 123000000L}, >> + .expected = {.tv_sec = 1078095600LL, .tv_nsec = 0L}, >> + .time_offset = 60, >> + }, >> +}; >> + >> static void time_testcase_desc(struct fat_timestamp_testcase *t, >> char *desc) >> { >> strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); >> } >> >> +static void unix2fat_clamp_testcase_desc(struct fat_unix2fat_clamp_testcase *t, >> + char *desc) >> +{ >> + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); >> +} >> + >> +static void truncate_atime_testcase_desc(struct fat_truncate_atime_testcase *t, >> + char *desc) >> +{ >> + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); >> +} >> + >> KUNIT_ARRAY_PARAM(fat_time, time_test_cases, time_testcase_desc); >> +KUNIT_ARRAY_PARAM(fat_unix2fat_clamp, unix2fat_clamp_test_cases, >> + unix2fat_clamp_testcase_desc); >> +KUNIT_ARRAY_PARAM(fat_truncate_atime, truncate_atime_test_cases, >> + truncate_atime_testcase_desc); >> + >> +static void fat_test_set_time_offset(struct msdos_sb_info *sbi, int time_offset) >> +{ >> + *sbi = (struct msdos_sb_info){}; >> + sbi->options.tz_set = 1; >> + sbi->options.time_offset = time_offset; >> +} >> >> static void fat_time_fat2unix_test(struct kunit *test) >> { >> @@ -135,8 +230,7 @@ static void fat_time_fat2unix_test(struct kunit *test) >> struct fat_timestamp_testcase *testcase = >> (struct fat_timestamp_testcase *)test->param_value; >> >> - fake_sb.options.tz_set = 1; >> - fake_sb.options.time_offset = testcase->time_offset; >> + fat_test_set_time_offset(&fake_sb, testcase->time_offset); >> >> fat_time_fat2unix(&fake_sb, &ts, >> testcase->time, >> @@ -160,18 +254,17 @@ static void fat_time_unix2fat_test(struct kunit *test) >> struct fat_timestamp_testcase *testcase = >> (struct fat_timestamp_testcase *)test->param_value; >> >> - fake_sb.options.tz_set = 1; >> - fake_sb.options.time_offset = testcase->time_offset; >> + fat_test_set_time_offset(&fake_sb, testcase->time_offset); >> >> fat_time_unix2fat(&fake_sb, &testcase->ts, >> &time, &date, &cs); >> KUNIT_EXPECT_EQ_MSG(test, >> - le16_to_cpu(testcase->time), >> - le16_to_cpu(time), >> + testcase->time, >> + time, >> "Time mismatch\n"); >> KUNIT_EXPECT_EQ_MSG(test, >> - le16_to_cpu(testcase->date), >> - le16_to_cpu(date), >> + testcase->date, >> + date, >> "Date mismatch\n"); >> KUNIT_EXPECT_EQ_MSG(test, >> testcase->cs, >> @@ -179,10 +272,82 @@ static void fat_time_unix2fat_test(struct kunit *test) >> "Centisecond mismatch\n"); >> } >> >> +static void fat_time_unix2fat_clamp_test(struct kunit *test) >> +{ >> + static struct msdos_sb_info fake_sb; >> + __le16 date, time; >> + u8 cs; >> + struct fat_unix2fat_clamp_testcase *testcase = >> + (struct fat_unix2fat_clamp_testcase *)test->param_value; >> + >> + fat_test_set_time_offset(&fake_sb, testcase->time_offset); >> + >> + fat_time_unix2fat(&fake_sb, &testcase->ts, &time, &date, &cs); >> + KUNIT_EXPECT_EQ_MSG(test, >> + testcase->time, >> + time, >> + "Clamped time mismatch\n"); >> + KUNIT_EXPECT_EQ_MSG(test, >> + testcase->date, >> + date, >> + "Clamped date mismatch\n"); >> + KUNIT_EXPECT_EQ_MSG(test, >> + testcase->cs, >> + cs, >> + "Clamped centisecond mismatch\n"); >> +} >> + >> +static void fat_time_unix2fat_no_csec_test(struct kunit *test) >> +{ >> + static struct msdos_sb_info fake_sb; >> + struct timespec64 ts = { >> + .tv_sec = 946684799LL, >> + .tv_nsec = 0L, >> + }; >> + __le16 date, time; >> + >> + fat_test_set_time_offset(&fake_sb, 0); >> + >> + fat_time_unix2fat(&fake_sb, &ts, &time, &date, NULL); >> + KUNIT_EXPECT_EQ_MSG(test, >> + 49021, >> + le16_to_cpu(time), >> + "Time mismatch without centiseconds\n"); >> + KUNIT_EXPECT_EQ_MSG(test, >> + 10143, >> + le16_to_cpu(date), >> + "Date mismatch without centiseconds\n"); >> +} >> + >> +static void fat_truncate_atime_test(struct kunit *test) >> +{ >> + static struct msdos_sb_info fake_sb; >> + struct timespec64 actual; >> + struct fat_truncate_atime_testcase *testcase = >> + (struct fat_truncate_atime_testcase *)test->param_value; >> + >> + fat_test_set_time_offset(&fake_sb, testcase->time_offset); >> + >> + actual = fat_truncate_atime(&fake_sb, &testcase->ts); >> + KUNIT_EXPECT_EQ_MSG(test, >> + testcase->expected.tv_sec, >> + actual.tv_sec, >> + "Atime truncation seconds mismatch\n"); >> + KUNIT_EXPECT_EQ_MSG(test, >> + testcase->expected.tv_nsec, >> + actual.tv_nsec, >> + "Atime truncation nanoseconds mismatch\n"); >> +} >> + >> static struct kunit_case fat_test_cases[] = { >> KUNIT_CASE(fat_checksum_test), >> KUNIT_CASE_PARAM(fat_time_fat2unix_test, fat_time_gen_params), >> KUNIT_CASE_PARAM(fat_time_unix2fat_test, fat_time_gen_params), >> + KUNIT_CASE_PARAM(fat_time_unix2fat_clamp_test, >> + fat_unix2fat_clamp_gen_params), >> + KUNIT_CASE(fat_time_unix2fat_no_csec_test), >> + KUNIT_CASE_PARAM(fat_truncate_atime_test, >> + fat_truncate_atime_gen_params), >> {}, >> }; -- OGAWA Hirofumi