From: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
To: Christian Brauner <brauner@kernel.org>
Cc: aviv.daum@gmail.com, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2] fat: add KUnit tests for timestamp conversion helpers
Date: Tue, 24 Mar 2026 16:19:50 +0900 [thread overview]
Message-ID: <87ecl9zobt.fsf@mail.parknet.co.jp> (raw)
In-Reply-To: <87h5qgsbei.fsf@mail.parknet.co.jp>
Hi, Christian
Ping? IIRC, you requested me to send FAT patches (fs/*) to you.
Thanks.
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> writes:
> aviv.daum@gmail.com writes:
>
>> From: avivdaum <aviv.daum@gmail.com>
>>
>> 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 <aviv.daum@gmail.com>
>
> Looks good. Thanks.
>
> Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
>
>> 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 <hirofumi@mail.parknet.co.jp>
next prev parent reply other threads:[~2026-03-24 7:25 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-15 14:42 [PATCH] fat: add KUnit tests for timestamp conversion helpers aviv.daum
2026-03-15 17:38 ` OGAWA Hirofumi
2026-03-15 22:24 ` [PATCH v2] " aviv.daum
2026-03-16 3:25 ` OGAWA Hirofumi
2026-03-24 7:19 ` OGAWA Hirofumi [this message]
2026-03-24 7:48 ` Christian Brauner
2026-03-24 8:02 ` OGAWA Hirofumi
2026-03-24 7:47 ` Christian Brauner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87ecl9zobt.fsf@mail.parknet.co.jp \
--to=hirofumi@mail.parknet.co.jp \
--cc=aviv.daum@gmail.com \
--cc=brauner@kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.