162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/init.h>
762306a36Sopenharmony_ci#include <linux/buffer_head.h>
862306a36Sopenharmony_ci#include <linux/mpage.h>
962306a36Sopenharmony_ci#include <linux/bio.h>
1062306a36Sopenharmony_ci#include <linux/blkdev.h>
1162306a36Sopenharmony_ci#include <linux/time.h>
1262306a36Sopenharmony_ci#include <linux/writeback.h>
1362306a36Sopenharmony_ci#include <linux/uio.h>
1462306a36Sopenharmony_ci#include <linux/random.h>
1562306a36Sopenharmony_ci#include <linux/iversion.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "exfat_raw.h"
1862306a36Sopenharmony_ci#include "exfat_fs.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciint __exfat_write_inode(struct inode *inode, int sync)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	unsigned long long on_disk_size;
2362306a36Sopenharmony_ci	struct exfat_dentry *ep, *ep2;
2462306a36Sopenharmony_ci	struct exfat_entry_set_cache es;
2562306a36Sopenharmony_ci	struct super_block *sb = inode->i_sb;
2662306a36Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
2762306a36Sopenharmony_ci	struct exfat_inode_info *ei = EXFAT_I(inode);
2862306a36Sopenharmony_ci	bool is_dir = (ei->type == TYPE_DIR) ? true : false;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (inode->i_ino == EXFAT_ROOT_INO)
3162306a36Sopenharmony_ci		return 0;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	/*
3462306a36Sopenharmony_ci	 * If the inode is already unlinked, there is no need for updating it.
3562306a36Sopenharmony_ci	 */
3662306a36Sopenharmony_ci	if (ei->dir.dir == DIR_DELETED)
3762306a36Sopenharmony_ci		return 0;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (is_dir && ei->dir.dir == sbi->root_dir && ei->entry == -1)
4062306a36Sopenharmony_ci		return 0;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	exfat_set_volume_dirty(sb);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/* get the directory entry of given file or directory */
4562306a36Sopenharmony_ci	if (exfat_get_dentry_set(&es, sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES))
4662306a36Sopenharmony_ci		return -EIO;
4762306a36Sopenharmony_ci	ep = exfat_get_dentry_cached(&es, ES_IDX_FILE);
4862306a36Sopenharmony_ci	ep2 = exfat_get_dentry_cached(&es, ES_IDX_STREAM);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	ep->dentry.file.attr = cpu_to_le16(exfat_make_attr(inode));
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/* set FILE_INFO structure using the acquired struct exfat_dentry */
5362306a36Sopenharmony_ci	exfat_set_entry_time(sbi, &ei->i_crtime,
5462306a36Sopenharmony_ci			&ep->dentry.file.create_tz,
5562306a36Sopenharmony_ci			&ep->dentry.file.create_time,
5662306a36Sopenharmony_ci			&ep->dentry.file.create_date,
5762306a36Sopenharmony_ci			&ep->dentry.file.create_time_cs);
5862306a36Sopenharmony_ci	exfat_set_entry_time(sbi, &inode->i_mtime,
5962306a36Sopenharmony_ci			&ep->dentry.file.modify_tz,
6062306a36Sopenharmony_ci			&ep->dentry.file.modify_time,
6162306a36Sopenharmony_ci			&ep->dentry.file.modify_date,
6262306a36Sopenharmony_ci			&ep->dentry.file.modify_time_cs);
6362306a36Sopenharmony_ci	exfat_set_entry_time(sbi, &inode->i_atime,
6462306a36Sopenharmony_ci			&ep->dentry.file.access_tz,
6562306a36Sopenharmony_ci			&ep->dentry.file.access_time,
6662306a36Sopenharmony_ci			&ep->dentry.file.access_date,
6762306a36Sopenharmony_ci			NULL);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* File size should be zero if there is no cluster allocated */
7062306a36Sopenharmony_ci	on_disk_size = i_size_read(inode);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (ei->start_clu == EXFAT_EOF_CLUSTER)
7362306a36Sopenharmony_ci		on_disk_size = 0;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size);
7662306a36Sopenharmony_ci	ep2->dentry.stream.size = ep2->dentry.stream.valid_size;
7762306a36Sopenharmony_ci	if (on_disk_size) {
7862306a36Sopenharmony_ci		ep2->dentry.stream.flags = ei->flags;
7962306a36Sopenharmony_ci		ep2->dentry.stream.start_clu = cpu_to_le32(ei->start_clu);
8062306a36Sopenharmony_ci	} else {
8162306a36Sopenharmony_ci		ep2->dentry.stream.flags = ALLOC_FAT_CHAIN;
8262306a36Sopenharmony_ci		ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	exfat_update_dir_chksum_with_entry_set(&es);
8662306a36Sopenharmony_ci	return exfat_put_dentry_set(&es, sync);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ciint exfat_write_inode(struct inode *inode, struct writeback_control *wbc)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	int ret;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
9462306a36Sopenharmony_ci	ret = __exfat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
9562306a36Sopenharmony_ci	mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return ret;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_civoid exfat_sync_inode(struct inode *inode)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	lockdep_assert_held(&EXFAT_SB(inode->i_sb)->s_lock);
10362306a36Sopenharmony_ci	__exfat_write_inode(inode, 1);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/*
10762306a36Sopenharmony_ci * Input: inode, (logical) clu_offset, target allocation area
10862306a36Sopenharmony_ci * Output: errcode, cluster number
10962306a36Sopenharmony_ci * *clu = (~0), if it's unable to allocate a new cluster
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_cistatic int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
11262306a36Sopenharmony_ci		unsigned int *clu, int create)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	int ret;
11562306a36Sopenharmony_ci	unsigned int last_clu;
11662306a36Sopenharmony_ci	struct exfat_chain new_clu;
11762306a36Sopenharmony_ci	struct super_block *sb = inode->i_sb;
11862306a36Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
11962306a36Sopenharmony_ci	struct exfat_inode_info *ei = EXFAT_I(inode);
12062306a36Sopenharmony_ci	unsigned int local_clu_offset = clu_offset;
12162306a36Sopenharmony_ci	unsigned int num_to_be_allocated = 0, num_clusters = 0;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (ei->i_size_ondisk > 0)
12462306a36Sopenharmony_ci		num_clusters =
12562306a36Sopenharmony_ci			EXFAT_B_TO_CLU_ROUND_UP(ei->i_size_ondisk, sbi);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (clu_offset >= num_clusters)
12862306a36Sopenharmony_ci		num_to_be_allocated = clu_offset - num_clusters + 1;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (!create && (num_to_be_allocated > 0)) {
13162306a36Sopenharmony_ci		*clu = EXFAT_EOF_CLUSTER;
13262306a36Sopenharmony_ci		return 0;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	*clu = last_clu = ei->start_clu;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (ei->flags == ALLOC_NO_FAT_CHAIN) {
13862306a36Sopenharmony_ci		if (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) {
13962306a36Sopenharmony_ci			last_clu += clu_offset - 1;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci			if (clu_offset == num_clusters)
14262306a36Sopenharmony_ci				*clu = EXFAT_EOF_CLUSTER;
14362306a36Sopenharmony_ci			else
14462306a36Sopenharmony_ci				*clu += clu_offset;
14562306a36Sopenharmony_ci		}
14662306a36Sopenharmony_ci	} else if (ei->type == TYPE_FILE) {
14762306a36Sopenharmony_ci		unsigned int fclus = 0;
14862306a36Sopenharmony_ci		int err = exfat_get_cluster(inode, clu_offset,
14962306a36Sopenharmony_ci				&fclus, clu, &last_clu, 1);
15062306a36Sopenharmony_ci		if (err)
15162306a36Sopenharmony_ci			return -EIO;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		clu_offset -= fclus;
15462306a36Sopenharmony_ci	} else {
15562306a36Sopenharmony_ci		/* hint information */
15662306a36Sopenharmony_ci		if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER &&
15762306a36Sopenharmony_ci		    ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) {
15862306a36Sopenharmony_ci			clu_offset -= ei->hint_bmap.off;
15962306a36Sopenharmony_ci			/* hint_bmap.clu should be valid */
16062306a36Sopenharmony_ci			WARN_ON(ei->hint_bmap.clu < 2);
16162306a36Sopenharmony_ci			*clu = ei->hint_bmap.clu;
16262306a36Sopenharmony_ci		}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		while (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) {
16562306a36Sopenharmony_ci			last_clu = *clu;
16662306a36Sopenharmony_ci			if (exfat_get_next_cluster(sb, clu))
16762306a36Sopenharmony_ci				return -EIO;
16862306a36Sopenharmony_ci			clu_offset--;
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (*clu == EXFAT_EOF_CLUSTER) {
17362306a36Sopenharmony_ci		exfat_set_volume_dirty(sb);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		new_clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ?
17662306a36Sopenharmony_ci				EXFAT_EOF_CLUSTER : last_clu + 1;
17762306a36Sopenharmony_ci		new_clu.size = 0;
17862306a36Sopenharmony_ci		new_clu.flags = ei->flags;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		/* allocate a cluster */
18162306a36Sopenharmony_ci		if (num_to_be_allocated < 1) {
18262306a36Sopenharmony_ci			/* Broken FAT (i_sze > allocated FAT) */
18362306a36Sopenharmony_ci			exfat_fs_error(sb, "broken FAT chain.");
18462306a36Sopenharmony_ci			return -EIO;
18562306a36Sopenharmony_ci		}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		ret = exfat_alloc_cluster(inode, num_to_be_allocated, &new_clu,
18862306a36Sopenharmony_ci				inode_needs_sync(inode));
18962306a36Sopenharmony_ci		if (ret)
19062306a36Sopenharmony_ci			return ret;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		if (new_clu.dir == EXFAT_EOF_CLUSTER ||
19362306a36Sopenharmony_ci		    new_clu.dir == EXFAT_FREE_CLUSTER) {
19462306a36Sopenharmony_ci			exfat_fs_error(sb,
19562306a36Sopenharmony_ci				"bogus cluster new allocated (last_clu : %u, new_clu : %u)",
19662306a36Sopenharmony_ci				last_clu, new_clu.dir);
19762306a36Sopenharmony_ci			return -EIO;
19862306a36Sopenharmony_ci		}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		/* append to the FAT chain */
20162306a36Sopenharmony_ci		if (last_clu == EXFAT_EOF_CLUSTER) {
20262306a36Sopenharmony_ci			if (new_clu.flags == ALLOC_FAT_CHAIN)
20362306a36Sopenharmony_ci				ei->flags = ALLOC_FAT_CHAIN;
20462306a36Sopenharmony_ci			ei->start_clu = new_clu.dir;
20562306a36Sopenharmony_ci		} else {
20662306a36Sopenharmony_ci			if (new_clu.flags != ei->flags) {
20762306a36Sopenharmony_ci				/* no-fat-chain bit is disabled,
20862306a36Sopenharmony_ci				 * so fat-chain should be synced with
20962306a36Sopenharmony_ci				 * alloc-bitmap
21062306a36Sopenharmony_ci				 */
21162306a36Sopenharmony_ci				exfat_chain_cont_cluster(sb, ei->start_clu,
21262306a36Sopenharmony_ci					num_clusters);
21362306a36Sopenharmony_ci				ei->flags = ALLOC_FAT_CHAIN;
21462306a36Sopenharmony_ci			}
21562306a36Sopenharmony_ci			if (new_clu.flags == ALLOC_FAT_CHAIN)
21662306a36Sopenharmony_ci				if (exfat_ent_set(sb, last_clu, new_clu.dir))
21762306a36Sopenharmony_ci					return -EIO;
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		num_clusters += num_to_be_allocated;
22162306a36Sopenharmony_ci		*clu = new_clu.dir;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		inode->i_blocks += EXFAT_CLU_TO_B(num_to_be_allocated, sbi) >> 9;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		/*
22662306a36Sopenharmony_ci		 * Move *clu pointer along FAT chains (hole care) because the
22762306a36Sopenharmony_ci		 * caller of this function expect *clu to be the last cluster.
22862306a36Sopenharmony_ci		 * This only works when num_to_be_allocated >= 2,
22962306a36Sopenharmony_ci		 * *clu = (the first cluster of the allocated chain) =>
23062306a36Sopenharmony_ci		 * (the last cluster of ...)
23162306a36Sopenharmony_ci		 */
23262306a36Sopenharmony_ci		if (ei->flags == ALLOC_NO_FAT_CHAIN) {
23362306a36Sopenharmony_ci			*clu += num_to_be_allocated - 1;
23462306a36Sopenharmony_ci		} else {
23562306a36Sopenharmony_ci			while (num_to_be_allocated > 1) {
23662306a36Sopenharmony_ci				if (exfat_get_next_cluster(sb, clu))
23762306a36Sopenharmony_ci					return -EIO;
23862306a36Sopenharmony_ci				num_to_be_allocated--;
23962306a36Sopenharmony_ci			}
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/* hint information */
24562306a36Sopenharmony_ci	ei->hint_bmap.off = local_clu_offset;
24662306a36Sopenharmony_ci	ei->hint_bmap.clu = *clu;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return 0;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int exfat_map_new_buffer(struct exfat_inode_info *ei,
25262306a36Sopenharmony_ci		struct buffer_head *bh, loff_t pos)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	if (buffer_delay(bh) && pos > ei->i_size_aligned)
25562306a36Sopenharmony_ci		return -EIO;
25662306a36Sopenharmony_ci	set_buffer_new(bh);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/*
25962306a36Sopenharmony_ci	 * Adjust i_size_aligned if i_size_ondisk is bigger than it.
26062306a36Sopenharmony_ci	 */
26162306a36Sopenharmony_ci	if (ei->i_size_ondisk > ei->i_size_aligned)
26262306a36Sopenharmony_ci		ei->i_size_aligned = ei->i_size_ondisk;
26362306a36Sopenharmony_ci	return 0;
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic int exfat_get_block(struct inode *inode, sector_t iblock,
26762306a36Sopenharmony_ci		struct buffer_head *bh_result, int create)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct exfat_inode_info *ei = EXFAT_I(inode);
27062306a36Sopenharmony_ci	struct super_block *sb = inode->i_sb;
27162306a36Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
27262306a36Sopenharmony_ci	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
27362306a36Sopenharmony_ci	int err = 0;
27462306a36Sopenharmony_ci	unsigned long mapped_blocks = 0;
27562306a36Sopenharmony_ci	unsigned int cluster, sec_offset;
27662306a36Sopenharmony_ci	sector_t last_block;
27762306a36Sopenharmony_ci	sector_t phys = 0;
27862306a36Sopenharmony_ci	loff_t pos;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	mutex_lock(&sbi->s_lock);
28162306a36Sopenharmony_ci	last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size_read(inode), sb);
28262306a36Sopenharmony_ci	if (iblock >= last_block && !create)
28362306a36Sopenharmony_ci		goto done;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* Is this block already allocated? */
28662306a36Sopenharmony_ci	err = exfat_map_cluster(inode, iblock >> sbi->sect_per_clus_bits,
28762306a36Sopenharmony_ci			&cluster, create);
28862306a36Sopenharmony_ci	if (err) {
28962306a36Sopenharmony_ci		if (err != -ENOSPC)
29062306a36Sopenharmony_ci			exfat_fs_error_ratelimit(sb,
29162306a36Sopenharmony_ci				"failed to bmap (inode : %p iblock : %llu, err : %d)",
29262306a36Sopenharmony_ci				inode, (unsigned long long)iblock, err);
29362306a36Sopenharmony_ci		goto unlock_ret;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (cluster == EXFAT_EOF_CLUSTER)
29762306a36Sopenharmony_ci		goto done;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* sector offset in cluster */
30062306a36Sopenharmony_ci	sec_offset = iblock & (sbi->sect_per_clus - 1);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset;
30362306a36Sopenharmony_ci	mapped_blocks = sbi->sect_per_clus - sec_offset;
30462306a36Sopenharmony_ci	max_blocks = min(mapped_blocks, max_blocks);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* Treat newly added block / cluster */
30762306a36Sopenharmony_ci	if (iblock < last_block)
30862306a36Sopenharmony_ci		create = 0;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (create || buffer_delay(bh_result)) {
31162306a36Sopenharmony_ci		pos = EXFAT_BLK_TO_B((iblock + 1), sb);
31262306a36Sopenharmony_ci		if (ei->i_size_ondisk < pos)
31362306a36Sopenharmony_ci			ei->i_size_ondisk = pos;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (create) {
31762306a36Sopenharmony_ci		err = exfat_map_new_buffer(ei, bh_result, pos);
31862306a36Sopenharmony_ci		if (err) {
31962306a36Sopenharmony_ci			exfat_fs_error(sb,
32062306a36Sopenharmony_ci					"requested for bmap out of range(pos : (%llu) > i_size_aligned(%llu)\n",
32162306a36Sopenharmony_ci					pos, ei->i_size_aligned);
32262306a36Sopenharmony_ci			goto unlock_ret;
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (buffer_delay(bh_result))
32762306a36Sopenharmony_ci		clear_buffer_delay(bh_result);
32862306a36Sopenharmony_ci	map_bh(bh_result, sb, phys);
32962306a36Sopenharmony_cidone:
33062306a36Sopenharmony_ci	bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb);
33162306a36Sopenharmony_ciunlock_ret:
33262306a36Sopenharmony_ci	mutex_unlock(&sbi->s_lock);
33362306a36Sopenharmony_ci	return err;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int exfat_read_folio(struct file *file, struct folio *folio)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	return mpage_read_folio(folio, exfat_get_block);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic void exfat_readahead(struct readahead_control *rac)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	mpage_readahead(rac, exfat_get_block);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic int exfat_writepages(struct address_space *mapping,
34762306a36Sopenharmony_ci		struct writeback_control *wbc)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	return mpage_writepages(mapping, wbc, exfat_get_block);
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic void exfat_write_failed(struct address_space *mapping, loff_t to)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct inode *inode = mapping->host;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (to > i_size_read(inode)) {
35762306a36Sopenharmony_ci		truncate_pagecache(inode, i_size_read(inode));
35862306a36Sopenharmony_ci		inode->i_mtime = inode_set_ctime_current(inode);
35962306a36Sopenharmony_ci		exfat_truncate(inode);
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic int exfat_write_begin(struct file *file, struct address_space *mapping,
36462306a36Sopenharmony_ci		loff_t pos, unsigned int len,
36562306a36Sopenharmony_ci		struct page **pagep, void **fsdata)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	int ret;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	*pagep = NULL;
37062306a36Sopenharmony_ci	ret = cont_write_begin(file, mapping, pos, len, pagep, fsdata,
37162306a36Sopenharmony_ci			       exfat_get_block,
37262306a36Sopenharmony_ci			       &EXFAT_I(mapping->host)->i_size_ondisk);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (ret < 0)
37562306a36Sopenharmony_ci		exfat_write_failed(mapping, pos+len);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return ret;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int exfat_write_end(struct file *file, struct address_space *mapping,
38162306a36Sopenharmony_ci		loff_t pos, unsigned int len, unsigned int copied,
38262306a36Sopenharmony_ci		struct page *pagep, void *fsdata)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct inode *inode = mapping->host;
38562306a36Sopenharmony_ci	struct exfat_inode_info *ei = EXFAT_I(inode);
38662306a36Sopenharmony_ci	int err;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (ei->i_size_aligned < i_size_read(inode)) {
39162306a36Sopenharmony_ci		exfat_fs_error(inode->i_sb,
39262306a36Sopenharmony_ci			"invalid size(size(%llu) > aligned(%llu)\n",
39362306a36Sopenharmony_ci			i_size_read(inode), ei->i_size_aligned);
39462306a36Sopenharmony_ci		return -EIO;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (err < len)
39862306a36Sopenharmony_ci		exfat_write_failed(mapping, pos+len);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (!(err < 0) && !(ei->attr & ATTR_ARCHIVE)) {
40162306a36Sopenharmony_ci		inode->i_mtime = inode_set_ctime_current(inode);
40262306a36Sopenharmony_ci		ei->attr |= ATTR_ARCHIVE;
40362306a36Sopenharmony_ci		mark_inode_dirty(inode);
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return err;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct address_space *mapping = iocb->ki_filp->f_mapping;
41262306a36Sopenharmony_ci	struct inode *inode = mapping->host;
41362306a36Sopenharmony_ci	loff_t size = iocb->ki_pos + iov_iter_count(iter);
41462306a36Sopenharmony_ci	int rw = iov_iter_rw(iter);
41562306a36Sopenharmony_ci	ssize_t ret;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (rw == WRITE) {
41862306a36Sopenharmony_ci		/*
41962306a36Sopenharmony_ci		 * FIXME: blockdev_direct_IO() doesn't use ->write_begin(),
42062306a36Sopenharmony_ci		 * so we need to update the ->i_size_aligned to block boundary.
42162306a36Sopenharmony_ci		 *
42262306a36Sopenharmony_ci		 * But we must fill the remaining area or hole by nul for
42362306a36Sopenharmony_ci		 * updating ->i_size_aligned
42462306a36Sopenharmony_ci		 *
42562306a36Sopenharmony_ci		 * Return 0, and fallback to normal buffered write.
42662306a36Sopenharmony_ci		 */
42762306a36Sopenharmony_ci		if (EXFAT_I(inode)->i_size_aligned < size)
42862306a36Sopenharmony_ci			return 0;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/*
43262306a36Sopenharmony_ci	 * Need to use the DIO_LOCKING for avoiding the race
43362306a36Sopenharmony_ci	 * condition of exfat_get_block() and ->truncate().
43462306a36Sopenharmony_ci	 */
43562306a36Sopenharmony_ci	ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block);
43662306a36Sopenharmony_ci	if (ret < 0 && (rw & WRITE))
43762306a36Sopenharmony_ci		exfat_write_failed(mapping, size);
43862306a36Sopenharmony_ci	return ret;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic sector_t exfat_aop_bmap(struct address_space *mapping, sector_t block)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	sector_t blocknr;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/* exfat_get_cluster() assumes the requested blocknr isn't truncated. */
44662306a36Sopenharmony_ci	down_read(&EXFAT_I(mapping->host)->truncate_lock);
44762306a36Sopenharmony_ci	blocknr = generic_block_bmap(mapping, block, exfat_get_block);
44862306a36Sopenharmony_ci	up_read(&EXFAT_I(mapping->host)->truncate_lock);
44962306a36Sopenharmony_ci	return blocknr;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/*
45362306a36Sopenharmony_ci * exfat_block_truncate_page() zeroes out a mapping from file offset `from'
45462306a36Sopenharmony_ci * up to the end of the block which corresponds to `from'.
45562306a36Sopenharmony_ci * This is required during truncate to physically zeroout the tail end
45662306a36Sopenharmony_ci * of that block so it doesn't yield old data if the file is later grown.
45762306a36Sopenharmony_ci * Also, avoid causing failure from fsx for cases of "data past EOF"
45862306a36Sopenharmony_ci */
45962306a36Sopenharmony_ciint exfat_block_truncate_page(struct inode *inode, loff_t from)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	return block_truncate_page(inode->i_mapping, from, exfat_get_block);
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic const struct address_space_operations exfat_aops = {
46562306a36Sopenharmony_ci	.dirty_folio	= block_dirty_folio,
46662306a36Sopenharmony_ci	.invalidate_folio = block_invalidate_folio,
46762306a36Sopenharmony_ci	.read_folio	= exfat_read_folio,
46862306a36Sopenharmony_ci	.readahead	= exfat_readahead,
46962306a36Sopenharmony_ci	.writepages	= exfat_writepages,
47062306a36Sopenharmony_ci	.write_begin	= exfat_write_begin,
47162306a36Sopenharmony_ci	.write_end	= exfat_write_end,
47262306a36Sopenharmony_ci	.direct_IO	= exfat_direct_IO,
47362306a36Sopenharmony_ci	.bmap		= exfat_aop_bmap,
47462306a36Sopenharmony_ci	.migrate_folio	= buffer_migrate_folio,
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic inline unsigned long exfat_hash(loff_t i_pos)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	return hash_32(i_pos, EXFAT_HASH_BITS);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_civoid exfat_hash_inode(struct inode *inode, loff_t i_pos)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
48562306a36Sopenharmony_ci	struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	spin_lock(&sbi->inode_hash_lock);
48862306a36Sopenharmony_ci	EXFAT_I(inode)->i_pos = i_pos;
48962306a36Sopenharmony_ci	hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head);
49062306a36Sopenharmony_ci	spin_unlock(&sbi->inode_hash_lock);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_civoid exfat_unhash_inode(struct inode *inode)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	spin_lock(&sbi->inode_hash_lock);
49862306a36Sopenharmony_ci	hlist_del_init(&EXFAT_I(inode)->i_hash_fat);
49962306a36Sopenharmony_ci	EXFAT_I(inode)->i_pos = 0;
50062306a36Sopenharmony_ci	spin_unlock(&sbi->inode_hash_lock);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistruct inode *exfat_iget(struct super_block *sb, loff_t i_pos)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
50662306a36Sopenharmony_ci	struct exfat_inode_info *info;
50762306a36Sopenharmony_ci	struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos);
50862306a36Sopenharmony_ci	struct inode *inode = NULL;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	spin_lock(&sbi->inode_hash_lock);
51162306a36Sopenharmony_ci	hlist_for_each_entry(info, head, i_hash_fat) {
51262306a36Sopenharmony_ci		WARN_ON(info->vfs_inode.i_sb != sb);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		if (i_pos != info->i_pos)
51562306a36Sopenharmony_ci			continue;
51662306a36Sopenharmony_ci		inode = igrab(&info->vfs_inode);
51762306a36Sopenharmony_ci		if (inode)
51862306a36Sopenharmony_ci			break;
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci	spin_unlock(&sbi->inode_hash_lock);
52162306a36Sopenharmony_ci	return inode;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/* doesn't deal with root inode */
52562306a36Sopenharmony_cistatic int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
52862306a36Sopenharmony_ci	struct exfat_inode_info *ei = EXFAT_I(inode);
52962306a36Sopenharmony_ci	loff_t size = info->size;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	ei->dir = info->dir;
53262306a36Sopenharmony_ci	ei->entry = info->entry;
53362306a36Sopenharmony_ci	ei->attr = info->attr;
53462306a36Sopenharmony_ci	ei->start_clu = info->start_clu;
53562306a36Sopenharmony_ci	ei->flags = info->flags;
53662306a36Sopenharmony_ci	ei->type = info->type;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	ei->version = 0;
53962306a36Sopenharmony_ci	ei->hint_stat.eidx = 0;
54062306a36Sopenharmony_ci	ei->hint_stat.clu = info->start_clu;
54162306a36Sopenharmony_ci	ei->hint_femp.eidx = EXFAT_HINT_NONE;
54262306a36Sopenharmony_ci	ei->hint_bmap.off = EXFAT_EOF_CLUSTER;
54362306a36Sopenharmony_ci	ei->i_pos = 0;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	inode->i_uid = sbi->options.fs_uid;
54662306a36Sopenharmony_ci	inode->i_gid = sbi->options.fs_gid;
54762306a36Sopenharmony_ci	inode_inc_iversion(inode);
54862306a36Sopenharmony_ci	inode->i_generation = get_random_u32();
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (info->attr & ATTR_SUBDIR) { /* directory */
55162306a36Sopenharmony_ci		inode->i_generation &= ~1;
55262306a36Sopenharmony_ci		inode->i_mode = exfat_make_mode(sbi, info->attr, 0777);
55362306a36Sopenharmony_ci		inode->i_op = &exfat_dir_inode_operations;
55462306a36Sopenharmony_ci		inode->i_fop = &exfat_dir_operations;
55562306a36Sopenharmony_ci		set_nlink(inode, info->num_subdirs);
55662306a36Sopenharmony_ci	} else { /* regular file */
55762306a36Sopenharmony_ci		inode->i_generation |= 1;
55862306a36Sopenharmony_ci		inode->i_mode = exfat_make_mode(sbi, info->attr, 0777);
55962306a36Sopenharmony_ci		inode->i_op = &exfat_file_inode_operations;
56062306a36Sopenharmony_ci		inode->i_fop = &exfat_file_operations;
56162306a36Sopenharmony_ci		inode->i_mapping->a_ops = &exfat_aops;
56262306a36Sopenharmony_ci		inode->i_mapping->nrpages = 0;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	i_size_write(inode, size);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/* ondisk and aligned size should be aligned with block size */
56862306a36Sopenharmony_ci	if (size & (inode->i_sb->s_blocksize - 1)) {
56962306a36Sopenharmony_ci		size |= (inode->i_sb->s_blocksize - 1);
57062306a36Sopenharmony_ci		size++;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	ei->i_size_aligned = size;
57462306a36Sopenharmony_ci	ei->i_size_ondisk = size;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	exfat_save_attr(inode, info->attr);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
57962306a36Sopenharmony_ci	inode->i_mtime = info->mtime;
58062306a36Sopenharmony_ci	inode_set_ctime_to_ts(inode, info->mtime);
58162306a36Sopenharmony_ci	ei->i_crtime = info->crtime;
58262306a36Sopenharmony_ci	inode->i_atime = info->atime;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	return 0;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistruct inode *exfat_build_inode(struct super_block *sb,
58862306a36Sopenharmony_ci		struct exfat_dir_entry *info, loff_t i_pos)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct inode *inode;
59162306a36Sopenharmony_ci	int err;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	inode = exfat_iget(sb, i_pos);
59462306a36Sopenharmony_ci	if (inode)
59562306a36Sopenharmony_ci		goto out;
59662306a36Sopenharmony_ci	inode = new_inode(sb);
59762306a36Sopenharmony_ci	if (!inode) {
59862306a36Sopenharmony_ci		inode = ERR_PTR(-ENOMEM);
59962306a36Sopenharmony_ci		goto out;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci	inode->i_ino = iunique(sb, EXFAT_ROOT_INO);
60262306a36Sopenharmony_ci	inode_set_iversion(inode, 1);
60362306a36Sopenharmony_ci	err = exfat_fill_inode(inode, info);
60462306a36Sopenharmony_ci	if (err) {
60562306a36Sopenharmony_ci		iput(inode);
60662306a36Sopenharmony_ci		inode = ERR_PTR(err);
60762306a36Sopenharmony_ci		goto out;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci	exfat_hash_inode(inode, i_pos);
61062306a36Sopenharmony_ci	insert_inode_hash(inode);
61162306a36Sopenharmony_ciout:
61262306a36Sopenharmony_ci	return inode;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_civoid exfat_evict_inode(struct inode *inode)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	truncate_inode_pages(&inode->i_data, 0);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (!inode->i_nlink) {
62062306a36Sopenharmony_ci		i_size_write(inode, 0);
62162306a36Sopenharmony_ci		mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
62262306a36Sopenharmony_ci		__exfat_truncate(inode);
62362306a36Sopenharmony_ci		mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock);
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	invalidate_inode_buffers(inode);
62762306a36Sopenharmony_ci	clear_inode(inode);
62862306a36Sopenharmony_ci	exfat_cache_inval_inode(inode);
62962306a36Sopenharmony_ci	exfat_unhash_inode(inode);
63062306a36Sopenharmony_ci}
631