162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/hpfs/file.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  file VFS functions
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "hpfs_fn.h"
1162306a36Sopenharmony_ci#include <linux/mpage.h>
1262306a36Sopenharmony_ci#include <linux/iomap.h>
1362306a36Sopenharmony_ci#include <linux/fiemap.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define BLOCKS(size) (((size) + 511) >> 9)
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic int hpfs_file_release(struct inode *inode, struct file *file)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	hpfs_lock(inode->i_sb);
2062306a36Sopenharmony_ci	hpfs_write_if_changed(inode);
2162306a36Sopenharmony_ci	hpfs_unlock(inode->i_sb);
2262306a36Sopenharmony_ci	return 0;
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciint hpfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct inode *inode = file->f_mapping->host;
2862306a36Sopenharmony_ci	int ret;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	ret = file_write_and_wait_range(file, start, end);
3162306a36Sopenharmony_ci	if (ret)
3262306a36Sopenharmony_ci		return ret;
3362306a36Sopenharmony_ci	return sync_blockdev(inode->i_sb->s_bdev);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * generic_file_read often calls bmap with non-existing sector,
3862306a36Sopenharmony_ci * so we must ignore such errors.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic secno hpfs_bmap(struct inode *inode, unsigned file_secno, unsigned *n_secs)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
4462306a36Sopenharmony_ci	unsigned n, disk_secno;
4562306a36Sopenharmony_ci	struct fnode *fnode;
4662306a36Sopenharmony_ci	struct buffer_head *bh;
4762306a36Sopenharmony_ci	if (BLOCKS(hpfs_i(inode)->mmu_private) <= file_secno) return 0;
4862306a36Sopenharmony_ci	n = file_secno - hpfs_inode->i_file_sec;
4962306a36Sopenharmony_ci	if (n < hpfs_inode->i_n_secs) {
5062306a36Sopenharmony_ci		*n_secs = hpfs_inode->i_n_secs - n;
5162306a36Sopenharmony_ci		return hpfs_inode->i_disk_sec + n;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci	if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0;
5462306a36Sopenharmony_ci	disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh);
5562306a36Sopenharmony_ci	if (disk_secno == -1) return 0;
5662306a36Sopenharmony_ci	if (hpfs_chk_sectors(inode->i_sb, disk_secno, 1, "bmap")) return 0;
5762306a36Sopenharmony_ci	n = file_secno - hpfs_inode->i_file_sec;
5862306a36Sopenharmony_ci	if (n < hpfs_inode->i_n_secs) {
5962306a36Sopenharmony_ci		*n_secs = hpfs_inode->i_n_secs - n;
6062306a36Sopenharmony_ci		return hpfs_inode->i_disk_sec + n;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci	*n_secs = 1;
6362306a36Sopenharmony_ci	return disk_secno;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_civoid hpfs_truncate(struct inode *i)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	if (IS_IMMUTABLE(i)) return /*-EPERM*/;
6962306a36Sopenharmony_ci	hpfs_lock_assert(i->i_sb);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	hpfs_i(i)->i_n_secs = 0;
7262306a36Sopenharmony_ci	i->i_blocks = 1 + ((i->i_size + 511) >> 9);
7362306a36Sopenharmony_ci	hpfs_i(i)->mmu_private = i->i_size;
7462306a36Sopenharmony_ci	hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
7562306a36Sopenharmony_ci	hpfs_write_inode(i);
7662306a36Sopenharmony_ci	hpfs_i(i)->i_n_secs = 0;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	int r;
8262306a36Sopenharmony_ci	secno s;
8362306a36Sopenharmony_ci	unsigned n_secs;
8462306a36Sopenharmony_ci	hpfs_lock(inode->i_sb);
8562306a36Sopenharmony_ci	s = hpfs_bmap(inode, iblock, &n_secs);
8662306a36Sopenharmony_ci	if (s) {
8762306a36Sopenharmony_ci		if (bh_result->b_size >> 9 < n_secs)
8862306a36Sopenharmony_ci			n_secs = bh_result->b_size >> 9;
8962306a36Sopenharmony_ci		n_secs = hpfs_search_hotfix_map_for_range(inode->i_sb, s, n_secs);
9062306a36Sopenharmony_ci		if (unlikely(!n_secs)) {
9162306a36Sopenharmony_ci			s = hpfs_search_hotfix_map(inode->i_sb, s);
9262306a36Sopenharmony_ci			n_secs = 1;
9362306a36Sopenharmony_ci		}
9462306a36Sopenharmony_ci		map_bh(bh_result, inode->i_sb, s);
9562306a36Sopenharmony_ci		bh_result->b_size = n_secs << 9;
9662306a36Sopenharmony_ci		goto ret_0;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci	if (!create) goto ret_0;
9962306a36Sopenharmony_ci	if (iblock<<9 != hpfs_i(inode)->mmu_private) {
10062306a36Sopenharmony_ci		BUG();
10162306a36Sopenharmony_ci		r = -EIO;
10262306a36Sopenharmony_ci		goto ret_r;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci	if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) {
10562306a36Sopenharmony_ci		hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1);
10662306a36Sopenharmony_ci		r = -ENOSPC;
10762306a36Sopenharmony_ci		goto ret_r;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci	inode->i_blocks++;
11062306a36Sopenharmony_ci	hpfs_i(inode)->mmu_private += 512;
11162306a36Sopenharmony_ci	set_buffer_new(bh_result);
11262306a36Sopenharmony_ci	map_bh(bh_result, inode->i_sb, hpfs_search_hotfix_map(inode->i_sb, s));
11362306a36Sopenharmony_ci	ret_0:
11462306a36Sopenharmony_ci	r = 0;
11562306a36Sopenharmony_ci	ret_r:
11662306a36Sopenharmony_ci	hpfs_unlock(inode->i_sb);
11762306a36Sopenharmony_ci	return r;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int hpfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
12162306a36Sopenharmony_ci		unsigned flags, struct iomap *iomap, struct iomap *srcmap)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct super_block *sb = inode->i_sb;
12462306a36Sopenharmony_ci	unsigned int blkbits = inode->i_blkbits;
12562306a36Sopenharmony_ci	unsigned int n_secs;
12662306a36Sopenharmony_ci	secno s;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (WARN_ON_ONCE(flags & (IOMAP_WRITE | IOMAP_ZERO)))
12962306a36Sopenharmony_ci		return -EINVAL;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	iomap->bdev = inode->i_sb->s_bdev;
13262306a36Sopenharmony_ci	iomap->offset = offset;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	hpfs_lock(sb);
13562306a36Sopenharmony_ci	s = hpfs_bmap(inode, offset >> blkbits, &n_secs);
13662306a36Sopenharmony_ci	if (s) {
13762306a36Sopenharmony_ci		n_secs = hpfs_search_hotfix_map_for_range(sb, s,
13862306a36Sopenharmony_ci				min_t(loff_t, n_secs, length));
13962306a36Sopenharmony_ci		if (unlikely(!n_secs)) {
14062306a36Sopenharmony_ci			s = hpfs_search_hotfix_map(sb, s);
14162306a36Sopenharmony_ci			n_secs = 1;
14262306a36Sopenharmony_ci		}
14362306a36Sopenharmony_ci		iomap->type = IOMAP_MAPPED;
14462306a36Sopenharmony_ci		iomap->flags = IOMAP_F_MERGED;
14562306a36Sopenharmony_ci		iomap->addr = (u64)s << blkbits;
14662306a36Sopenharmony_ci		iomap->length = (u64)n_secs << blkbits;
14762306a36Sopenharmony_ci	} else {
14862306a36Sopenharmony_ci		iomap->type = IOMAP_HOLE;
14962306a36Sopenharmony_ci		iomap->addr = IOMAP_NULL_ADDR;
15062306a36Sopenharmony_ci		iomap->length = 1 << blkbits;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	hpfs_unlock(sb);
15462306a36Sopenharmony_ci	return 0;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic const struct iomap_ops hpfs_iomap_ops = {
15862306a36Sopenharmony_ci	.iomap_begin		= hpfs_iomap_begin,
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int hpfs_read_folio(struct file *file, struct folio *folio)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	return mpage_read_folio(folio, hpfs_get_block);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic void hpfs_readahead(struct readahead_control *rac)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	mpage_readahead(rac, hpfs_get_block);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic int hpfs_writepages(struct address_space *mapping,
17262306a36Sopenharmony_ci			   struct writeback_control *wbc)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	return mpage_writepages(mapping, wbc, hpfs_get_block);
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void hpfs_write_failed(struct address_space *mapping, loff_t to)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct inode *inode = mapping->host;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	hpfs_lock(inode->i_sb);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (to > inode->i_size) {
18462306a36Sopenharmony_ci		truncate_pagecache(inode, inode->i_size);
18562306a36Sopenharmony_ci		hpfs_truncate(inode);
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	hpfs_unlock(inode->i_sb);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int hpfs_write_begin(struct file *file, struct address_space *mapping,
19262306a36Sopenharmony_ci			loff_t pos, unsigned len,
19362306a36Sopenharmony_ci			struct page **pagep, void **fsdata)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	int ret;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	*pagep = NULL;
19862306a36Sopenharmony_ci	ret = cont_write_begin(file, mapping, pos, len, pagep, fsdata,
19962306a36Sopenharmony_ci				hpfs_get_block,
20062306a36Sopenharmony_ci				&hpfs_i(mapping->host)->mmu_private);
20162306a36Sopenharmony_ci	if (unlikely(ret))
20262306a36Sopenharmony_ci		hpfs_write_failed(mapping, pos + len);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return ret;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int hpfs_write_end(struct file *file, struct address_space *mapping,
20862306a36Sopenharmony_ci			loff_t pos, unsigned len, unsigned copied,
20962306a36Sopenharmony_ci			struct page *pagep, void *fsdata)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	struct inode *inode = mapping->host;
21262306a36Sopenharmony_ci	int err;
21362306a36Sopenharmony_ci	err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
21462306a36Sopenharmony_ci	if (err < len)
21562306a36Sopenharmony_ci		hpfs_write_failed(mapping, pos + len);
21662306a36Sopenharmony_ci	if (!(err < 0)) {
21762306a36Sopenharmony_ci		/* make sure we write it on close, if not earlier */
21862306a36Sopenharmony_ci		hpfs_lock(inode->i_sb);
21962306a36Sopenharmony_ci		hpfs_i(inode)->i_dirty = 1;
22062306a36Sopenharmony_ci		hpfs_unlock(inode->i_sb);
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci	return err;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	return generic_block_bmap(mapping, block, hpfs_get_block);
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic int hpfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	int ret;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	inode_lock(inode);
23562306a36Sopenharmony_ci	len = min_t(u64, len, i_size_read(inode));
23662306a36Sopenharmony_ci	ret = iomap_fiemap(inode, fieinfo, start, len, &hpfs_iomap_ops);
23762306a36Sopenharmony_ci	inode_unlock(inode);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return ret;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ciconst struct address_space_operations hpfs_aops = {
24362306a36Sopenharmony_ci	.dirty_folio	= block_dirty_folio,
24462306a36Sopenharmony_ci	.invalidate_folio = block_invalidate_folio,
24562306a36Sopenharmony_ci	.read_folio = hpfs_read_folio,
24662306a36Sopenharmony_ci	.readahead = hpfs_readahead,
24762306a36Sopenharmony_ci	.writepages = hpfs_writepages,
24862306a36Sopenharmony_ci	.write_begin = hpfs_write_begin,
24962306a36Sopenharmony_ci	.write_end = hpfs_write_end,
25062306a36Sopenharmony_ci	.bmap = _hpfs_bmap,
25162306a36Sopenharmony_ci	.migrate_folio = buffer_migrate_folio,
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ciconst struct file_operations hpfs_file_ops =
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	.llseek		= generic_file_llseek,
25762306a36Sopenharmony_ci	.read_iter	= generic_file_read_iter,
25862306a36Sopenharmony_ci	.write_iter	= generic_file_write_iter,
25962306a36Sopenharmony_ci	.mmap		= generic_file_mmap,
26062306a36Sopenharmony_ci	.release	= hpfs_file_release,
26162306a36Sopenharmony_ci	.fsync		= hpfs_file_fsync,
26262306a36Sopenharmony_ci	.splice_read	= filemap_splice_read,
26362306a36Sopenharmony_ci	.unlocked_ioctl	= hpfs_ioctl,
26462306a36Sopenharmony_ci	.compat_ioctl	= compat_ptr_ioctl,
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ciconst struct inode_operations hpfs_file_iops =
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	.setattr	= hpfs_setattr,
27062306a36Sopenharmony_ci	.fiemap		= hpfs_fiemap,
27162306a36Sopenharmony_ci};
272