From nobody Sat Feb 7 08:27:26 2026 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.4]) (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 05ACE31576D; Fri, 26 Dec 2025 09:45:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766742342; cv=none; b=mL+l0lG1v8+CXNOlvJHxX0l7kSZUs6K8zc9+OWqj24J+o3fHXi6s+9XsvV8p2Y33kuYsMrro3c0A7qnvFcl+TltNePSFlaWgCUJY2LHfz1WgCy6Shc0xn1Vq2eQORQVj6SF4l8PJrsnNWJYHJ0TkA1IUTHp2NY4FyETgJUxJFEU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766742342; c=relaxed/simple; bh=m8VAlUB9Ouq9dJggFfY52aVdUdWKdTiZu9urVGJLxbo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iU+5+AXWAvEgMZukkmFtVwcyhb7wQ04ek6lIMrnd4Zj+hvOz56YHDM5jWxDbZuIbBsJhjjsGr3/HTxDz+VFdbKzOF76oh/YrImgf557GVUwmvlBIfSQpj0lGCqsCatGctfFJre42QcnjeNQv5GS4LEpM7q7RbMr9jSUAPdv4ymM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=RZzh4Jhu; arc=none smtp.client-ip=220.197.31.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="RZzh4Jhu" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=OL z45/biIqsJRdyUEJ63VpvHd0PioSptcgwR0uanzps=; b=RZzh4JhufGIcr//OuB i6mBrlVev8V2Ep3ctDH3Eds6JCqxsH0pHV9HaCyz2bJuhJZhWrTiV7yalJp5eQx5 iLWFlWiSXhWWWCtenP6HqHagDR/bKmYQU42EDhg6ktAMx5IG9pTD1l/W5z8P1ZkW WJ58+UmyapNTQkR3AeW4zrynw= Received: from chi-Redmi-Book.. (unknown []) by gzsmtp5 (Coremail) with SMTP id QCgvCgCnlXIPWU5p9JFCJA--.53S11; Fri, 26 Dec 2025 17:44:54 +0800 (CST) From: Chi Zhiling To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Namjae Jeon , Sungjong Seo , Yuezhang Mo , Alexander Viro , Christian Brauner , Jan Kara , Matthew Wilcox , Chi Zhiling Subject: [PATCH v1 9/9] exfat: support multi-cluster for exfat_get_cluster Date: Fri, 26 Dec 2025 17:44:40 +0800 Message-ID: <20251226094440.455563-10-chizhiling@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251226094440.455563-1-chizhiling@163.com> References: <20251226094440.455563-1-chizhiling@163.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: QCgvCgCnlXIPWU5p9JFCJA--.53S11 X-Coremail-Antispam: 1Uf129KBjvJXoWxWw1fJw4kAF4UuFWkCF1rJFb_yoW7JFyrpr WxKayrtrZxXasruw4xtrs5ZryS93Z7GFW5J347Jry5Crn0yr4F9r1Dt3s0yF18Gw4kua1j vr1Fgw1UurnxGaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07Um2NNUUUUU= X-CM-SenderInfo: hfkl6xxlol0wi6rwjhhfrp/xtbC3BdJ5mlOWRe78QAA3H Content-Type: text/plain; charset="utf-8" From: Chi Zhiling This patch introduces a count parameter to exfat_get_cluster, which serves as an input parameter for the caller to specify the desired number of clusters, and as an output parameter to store the length of consecutive clusters. This patch can improve read performance by reducing the number of get_block calls in sequential read scenarios. speacially in small cluster size. According to my test data, the performance improvement is approximately 10% when read FAT_CHAIN file with 512 bytes of cluster size. 454 MB/s -> 511 MB/s Signed-off-by: Chi Zhiling --- fs/exfat/cache.c | 51 +++++++++++++++++++++++++++++++++++++++++---- fs/exfat/exfat_fs.h | 2 +- fs/exfat/inode.c | 5 +++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c index 57a66c067394..80efe2e0393d 100644 --- a/fs/exfat/cache.c +++ b/fs/exfat/cache.c @@ -234,7 +234,8 @@ static inline void cache_init(struct exfat_cache_id *ci= d, } =20 int exfat_get_cluster(struct inode *inode, unsigned int cluster, - unsigned int *dclus, unsigned int *last_dclus) + unsigned int *dclus, unsigned int *count, + unsigned int *last_dclus) { struct super_block *sb =3D inode->i_sb; struct exfat_sb_info *sbi =3D EXFAT_SB(sb); @@ -243,6 +244,7 @@ int exfat_get_cluster(struct inode *inode, unsigned int= cluster, struct buffer_head *bh =3D NULL; struct exfat_cache_id cid; unsigned int content, fclus; + unsigned int end =3D (*count <=3D 1) ? cluster : cluster + *count - 1; =20 if (ei->start_clu =3D=3D EXFAT_FREE_CLUSTER) { exfat_fs_error(sb, @@ -256,17 +258,33 @@ int exfat_get_cluster(struct inode *inode, unsigned i= nt cluster, *last_dclus =3D *dclus; =20 /* - * Don`t use exfat_cache if zero offset or non-cluster allocation + * This case should not exist, as exfat_map_cluster function doesn't + * call this routine when start_clu =3D=3D EXFAT_EOF_CLUSTER. + * This case is retained here for routine completeness. */ - if (cluster =3D=3D 0 || *dclus =3D=3D EXFAT_EOF_CLUSTER) + if (*dclus =3D=3D EXFAT_EOF_CLUSTER) { + *count =3D 0; + return 0; + } + + /* If only the first cluster is needed, return now. */ + if (fclus =3D=3D cluster && *count =3D=3D 1) return 0; =20 cache_init(&cid, fclus, *dclus); exfat_cache_lookup(inode, cluster, &cid, &fclus, dclus); =20 - if (fclus =3D=3D cluster) + /* + * Return on cache hit to keep the code simple. + */ + if (fclus =3D=3D cluster) { + *count =3D cid.fcluster + cid.nr_contig - fclus + 1; return 0; + } =20 + /* + * Find the first cluster we need. + */ while (fclus < cluster) { /* prevent the infinite loop of cluster chain */ if (fclus > limit) { @@ -290,6 +308,31 @@ int exfat_get_cluster(struct inode *inode, unsigned in= t cluster, cache_init(&cid, fclus, *dclus); } =20 + /* + * Collect the remaining clusters of this contiguous extent. + */ + if (*dclus !=3D EXFAT_EOF_CLUSTER) { + unsigned int clu =3D *dclus; + + /* + * Now the cid cache contains the first cluster requested, + * Advance the fclus to the last cluster of contiguous + * extent, then update the count and cid cache accordingly. + */ + while (fclus < end) { + if (exfat_ent_get(sb, clu, &content, &bh)) + goto err; + if (++clu !=3D content) { + /* TODO: read ahead if content valid */ + break; + } + fclus++; + } + cid.nr_contig =3D fclus - cid.fcluster; + *count =3D fclus - cluster + 1; + } else { + *count =3D 0; + } brelse(bh); exfat_cache_add(inode, &cid); return 0; diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h index e58d8eed5495..2dbed5f8ec26 100644 --- a/fs/exfat/exfat_fs.h +++ b/fs/exfat/exfat_fs.h @@ -486,7 +486,7 @@ int exfat_cache_init(void); void exfat_cache_shutdown(void); void exfat_cache_inval_inode(struct inode *inode); int exfat_get_cluster(struct inode *inode, unsigned int cluster, - unsigned int *dclus, unsigned int *last_dclus); + unsigned int *dclus, unsigned int *count, unsigned int *last_dclus); =20 /* dir.c */ extern const struct inode_operations exfat_dir_inode_operations; diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c index 8c49ab15eafe..317bc363f7d9 100644 --- a/fs/exfat/inode.c +++ b/fs/exfat/inode.c @@ -134,6 +134,7 @@ static int exfat_map_cluster(struct inode *inode, unsig= ned int clu_offset, struct exfat_inode_info *ei =3D EXFAT_I(inode); unsigned int local_clu_offset =3D clu_offset; unsigned int num_to_be_allocated =3D 0, num_clusters; + unsigned int hint_count =3D max(*count, 1); =20 num_clusters =3D EXFAT_B_TO_CLU(exfat_ondisk_size(inode), sbi); =20 @@ -159,11 +160,11 @@ static int exfat_map_cluster(struct inode *inode, uns= igned int clu_offset, *count =3D 0; } } else if (ei->type =3D=3D TYPE_FILE) { + *count =3D hint_count; int err =3D exfat_get_cluster(inode, clu_offset, - clu, &last_clu); + clu, count, &last_clu); if (err) return -EIO; - *count =3D (*clu =3D=3D EXFAT_EOF_CLUSTER) ? 0 : 1; } else { unsigned int fclus =3D 0; /* hint information */ --=20 2.43.0