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