brintos

brintos / linux-shallow public Read only

0
0
Text · 25.3 KiB · a5a861d Raw
1011 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  linux/fs/affs/file.c4 *5 *  (c) 1996  Hans-Joachim Widmaier - Rewritten6 *7 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.8 *9 *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.10 *11 *  (C) 1991  Linus Torvalds - minix filesystem12 *13 *  affs regular file handling primitives14 */15 16#include <linux/uio.h>17#include <linux/blkdev.h>18#include <linux/mpage.h>19#include "affs.h"20 21static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);22 23static int24affs_file_open(struct inode *inode, struct file *filp)25{26	pr_debug("open(%lu,%d)\n",27		 inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));28	atomic_inc(&AFFS_I(inode)->i_opencnt);29	return 0;30}31 32static int33affs_file_release(struct inode *inode, struct file *filp)34{35	pr_debug("release(%lu, %d)\n",36		 inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));37 38	if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) {39		inode_lock(inode);40		if (inode->i_size != AFFS_I(inode)->mmu_private)41			affs_truncate(inode);42		affs_free_prealloc(inode);43		inode_unlock(inode);44	}45 46	return 0;47}48 49static int50affs_grow_extcache(struct inode *inode, u32 lc_idx)51{52	struct super_block	*sb = inode->i_sb;53	struct buffer_head	*bh;54	u32 lc_max;55	int i, j, key;56 57	if (!AFFS_I(inode)->i_lc) {58		char *ptr = (char *)get_zeroed_page(GFP_NOFS);59		if (!ptr)60			return -ENOMEM;61		AFFS_I(inode)->i_lc = (u32 *)ptr;62		AFFS_I(inode)->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);63	}64 65	lc_max = AFFS_LC_SIZE << AFFS_I(inode)->i_lc_shift;66 67	if (AFFS_I(inode)->i_extcnt > lc_max) {68		u32 lc_shift, lc_mask, tmp, off;69 70		/* need to recalculate linear cache, start from old size */71		lc_shift = AFFS_I(inode)->i_lc_shift;72		tmp = (AFFS_I(inode)->i_extcnt / AFFS_LC_SIZE) >> lc_shift;73		for (; tmp; tmp >>= 1)74			lc_shift++;75		lc_mask = (1 << lc_shift) - 1;76 77		/* fix idx and old size to new shift */78		lc_idx >>= (lc_shift - AFFS_I(inode)->i_lc_shift);79		AFFS_I(inode)->i_lc_size >>= (lc_shift - AFFS_I(inode)->i_lc_shift);80 81		/* first shrink old cache to make more space */82		off = 1 << (lc_shift - AFFS_I(inode)->i_lc_shift);83		for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off)84			AFFS_I(inode)->i_ac[i] = AFFS_I(inode)->i_ac[j];85 86		AFFS_I(inode)->i_lc_shift = lc_shift;87		AFFS_I(inode)->i_lc_mask = lc_mask;88	}89 90	/* fill cache to the needed index */91	i = AFFS_I(inode)->i_lc_size;92	AFFS_I(inode)->i_lc_size = lc_idx + 1;93	for (; i <= lc_idx; i++) {94		if (!i) {95			AFFS_I(inode)->i_lc[0] = inode->i_ino;96			continue;97		}98		key = AFFS_I(inode)->i_lc[i - 1];99		j = AFFS_I(inode)->i_lc_mask + 1;100		// unlock cache101		for (; j > 0; j--) {102			bh = affs_bread(sb, key);103			if (!bh)104				goto err;105			key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);106			affs_brelse(bh);107		}108		// lock cache109		AFFS_I(inode)->i_lc[i] = key;110	}111 112	return 0;113 114err:115	// lock cache116	return -EIO;117}118 119static struct buffer_head *120affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext)121{122	struct super_block *sb = inode->i_sb;123	struct buffer_head *new_bh;124	u32 blocknr, tmp;125 126	blocknr = affs_alloc_block(inode, bh->b_blocknr);127	if (!blocknr)128		return ERR_PTR(-ENOSPC);129 130	new_bh = affs_getzeroblk(sb, blocknr);131	if (!new_bh) {132		affs_free_block(sb, blocknr);133		return ERR_PTR(-EIO);134	}135 136	AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST);137	AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr);138	AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE);139	AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino);140	affs_fix_checksum(sb, new_bh);141 142	mark_buffer_dirty_inode(new_bh, inode);143 144	tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);145	if (tmp)146		affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp);147	AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr);148	affs_adjust_checksum(bh, blocknr - tmp);149	mark_buffer_dirty_inode(bh, inode);150 151	AFFS_I(inode)->i_extcnt++;152	mark_inode_dirty(inode);153 154	return new_bh;155}156 157static inline struct buffer_head *158affs_get_extblock(struct inode *inode, u32 ext)159{160	/* inline the simplest case: same extended block as last time */161	struct buffer_head *bh = AFFS_I(inode)->i_ext_bh;162	if (ext == AFFS_I(inode)->i_ext_last)163		get_bh(bh);164	else165		/* we have to do more (not inlined) */166		bh = affs_get_extblock_slow(inode, ext);167 168	return bh;169}170 171static struct buffer_head *172affs_get_extblock_slow(struct inode *inode, u32 ext)173{174	struct super_block *sb = inode->i_sb;175	struct buffer_head *bh;176	u32 ext_key;177	u32 lc_idx, lc_off, ac_idx;178	u32 tmp, idx;179 180	if (ext == AFFS_I(inode)->i_ext_last + 1) {181		/* read the next extended block from the current one */182		bh = AFFS_I(inode)->i_ext_bh;183		ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);184		if (ext < AFFS_I(inode)->i_extcnt)185			goto read_ext;186		BUG_ON(ext > AFFS_I(inode)->i_extcnt);187		bh = affs_alloc_extblock(inode, bh, ext);188		if (IS_ERR(bh))189			return bh;190		goto store_ext;191	}192 193	if (ext == 0) {194		/* we seek back to the file header block */195		ext_key = inode->i_ino;196		goto read_ext;197	}198 199	if (ext >= AFFS_I(inode)->i_extcnt) {200		struct buffer_head *prev_bh;201 202		/* allocate a new extended block */203		BUG_ON(ext > AFFS_I(inode)->i_extcnt);204 205		/* get previous extended block */206		prev_bh = affs_get_extblock(inode, ext - 1);207		if (IS_ERR(prev_bh))208			return prev_bh;209		bh = affs_alloc_extblock(inode, prev_bh, ext);210		affs_brelse(prev_bh);211		if (IS_ERR(bh))212			return bh;213		goto store_ext;214	}215 216again:217	/* check if there is an extended cache and whether it's large enough */218	lc_idx = ext >> AFFS_I(inode)->i_lc_shift;219	lc_off = ext & AFFS_I(inode)->i_lc_mask;220 221	if (lc_idx >= AFFS_I(inode)->i_lc_size) {222		int err;223 224		err = affs_grow_extcache(inode, lc_idx);225		if (err)226			return ERR_PTR(err);227		goto again;228	}229 230	/* every n'th key we find in the linear cache */231	if (!lc_off) {232		ext_key = AFFS_I(inode)->i_lc[lc_idx];233		goto read_ext;234	}235 236	/* maybe it's still in the associative cache */237	ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK;238	if (AFFS_I(inode)->i_ac[ac_idx].ext == ext) {239		ext_key = AFFS_I(inode)->i_ac[ac_idx].key;240		goto read_ext;241	}242 243	/* try to find one of the previous extended blocks */244	tmp = ext;245	idx = ac_idx;246	while (--tmp, --lc_off > 0) {247		idx = (idx - 1) & AFFS_AC_MASK;248		if (AFFS_I(inode)->i_ac[idx].ext == tmp) {249			ext_key = AFFS_I(inode)->i_ac[idx].key;250			goto find_ext;251		}252	}253 254	/* fall back to the linear cache */255	ext_key = AFFS_I(inode)->i_lc[lc_idx];256find_ext:257	/* read all extended blocks until we find the one we need */258	//unlock cache259	do {260		bh = affs_bread(sb, ext_key);261		if (!bh)262			goto err_bread;263		ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);264		affs_brelse(bh);265		tmp++;266	} while (tmp < ext);267	//lock cache268 269	/* store it in the associative cache */270	// recalculate ac_idx?271	AFFS_I(inode)->i_ac[ac_idx].ext = ext;272	AFFS_I(inode)->i_ac[ac_idx].key = ext_key;273 274read_ext:275	/* finally read the right extended block */276	//unlock cache277	bh = affs_bread(sb, ext_key);278	if (!bh)279		goto err_bread;280	//lock cache281 282store_ext:283	/* release old cached extended block and store the new one */284	affs_brelse(AFFS_I(inode)->i_ext_bh);285	AFFS_I(inode)->i_ext_last = ext;286	AFFS_I(inode)->i_ext_bh = bh;287	get_bh(bh);288 289	return bh;290 291err_bread:292	affs_brelse(bh);293	return ERR_PTR(-EIO);294}295 296static int297affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)298{299	struct super_block	*sb = inode->i_sb;300	struct buffer_head	*ext_bh;301	u32			 ext;302 303	pr_debug("%s(%lu, %llu)\n", __func__, inode->i_ino,304		 (unsigned long long)block);305 306	BUG_ON(block > (sector_t)0x7fffffffUL);307 308	if (block >= AFFS_I(inode)->i_blkcnt) {309		if (block > AFFS_I(inode)->i_blkcnt || !create)310			goto err_big;311	} else312		create = 0;313 314	//lock cache315	affs_lock_ext(inode);316 317	ext = (u32)block / AFFS_SB(sb)->s_hashsize;318	block -= ext * AFFS_SB(sb)->s_hashsize;319	ext_bh = affs_get_extblock(inode, ext);320	if (IS_ERR(ext_bh))321		goto err_ext;322	map_bh(bh_result, sb, (sector_t)be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block)));323 324	if (create) {325		u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);326		if (!blocknr)327			goto err_alloc;328		set_buffer_new(bh_result);329		AFFS_I(inode)->mmu_private += AFFS_SB(sb)->s_data_blksize;330		AFFS_I(inode)->i_blkcnt++;331 332		/* store new block */333		if (bh_result->b_blocknr)334			affs_warning(sb, "get_block",335				     "block already set (%llx)",336				     (unsigned long long)bh_result->b_blocknr);337		AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr);338		AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1);339		affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1);340		bh_result->b_blocknr = blocknr;341 342		if (!block) {343			/* insert first block into header block */344			u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data);345			if (tmp)346				affs_warning(sb, "get_block", "first block already set (%d)", tmp);347			AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr);348			affs_adjust_checksum(ext_bh, blocknr - tmp);349		}350	}351 352	affs_brelse(ext_bh);353	//unlock cache354	affs_unlock_ext(inode);355	return 0;356 357err_big:358	affs_error(inode->i_sb, "get_block", "strange block request %llu",359		   (unsigned long long)block);360	return -EIO;361err_ext:362	// unlock cache363	affs_unlock_ext(inode);364	return PTR_ERR(ext_bh);365err_alloc:366	brelse(ext_bh);367	clear_buffer_mapped(bh_result);368	bh_result->b_bdev = NULL;369	// unlock cache370	affs_unlock_ext(inode);371	return -ENOSPC;372}373 374static int affs_writepages(struct address_space *mapping,375			   struct writeback_control *wbc)376{377	return mpage_writepages(mapping, wbc, affs_get_block);378}379 380static int affs_read_folio(struct file *file, struct folio *folio)381{382	return block_read_full_folio(folio, affs_get_block);383}384 385static void affs_write_failed(struct address_space *mapping, loff_t to)386{387	struct inode *inode = mapping->host;388 389	if (to > inode->i_size) {390		truncate_pagecache(inode, inode->i_size);391		affs_truncate(inode);392	}393}394 395static ssize_t396affs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)397{398	struct file *file = iocb->ki_filp;399	struct address_space *mapping = file->f_mapping;400	struct inode *inode = mapping->host;401	size_t count = iov_iter_count(iter);402	loff_t offset = iocb->ki_pos;403	ssize_t ret;404 405	if (iov_iter_rw(iter) == WRITE) {406		loff_t size = offset + count;407 408		if (AFFS_I(inode)->mmu_private < size)409			return 0;410	}411 412	ret = blockdev_direct_IO(iocb, inode, iter, affs_get_block);413	if (ret < 0 && iov_iter_rw(iter) == WRITE)414		affs_write_failed(mapping, offset + count);415	return ret;416}417 418static int affs_write_begin(struct file *file, struct address_space *mapping,419			loff_t pos, unsigned len,420			struct folio **foliop, void **fsdata)421{422	int ret;423 424	ret = cont_write_begin(file, mapping, pos, len, foliop, fsdata,425				affs_get_block,426				&AFFS_I(mapping->host)->mmu_private);427	if (unlikely(ret))428		affs_write_failed(mapping, pos + len);429 430	return ret;431}432 433static int affs_write_end(struct file *file, struct address_space *mapping,434			  loff_t pos, unsigned int len, unsigned int copied,435			  struct folio *folio, void *fsdata)436{437	struct inode *inode = mapping->host;438	int ret;439 440	ret = generic_write_end(file, mapping, pos, len, copied, folio, fsdata);441 442	/* Clear Archived bit on file writes, as AmigaOS would do */443	if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {444		AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;445		mark_inode_dirty(inode);446	}447 448	return ret;449}450 451static sector_t _affs_bmap(struct address_space *mapping, sector_t block)452{453	return generic_block_bmap(mapping,block,affs_get_block);454}455 456const struct address_space_operations affs_aops = {457	.dirty_folio	= block_dirty_folio,458	.invalidate_folio = block_invalidate_folio,459	.read_folio = affs_read_folio,460	.writepages = affs_writepages,461	.write_begin = affs_write_begin,462	.write_end = affs_write_end,463	.direct_IO = affs_direct_IO,464	.migrate_folio = buffer_migrate_folio,465	.bmap = _affs_bmap466};467 468static inline struct buffer_head *469affs_bread_ino(struct inode *inode, int block, int create)470{471	struct buffer_head *bh, tmp_bh;472	int err;473 474	tmp_bh.b_state = 0;475	err = affs_get_block(inode, block, &tmp_bh, create);476	if (!err) {477		bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr);478		if (bh) {479			bh->b_state |= tmp_bh.b_state;480			return bh;481		}482		err = -EIO;483	}484	return ERR_PTR(err);485}486 487static inline struct buffer_head *488affs_getzeroblk_ino(struct inode *inode, int block)489{490	struct buffer_head *bh, tmp_bh;491	int err;492 493	tmp_bh.b_state = 0;494	err = affs_get_block(inode, block, &tmp_bh, 1);495	if (!err) {496		bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr);497		if (bh) {498			bh->b_state |= tmp_bh.b_state;499			return bh;500		}501		err = -EIO;502	}503	return ERR_PTR(err);504}505 506static inline struct buffer_head *507affs_getemptyblk_ino(struct inode *inode, int block)508{509	struct buffer_head *bh, tmp_bh;510	int err;511 512	tmp_bh.b_state = 0;513	err = affs_get_block(inode, block, &tmp_bh, 1);514	if (!err) {515		bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr);516		if (bh) {517			bh->b_state |= tmp_bh.b_state;518			return bh;519		}520		err = -EIO;521	}522	return ERR_PTR(err);523}524 525static int affs_do_read_folio_ofs(struct folio *folio, size_t to, int create)526{527	struct inode *inode = folio->mapping->host;528	struct super_block *sb = inode->i_sb;529	struct buffer_head *bh;530	size_t pos = 0;531	size_t bidx, boff, bsize;532	u32 tmp;533 534	pr_debug("%s(%lu, %ld, 0, %zu)\n", __func__, inode->i_ino,535		 folio->index, to);536	BUG_ON(to > folio_size(folio));537	bsize = AFFS_SB(sb)->s_data_blksize;538	tmp = folio_pos(folio);539	bidx = tmp / bsize;540	boff = tmp % bsize;541 542	while (pos < to) {543		bh = affs_bread_ino(inode, bidx, create);544		if (IS_ERR(bh))545			return PTR_ERR(bh);546		tmp = min(bsize - boff, to - pos);547		BUG_ON(pos + tmp > to || tmp > bsize);548		memcpy_to_folio(folio, pos, AFFS_DATA(bh) + boff, tmp);549		affs_brelse(bh);550		bidx++;551		pos += tmp;552		boff = 0;553	}554	return 0;555}556 557static int558affs_extent_file_ofs(struct inode *inode, u32 newsize)559{560	struct super_block *sb = inode->i_sb;561	struct buffer_head *bh, *prev_bh;562	u32 bidx, boff;563	u32 size, bsize;564	u32 tmp;565 566	pr_debug("%s(%lu, %d)\n", __func__, inode->i_ino, newsize);567	bsize = AFFS_SB(sb)->s_data_blksize;568	bh = NULL;569	size = AFFS_I(inode)->mmu_private;570	bidx = size / bsize;571	boff = size % bsize;572	if (boff) {573		bh = affs_bread_ino(inode, bidx, 0);574		if (IS_ERR(bh))575			return PTR_ERR(bh);576		tmp = min(bsize - boff, newsize - size);577		BUG_ON(boff + tmp > bsize || tmp > bsize);578		memset(AFFS_DATA(bh) + boff, 0, tmp);579		be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp);580		affs_fix_checksum(sb, bh);581		mark_buffer_dirty_inode(bh, inode);582		size += tmp;583		bidx++;584	} else if (bidx) {585		bh = affs_bread_ino(inode, bidx - 1, 0);586		if (IS_ERR(bh))587			return PTR_ERR(bh);588	}589 590	while (size < newsize) {591		prev_bh = bh;592		bh = affs_getzeroblk_ino(inode, bidx);593		if (IS_ERR(bh))594			goto out;595		tmp = min(bsize, newsize - size);596		BUG_ON(tmp > bsize);597		AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);598		AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);599		AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);600		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);601		affs_fix_checksum(sb, bh);602		bh->b_state &= ~(1UL << BH_New);603		mark_buffer_dirty_inode(bh, inode);604		if (prev_bh) {605			u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);606 607			if (tmp_next)608				affs_warning(sb, "extent_file_ofs",609					     "next block already set for %d (%d)",610					     bidx, tmp_next);611			AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);612			affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);613			mark_buffer_dirty_inode(prev_bh, inode);614			affs_brelse(prev_bh);615		}616		size += bsize;617		bidx++;618	}619	affs_brelse(bh);620	inode->i_size = AFFS_I(inode)->mmu_private = newsize;621	return 0;622 623out:624	inode->i_size = AFFS_I(inode)->mmu_private = newsize;625	return PTR_ERR(bh);626}627 628static int affs_read_folio_ofs(struct file *file, struct folio *folio)629{630	struct inode *inode = folio->mapping->host;631	size_t to;632	int err;633 634	pr_debug("%s(%lu, %ld)\n", __func__, inode->i_ino, folio->index);635	to = folio_size(folio);636	if (folio_pos(folio) + to > inode->i_size) {637		to = inode->i_size - folio_pos(folio);638		folio_zero_segment(folio, to, folio_size(folio));639	}640 641	err = affs_do_read_folio_ofs(folio, to, 0);642	if (!err)643		folio_mark_uptodate(folio);644	folio_unlock(folio);645	return err;646}647 648static int affs_write_begin_ofs(struct file *file, struct address_space *mapping,649				loff_t pos, unsigned len,650				struct folio **foliop, void **fsdata)651{652	struct inode *inode = mapping->host;653	struct folio *folio;654	pgoff_t index;655	int err = 0;656 657	pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos,658		 pos + len);659	if (pos > AFFS_I(inode)->mmu_private) {660		/* XXX: this probably leaves a too-big i_size in case of661		 * failure. Should really be updating i_size at write_end time662		 */663		err = affs_extent_file_ofs(inode, pos);664		if (err)665			return err;666	}667 668	index = pos >> PAGE_SHIFT;669	folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,670			mapping_gfp_mask(mapping));671	if (IS_ERR(folio))672		return PTR_ERR(folio);673	*foliop = folio;674 675	if (folio_test_uptodate(folio))676		return 0;677 678	/* XXX: inefficient but safe in the face of short writes */679	err = affs_do_read_folio_ofs(folio, folio_size(folio), 1);680	if (err) {681		folio_unlock(folio);682		folio_put(folio);683	}684	return err;685}686 687static int affs_write_end_ofs(struct file *file, struct address_space *mapping,688				loff_t pos, unsigned len, unsigned copied,689				struct folio *folio, void *fsdata)690{691	struct inode *inode = mapping->host;692	struct super_block *sb = inode->i_sb;693	struct buffer_head *bh, *prev_bh;694	char *data;695	u32 bidx, boff, bsize;696	unsigned from, to;697	u32 tmp;698	int written;699 700	from = pos & (PAGE_SIZE - 1);701	to = from + len;702	/*703	 * XXX: not sure if this can handle short copies (len < copied), but704	 * we don't have to, because the folio should always be uptodate here,705	 * due to write_begin.706	 */707 708	pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos,709		 pos + len);710	bsize = AFFS_SB(sb)->s_data_blksize;711	data = folio_address(folio);712 713	bh = NULL;714	written = 0;715	tmp = (folio->index << PAGE_SHIFT) + from;716	bidx = tmp / bsize;717	boff = tmp % bsize;718	if (boff) {719		bh = affs_bread_ino(inode, bidx, 0);720		if (IS_ERR(bh)) {721			written = PTR_ERR(bh);722			goto err_first_bh;723		}724		tmp = min(bsize - boff, to - from);725		BUG_ON(boff + tmp > bsize || tmp > bsize);726		memcpy(AFFS_DATA(bh) + boff, data + from, tmp);727		be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp);728		affs_fix_checksum(sb, bh);729		mark_buffer_dirty_inode(bh, inode);730		written += tmp;731		from += tmp;732		bidx++;733	} else if (bidx) {734		bh = affs_bread_ino(inode, bidx - 1, 0);735		if (IS_ERR(bh)) {736			written = PTR_ERR(bh);737			goto err_first_bh;738		}739	}740	while (from + bsize <= to) {741		prev_bh = bh;742		bh = affs_getemptyblk_ino(inode, bidx);743		if (IS_ERR(bh))744			goto err_bh;745		memcpy(AFFS_DATA(bh), data + from, bsize);746		if (buffer_new(bh)) {747			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);748			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);749			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);750			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);751			AFFS_DATA_HEAD(bh)->next = 0;752			bh->b_state &= ~(1UL << BH_New);753			if (prev_bh) {754				u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);755 756				if (tmp_next)757					affs_warning(sb, "commit_write_ofs",758						     "next block already set for %d (%d)",759						     bidx, tmp_next);760				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);761				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);762				mark_buffer_dirty_inode(prev_bh, inode);763			}764		}765		affs_brelse(prev_bh);766		affs_fix_checksum(sb, bh);767		mark_buffer_dirty_inode(bh, inode);768		written += bsize;769		from += bsize;770		bidx++;771	}772	if (from < to) {773		prev_bh = bh;774		bh = affs_bread_ino(inode, bidx, 1);775		if (IS_ERR(bh))776			goto err_bh;777		tmp = min(bsize, to - from);778		BUG_ON(tmp > bsize);779		memcpy(AFFS_DATA(bh), data + from, tmp);780		if (buffer_new(bh)) {781			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);782			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);783			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);784			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);785			AFFS_DATA_HEAD(bh)->next = 0;786			bh->b_state &= ~(1UL << BH_New);787			if (prev_bh) {788				u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);789 790				if (tmp_next)791					affs_warning(sb, "commit_write_ofs",792						     "next block already set for %d (%d)",793						     bidx, tmp_next);794				AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);795				affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next);796				mark_buffer_dirty_inode(prev_bh, inode);797			}798		} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)799			AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);800		affs_brelse(prev_bh);801		affs_fix_checksum(sb, bh);802		mark_buffer_dirty_inode(bh, inode);803		written += tmp;804		from += tmp;805		bidx++;806	}807	folio_mark_uptodate(folio);808 809done:810	affs_brelse(bh);811	tmp = (folio->index << PAGE_SHIFT) + from;812	if (tmp > inode->i_size)813		inode->i_size = AFFS_I(inode)->mmu_private = tmp;814 815	/* Clear Archived bit on file writes, as AmigaOS would do */816	if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) {817		AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED;818		mark_inode_dirty(inode);819	}820 821err_first_bh:822	folio_unlock(folio);823	folio_put(folio);824 825	return written;826 827err_bh:828	bh = prev_bh;829	if (!written)830		written = PTR_ERR(bh);831	goto done;832}833 834const struct address_space_operations affs_aops_ofs = {835	.dirty_folio	= block_dirty_folio,836	.invalidate_folio = block_invalidate_folio,837	.read_folio = affs_read_folio_ofs,838	//.writepages = affs_writepages_ofs,839	.write_begin = affs_write_begin_ofs,840	.write_end = affs_write_end_ofs,841	.migrate_folio = filemap_migrate_folio,842};843 844/* Free any preallocated blocks. */845 846void847affs_free_prealloc(struct inode *inode)848{849	struct super_block *sb = inode->i_sb;850 851	pr_debug("free_prealloc(ino=%lu)\n", inode->i_ino);852 853	while (AFFS_I(inode)->i_pa_cnt) {854		AFFS_I(inode)->i_pa_cnt--;855		affs_free_block(sb, ++AFFS_I(inode)->i_lastalloc);856	}857}858 859/* Truncate (or enlarge) a file to the requested size. */860 861void862affs_truncate(struct inode *inode)863{864	struct super_block *sb = inode->i_sb;865	u32 ext, ext_key;866	u32 last_blk, blkcnt, blk;867	u32 size;868	struct buffer_head *ext_bh;869	int i;870 871	pr_debug("truncate(inode=%lu, oldsize=%llu, newsize=%llu)\n",872		 inode->i_ino, AFFS_I(inode)->mmu_private, inode->i_size);873 874	last_blk = 0;875	ext = 0;876	if (inode->i_size) {877		last_blk = ((u32)inode->i_size - 1) / AFFS_SB(sb)->s_data_blksize;878		ext = last_blk / AFFS_SB(sb)->s_hashsize;879	}880 881	if (inode->i_size > AFFS_I(inode)->mmu_private) {882		struct address_space *mapping = inode->i_mapping;883		struct folio *folio;884		void *fsdata = NULL;885		loff_t isize = inode->i_size;886		int res;887 888		res = mapping->a_ops->write_begin(NULL, mapping, isize, 0, &folio, &fsdata);889		if (!res)890			res = mapping->a_ops->write_end(NULL, mapping, isize, 0, 0, folio, fsdata);891		else892			inode->i_size = AFFS_I(inode)->mmu_private;893		mark_inode_dirty(inode);894		return;895	} else if (inode->i_size == AFFS_I(inode)->mmu_private)896		return;897 898	// lock cache899	ext_bh = affs_get_extblock(inode, ext);900	if (IS_ERR(ext_bh)) {901		affs_warning(sb, "truncate",902			     "unexpected read error for ext block %u (%ld)",903			     ext, PTR_ERR(ext_bh));904		return;905	}906	if (AFFS_I(inode)->i_lc) {907		/* clear linear cache */908		i = (ext + 1) >> AFFS_I(inode)->i_lc_shift;909		if (AFFS_I(inode)->i_lc_size > i) {910			AFFS_I(inode)->i_lc_size = i;911			for (; i < AFFS_LC_SIZE; i++)912				AFFS_I(inode)->i_lc[i] = 0;913		}914		/* clear associative cache */915		for (i = 0; i < AFFS_AC_SIZE; i++)916			if (AFFS_I(inode)->i_ac[i].ext >= ext)917				AFFS_I(inode)->i_ac[i].ext = 0;918	}919	ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);920 921	blkcnt = AFFS_I(inode)->i_blkcnt;922	i = 0;923	blk = last_blk;924	if (inode->i_size) {925		i = last_blk % AFFS_SB(sb)->s_hashsize + 1;926		blk++;927	} else928		AFFS_HEAD(ext_bh)->first_data = 0;929	AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i);930	size = AFFS_SB(sb)->s_hashsize;931	if (size > blkcnt - blk + i)932		size = blkcnt - blk + i;933	for (; i < size; i++, blk++) {934		affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));935		AFFS_BLOCK(sb, ext_bh, i) = 0;936	}937	AFFS_TAIL(sb, ext_bh)->extension = 0;938	affs_fix_checksum(sb, ext_bh);939	mark_buffer_dirty_inode(ext_bh, inode);940	affs_brelse(ext_bh);941 942	if (inode->i_size) {943		AFFS_I(inode)->i_blkcnt = last_blk + 1;944		AFFS_I(inode)->i_extcnt = ext + 1;945		if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS)) {946			struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);947			u32 tmp;948			if (IS_ERR(bh)) {949				affs_warning(sb, "truncate",950					     "unexpected read error for last block %u (%ld)",951					     ext, PTR_ERR(bh));952				return;953			}954			tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);955			AFFS_DATA_HEAD(bh)->next = 0;956			affs_adjust_checksum(bh, -tmp);957			affs_brelse(bh);958		}959	} else {960		AFFS_I(inode)->i_blkcnt = 0;961		AFFS_I(inode)->i_extcnt = 1;962	}963	AFFS_I(inode)->mmu_private = inode->i_size;964	// unlock cache965 966	while (ext_key) {967		ext_bh = affs_bread(sb, ext_key);968		size = AFFS_SB(sb)->s_hashsize;969		if (size > blkcnt - blk)970			size = blkcnt - blk;971		for (i = 0; i < size; i++, blk++)972			affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));973		affs_free_block(sb, ext_key);974		ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);975		affs_brelse(ext_bh);976	}977	affs_free_prealloc(inode);978}979 980int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)981{982	struct inode *inode = filp->f_mapping->host;983	int ret, err;984 985	err = file_write_and_wait_range(filp, start, end);986	if (err)987		return err;988 989	inode_lock(inode);990	ret = write_inode_now(inode, 0);991	err = sync_blockdev(inode->i_sb->s_bdev);992	if (!ret)993		ret = err;994	inode_unlock(inode);995	return ret;996}997const struct file_operations affs_file_operations = {998	.llseek		= generic_file_llseek,999	.read_iter	= generic_file_read_iter,1000	.write_iter	= generic_file_write_iter,1001	.mmap		= generic_file_mmap,1002	.open		= affs_file_open,1003	.release	= affs_file_release,1004	.fsync		= affs_file_fsync,1005	.splice_read	= filemap_splice_read,1006};1007 1008const struct inode_operations affs_file_inode_operations = {1009	.setattr	= affs_notify_change,1010};1011