18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/fs/affs/file.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  (c) 1996  Hans-Joachim Widmaier - Rewritten
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  (C) 1991  Linus Torvalds - minix filesystem
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *  affs regular file handling primitives
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/uio.h>
178c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
188c2ecf20Sopenharmony_ci#include "affs.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic int
238c2ecf20Sopenharmony_ciaffs_file_open(struct inode *inode, struct file *filp)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	pr_debug("open(%lu,%d)\n",
268c2ecf20Sopenharmony_ci		 inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
278c2ecf20Sopenharmony_ci	atomic_inc(&AFFS_I(inode)->i_opencnt);
288c2ecf20Sopenharmony_ci	return 0;
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic int
328c2ecf20Sopenharmony_ciaffs_file_release(struct inode *inode, struct file *filp)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	pr_debug("release(%lu, %d)\n",
358c2ecf20Sopenharmony_ci		 inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) {
388c2ecf20Sopenharmony_ci		inode_lock(inode);
398c2ecf20Sopenharmony_ci		if (inode->i_size != AFFS_I(inode)->mmu_private)
408c2ecf20Sopenharmony_ci			affs_truncate(inode);
418c2ecf20Sopenharmony_ci		affs_free_prealloc(inode);
428c2ecf20Sopenharmony_ci		inode_unlock(inode);
438c2ecf20Sopenharmony_ci	}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	return 0;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int
498c2ecf20Sopenharmony_ciaffs_grow_extcache(struct inode *inode, u32 lc_idx)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct super_block	*sb = inode->i_sb;
528c2ecf20Sopenharmony_ci	struct buffer_head	*bh;
538c2ecf20Sopenharmony_ci	u32 lc_max;
548c2ecf20Sopenharmony_ci	int i, j, key;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (!AFFS_I(inode)->i_lc) {
578c2ecf20Sopenharmony_ci		char *ptr = (char *)get_zeroed_page(GFP_NOFS);
588c2ecf20Sopenharmony_ci		if (!ptr)
598c2ecf20Sopenharmony_ci			return -ENOMEM;
608c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_lc = (u32 *)ptr;
618c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	lc_max = AFFS_LC_SIZE << AFFS_I(inode)->i_lc_shift;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (AFFS_I(inode)->i_extcnt > lc_max) {
678c2ecf20Sopenharmony_ci		u32 lc_shift, lc_mask, tmp, off;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		/* need to recalculate linear cache, start from old size */
708c2ecf20Sopenharmony_ci		lc_shift = AFFS_I(inode)->i_lc_shift;
718c2ecf20Sopenharmony_ci		tmp = (AFFS_I(inode)->i_extcnt / AFFS_LC_SIZE) >> lc_shift;
728c2ecf20Sopenharmony_ci		for (; tmp; tmp >>= 1)
738c2ecf20Sopenharmony_ci			lc_shift++;
748c2ecf20Sopenharmony_ci		lc_mask = (1 << lc_shift) - 1;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci		/* fix idx and old size to new shift */
778c2ecf20Sopenharmony_ci		lc_idx >>= (lc_shift - AFFS_I(inode)->i_lc_shift);
788c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_lc_size >>= (lc_shift - AFFS_I(inode)->i_lc_shift);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		/* first shrink old cache to make more space */
818c2ecf20Sopenharmony_ci		off = 1 << (lc_shift - AFFS_I(inode)->i_lc_shift);
828c2ecf20Sopenharmony_ci		for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off)
838c2ecf20Sopenharmony_ci			AFFS_I(inode)->i_ac[i] = AFFS_I(inode)->i_ac[j];
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_lc_shift = lc_shift;
868c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_lc_mask = lc_mask;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* fill cache to the needed index */
908c2ecf20Sopenharmony_ci	i = AFFS_I(inode)->i_lc_size;
918c2ecf20Sopenharmony_ci	AFFS_I(inode)->i_lc_size = lc_idx + 1;
928c2ecf20Sopenharmony_ci	for (; i <= lc_idx; i++) {
938c2ecf20Sopenharmony_ci		if (!i) {
948c2ecf20Sopenharmony_ci			AFFS_I(inode)->i_lc[0] = inode->i_ino;
958c2ecf20Sopenharmony_ci			continue;
968c2ecf20Sopenharmony_ci		}
978c2ecf20Sopenharmony_ci		key = AFFS_I(inode)->i_lc[i - 1];
988c2ecf20Sopenharmony_ci		j = AFFS_I(inode)->i_lc_mask + 1;
998c2ecf20Sopenharmony_ci		// unlock cache
1008c2ecf20Sopenharmony_ci		for (; j > 0; j--) {
1018c2ecf20Sopenharmony_ci			bh = affs_bread(sb, key);
1028c2ecf20Sopenharmony_ci			if (!bh)
1038c2ecf20Sopenharmony_ci				goto err;
1048c2ecf20Sopenharmony_ci			key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
1058c2ecf20Sopenharmony_ci			affs_brelse(bh);
1068c2ecf20Sopenharmony_ci		}
1078c2ecf20Sopenharmony_ci		// lock cache
1088c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_lc[i] = key;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cierr:
1148c2ecf20Sopenharmony_ci	// lock cache
1158c2ecf20Sopenharmony_ci	return -EIO;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic struct buffer_head *
1198c2ecf20Sopenharmony_ciaffs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
1228c2ecf20Sopenharmony_ci	struct buffer_head *new_bh;
1238c2ecf20Sopenharmony_ci	u32 blocknr, tmp;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	blocknr = affs_alloc_block(inode, bh->b_blocknr);
1268c2ecf20Sopenharmony_ci	if (!blocknr)
1278c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOSPC);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	new_bh = affs_getzeroblk(sb, blocknr);
1308c2ecf20Sopenharmony_ci	if (!new_bh) {
1318c2ecf20Sopenharmony_ci		affs_free_block(sb, blocknr);
1328c2ecf20Sopenharmony_ci		return ERR_PTR(-EIO);
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST);
1368c2ecf20Sopenharmony_ci	AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr);
1378c2ecf20Sopenharmony_ci	AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE);
1388c2ecf20Sopenharmony_ci	AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino);
1398c2ecf20Sopenharmony_ci	affs_fix_checksum(sb, new_bh);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	mark_buffer_dirty_inode(new_bh, inode);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
1448c2ecf20Sopenharmony_ci	if (tmp)
1458c2ecf20Sopenharmony_ci		affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp);
1468c2ecf20Sopenharmony_ci	AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr);
1478c2ecf20Sopenharmony_ci	affs_adjust_checksum(bh, blocknr - tmp);
1488c2ecf20Sopenharmony_ci	mark_buffer_dirty_inode(bh, inode);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	AFFS_I(inode)->i_extcnt++;
1518c2ecf20Sopenharmony_ci	mark_inode_dirty(inode);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return new_bh;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic inline struct buffer_head *
1578c2ecf20Sopenharmony_ciaffs_get_extblock(struct inode *inode, u32 ext)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	/* inline the simplest case: same extended block as last time */
1608c2ecf20Sopenharmony_ci	struct buffer_head *bh = AFFS_I(inode)->i_ext_bh;
1618c2ecf20Sopenharmony_ci	if (ext == AFFS_I(inode)->i_ext_last)
1628c2ecf20Sopenharmony_ci		get_bh(bh);
1638c2ecf20Sopenharmony_ci	else
1648c2ecf20Sopenharmony_ci		/* we have to do more (not inlined) */
1658c2ecf20Sopenharmony_ci		bh = affs_get_extblock_slow(inode, ext);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	return bh;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic struct buffer_head *
1718c2ecf20Sopenharmony_ciaffs_get_extblock_slow(struct inode *inode, u32 ext)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
1748c2ecf20Sopenharmony_ci	struct buffer_head *bh;
1758c2ecf20Sopenharmony_ci	u32 ext_key;
1768c2ecf20Sopenharmony_ci	u32 lc_idx, lc_off, ac_idx;
1778c2ecf20Sopenharmony_ci	u32 tmp, idx;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (ext == AFFS_I(inode)->i_ext_last + 1) {
1808c2ecf20Sopenharmony_ci		/* read the next extended block from the current one */
1818c2ecf20Sopenharmony_ci		bh = AFFS_I(inode)->i_ext_bh;
1828c2ecf20Sopenharmony_ci		ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
1838c2ecf20Sopenharmony_ci		if (ext < AFFS_I(inode)->i_extcnt)
1848c2ecf20Sopenharmony_ci			goto read_ext;
1858c2ecf20Sopenharmony_ci		BUG_ON(ext > AFFS_I(inode)->i_extcnt);
1868c2ecf20Sopenharmony_ci		bh = affs_alloc_extblock(inode, bh, ext);
1878c2ecf20Sopenharmony_ci		if (IS_ERR(bh))
1888c2ecf20Sopenharmony_ci			return bh;
1898c2ecf20Sopenharmony_ci		goto store_ext;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (ext == 0) {
1938c2ecf20Sopenharmony_ci		/* we seek back to the file header block */
1948c2ecf20Sopenharmony_ci		ext_key = inode->i_ino;
1958c2ecf20Sopenharmony_ci		goto read_ext;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (ext >= AFFS_I(inode)->i_extcnt) {
1998c2ecf20Sopenharmony_ci		struct buffer_head *prev_bh;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		/* allocate a new extended block */
2028c2ecf20Sopenharmony_ci		BUG_ON(ext > AFFS_I(inode)->i_extcnt);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		/* get previous extended block */
2058c2ecf20Sopenharmony_ci		prev_bh = affs_get_extblock(inode, ext - 1);
2068c2ecf20Sopenharmony_ci		if (IS_ERR(prev_bh))
2078c2ecf20Sopenharmony_ci			return prev_bh;
2088c2ecf20Sopenharmony_ci		bh = affs_alloc_extblock(inode, prev_bh, ext);
2098c2ecf20Sopenharmony_ci		affs_brelse(prev_bh);
2108c2ecf20Sopenharmony_ci		if (IS_ERR(bh))
2118c2ecf20Sopenharmony_ci			return bh;
2128c2ecf20Sopenharmony_ci		goto store_ext;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ciagain:
2168c2ecf20Sopenharmony_ci	/* check if there is an extended cache and whether it's large enough */
2178c2ecf20Sopenharmony_ci	lc_idx = ext >> AFFS_I(inode)->i_lc_shift;
2188c2ecf20Sopenharmony_ci	lc_off = ext & AFFS_I(inode)->i_lc_mask;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (lc_idx >= AFFS_I(inode)->i_lc_size) {
2218c2ecf20Sopenharmony_ci		int err;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		err = affs_grow_extcache(inode, lc_idx);
2248c2ecf20Sopenharmony_ci		if (err)
2258c2ecf20Sopenharmony_ci			return ERR_PTR(err);
2268c2ecf20Sopenharmony_ci		goto again;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* every n'th key we find in the linear cache */
2308c2ecf20Sopenharmony_ci	if (!lc_off) {
2318c2ecf20Sopenharmony_ci		ext_key = AFFS_I(inode)->i_lc[lc_idx];
2328c2ecf20Sopenharmony_ci		goto read_ext;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	/* maybe it's still in the associative cache */
2368c2ecf20Sopenharmony_ci	ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK;
2378c2ecf20Sopenharmony_ci	if (AFFS_I(inode)->i_ac[ac_idx].ext == ext) {
2388c2ecf20Sopenharmony_ci		ext_key = AFFS_I(inode)->i_ac[ac_idx].key;
2398c2ecf20Sopenharmony_ci		goto read_ext;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* try to find one of the previous extended blocks */
2438c2ecf20Sopenharmony_ci	tmp = ext;
2448c2ecf20Sopenharmony_ci	idx = ac_idx;
2458c2ecf20Sopenharmony_ci	while (--tmp, --lc_off > 0) {
2468c2ecf20Sopenharmony_ci		idx = (idx - 1) & AFFS_AC_MASK;
2478c2ecf20Sopenharmony_ci		if (AFFS_I(inode)->i_ac[idx].ext == tmp) {
2488c2ecf20Sopenharmony_ci			ext_key = AFFS_I(inode)->i_ac[idx].key;
2498c2ecf20Sopenharmony_ci			goto find_ext;
2508c2ecf20Sopenharmony_ci		}
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* fall back to the linear cache */
2548c2ecf20Sopenharmony_ci	ext_key = AFFS_I(inode)->i_lc[lc_idx];
2558c2ecf20Sopenharmony_cifind_ext:
2568c2ecf20Sopenharmony_ci	/* read all extended blocks until we find the one we need */
2578c2ecf20Sopenharmony_ci	//unlock cache
2588c2ecf20Sopenharmony_ci	do {
2598c2ecf20Sopenharmony_ci		bh = affs_bread(sb, ext_key);
2608c2ecf20Sopenharmony_ci		if (!bh)
2618c2ecf20Sopenharmony_ci			goto err_bread;
2628c2ecf20Sopenharmony_ci		ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
2638c2ecf20Sopenharmony_ci		affs_brelse(bh);
2648c2ecf20Sopenharmony_ci		tmp++;
2658c2ecf20Sopenharmony_ci	} while (tmp < ext);
2668c2ecf20Sopenharmony_ci	//lock cache
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/* store it in the associative cache */
2698c2ecf20Sopenharmony_ci	// recalculate ac_idx?
2708c2ecf20Sopenharmony_ci	AFFS_I(inode)->i_ac[ac_idx].ext = ext;
2718c2ecf20Sopenharmony_ci	AFFS_I(inode)->i_ac[ac_idx].key = ext_key;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciread_ext:
2748c2ecf20Sopenharmony_ci	/* finally read the right extended block */
2758c2ecf20Sopenharmony_ci	//unlock cache
2768c2ecf20Sopenharmony_ci	bh = affs_bread(sb, ext_key);
2778c2ecf20Sopenharmony_ci	if (!bh)
2788c2ecf20Sopenharmony_ci		goto err_bread;
2798c2ecf20Sopenharmony_ci	//lock cache
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistore_ext:
2828c2ecf20Sopenharmony_ci	/* release old cached extended block and store the new one */
2838c2ecf20Sopenharmony_ci	affs_brelse(AFFS_I(inode)->i_ext_bh);
2848c2ecf20Sopenharmony_ci	AFFS_I(inode)->i_ext_last = ext;
2858c2ecf20Sopenharmony_ci	AFFS_I(inode)->i_ext_bh = bh;
2868c2ecf20Sopenharmony_ci	get_bh(bh);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return bh;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cierr_bread:
2918c2ecf20Sopenharmony_ci	affs_brelse(bh);
2928c2ecf20Sopenharmony_ci	return ERR_PTR(-EIO);
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int
2968c2ecf20Sopenharmony_ciaffs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct super_block	*sb = inode->i_sb;
2998c2ecf20Sopenharmony_ci	struct buffer_head	*ext_bh;
3008c2ecf20Sopenharmony_ci	u32			 ext;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	pr_debug("%s(%lu, %llu)\n", __func__, inode->i_ino,
3038c2ecf20Sopenharmony_ci		 (unsigned long long)block);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	BUG_ON(block > (sector_t)0x7fffffffUL);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (block >= AFFS_I(inode)->i_blkcnt) {
3088c2ecf20Sopenharmony_ci		if (block > AFFS_I(inode)->i_blkcnt || !create)
3098c2ecf20Sopenharmony_ci			goto err_big;
3108c2ecf20Sopenharmony_ci	} else
3118c2ecf20Sopenharmony_ci		create = 0;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	//lock cache
3148c2ecf20Sopenharmony_ci	affs_lock_ext(inode);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	ext = (u32)block / AFFS_SB(sb)->s_hashsize;
3178c2ecf20Sopenharmony_ci	block -= ext * AFFS_SB(sb)->s_hashsize;
3188c2ecf20Sopenharmony_ci	ext_bh = affs_get_extblock(inode, ext);
3198c2ecf20Sopenharmony_ci	if (IS_ERR(ext_bh))
3208c2ecf20Sopenharmony_ci		goto err_ext;
3218c2ecf20Sopenharmony_ci	map_bh(bh_result, sb, (sector_t)be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block)));
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (create) {
3248c2ecf20Sopenharmony_ci		u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);
3258c2ecf20Sopenharmony_ci		if (!blocknr)
3268c2ecf20Sopenharmony_ci			goto err_alloc;
3278c2ecf20Sopenharmony_ci		set_buffer_new(bh_result);
3288c2ecf20Sopenharmony_ci		AFFS_I(inode)->mmu_private += AFFS_SB(sb)->s_data_blksize;
3298c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_blkcnt++;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci		/* store new block */
3328c2ecf20Sopenharmony_ci		if (bh_result->b_blocknr)
3338c2ecf20Sopenharmony_ci			affs_warning(sb, "get_block",
3348c2ecf20Sopenharmony_ci				     "block already set (%llx)",
3358c2ecf20Sopenharmony_ci				     (unsigned long long)bh_result->b_blocknr);
3368c2ecf20Sopenharmony_ci		AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr);
3378c2ecf20Sopenharmony_ci		AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1);
3388c2ecf20Sopenharmony_ci		affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1);
3398c2ecf20Sopenharmony_ci		bh_result->b_blocknr = blocknr;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		if (!block) {
3428c2ecf20Sopenharmony_ci			/* insert first block into header block */
3438c2ecf20Sopenharmony_ci			u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data);
3448c2ecf20Sopenharmony_ci			if (tmp)
3458c2ecf20Sopenharmony_ci				affs_warning(sb, "get_block", "first block already set (%d)", tmp);
3468c2ecf20Sopenharmony_ci			AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr);
3478c2ecf20Sopenharmony_ci			affs_adjust_checksum(ext_bh, blocknr - tmp);
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	affs_brelse(ext_bh);
3528c2ecf20Sopenharmony_ci	//unlock cache
3538c2ecf20Sopenharmony_ci	affs_unlock_ext(inode);
3548c2ecf20Sopenharmony_ci	return 0;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cierr_big:
3578c2ecf20Sopenharmony_ci	affs_error(inode->i_sb, "get_block", "strange block request %llu",
3588c2ecf20Sopenharmony_ci		   (unsigned long long)block);
3598c2ecf20Sopenharmony_ci	return -EIO;
3608c2ecf20Sopenharmony_cierr_ext:
3618c2ecf20Sopenharmony_ci	// unlock cache
3628c2ecf20Sopenharmony_ci	affs_unlock_ext(inode);
3638c2ecf20Sopenharmony_ci	return PTR_ERR(ext_bh);
3648c2ecf20Sopenharmony_cierr_alloc:
3658c2ecf20Sopenharmony_ci	brelse(ext_bh);
3668c2ecf20Sopenharmony_ci	clear_buffer_mapped(bh_result);
3678c2ecf20Sopenharmony_ci	bh_result->b_bdev = NULL;
3688c2ecf20Sopenharmony_ci	// unlock cache
3698c2ecf20Sopenharmony_ci	affs_unlock_ext(inode);
3708c2ecf20Sopenharmony_ci	return -ENOSPC;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic int affs_writepage(struct page *page, struct writeback_control *wbc)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	return block_write_full_page(page, affs_get_block, wbc);
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int affs_readpage(struct file *file, struct page *page)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	return block_read_full_page(page, affs_get_block);
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic void affs_write_failed(struct address_space *mapping, loff_t to)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct inode *inode = mapping->host;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if (to > inode->i_size) {
3888c2ecf20Sopenharmony_ci		truncate_pagecache(inode, inode->i_size);
3898c2ecf20Sopenharmony_ci		affs_truncate(inode);
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic ssize_t
3948c2ecf20Sopenharmony_ciaffs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct file *file = iocb->ki_filp;
3978c2ecf20Sopenharmony_ci	struct address_space *mapping = file->f_mapping;
3988c2ecf20Sopenharmony_ci	struct inode *inode = mapping->host;
3998c2ecf20Sopenharmony_ci	size_t count = iov_iter_count(iter);
4008c2ecf20Sopenharmony_ci	loff_t offset = iocb->ki_pos;
4018c2ecf20Sopenharmony_ci	ssize_t ret;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (iov_iter_rw(iter) == WRITE) {
4048c2ecf20Sopenharmony_ci		loff_t size = offset + count;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci		if (AFFS_I(inode)->mmu_private < size)
4078c2ecf20Sopenharmony_ci			return 0;
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	ret = blockdev_direct_IO(iocb, inode, iter, affs_get_block);
4118c2ecf20Sopenharmony_ci	if (ret < 0 && iov_iter_rw(iter) == WRITE)
4128c2ecf20Sopenharmony_ci		affs_write_failed(mapping, offset + count);
4138c2ecf20Sopenharmony_ci	return ret;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic int affs_write_begin(struct file *file, struct address_space *mapping,
4178c2ecf20Sopenharmony_ci			loff_t pos, unsigned len, unsigned flags,
4188c2ecf20Sopenharmony_ci			struct page **pagep, void **fsdata)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	int ret;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	*pagep = NULL;
4238c2ecf20Sopenharmony_ci	ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
4248c2ecf20Sopenharmony_ci				affs_get_block,
4258c2ecf20Sopenharmony_ci				&AFFS_I(mapping->host)->mmu_private);
4268c2ecf20Sopenharmony_ci	if (unlikely(ret))
4278c2ecf20Sopenharmony_ci		affs_write_failed(mapping, pos + len);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	return ret;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int affs_write_end(struct file *file, struct address_space *mapping,
4338c2ecf20Sopenharmony_ci			  loff_t pos, unsigned int len, unsigned int copied,
4348c2ecf20Sopenharmony_ci			  struct page *page, void *fsdata)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	struct inode *inode = mapping->host;
4378c2ecf20Sopenharmony_ci	int ret;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	/* Clear Archived bit on file writes, as AmigaOS would do */
4428c2ecf20Sopenharmony_ci	if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
4438c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
4448c2ecf20Sopenharmony_ci		mark_inode_dirty(inode);
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	return ret;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic sector_t _affs_bmap(struct address_space *mapping, sector_t block)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	return generic_block_bmap(mapping,block,affs_get_block);
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ciconst struct address_space_operations affs_aops = {
4568c2ecf20Sopenharmony_ci	.readpage = affs_readpage,
4578c2ecf20Sopenharmony_ci	.writepage = affs_writepage,
4588c2ecf20Sopenharmony_ci	.write_begin = affs_write_begin,
4598c2ecf20Sopenharmony_ci	.write_end = affs_write_end,
4608c2ecf20Sopenharmony_ci	.direct_IO = affs_direct_IO,
4618c2ecf20Sopenharmony_ci	.bmap = _affs_bmap
4628c2ecf20Sopenharmony_ci};
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic inline struct buffer_head *
4658c2ecf20Sopenharmony_ciaffs_bread_ino(struct inode *inode, int block, int create)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	struct buffer_head *bh, tmp_bh;
4688c2ecf20Sopenharmony_ci	int err;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	tmp_bh.b_state = 0;
4718c2ecf20Sopenharmony_ci	err = affs_get_block(inode, block, &tmp_bh, create);
4728c2ecf20Sopenharmony_ci	if (!err) {
4738c2ecf20Sopenharmony_ci		bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr);
4748c2ecf20Sopenharmony_ci		if (bh) {
4758c2ecf20Sopenharmony_ci			bh->b_state |= tmp_bh.b_state;
4768c2ecf20Sopenharmony_ci			return bh;
4778c2ecf20Sopenharmony_ci		}
4788c2ecf20Sopenharmony_ci		err = -EIO;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci	return ERR_PTR(err);
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic inline struct buffer_head *
4848c2ecf20Sopenharmony_ciaffs_getzeroblk_ino(struct inode *inode, int block)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	struct buffer_head *bh, tmp_bh;
4878c2ecf20Sopenharmony_ci	int err;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	tmp_bh.b_state = 0;
4908c2ecf20Sopenharmony_ci	err = affs_get_block(inode, block, &tmp_bh, 1);
4918c2ecf20Sopenharmony_ci	if (!err) {
4928c2ecf20Sopenharmony_ci		bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr);
4938c2ecf20Sopenharmony_ci		if (bh) {
4948c2ecf20Sopenharmony_ci			bh->b_state |= tmp_bh.b_state;
4958c2ecf20Sopenharmony_ci			return bh;
4968c2ecf20Sopenharmony_ci		}
4978c2ecf20Sopenharmony_ci		err = -EIO;
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci	return ERR_PTR(err);
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic inline struct buffer_head *
5038c2ecf20Sopenharmony_ciaffs_getemptyblk_ino(struct inode *inode, int block)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct buffer_head *bh, tmp_bh;
5068c2ecf20Sopenharmony_ci	int err;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	tmp_bh.b_state = 0;
5098c2ecf20Sopenharmony_ci	err = affs_get_block(inode, block, &tmp_bh, 1);
5108c2ecf20Sopenharmony_ci	if (!err) {
5118c2ecf20Sopenharmony_ci		bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr);
5128c2ecf20Sopenharmony_ci		if (bh) {
5138c2ecf20Sopenharmony_ci			bh->b_state |= tmp_bh.b_state;
5148c2ecf20Sopenharmony_ci			return bh;
5158c2ecf20Sopenharmony_ci		}
5168c2ecf20Sopenharmony_ci		err = -EIO;
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci	return ERR_PTR(err);
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic int
5228c2ecf20Sopenharmony_ciaffs_do_readpage_ofs(struct page *page, unsigned to, int create)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct inode *inode = page->mapping->host;
5258c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
5268c2ecf20Sopenharmony_ci	struct buffer_head *bh;
5278c2ecf20Sopenharmony_ci	char *data;
5288c2ecf20Sopenharmony_ci	unsigned pos = 0;
5298c2ecf20Sopenharmony_ci	u32 bidx, boff, bsize;
5308c2ecf20Sopenharmony_ci	u32 tmp;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	pr_debug("%s(%lu, %ld, 0, %d)\n", __func__, inode->i_ino,
5338c2ecf20Sopenharmony_ci		 page->index, to);
5348c2ecf20Sopenharmony_ci	BUG_ON(to > PAGE_SIZE);
5358c2ecf20Sopenharmony_ci	bsize = AFFS_SB(sb)->s_data_blksize;
5368c2ecf20Sopenharmony_ci	tmp = page->index << PAGE_SHIFT;
5378c2ecf20Sopenharmony_ci	bidx = tmp / bsize;
5388c2ecf20Sopenharmony_ci	boff = tmp % bsize;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	while (pos < to) {
5418c2ecf20Sopenharmony_ci		bh = affs_bread_ino(inode, bidx, create);
5428c2ecf20Sopenharmony_ci		if (IS_ERR(bh))
5438c2ecf20Sopenharmony_ci			return PTR_ERR(bh);
5448c2ecf20Sopenharmony_ci		tmp = min(bsize - boff, to - pos);
5458c2ecf20Sopenharmony_ci		BUG_ON(pos + tmp > to || tmp > bsize);
5468c2ecf20Sopenharmony_ci		data = kmap_atomic(page);
5478c2ecf20Sopenharmony_ci		memcpy(data + pos, AFFS_DATA(bh) + boff, tmp);
5488c2ecf20Sopenharmony_ci		kunmap_atomic(data);
5498c2ecf20Sopenharmony_ci		affs_brelse(bh);
5508c2ecf20Sopenharmony_ci		bidx++;
5518c2ecf20Sopenharmony_ci		pos += tmp;
5528c2ecf20Sopenharmony_ci		boff = 0;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci	flush_dcache_page(page);
5558c2ecf20Sopenharmony_ci	return 0;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic int
5598c2ecf20Sopenharmony_ciaffs_extent_file_ofs(struct inode *inode, u32 newsize)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
5628c2ecf20Sopenharmony_ci	struct buffer_head *bh, *prev_bh;
5638c2ecf20Sopenharmony_ci	u32 bidx, boff;
5648c2ecf20Sopenharmony_ci	u32 size, bsize;
5658c2ecf20Sopenharmony_ci	u32 tmp;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	pr_debug("%s(%lu, %d)\n", __func__, inode->i_ino, newsize);
5688c2ecf20Sopenharmony_ci	bsize = AFFS_SB(sb)->s_data_blksize;
5698c2ecf20Sopenharmony_ci	bh = NULL;
5708c2ecf20Sopenharmony_ci	size = AFFS_I(inode)->mmu_private;
5718c2ecf20Sopenharmony_ci	bidx = size / bsize;
5728c2ecf20Sopenharmony_ci	boff = size % bsize;
5738c2ecf20Sopenharmony_ci	if (boff) {
5748c2ecf20Sopenharmony_ci		bh = affs_bread_ino(inode, bidx, 0);
5758c2ecf20Sopenharmony_ci		if (IS_ERR(bh))
5768c2ecf20Sopenharmony_ci			return PTR_ERR(bh);
5778c2ecf20Sopenharmony_ci		tmp = min(bsize - boff, newsize - size);
5788c2ecf20Sopenharmony_ci		BUG_ON(boff + tmp > bsize || tmp > bsize);
5798c2ecf20Sopenharmony_ci		memset(AFFS_DATA(bh) + boff, 0, tmp);
5808c2ecf20Sopenharmony_ci		be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp);
5818c2ecf20Sopenharmony_ci		affs_fix_checksum(sb, bh);
5828c2ecf20Sopenharmony_ci		mark_buffer_dirty_inode(bh, inode);
5838c2ecf20Sopenharmony_ci		size += tmp;
5848c2ecf20Sopenharmony_ci		bidx++;
5858c2ecf20Sopenharmony_ci	} else if (bidx) {
5868c2ecf20Sopenharmony_ci		bh = affs_bread_ino(inode, bidx - 1, 0);
5878c2ecf20Sopenharmony_ci		if (IS_ERR(bh))
5888c2ecf20Sopenharmony_ci			return PTR_ERR(bh);
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	while (size < newsize) {
5928c2ecf20Sopenharmony_ci		prev_bh = bh;
5938c2ecf20Sopenharmony_ci		bh = affs_getzeroblk_ino(inode, bidx);
5948c2ecf20Sopenharmony_ci		if (IS_ERR(bh))
5958c2ecf20Sopenharmony_ci			goto out;
5968c2ecf20Sopenharmony_ci		tmp = min(bsize, newsize - size);
5978c2ecf20Sopenharmony_ci		BUG_ON(tmp > bsize);
5988c2ecf20Sopenharmony_ci		AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
5998c2ecf20Sopenharmony_ci		AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
6008c2ecf20Sopenharmony_ci		AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
6018c2ecf20Sopenharmony_ci		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
6028c2ecf20Sopenharmony_ci		affs_fix_checksum(sb, bh);
6038c2ecf20Sopenharmony_ci		bh->b_state &= ~(1UL << BH_New);
6048c2ecf20Sopenharmony_ci		mark_buffer_dirty_inode(bh, inode);
6058c2ecf20Sopenharmony_ci		if (prev_bh) {
6068c2ecf20Sopenharmony_ci			u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci			if (tmp_next)
6098c2ecf20Sopenharmony_ci				affs_warning(sb, "extent_file_ofs",
6108c2ecf20Sopenharmony_ci					     "next block already set for %d (%d)",
6118c2ecf20Sopenharmony_ci					     bidx, tmp_next);
6128c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
6138c2ecf20Sopenharmony_ci			affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
6148c2ecf20Sopenharmony_ci			mark_buffer_dirty_inode(prev_bh, inode);
6158c2ecf20Sopenharmony_ci			affs_brelse(prev_bh);
6168c2ecf20Sopenharmony_ci		}
6178c2ecf20Sopenharmony_ci		size += bsize;
6188c2ecf20Sopenharmony_ci		bidx++;
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci	affs_brelse(bh);
6218c2ecf20Sopenharmony_ci	inode->i_size = AFFS_I(inode)->mmu_private = newsize;
6228c2ecf20Sopenharmony_ci	return 0;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ciout:
6258c2ecf20Sopenharmony_ci	inode->i_size = AFFS_I(inode)->mmu_private = newsize;
6268c2ecf20Sopenharmony_ci	return PTR_ERR(bh);
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic int
6308c2ecf20Sopenharmony_ciaffs_readpage_ofs(struct file *file, struct page *page)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	struct inode *inode = page->mapping->host;
6338c2ecf20Sopenharmony_ci	u32 to;
6348c2ecf20Sopenharmony_ci	int err;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	pr_debug("%s(%lu, %ld)\n", __func__, inode->i_ino, page->index);
6378c2ecf20Sopenharmony_ci	to = PAGE_SIZE;
6388c2ecf20Sopenharmony_ci	if (((page->index + 1) << PAGE_SHIFT) > inode->i_size) {
6398c2ecf20Sopenharmony_ci		to = inode->i_size & ~PAGE_MASK;
6408c2ecf20Sopenharmony_ci		memset(page_address(page) + to, 0, PAGE_SIZE - to);
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	err = affs_do_readpage_ofs(page, to, 0);
6448c2ecf20Sopenharmony_ci	if (!err)
6458c2ecf20Sopenharmony_ci		SetPageUptodate(page);
6468c2ecf20Sopenharmony_ci	unlock_page(page);
6478c2ecf20Sopenharmony_ci	return err;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cistatic int affs_write_begin_ofs(struct file *file, struct address_space *mapping,
6518c2ecf20Sopenharmony_ci				loff_t pos, unsigned len, unsigned flags,
6528c2ecf20Sopenharmony_ci				struct page **pagep, void **fsdata)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	struct inode *inode = mapping->host;
6558c2ecf20Sopenharmony_ci	struct page *page;
6568c2ecf20Sopenharmony_ci	pgoff_t index;
6578c2ecf20Sopenharmony_ci	int err = 0;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos,
6608c2ecf20Sopenharmony_ci		 pos + len);
6618c2ecf20Sopenharmony_ci	if (pos > AFFS_I(inode)->mmu_private) {
6628c2ecf20Sopenharmony_ci		/* XXX: this probably leaves a too-big i_size in case of
6638c2ecf20Sopenharmony_ci		 * failure. Should really be updating i_size at write_end time
6648c2ecf20Sopenharmony_ci		 */
6658c2ecf20Sopenharmony_ci		err = affs_extent_file_ofs(inode, pos);
6668c2ecf20Sopenharmony_ci		if (err)
6678c2ecf20Sopenharmony_ci			return err;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	index = pos >> PAGE_SHIFT;
6718c2ecf20Sopenharmony_ci	page = grab_cache_page_write_begin(mapping, index, flags);
6728c2ecf20Sopenharmony_ci	if (!page)
6738c2ecf20Sopenharmony_ci		return -ENOMEM;
6748c2ecf20Sopenharmony_ci	*pagep = page;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if (PageUptodate(page))
6778c2ecf20Sopenharmony_ci		return 0;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/* XXX: inefficient but safe in the face of short writes */
6808c2ecf20Sopenharmony_ci	err = affs_do_readpage_ofs(page, PAGE_SIZE, 1);
6818c2ecf20Sopenharmony_ci	if (err) {
6828c2ecf20Sopenharmony_ci		unlock_page(page);
6838c2ecf20Sopenharmony_ci		put_page(page);
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci	return err;
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_cistatic int affs_write_end_ofs(struct file *file, struct address_space *mapping,
6898c2ecf20Sopenharmony_ci				loff_t pos, unsigned len, unsigned copied,
6908c2ecf20Sopenharmony_ci				struct page *page, void *fsdata)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	struct inode *inode = mapping->host;
6938c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
6948c2ecf20Sopenharmony_ci	struct buffer_head *bh, *prev_bh;
6958c2ecf20Sopenharmony_ci	char *data;
6968c2ecf20Sopenharmony_ci	u32 bidx, boff, bsize;
6978c2ecf20Sopenharmony_ci	unsigned from, to;
6988c2ecf20Sopenharmony_ci	u32 tmp;
6998c2ecf20Sopenharmony_ci	int written;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	from = pos & (PAGE_SIZE - 1);
7028c2ecf20Sopenharmony_ci	to = from + len;
7038c2ecf20Sopenharmony_ci	/*
7048c2ecf20Sopenharmony_ci	 * XXX: not sure if this can handle short copies (len < copied), but
7058c2ecf20Sopenharmony_ci	 * we don't have to, because the page should always be uptodate here,
7068c2ecf20Sopenharmony_ci	 * due to write_begin.
7078c2ecf20Sopenharmony_ci	 */
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos,
7108c2ecf20Sopenharmony_ci		 pos + len);
7118c2ecf20Sopenharmony_ci	bsize = AFFS_SB(sb)->s_data_blksize;
7128c2ecf20Sopenharmony_ci	data = page_address(page);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	bh = NULL;
7158c2ecf20Sopenharmony_ci	written = 0;
7168c2ecf20Sopenharmony_ci	tmp = (page->index << PAGE_SHIFT) + from;
7178c2ecf20Sopenharmony_ci	bidx = tmp / bsize;
7188c2ecf20Sopenharmony_ci	boff = tmp % bsize;
7198c2ecf20Sopenharmony_ci	if (boff) {
7208c2ecf20Sopenharmony_ci		bh = affs_bread_ino(inode, bidx, 0);
7218c2ecf20Sopenharmony_ci		if (IS_ERR(bh)) {
7228c2ecf20Sopenharmony_ci			written = PTR_ERR(bh);
7238c2ecf20Sopenharmony_ci			goto err_first_bh;
7248c2ecf20Sopenharmony_ci		}
7258c2ecf20Sopenharmony_ci		tmp = min(bsize - boff, to - from);
7268c2ecf20Sopenharmony_ci		BUG_ON(boff + tmp > bsize || tmp > bsize);
7278c2ecf20Sopenharmony_ci		memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
7288c2ecf20Sopenharmony_ci		be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp);
7298c2ecf20Sopenharmony_ci		affs_fix_checksum(sb, bh);
7308c2ecf20Sopenharmony_ci		mark_buffer_dirty_inode(bh, inode);
7318c2ecf20Sopenharmony_ci		written += tmp;
7328c2ecf20Sopenharmony_ci		from += tmp;
7338c2ecf20Sopenharmony_ci		bidx++;
7348c2ecf20Sopenharmony_ci	} else if (bidx) {
7358c2ecf20Sopenharmony_ci		bh = affs_bread_ino(inode, bidx - 1, 0);
7368c2ecf20Sopenharmony_ci		if (IS_ERR(bh)) {
7378c2ecf20Sopenharmony_ci			written = PTR_ERR(bh);
7388c2ecf20Sopenharmony_ci			goto err_first_bh;
7398c2ecf20Sopenharmony_ci		}
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci	while (from + bsize <= to) {
7428c2ecf20Sopenharmony_ci		prev_bh = bh;
7438c2ecf20Sopenharmony_ci		bh = affs_getemptyblk_ino(inode, bidx);
7448c2ecf20Sopenharmony_ci		if (IS_ERR(bh))
7458c2ecf20Sopenharmony_ci			goto err_bh;
7468c2ecf20Sopenharmony_ci		memcpy(AFFS_DATA(bh), data + from, bsize);
7478c2ecf20Sopenharmony_ci		if (buffer_new(bh)) {
7488c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
7498c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
7508c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
7518c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);
7528c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->next = 0;
7538c2ecf20Sopenharmony_ci			bh->b_state &= ~(1UL << BH_New);
7548c2ecf20Sopenharmony_ci			if (prev_bh) {
7558c2ecf20Sopenharmony_ci				u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci				if (tmp_next)
7588c2ecf20Sopenharmony_ci					affs_warning(sb, "commit_write_ofs",
7598c2ecf20Sopenharmony_ci						     "next block already set for %d (%d)",
7608c2ecf20Sopenharmony_ci						     bidx, tmp_next);
7618c2ecf20Sopenharmony_ci				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
7628c2ecf20Sopenharmony_ci				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
7638c2ecf20Sopenharmony_ci				mark_buffer_dirty_inode(prev_bh, inode);
7648c2ecf20Sopenharmony_ci			}
7658c2ecf20Sopenharmony_ci		}
7668c2ecf20Sopenharmony_ci		affs_brelse(prev_bh);
7678c2ecf20Sopenharmony_ci		affs_fix_checksum(sb, bh);
7688c2ecf20Sopenharmony_ci		mark_buffer_dirty_inode(bh, inode);
7698c2ecf20Sopenharmony_ci		written += bsize;
7708c2ecf20Sopenharmony_ci		from += bsize;
7718c2ecf20Sopenharmony_ci		bidx++;
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci	if (from < to) {
7748c2ecf20Sopenharmony_ci		prev_bh = bh;
7758c2ecf20Sopenharmony_ci		bh = affs_bread_ino(inode, bidx, 1);
7768c2ecf20Sopenharmony_ci		if (IS_ERR(bh))
7778c2ecf20Sopenharmony_ci			goto err_bh;
7788c2ecf20Sopenharmony_ci		tmp = min(bsize, to - from);
7798c2ecf20Sopenharmony_ci		BUG_ON(tmp > bsize);
7808c2ecf20Sopenharmony_ci		memcpy(AFFS_DATA(bh), data + from, tmp);
7818c2ecf20Sopenharmony_ci		if (buffer_new(bh)) {
7828c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
7838c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
7848c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
7858c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
7868c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->next = 0;
7878c2ecf20Sopenharmony_ci			bh->b_state &= ~(1UL << BH_New);
7888c2ecf20Sopenharmony_ci			if (prev_bh) {
7898c2ecf20Sopenharmony_ci				u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci				if (tmp_next)
7928c2ecf20Sopenharmony_ci					affs_warning(sb, "commit_write_ofs",
7938c2ecf20Sopenharmony_ci						     "next block already set for %d (%d)",
7948c2ecf20Sopenharmony_ci						     bidx, tmp_next);
7958c2ecf20Sopenharmony_ci				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
7968c2ecf20Sopenharmony_ci				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);
7978c2ecf20Sopenharmony_ci				mark_buffer_dirty_inode(prev_bh, inode);
7988c2ecf20Sopenharmony_ci			}
7998c2ecf20Sopenharmony_ci		} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
8008c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
8018c2ecf20Sopenharmony_ci		affs_brelse(prev_bh);
8028c2ecf20Sopenharmony_ci		affs_fix_checksum(sb, bh);
8038c2ecf20Sopenharmony_ci		mark_buffer_dirty_inode(bh, inode);
8048c2ecf20Sopenharmony_ci		written += tmp;
8058c2ecf20Sopenharmony_ci		from += tmp;
8068c2ecf20Sopenharmony_ci		bidx++;
8078c2ecf20Sopenharmony_ci	}
8088c2ecf20Sopenharmony_ci	SetPageUptodate(page);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_cidone:
8118c2ecf20Sopenharmony_ci	affs_brelse(bh);
8128c2ecf20Sopenharmony_ci	tmp = (page->index << PAGE_SHIFT) + from;
8138c2ecf20Sopenharmony_ci	if (tmp > inode->i_size)
8148c2ecf20Sopenharmony_ci		inode->i_size = AFFS_I(inode)->mmu_private = tmp;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	/* Clear Archived bit on file writes, as AmigaOS would do */
8178c2ecf20Sopenharmony_ci	if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {
8188c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;
8198c2ecf20Sopenharmony_ci		mark_inode_dirty(inode);
8208c2ecf20Sopenharmony_ci	}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_cierr_first_bh:
8238c2ecf20Sopenharmony_ci	unlock_page(page);
8248c2ecf20Sopenharmony_ci	put_page(page);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	return written;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cierr_bh:
8298c2ecf20Sopenharmony_ci	bh = prev_bh;
8308c2ecf20Sopenharmony_ci	if (!written)
8318c2ecf20Sopenharmony_ci		written = PTR_ERR(bh);
8328c2ecf20Sopenharmony_ci	goto done;
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ciconst struct address_space_operations affs_aops_ofs = {
8368c2ecf20Sopenharmony_ci	.readpage = affs_readpage_ofs,
8378c2ecf20Sopenharmony_ci	//.writepage = affs_writepage_ofs,
8388c2ecf20Sopenharmony_ci	.write_begin = affs_write_begin_ofs,
8398c2ecf20Sopenharmony_ci	.write_end = affs_write_end_ofs
8408c2ecf20Sopenharmony_ci};
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci/* Free any preallocated blocks. */
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_civoid
8458c2ecf20Sopenharmony_ciaffs_free_prealloc(struct inode *inode)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	pr_debug("free_prealloc(ino=%lu)\n", inode->i_ino);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	while (AFFS_I(inode)->i_pa_cnt) {
8528c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_pa_cnt--;
8538c2ecf20Sopenharmony_ci		affs_free_block(sb, ++AFFS_I(inode)->i_lastalloc);
8548c2ecf20Sopenharmony_ci	}
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci/* Truncate (or enlarge) a file to the requested size. */
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_civoid
8608c2ecf20Sopenharmony_ciaffs_truncate(struct inode *inode)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
8638c2ecf20Sopenharmony_ci	u32 ext, ext_key;
8648c2ecf20Sopenharmony_ci	u32 last_blk, blkcnt, blk;
8658c2ecf20Sopenharmony_ci	u32 size;
8668c2ecf20Sopenharmony_ci	struct buffer_head *ext_bh;
8678c2ecf20Sopenharmony_ci	int i;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	pr_debug("truncate(inode=%lu, oldsize=%llu, newsize=%llu)\n",
8708c2ecf20Sopenharmony_ci		 inode->i_ino, AFFS_I(inode)->mmu_private, inode->i_size);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	last_blk = 0;
8738c2ecf20Sopenharmony_ci	ext = 0;
8748c2ecf20Sopenharmony_ci	if (inode->i_size) {
8758c2ecf20Sopenharmony_ci		last_blk = ((u32)inode->i_size - 1) / AFFS_SB(sb)->s_data_blksize;
8768c2ecf20Sopenharmony_ci		ext = last_blk / AFFS_SB(sb)->s_hashsize;
8778c2ecf20Sopenharmony_ci	}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	if (inode->i_size > AFFS_I(inode)->mmu_private) {
8808c2ecf20Sopenharmony_ci		struct address_space *mapping = inode->i_mapping;
8818c2ecf20Sopenharmony_ci		struct page *page;
8828c2ecf20Sopenharmony_ci		void *fsdata = NULL;
8838c2ecf20Sopenharmony_ci		loff_t isize = inode->i_size;
8848c2ecf20Sopenharmony_ci		int res;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci		res = mapping->a_ops->write_begin(NULL, mapping, isize, 0, 0, &page, &fsdata);
8878c2ecf20Sopenharmony_ci		if (!res)
8888c2ecf20Sopenharmony_ci			res = mapping->a_ops->write_end(NULL, mapping, isize, 0, 0, page, fsdata);
8898c2ecf20Sopenharmony_ci		else
8908c2ecf20Sopenharmony_ci			inode->i_size = AFFS_I(inode)->mmu_private;
8918c2ecf20Sopenharmony_ci		mark_inode_dirty(inode);
8928c2ecf20Sopenharmony_ci		return;
8938c2ecf20Sopenharmony_ci	} else if (inode->i_size == AFFS_I(inode)->mmu_private)
8948c2ecf20Sopenharmony_ci		return;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	// lock cache
8978c2ecf20Sopenharmony_ci	ext_bh = affs_get_extblock(inode, ext);
8988c2ecf20Sopenharmony_ci	if (IS_ERR(ext_bh)) {
8998c2ecf20Sopenharmony_ci		affs_warning(sb, "truncate",
9008c2ecf20Sopenharmony_ci			     "unexpected read error for ext block %u (%ld)",
9018c2ecf20Sopenharmony_ci			     ext, PTR_ERR(ext_bh));
9028c2ecf20Sopenharmony_ci		return;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci	if (AFFS_I(inode)->i_lc) {
9058c2ecf20Sopenharmony_ci		/* clear linear cache */
9068c2ecf20Sopenharmony_ci		i = (ext + 1) >> AFFS_I(inode)->i_lc_shift;
9078c2ecf20Sopenharmony_ci		if (AFFS_I(inode)->i_lc_size > i) {
9088c2ecf20Sopenharmony_ci			AFFS_I(inode)->i_lc_size = i;
9098c2ecf20Sopenharmony_ci			for (; i < AFFS_LC_SIZE; i++)
9108c2ecf20Sopenharmony_ci				AFFS_I(inode)->i_lc[i] = 0;
9118c2ecf20Sopenharmony_ci		}
9128c2ecf20Sopenharmony_ci		/* clear associative cache */
9138c2ecf20Sopenharmony_ci		for (i = 0; i < AFFS_AC_SIZE; i++)
9148c2ecf20Sopenharmony_ci			if (AFFS_I(inode)->i_ac[i].ext >= ext)
9158c2ecf20Sopenharmony_ci				AFFS_I(inode)->i_ac[i].ext = 0;
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci	ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	blkcnt = AFFS_I(inode)->i_blkcnt;
9208c2ecf20Sopenharmony_ci	i = 0;
9218c2ecf20Sopenharmony_ci	blk = last_blk;
9228c2ecf20Sopenharmony_ci	if (inode->i_size) {
9238c2ecf20Sopenharmony_ci		i = last_blk % AFFS_SB(sb)->s_hashsize + 1;
9248c2ecf20Sopenharmony_ci		blk++;
9258c2ecf20Sopenharmony_ci	} else
9268c2ecf20Sopenharmony_ci		AFFS_HEAD(ext_bh)->first_data = 0;
9278c2ecf20Sopenharmony_ci	AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i);
9288c2ecf20Sopenharmony_ci	size = AFFS_SB(sb)->s_hashsize;
9298c2ecf20Sopenharmony_ci	if (size > blkcnt - blk + i)
9308c2ecf20Sopenharmony_ci		size = blkcnt - blk + i;
9318c2ecf20Sopenharmony_ci	for (; i < size; i++, blk++) {
9328c2ecf20Sopenharmony_ci		affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
9338c2ecf20Sopenharmony_ci		AFFS_BLOCK(sb, ext_bh, i) = 0;
9348c2ecf20Sopenharmony_ci	}
9358c2ecf20Sopenharmony_ci	AFFS_TAIL(sb, ext_bh)->extension = 0;
9368c2ecf20Sopenharmony_ci	affs_fix_checksum(sb, ext_bh);
9378c2ecf20Sopenharmony_ci	mark_buffer_dirty_inode(ext_bh, inode);
9388c2ecf20Sopenharmony_ci	affs_brelse(ext_bh);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	if (inode->i_size) {
9418c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_blkcnt = last_blk + 1;
9428c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_extcnt = ext + 1;
9438c2ecf20Sopenharmony_ci		if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS)) {
9448c2ecf20Sopenharmony_ci			struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);
9458c2ecf20Sopenharmony_ci			u32 tmp;
9468c2ecf20Sopenharmony_ci			if (IS_ERR(bh)) {
9478c2ecf20Sopenharmony_ci				affs_warning(sb, "truncate",
9488c2ecf20Sopenharmony_ci					     "unexpected read error for last block %u (%ld)",
9498c2ecf20Sopenharmony_ci					     ext, PTR_ERR(bh));
9508c2ecf20Sopenharmony_ci				return;
9518c2ecf20Sopenharmony_ci			}
9528c2ecf20Sopenharmony_ci			tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
9538c2ecf20Sopenharmony_ci			AFFS_DATA_HEAD(bh)->next = 0;
9548c2ecf20Sopenharmony_ci			affs_adjust_checksum(bh, -tmp);
9558c2ecf20Sopenharmony_ci			affs_brelse(bh);
9568c2ecf20Sopenharmony_ci		}
9578c2ecf20Sopenharmony_ci	} else {
9588c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_blkcnt = 0;
9598c2ecf20Sopenharmony_ci		AFFS_I(inode)->i_extcnt = 1;
9608c2ecf20Sopenharmony_ci	}
9618c2ecf20Sopenharmony_ci	AFFS_I(inode)->mmu_private = inode->i_size;
9628c2ecf20Sopenharmony_ci	// unlock cache
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	while (ext_key) {
9658c2ecf20Sopenharmony_ci		ext_bh = affs_bread(sb, ext_key);
9668c2ecf20Sopenharmony_ci		size = AFFS_SB(sb)->s_hashsize;
9678c2ecf20Sopenharmony_ci		if (size > blkcnt - blk)
9688c2ecf20Sopenharmony_ci			size = blkcnt - blk;
9698c2ecf20Sopenharmony_ci		for (i = 0; i < size; i++, blk++)
9708c2ecf20Sopenharmony_ci			affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
9718c2ecf20Sopenharmony_ci		affs_free_block(sb, ext_key);
9728c2ecf20Sopenharmony_ci		ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
9738c2ecf20Sopenharmony_ci		affs_brelse(ext_bh);
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci	affs_free_prealloc(inode);
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ciint affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct inode *inode = filp->f_mapping->host;
9818c2ecf20Sopenharmony_ci	int ret, err;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	err = file_write_and_wait_range(filp, start, end);
9848c2ecf20Sopenharmony_ci	if (err)
9858c2ecf20Sopenharmony_ci		return err;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	inode_lock(inode);
9888c2ecf20Sopenharmony_ci	ret = write_inode_now(inode, 0);
9898c2ecf20Sopenharmony_ci	err = sync_blockdev(inode->i_sb->s_bdev);
9908c2ecf20Sopenharmony_ci	if (!ret)
9918c2ecf20Sopenharmony_ci		ret = err;
9928c2ecf20Sopenharmony_ci	inode_unlock(inode);
9938c2ecf20Sopenharmony_ci	return ret;
9948c2ecf20Sopenharmony_ci}
9958c2ecf20Sopenharmony_ciconst struct file_operations affs_file_operations = {
9968c2ecf20Sopenharmony_ci	.llseek		= generic_file_llseek,
9978c2ecf20Sopenharmony_ci	.read_iter	= generic_file_read_iter,
9988c2ecf20Sopenharmony_ci	.write_iter	= generic_file_write_iter,
9998c2ecf20Sopenharmony_ci	.mmap		= generic_file_mmap,
10008c2ecf20Sopenharmony_ci	.open		= affs_file_open,
10018c2ecf20Sopenharmony_ci	.release	= affs_file_release,
10028c2ecf20Sopenharmony_ci	.fsync		= affs_file_fsync,
10038c2ecf20Sopenharmony_ci	.splice_read	= generic_file_splice_read,
10048c2ecf20Sopenharmony_ci};
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ciconst struct inode_operations affs_file_inode_operations = {
10078c2ecf20Sopenharmony_ci	.setattr	= affs_notify_change,
10088c2ecf20Sopenharmony_ci};
1009