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 AE936182D0 for ; Mon, 16 Mar 2026 03: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=1773631562; cv=none; b=fXuq94ecH75CoWADPoYkTnh+gEkjYyEauww8yFHtF8PSEsBqc4Jn9uCxY0PCaeiktd8WpOvyNEn9/IOgncSoaJGA19brhbmlFvDvZ0Rp9Hj3P2Jco3+6pYSF7DR1d7uiMGhYAVP9RfmShUaTMcZipX1d+9vVk0dcp2KipIdFkWo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773631562; c=relaxed/simple; bh=zsb5za8EI6QoM38ovj18KX5UXn776a4ZiGYZ37/fbQA=; h=From:To:Cc:Subject:In-Reply-To:References:Date:Message-ID: MIME-Version:Content-Type; b=FOfsV8i3/34p65VxxqDd7eew3DoxdyUvHYnZH8xADuOCaLzgDfMvYAzwKrmffNoDsR4PN9XOvzBFnBtiYGwGps85LYQxA3cHTyb4yk6ed1TpzPfI8mLwe0ziWIIjHDe2FARxSt0PbVIK9oUivLwuXaNpgkFBSw+A/G+zCVaBElE= 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=axylzIYT; dkim=permerror (0-bit key) header.d=parknet.co.jp header.i=@parknet.co.jp header.b=GpJgq25K; 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="axylzIYT"; dkim=permerror (0-bit key) header.d=parknet.co.jp header.i=@parknet.co.jp header.b="GpJgq25K" Received: from ibmpc.myhome.or.jp (server.parknet.ne.jp [210.171.168.39]) by mail.parknet.co.jp (Postfix) with ESMTPSA id B6CB926F765D; Mon, 16 Mar 2026 12:25:57 +0900 (JST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=parknet.co.jp; s=20250114; t=1773631558; 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=hGFawDDToESgXYsllMpTo3izTFjpy8reDDOFHQH08yg=; b=axylzIYTbFzzbe3H45p3NgQBeAXWWJkouKaq8LPukXWgobb7vs2a5ExKNCotsogbQoTwyd Z+h1o9rBToZ8rGJ5b+qekZT5NahRbr2x12VFQh2m7Lu9goVQtcH77XfwONBgNUUWKtmRxh 5I3Of0eedS4fjBk84vso7m9efZbnUe4P84RWSdGnFg0fmuMngCN3ZmHnrNxcQVbU71coYI ProXPolAWYCidfF0AmBPicFjzLqSG0RSv/0VK9flXMWQl6MRj7ILpY1Q4adsESXCRtVRD4 McGoirqxckmgLntJYHCgqjKz1ebUN5jWeNmndLmmpec3sAOHnM8cBGx0hxWj9Q== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=parknet.co.jp; s=20250114-ed25519; t=1773631558; 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=hGFawDDToESgXYsllMpTo3izTFjpy8reDDOFHQH08yg=; b=GpJgq25Kg/XrDx0Mr6jooBxcHio/Fnlay5SVoMploVQu44ctasmmRWh5hjwVIDorwAVMFF d5s8a90gT8ErhMCQ== Received: from devron.myhome.or.jp (devron.myhome.or.jp [192.168.0.3]) by ibmpc.myhome.or.jp (Postfix) with ESMTPS id 44745E0015A; Mon, 16 Mar 2026 12:25:57 +0900 (JST) Received: by devron.myhome.or.jp (Postfix, from userid 1000) id 39290220008E; Mon, 16 Mar 2026 12:25:57 +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: <20260315222404.9678-1-aviv.daum@gmail.com> References: <20260315144212.24325-1-aviv.daum@gmail.com> <20260315222404.9678-1-aviv.daum@gmail.com> Date: Mon, 16 Mar 2026 12:25:57 +0900 Message-ID: <87h5qgsbei.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 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