1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/fs/affs/file.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * (c) 1996 Hans-Joachim Widmaier - Rewritten 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * (C) 1991 Linus Torvalds - minix filesystem 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * affs regular file handling primitives 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 16e2e40f2cSChristoph Hellwig #include <linux/uio.h> 173f1266f1SChristoph Hellwig #include <linux/blkdev.h> 181da177e4SLinus Torvalds #include "affs.h" 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext); 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds static int 231da177e4SLinus Torvalds affs_file_open(struct inode *inode, struct file *filp) 241da177e4SLinus Torvalds { 259606d9aaSFabian Frederick pr_debug("open(%lu,%d)\n", 26dca3c336SRoman Zippel inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); 27dca3c336SRoman Zippel atomic_inc(&AFFS_I(inode)->i_opencnt); 281da177e4SLinus Torvalds return 0; 291da177e4SLinus Torvalds } 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds static int 321da177e4SLinus Torvalds affs_file_release(struct inode *inode, struct file *filp) 331da177e4SLinus Torvalds { 349606d9aaSFabian Frederick pr_debug("release(%lu, %d)\n", 35dca3c336SRoman Zippel inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); 36dca3c336SRoman Zippel 37dca3c336SRoman Zippel if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) { 385955102cSAl Viro inode_lock(inode); 39dca3c336SRoman Zippel if (inode->i_size != AFFS_I(inode)->mmu_private) 40dca3c336SRoman Zippel affs_truncate(inode); 411da177e4SLinus Torvalds affs_free_prealloc(inode); 425955102cSAl Viro inode_unlock(inode); 43dca3c336SRoman Zippel } 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds return 0; 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds static int 491da177e4SLinus Torvalds affs_grow_extcache(struct inode *inode, u32 lc_idx) 501da177e4SLinus Torvalds { 511da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 521da177e4SLinus Torvalds struct buffer_head *bh; 531da177e4SLinus Torvalds u32 lc_max; 541da177e4SLinus Torvalds int i, j, key; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds if (!AFFS_I(inode)->i_lc) { 571da177e4SLinus Torvalds char *ptr = (char *)get_zeroed_page(GFP_NOFS); 581da177e4SLinus Torvalds if (!ptr) 591da177e4SLinus Torvalds return -ENOMEM; 601da177e4SLinus Torvalds AFFS_I(inode)->i_lc = (u32 *)ptr; 611da177e4SLinus Torvalds AFFS_I(inode)->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2); 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds lc_max = AFFS_LC_SIZE << AFFS_I(inode)->i_lc_shift; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds if (AFFS_I(inode)->i_extcnt > lc_max) { 671da177e4SLinus Torvalds u32 lc_shift, lc_mask, tmp, off; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds /* need to recalculate linear cache, start from old size */ 701da177e4SLinus Torvalds lc_shift = AFFS_I(inode)->i_lc_shift; 711da177e4SLinus Torvalds tmp = (AFFS_I(inode)->i_extcnt / AFFS_LC_SIZE) >> lc_shift; 721da177e4SLinus Torvalds for (; tmp; tmp >>= 1) 731da177e4SLinus Torvalds lc_shift++; 741da177e4SLinus Torvalds lc_mask = (1 << lc_shift) - 1; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds /* fix idx and old size to new shift */ 771da177e4SLinus Torvalds lc_idx >>= (lc_shift - AFFS_I(inode)->i_lc_shift); 781da177e4SLinus Torvalds AFFS_I(inode)->i_lc_size >>= (lc_shift - AFFS_I(inode)->i_lc_shift); 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds /* first shrink old cache to make more space */ 811da177e4SLinus Torvalds off = 1 << (lc_shift - AFFS_I(inode)->i_lc_shift); 821da177e4SLinus Torvalds for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off) 831da177e4SLinus Torvalds AFFS_I(inode)->i_ac[i] = AFFS_I(inode)->i_ac[j]; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds AFFS_I(inode)->i_lc_shift = lc_shift; 861da177e4SLinus Torvalds AFFS_I(inode)->i_lc_mask = lc_mask; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds /* fill cache to the needed index */ 901da177e4SLinus Torvalds i = AFFS_I(inode)->i_lc_size; 911da177e4SLinus Torvalds AFFS_I(inode)->i_lc_size = lc_idx + 1; 921da177e4SLinus Torvalds for (; i <= lc_idx; i++) { 931da177e4SLinus Torvalds if (!i) { 941da177e4SLinus Torvalds AFFS_I(inode)->i_lc[0] = inode->i_ino; 951da177e4SLinus Torvalds continue; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds key = AFFS_I(inode)->i_lc[i - 1]; 981da177e4SLinus Torvalds j = AFFS_I(inode)->i_lc_mask + 1; 991da177e4SLinus Torvalds // unlock cache 1001da177e4SLinus Torvalds for (; j > 0; j--) { 1011da177e4SLinus Torvalds bh = affs_bread(sb, key); 1021da177e4SLinus Torvalds if (!bh) 1031da177e4SLinus Torvalds goto err; 1041da177e4SLinus Torvalds key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 1051da177e4SLinus Torvalds affs_brelse(bh); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds // lock cache 1081da177e4SLinus Torvalds AFFS_I(inode)->i_lc[i] = key; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds return 0; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds err: 1141da177e4SLinus Torvalds // lock cache 1151da177e4SLinus Torvalds return -EIO; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds static struct buffer_head * 1191da177e4SLinus Torvalds affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 1221da177e4SLinus Torvalds struct buffer_head *new_bh; 1231da177e4SLinus Torvalds u32 blocknr, tmp; 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds blocknr = affs_alloc_block(inode, bh->b_blocknr); 1261da177e4SLinus Torvalds if (!blocknr) 1271da177e4SLinus Torvalds return ERR_PTR(-ENOSPC); 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds new_bh = affs_getzeroblk(sb, blocknr); 1301da177e4SLinus Torvalds if (!new_bh) { 1311da177e4SLinus Torvalds affs_free_block(sb, blocknr); 1321da177e4SLinus Torvalds return ERR_PTR(-EIO); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST); 1361da177e4SLinus Torvalds AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr); 1371da177e4SLinus Torvalds AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE); 1381da177e4SLinus Torvalds AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino); 1391da177e4SLinus Torvalds affs_fix_checksum(sb, new_bh); 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds mark_buffer_dirty_inode(new_bh, inode); 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 1441da177e4SLinus Torvalds if (tmp) 1451da177e4SLinus Torvalds affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp); 1461da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr); 1471da177e4SLinus Torvalds affs_adjust_checksum(bh, blocknr - tmp); 1481da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds AFFS_I(inode)->i_extcnt++; 1511da177e4SLinus Torvalds mark_inode_dirty(inode); 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds return new_bh; 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds static inline struct buffer_head * 1571da177e4SLinus Torvalds affs_get_extblock(struct inode *inode, u32 ext) 1581da177e4SLinus Torvalds { 1591da177e4SLinus Torvalds /* inline the simplest case: same extended block as last time */ 1601da177e4SLinus Torvalds struct buffer_head *bh = AFFS_I(inode)->i_ext_bh; 1611da177e4SLinus Torvalds if (ext == AFFS_I(inode)->i_ext_last) 162dca3c336SRoman Zippel get_bh(bh); 1631da177e4SLinus Torvalds else 1641da177e4SLinus Torvalds /* we have to do more (not inlined) */ 1651da177e4SLinus Torvalds bh = affs_get_extblock_slow(inode, ext); 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds return bh; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds static struct buffer_head * 1711da177e4SLinus Torvalds affs_get_extblock_slow(struct inode *inode, u32 ext) 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 1741da177e4SLinus Torvalds struct buffer_head *bh; 1751da177e4SLinus Torvalds u32 ext_key; 1761da177e4SLinus Torvalds u32 lc_idx, lc_off, ac_idx; 1771da177e4SLinus Torvalds u32 tmp, idx; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds if (ext == AFFS_I(inode)->i_ext_last + 1) { 1801da177e4SLinus Torvalds /* read the next extended block from the current one */ 1811da177e4SLinus Torvalds bh = AFFS_I(inode)->i_ext_bh; 1821da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 1831da177e4SLinus Torvalds if (ext < AFFS_I(inode)->i_extcnt) 1841da177e4SLinus Torvalds goto read_ext; 185afe305dcSFabian Frederick BUG_ON(ext > AFFS_I(inode)->i_extcnt); 1861da177e4SLinus Torvalds bh = affs_alloc_extblock(inode, bh, ext); 1871da177e4SLinus Torvalds if (IS_ERR(bh)) 1881da177e4SLinus Torvalds return bh; 1891da177e4SLinus Torvalds goto store_ext; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds if (ext == 0) { 1931da177e4SLinus Torvalds /* we seek back to the file header block */ 1941da177e4SLinus Torvalds ext_key = inode->i_ino; 1951da177e4SLinus Torvalds goto read_ext; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds if (ext >= AFFS_I(inode)->i_extcnt) { 1991da177e4SLinus Torvalds struct buffer_head *prev_bh; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds /* allocate a new extended block */ 202afe305dcSFabian Frederick BUG_ON(ext > AFFS_I(inode)->i_extcnt); 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds /* get previous extended block */ 2051da177e4SLinus Torvalds prev_bh = affs_get_extblock(inode, ext - 1); 2061da177e4SLinus Torvalds if (IS_ERR(prev_bh)) 2071da177e4SLinus Torvalds return prev_bh; 2081da177e4SLinus Torvalds bh = affs_alloc_extblock(inode, prev_bh, ext); 2091da177e4SLinus Torvalds affs_brelse(prev_bh); 2101da177e4SLinus Torvalds if (IS_ERR(bh)) 2111da177e4SLinus Torvalds return bh; 2121da177e4SLinus Torvalds goto store_ext; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds again: 2161da177e4SLinus Torvalds /* check if there is an extended cache and whether it's large enough */ 2171da177e4SLinus Torvalds lc_idx = ext >> AFFS_I(inode)->i_lc_shift; 2181da177e4SLinus Torvalds lc_off = ext & AFFS_I(inode)->i_lc_mask; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds if (lc_idx >= AFFS_I(inode)->i_lc_size) { 2211da177e4SLinus Torvalds int err; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds err = affs_grow_extcache(inode, lc_idx); 2241da177e4SLinus Torvalds if (err) 2251da177e4SLinus Torvalds return ERR_PTR(err); 2261da177e4SLinus Torvalds goto again; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /* every n'th key we find in the linear cache */ 2301da177e4SLinus Torvalds if (!lc_off) { 2311da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_lc[lc_idx]; 2321da177e4SLinus Torvalds goto read_ext; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds /* maybe it's still in the associative cache */ 2361da177e4SLinus Torvalds ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK; 2371da177e4SLinus Torvalds if (AFFS_I(inode)->i_ac[ac_idx].ext == ext) { 2381da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_ac[ac_idx].key; 2391da177e4SLinus Torvalds goto read_ext; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds /* try to find one of the previous extended blocks */ 2431da177e4SLinus Torvalds tmp = ext; 2441da177e4SLinus Torvalds idx = ac_idx; 2451da177e4SLinus Torvalds while (--tmp, --lc_off > 0) { 2461da177e4SLinus Torvalds idx = (idx - 1) & AFFS_AC_MASK; 2471da177e4SLinus Torvalds if (AFFS_I(inode)->i_ac[idx].ext == tmp) { 2481da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_ac[idx].key; 2491da177e4SLinus Torvalds goto find_ext; 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds /* fall back to the linear cache */ 2541da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_lc[lc_idx]; 2551da177e4SLinus Torvalds find_ext: 2561da177e4SLinus Torvalds /* read all extended blocks until we find the one we need */ 2571da177e4SLinus Torvalds //unlock cache 2581da177e4SLinus Torvalds do { 2591da177e4SLinus Torvalds bh = affs_bread(sb, ext_key); 2601da177e4SLinus Torvalds if (!bh) 2611da177e4SLinus Torvalds goto err_bread; 2621da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 2631da177e4SLinus Torvalds affs_brelse(bh); 2641da177e4SLinus Torvalds tmp++; 2651da177e4SLinus Torvalds } while (tmp < ext); 2661da177e4SLinus Torvalds //lock cache 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds /* store it in the associative cache */ 2691da177e4SLinus Torvalds // recalculate ac_idx? 2701da177e4SLinus Torvalds AFFS_I(inode)->i_ac[ac_idx].ext = ext; 2711da177e4SLinus Torvalds AFFS_I(inode)->i_ac[ac_idx].key = ext_key; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds read_ext: 2741da177e4SLinus Torvalds /* finally read the right extended block */ 2751da177e4SLinus Torvalds //unlock cache 2761da177e4SLinus Torvalds bh = affs_bread(sb, ext_key); 2771da177e4SLinus Torvalds if (!bh) 2781da177e4SLinus Torvalds goto err_bread; 2791da177e4SLinus Torvalds //lock cache 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds store_ext: 2821da177e4SLinus Torvalds /* release old cached extended block and store the new one */ 2831da177e4SLinus Torvalds affs_brelse(AFFS_I(inode)->i_ext_bh); 2841da177e4SLinus Torvalds AFFS_I(inode)->i_ext_last = ext; 2851da177e4SLinus Torvalds AFFS_I(inode)->i_ext_bh = bh; 286dca3c336SRoman Zippel get_bh(bh); 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds return bh; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds err_bread: 2911da177e4SLinus Torvalds affs_brelse(bh); 2921da177e4SLinus Torvalds return ERR_PTR(-EIO); 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds static int 2961da177e4SLinus Torvalds affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create) 2971da177e4SLinus Torvalds { 2981da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2991da177e4SLinus Torvalds struct buffer_head *ext_bh; 3001da177e4SLinus Torvalds u32 ext; 3011da177e4SLinus Torvalds 30208fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %llu)\n", __func__, inode->i_ino, 30308fe100dSGeert Uytterhoeven (unsigned long long)block); 3041da177e4SLinus Torvalds 3058d4b6900SJulia Lawall BUG_ON(block > (sector_t)0x7fffffffUL); 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds if (block >= AFFS_I(inode)->i_blkcnt) { 3081da177e4SLinus Torvalds if (block > AFFS_I(inode)->i_blkcnt || !create) 3091da177e4SLinus Torvalds goto err_big; 3101da177e4SLinus Torvalds } else 3111da177e4SLinus Torvalds create = 0; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds //lock cache 3141da177e4SLinus Torvalds affs_lock_ext(inode); 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds ext = (u32)block / AFFS_SB(sb)->s_hashsize; 3171da177e4SLinus Torvalds block -= ext * AFFS_SB(sb)->s_hashsize; 3181da177e4SLinus Torvalds ext_bh = affs_get_extblock(inode, ext); 3191da177e4SLinus Torvalds if (IS_ERR(ext_bh)) 3201da177e4SLinus Torvalds goto err_ext; 3211da177e4SLinus Torvalds map_bh(bh_result, sb, (sector_t)be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block))); 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds if (create) { 3241da177e4SLinus Torvalds u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr); 3251da177e4SLinus Torvalds if (!blocknr) 3261da177e4SLinus Torvalds goto err_alloc; 3271da177e4SLinus Torvalds set_buffer_new(bh_result); 3281da177e4SLinus Torvalds AFFS_I(inode)->mmu_private += AFFS_SB(sb)->s_data_blksize; 3291da177e4SLinus Torvalds AFFS_I(inode)->i_blkcnt++; 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds /* store new block */ 3321da177e4SLinus Torvalds if (bh_result->b_blocknr) 33308fe100dSGeert Uytterhoeven affs_warning(sb, "get_block", 33408fe100dSGeert Uytterhoeven "block already set (%llx)", 33508fe100dSGeert Uytterhoeven (unsigned long long)bh_result->b_blocknr); 3361da177e4SLinus Torvalds AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr); 3371da177e4SLinus Torvalds AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1); 3381da177e4SLinus Torvalds affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1); 3391da177e4SLinus Torvalds bh_result->b_blocknr = blocknr; 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds if (!block) { 3421da177e4SLinus Torvalds /* insert first block into header block */ 3431da177e4SLinus Torvalds u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data); 3441da177e4SLinus Torvalds if (tmp) 3451da177e4SLinus Torvalds affs_warning(sb, "get_block", "first block already set (%d)", tmp); 3461da177e4SLinus Torvalds AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr); 3471da177e4SLinus Torvalds affs_adjust_checksum(ext_bh, blocknr - tmp); 3481da177e4SLinus Torvalds } 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds affs_brelse(ext_bh); 3521da177e4SLinus Torvalds //unlock cache 3531da177e4SLinus Torvalds affs_unlock_ext(inode); 3541da177e4SLinus Torvalds return 0; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds err_big: 35708fe100dSGeert Uytterhoeven affs_error(inode->i_sb, "get_block", "strange block request %llu", 35808fe100dSGeert Uytterhoeven (unsigned long long)block); 3591da177e4SLinus Torvalds return -EIO; 3601da177e4SLinus Torvalds err_ext: 3611da177e4SLinus Torvalds // unlock cache 3621da177e4SLinus Torvalds affs_unlock_ext(inode); 3631da177e4SLinus Torvalds return PTR_ERR(ext_bh); 3641da177e4SLinus Torvalds err_alloc: 3651da177e4SLinus Torvalds brelse(ext_bh); 3661da177e4SLinus Torvalds clear_buffer_mapped(bh_result); 3671da177e4SLinus Torvalds bh_result->b_bdev = NULL; 3681da177e4SLinus Torvalds // unlock cache 3691da177e4SLinus Torvalds affs_unlock_ext(inode); 3701da177e4SLinus Torvalds return -ENOSPC; 3711da177e4SLinus Torvalds } 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds static int affs_writepage(struct page *page, struct writeback_control *wbc) 3741da177e4SLinus Torvalds { 3751da177e4SLinus Torvalds return block_write_full_page(page, affs_get_block, wbc); 3761da177e4SLinus Torvalds } 377f2b6a16eSNick Piggin 3782c69e205SMatthew Wilcox (Oracle) static int affs_read_folio(struct file *file, struct folio *folio) 3791da177e4SLinus Torvalds { 3802c69e205SMatthew Wilcox (Oracle) return block_read_full_folio(folio, affs_get_block); 3811da177e4SLinus Torvalds } 382f2b6a16eSNick Piggin 3831dc1834fSMarco Stornelli static void affs_write_failed(struct address_space *mapping, loff_t to) 3841dc1834fSMarco Stornelli { 3851dc1834fSMarco Stornelli struct inode *inode = mapping->host; 3861dc1834fSMarco Stornelli 3871dc1834fSMarco Stornelli if (to > inode->i_size) { 3887caef267SKirill A. Shutemov truncate_pagecache(inode, inode->i_size); 3891dc1834fSMarco Stornelli affs_truncate(inode); 3901dc1834fSMarco Stornelli } 3911dc1834fSMarco Stornelli } 3921dc1834fSMarco Stornelli 3939abb4083SFabian Frederick static ssize_t 394c8b8e32dSChristoph Hellwig affs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) 3959abb4083SFabian Frederick { 3969abb4083SFabian Frederick struct file *file = iocb->ki_filp; 3979abb4083SFabian Frederick struct address_space *mapping = file->f_mapping; 3989abb4083SFabian Frederick struct inode *inode = mapping->host; 3999abb4083SFabian Frederick size_t count = iov_iter_count(iter); 400c8b8e32dSChristoph Hellwig loff_t offset = iocb->ki_pos; 4019abb4083SFabian Frederick ssize_t ret; 4029abb4083SFabian Frederick 4036f673763SOmar Sandoval if (iov_iter_rw(iter) == WRITE) { 40492b20708SFabian Frederick loff_t size = offset + count; 40592b20708SFabian Frederick 40692b20708SFabian Frederick if (AFFS_I(inode)->mmu_private < size) 40792b20708SFabian Frederick return 0; 40892b20708SFabian Frederick } 40992b20708SFabian Frederick 410c8b8e32dSChristoph Hellwig ret = blockdev_direct_IO(iocb, inode, iter, affs_get_block); 4116f673763SOmar Sandoval if (ret < 0 && iov_iter_rw(iter) == WRITE) 4129abb4083SFabian Frederick affs_write_failed(mapping, offset + count); 4139abb4083SFabian Frederick return ret; 4149abb4083SFabian Frederick } 4159abb4083SFabian Frederick 416f2b6a16eSNick Piggin static int affs_write_begin(struct file *file, struct address_space *mapping, 4179d6b0cd7SMatthew Wilcox (Oracle) loff_t pos, unsigned len, 418f2b6a16eSNick Piggin struct page **pagep, void **fsdata) 4191da177e4SLinus Torvalds { 420282dc178SChristoph Hellwig int ret; 421282dc178SChristoph Hellwig 422f2b6a16eSNick Piggin *pagep = NULL; 423be3bbbc5SMatthew Wilcox (Oracle) ret = cont_write_begin(file, mapping, pos, len, pagep, fsdata, 424f2b6a16eSNick Piggin affs_get_block, 425f2b6a16eSNick Piggin &AFFS_I(mapping->host)->mmu_private); 4261dc1834fSMarco Stornelli if (unlikely(ret)) 4271dc1834fSMarco Stornelli affs_write_failed(mapping, pos + len); 428282dc178SChristoph Hellwig 429282dc178SChristoph Hellwig return ret; 4301da177e4SLinus Torvalds } 431f2b6a16eSNick Piggin 432d3a84a8dSMax Staudt static int affs_write_end(struct file *file, struct address_space *mapping, 433d3a84a8dSMax Staudt loff_t pos, unsigned int len, unsigned int copied, 434d3a84a8dSMax Staudt struct page *page, void *fsdata) 435d3a84a8dSMax Staudt { 436d3a84a8dSMax Staudt struct inode *inode = mapping->host; 437d3a84a8dSMax Staudt int ret; 438d3a84a8dSMax Staudt 439d3a84a8dSMax Staudt ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); 440d3a84a8dSMax Staudt 441d3a84a8dSMax Staudt /* Clear Archived bit on file writes, as AmigaOS would do */ 442d3a84a8dSMax Staudt if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) { 443d3a84a8dSMax Staudt AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED; 444d3a84a8dSMax Staudt mark_inode_dirty(inode); 445d3a84a8dSMax Staudt } 446d3a84a8dSMax Staudt 447d3a84a8dSMax Staudt return ret; 448d3a84a8dSMax Staudt } 449d3a84a8dSMax Staudt 4501da177e4SLinus Torvalds static sector_t _affs_bmap(struct address_space *mapping, sector_t block) 4511da177e4SLinus Torvalds { 4521da177e4SLinus Torvalds return generic_block_bmap(mapping,block,affs_get_block); 4531da177e4SLinus Torvalds } 454f2b6a16eSNick Piggin 455f5e54d6eSChristoph Hellwig const struct address_space_operations affs_aops = { 456e621900aSMatthew Wilcox (Oracle) .dirty_folio = block_dirty_folio, 4577ba13abbSMatthew Wilcox (Oracle) .invalidate_folio = block_invalidate_folio, 4582c69e205SMatthew Wilcox (Oracle) .read_folio = affs_read_folio, 4591da177e4SLinus Torvalds .writepage = affs_writepage, 460f2b6a16eSNick Piggin .write_begin = affs_write_begin, 461d3a84a8dSMax Staudt .write_end = affs_write_end, 4629abb4083SFabian Frederick .direct_IO = affs_direct_IO, 4631da177e4SLinus Torvalds .bmap = _affs_bmap 4641da177e4SLinus Torvalds }; 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds static inline struct buffer_head * 4671da177e4SLinus Torvalds affs_bread_ino(struct inode *inode, int block, int create) 4681da177e4SLinus Torvalds { 4691da177e4SLinus Torvalds struct buffer_head *bh, tmp_bh; 4701da177e4SLinus Torvalds int err; 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds tmp_bh.b_state = 0; 4731da177e4SLinus Torvalds err = affs_get_block(inode, block, &tmp_bh, create); 4741da177e4SLinus Torvalds if (!err) { 4751da177e4SLinus Torvalds bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr); 4761da177e4SLinus Torvalds if (bh) { 4771da177e4SLinus Torvalds bh->b_state |= tmp_bh.b_state; 4781da177e4SLinus Torvalds return bh; 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds err = -EIO; 4811da177e4SLinus Torvalds } 4821da177e4SLinus Torvalds return ERR_PTR(err); 4831da177e4SLinus Torvalds } 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds static inline struct buffer_head * 4861da177e4SLinus Torvalds affs_getzeroblk_ino(struct inode *inode, int block) 4871da177e4SLinus Torvalds { 4881da177e4SLinus Torvalds struct buffer_head *bh, tmp_bh; 4891da177e4SLinus Torvalds int err; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds tmp_bh.b_state = 0; 4921da177e4SLinus Torvalds err = affs_get_block(inode, block, &tmp_bh, 1); 4931da177e4SLinus Torvalds if (!err) { 4941da177e4SLinus Torvalds bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr); 4951da177e4SLinus Torvalds if (bh) { 4961da177e4SLinus Torvalds bh->b_state |= tmp_bh.b_state; 4971da177e4SLinus Torvalds return bh; 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds err = -EIO; 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds return ERR_PTR(err); 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds static inline struct buffer_head * 5051da177e4SLinus Torvalds affs_getemptyblk_ino(struct inode *inode, int block) 5061da177e4SLinus Torvalds { 5071da177e4SLinus Torvalds struct buffer_head *bh, tmp_bh; 5081da177e4SLinus Torvalds int err; 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds tmp_bh.b_state = 0; 5111da177e4SLinus Torvalds err = affs_get_block(inode, block, &tmp_bh, 1); 5121da177e4SLinus Torvalds if (!err) { 5131da177e4SLinus Torvalds bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr); 5141da177e4SLinus Torvalds if (bh) { 5151da177e4SLinus Torvalds bh->b_state |= tmp_bh.b_state; 5161da177e4SLinus Torvalds return bh; 5171da177e4SLinus Torvalds } 5181da177e4SLinus Torvalds err = -EIO; 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds return ERR_PTR(err); 5211da177e4SLinus Torvalds } 5221da177e4SLinus Torvalds 5231da177e4SLinus Torvalds static int 524077e073eSFabian Frederick affs_do_readpage_ofs(struct page *page, unsigned to, int create) 5251da177e4SLinus Torvalds { 5261da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 5271da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 5281da177e4SLinus Torvalds struct buffer_head *bh; 5291da177e4SLinus Torvalds char *data; 5300c89d670SFabian Frederick unsigned pos = 0; 5311da177e4SLinus Torvalds u32 bidx, boff, bsize; 5321da177e4SLinus Torvalds u32 tmp; 5331da177e4SLinus Torvalds 53408fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %ld, 0, %d)\n", __func__, inode->i_ino, 5350c89d670SFabian Frederick page->index, to); 53609cbfeafSKirill A. Shutemov BUG_ON(to > PAGE_SIZE); 5371da177e4SLinus Torvalds bsize = AFFS_SB(sb)->s_data_blksize; 53809cbfeafSKirill A. Shutemov tmp = page->index << PAGE_SHIFT; 5391da177e4SLinus Torvalds bidx = tmp / bsize; 5401da177e4SLinus Torvalds boff = tmp % bsize; 5411da177e4SLinus Torvalds 5420c89d670SFabian Frederick while (pos < to) { 543077e073eSFabian Frederick bh = affs_bread_ino(inode, bidx, create); 5441da177e4SLinus Torvalds if (IS_ERR(bh)) 5451da177e4SLinus Torvalds return PTR_ERR(bh); 5460c89d670SFabian Frederick tmp = min(bsize - boff, to - pos); 5470c89d670SFabian Frederick BUG_ON(pos + tmp > to || tmp > bsize); 5480bacbe52SAl Viro data = kmap_atomic(page); 5490c89d670SFabian Frederick memcpy(data + pos, AFFS_DATA(bh) + boff, tmp); 5500bacbe52SAl Viro kunmap_atomic(data); 5511da177e4SLinus Torvalds affs_brelse(bh); 5521da177e4SLinus Torvalds bidx++; 5530c89d670SFabian Frederick pos += tmp; 5541da177e4SLinus Torvalds boff = 0; 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds flush_dcache_page(page); 5571da177e4SLinus Torvalds return 0; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds static int 5611da177e4SLinus Torvalds affs_extent_file_ofs(struct inode *inode, u32 newsize) 5621da177e4SLinus Torvalds { 5631da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 5641da177e4SLinus Torvalds struct buffer_head *bh, *prev_bh; 5651da177e4SLinus Torvalds u32 bidx, boff; 5661da177e4SLinus Torvalds u32 size, bsize; 5671da177e4SLinus Torvalds u32 tmp; 5681da177e4SLinus Torvalds 56908fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %d)\n", __func__, inode->i_ino, newsize); 5701da177e4SLinus Torvalds bsize = AFFS_SB(sb)->s_data_blksize; 5711da177e4SLinus Torvalds bh = NULL; 5721da177e4SLinus Torvalds size = AFFS_I(inode)->mmu_private; 5731da177e4SLinus Torvalds bidx = size / bsize; 5741da177e4SLinus Torvalds boff = size % bsize; 5751da177e4SLinus Torvalds if (boff) { 5761da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 0); 5771da177e4SLinus Torvalds if (IS_ERR(bh)) 5781da177e4SLinus Torvalds return PTR_ERR(bh); 5791da177e4SLinus Torvalds tmp = min(bsize - boff, newsize - size); 5808d4b6900SJulia Lawall BUG_ON(boff + tmp > bsize || tmp > bsize); 5811da177e4SLinus Torvalds memset(AFFS_DATA(bh) + boff, 0, tmp); 5826369a4abSMarcin Slusarz be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp); 5831da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 5841da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 5851da177e4SLinus Torvalds size += tmp; 5861da177e4SLinus Torvalds bidx++; 5871da177e4SLinus Torvalds } else if (bidx) { 5881da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx - 1, 0); 5891da177e4SLinus Torvalds if (IS_ERR(bh)) 5901da177e4SLinus Torvalds return PTR_ERR(bh); 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds while (size < newsize) { 5941da177e4SLinus Torvalds prev_bh = bh; 5951da177e4SLinus Torvalds bh = affs_getzeroblk_ino(inode, bidx); 5961da177e4SLinus Torvalds if (IS_ERR(bh)) 5971da177e4SLinus Torvalds goto out; 5981da177e4SLinus Torvalds tmp = min(bsize, newsize - size); 5998d4b6900SJulia Lawall BUG_ON(tmp > bsize); 6001da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 6011da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); 6021da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); 6031da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); 6041da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 6051da177e4SLinus Torvalds bh->b_state &= ~(1UL << BH_New); 6061da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 6071da177e4SLinus Torvalds if (prev_bh) { 60873516aceSFabian Frederick u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); 60973516aceSFabian Frederick 61073516aceSFabian Frederick if (tmp_next) 61173516aceSFabian Frederick affs_warning(sb, "extent_file_ofs", 61273516aceSFabian Frederick "next block already set for %d (%d)", 61373516aceSFabian Frederick bidx, tmp_next); 6141da177e4SLinus Torvalds AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); 61573516aceSFabian Frederick affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next); 6161da177e4SLinus Torvalds mark_buffer_dirty_inode(prev_bh, inode); 6171da177e4SLinus Torvalds affs_brelse(prev_bh); 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds size += bsize; 6201da177e4SLinus Torvalds bidx++; 6211da177e4SLinus Torvalds } 6221da177e4SLinus Torvalds affs_brelse(bh); 6231da177e4SLinus Torvalds inode->i_size = AFFS_I(inode)->mmu_private = newsize; 6241da177e4SLinus Torvalds return 0; 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds out: 6271da177e4SLinus Torvalds inode->i_size = AFFS_I(inode)->mmu_private = newsize; 6281da177e4SLinus Torvalds return PTR_ERR(bh); 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds static int 632*1b6f3c87SMatthew Wilcox (Oracle) affs_read_folio_ofs(struct file *file, struct folio *folio) 6331da177e4SLinus Torvalds { 634*1b6f3c87SMatthew Wilcox (Oracle) struct page *page = &folio->page; 6351da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 6361da177e4SLinus Torvalds u32 to; 6371da177e4SLinus Torvalds int err; 6381da177e4SLinus Torvalds 63908fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %ld)\n", __func__, inode->i_ino, page->index); 64009cbfeafSKirill A. Shutemov to = PAGE_SIZE; 64109cbfeafSKirill A. Shutemov if (((page->index + 1) << PAGE_SHIFT) > inode->i_size) { 64209cbfeafSKirill A. Shutemov to = inode->i_size & ~PAGE_MASK; 64309cbfeafSKirill A. Shutemov memset(page_address(page) + to, 0, PAGE_SIZE - to); 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds 646077e073eSFabian Frederick err = affs_do_readpage_ofs(page, to, 0); 6471da177e4SLinus Torvalds if (!err) 6481da177e4SLinus Torvalds SetPageUptodate(page); 6491da177e4SLinus Torvalds unlock_page(page); 6501da177e4SLinus Torvalds return err; 6511da177e4SLinus Torvalds } 6521da177e4SLinus Torvalds 653f2b6a16eSNick Piggin static int affs_write_begin_ofs(struct file *file, struct address_space *mapping, 6549d6b0cd7SMatthew Wilcox (Oracle) loff_t pos, unsigned len, 655f2b6a16eSNick Piggin struct page **pagep, void **fsdata) 6561da177e4SLinus Torvalds { 657f2b6a16eSNick Piggin struct inode *inode = mapping->host; 658f2b6a16eSNick Piggin struct page *page; 659f2b6a16eSNick Piggin pgoff_t index; 6601da177e4SLinus Torvalds int err = 0; 6611da177e4SLinus Torvalds 66208fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos, 66308fe100dSGeert Uytterhoeven pos + len); 664f2b6a16eSNick Piggin if (pos > AFFS_I(inode)->mmu_private) { 665f2b6a16eSNick Piggin /* XXX: this probably leaves a too-big i_size in case of 666f2b6a16eSNick Piggin * failure. Should really be updating i_size at write_end time 667f2b6a16eSNick Piggin */ 668f2b6a16eSNick Piggin err = affs_extent_file_ofs(inode, pos); 6691da177e4SLinus Torvalds if (err) 6701da177e4SLinus Torvalds return err; 6711da177e4SLinus Torvalds } 672f2b6a16eSNick Piggin 67309cbfeafSKirill A. Shutemov index = pos >> PAGE_SHIFT; 674b7446e7cSMatthew Wilcox (Oracle) page = grab_cache_page_write_begin(mapping, index); 675f2b6a16eSNick Piggin if (!page) 676f2b6a16eSNick Piggin return -ENOMEM; 677f2b6a16eSNick Piggin *pagep = page; 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds if (PageUptodate(page)) 6801da177e4SLinus Torvalds return 0; 6811da177e4SLinus Torvalds 682f2b6a16eSNick Piggin /* XXX: inefficient but safe in the face of short writes */ 683077e073eSFabian Frederick err = affs_do_readpage_ofs(page, PAGE_SIZE, 1); 684f2b6a16eSNick Piggin if (err) { 685f2b6a16eSNick Piggin unlock_page(page); 68609cbfeafSKirill A. Shutemov put_page(page); 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds return err; 6891da177e4SLinus Torvalds } 6901da177e4SLinus Torvalds 691f2b6a16eSNick Piggin static int affs_write_end_ofs(struct file *file, struct address_space *mapping, 692f2b6a16eSNick Piggin loff_t pos, unsigned len, unsigned copied, 693f2b6a16eSNick Piggin struct page *page, void *fsdata) 6941da177e4SLinus Torvalds { 695f2b6a16eSNick Piggin struct inode *inode = mapping->host; 6961da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 6971da177e4SLinus Torvalds struct buffer_head *bh, *prev_bh; 6981da177e4SLinus Torvalds char *data; 6991da177e4SLinus Torvalds u32 bidx, boff, bsize; 700f2b6a16eSNick Piggin unsigned from, to; 7011da177e4SLinus Torvalds u32 tmp; 7021da177e4SLinus Torvalds int written; 7031da177e4SLinus Torvalds 70409cbfeafSKirill A. Shutemov from = pos & (PAGE_SIZE - 1); 705a80f2d22SFabian Frederick to = from + len; 706f2b6a16eSNick Piggin /* 707f2b6a16eSNick Piggin * XXX: not sure if this can handle short copies (len < copied), but 708f2b6a16eSNick Piggin * we don't have to, because the page should always be uptodate here, 709f2b6a16eSNick Piggin * due to write_begin. 710f2b6a16eSNick Piggin */ 711f2b6a16eSNick Piggin 71208fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos, 71308fe100dSGeert Uytterhoeven pos + len); 7141da177e4SLinus Torvalds bsize = AFFS_SB(sb)->s_data_blksize; 7151da177e4SLinus Torvalds data = page_address(page); 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds bh = NULL; 7181da177e4SLinus Torvalds written = 0; 71909cbfeafSKirill A. Shutemov tmp = (page->index << PAGE_SHIFT) + from; 7201da177e4SLinus Torvalds bidx = tmp / bsize; 7211da177e4SLinus Torvalds boff = tmp % bsize; 7221da177e4SLinus Torvalds if (boff) { 7231da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 0); 7243d5d472cSTaesoo Kim if (IS_ERR(bh)) { 7253d5d472cSTaesoo Kim written = PTR_ERR(bh); 7263d5d472cSTaesoo Kim goto err_first_bh; 7273d5d472cSTaesoo Kim } 7281da177e4SLinus Torvalds tmp = min(bsize - boff, to - from); 7298d4b6900SJulia Lawall BUG_ON(boff + tmp > bsize || tmp > bsize); 7301da177e4SLinus Torvalds memcpy(AFFS_DATA(bh) + boff, data + from, tmp); 7316369a4abSMarcin Slusarz be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp); 7321da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 7331da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 7341da177e4SLinus Torvalds written += tmp; 7351da177e4SLinus Torvalds from += tmp; 7361da177e4SLinus Torvalds bidx++; 7371da177e4SLinus Torvalds } else if (bidx) { 7381da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx - 1, 0); 7393d5d472cSTaesoo Kim if (IS_ERR(bh)) { 7403d5d472cSTaesoo Kim written = PTR_ERR(bh); 7413d5d472cSTaesoo Kim goto err_first_bh; 7423d5d472cSTaesoo Kim } 7431da177e4SLinus Torvalds } 7441da177e4SLinus Torvalds while (from + bsize <= to) { 7451da177e4SLinus Torvalds prev_bh = bh; 7461da177e4SLinus Torvalds bh = affs_getemptyblk_ino(inode, bidx); 7471da177e4SLinus Torvalds if (IS_ERR(bh)) 7483d5d472cSTaesoo Kim goto err_bh; 7491da177e4SLinus Torvalds memcpy(AFFS_DATA(bh), data + from, bsize); 7501da177e4SLinus Torvalds if (buffer_new(bh)) { 7511da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 7521da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); 7531da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); 7541da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize); 7551da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->next = 0; 7561da177e4SLinus Torvalds bh->b_state &= ~(1UL << BH_New); 7571da177e4SLinus Torvalds if (prev_bh) { 75873516aceSFabian Frederick u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); 75973516aceSFabian Frederick 76073516aceSFabian Frederick if (tmp_next) 76173516aceSFabian Frederick affs_warning(sb, "commit_write_ofs", 76273516aceSFabian Frederick "next block already set for %d (%d)", 76373516aceSFabian Frederick bidx, tmp_next); 7641da177e4SLinus Torvalds AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); 76573516aceSFabian Frederick affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next); 7661da177e4SLinus Torvalds mark_buffer_dirty_inode(prev_bh, inode); 7671da177e4SLinus Torvalds } 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds affs_brelse(prev_bh); 7701da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 7711da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 7721da177e4SLinus Torvalds written += bsize; 7731da177e4SLinus Torvalds from += bsize; 7741da177e4SLinus Torvalds bidx++; 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds if (from < to) { 7771da177e4SLinus Torvalds prev_bh = bh; 7781da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 1); 7791da177e4SLinus Torvalds if (IS_ERR(bh)) 7803d5d472cSTaesoo Kim goto err_bh; 7811da177e4SLinus Torvalds tmp = min(bsize, to - from); 7828d4b6900SJulia Lawall BUG_ON(tmp > bsize); 7831da177e4SLinus Torvalds memcpy(AFFS_DATA(bh), data + from, tmp); 7841da177e4SLinus Torvalds if (buffer_new(bh)) { 7851da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 7861da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); 7871da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); 7881da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); 7891da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->next = 0; 7901da177e4SLinus Torvalds bh->b_state &= ~(1UL << BH_New); 7911da177e4SLinus Torvalds if (prev_bh) { 79273516aceSFabian Frederick u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); 79373516aceSFabian Frederick 79473516aceSFabian Frederick if (tmp_next) 79573516aceSFabian Frederick affs_warning(sb, "commit_write_ofs", 79673516aceSFabian Frederick "next block already set for %d (%d)", 79773516aceSFabian Frederick bidx, tmp_next); 7981da177e4SLinus Torvalds AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); 79973516aceSFabian Frederick affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next); 8001da177e4SLinus Torvalds mark_buffer_dirty_inode(prev_bh, inode); 8011da177e4SLinus Torvalds } 8021da177e4SLinus Torvalds } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp) 8031da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); 8041da177e4SLinus Torvalds affs_brelse(prev_bh); 8051da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 8061da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 8071da177e4SLinus Torvalds written += tmp; 8081da177e4SLinus Torvalds from += tmp; 8091da177e4SLinus Torvalds bidx++; 8101da177e4SLinus Torvalds } 8111da177e4SLinus Torvalds SetPageUptodate(page); 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds done: 8141da177e4SLinus Torvalds affs_brelse(bh); 81509cbfeafSKirill A. Shutemov tmp = (page->index << PAGE_SHIFT) + from; 8161da177e4SLinus Torvalds if (tmp > inode->i_size) 8171da177e4SLinus Torvalds inode->i_size = AFFS_I(inode)->mmu_private = tmp; 8181da177e4SLinus Torvalds 819d3a84a8dSMax Staudt /* Clear Archived bit on file writes, as AmigaOS would do */ 820d3a84a8dSMax Staudt if (AFFS_I(inode)->i_protect & FIBF_ARCHIVED) { 821d3a84a8dSMax Staudt AFFS_I(inode)->i_protect &= ~FIBF_ARCHIVED; 822d3a84a8dSMax Staudt mark_inode_dirty(inode); 823d3a84a8dSMax Staudt } 824d3a84a8dSMax Staudt 8253d5d472cSTaesoo Kim err_first_bh: 826f2b6a16eSNick Piggin unlock_page(page); 82709cbfeafSKirill A. Shutemov put_page(page); 828f2b6a16eSNick Piggin 8291da177e4SLinus Torvalds return written; 8301da177e4SLinus Torvalds 8313d5d472cSTaesoo Kim err_bh: 8321da177e4SLinus Torvalds bh = prev_bh; 8331da177e4SLinus Torvalds if (!written) 8341da177e4SLinus Torvalds written = PTR_ERR(bh); 8351da177e4SLinus Torvalds goto done; 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 838f5e54d6eSChristoph Hellwig const struct address_space_operations affs_aops_ofs = { 839e621900aSMatthew Wilcox (Oracle) .dirty_folio = block_dirty_folio, 8407ba13abbSMatthew Wilcox (Oracle) .invalidate_folio = block_invalidate_folio, 841*1b6f3c87SMatthew Wilcox (Oracle) .read_folio = affs_read_folio_ofs, 8421da177e4SLinus Torvalds //.writepage = affs_writepage_ofs, 843f2b6a16eSNick Piggin .write_begin = affs_write_begin_ofs, 844f2b6a16eSNick Piggin .write_end = affs_write_end_ofs 8451da177e4SLinus Torvalds }; 8461da177e4SLinus Torvalds 8471da177e4SLinus Torvalds /* Free any preallocated blocks. */ 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds void 8501da177e4SLinus Torvalds affs_free_prealloc(struct inode *inode) 8511da177e4SLinus Torvalds { 8521da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 8531da177e4SLinus Torvalds 8549606d9aaSFabian Frederick pr_debug("free_prealloc(ino=%lu)\n", inode->i_ino); 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds while (AFFS_I(inode)->i_pa_cnt) { 8571da177e4SLinus Torvalds AFFS_I(inode)->i_pa_cnt--; 8581da177e4SLinus Torvalds affs_free_block(sb, ++AFFS_I(inode)->i_lastalloc); 8591da177e4SLinus Torvalds } 8601da177e4SLinus Torvalds } 8611da177e4SLinus Torvalds 8621da177e4SLinus Torvalds /* Truncate (or enlarge) a file to the requested size. */ 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds void 8651da177e4SLinus Torvalds affs_truncate(struct inode *inode) 8661da177e4SLinus Torvalds { 8671da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 8681da177e4SLinus Torvalds u32 ext, ext_key; 8691da177e4SLinus Torvalds u32 last_blk, blkcnt, blk; 8701da177e4SLinus Torvalds u32 size; 8711da177e4SLinus Torvalds struct buffer_head *ext_bh; 8721da177e4SLinus Torvalds int i; 8731da177e4SLinus Torvalds 87408fe100dSGeert Uytterhoeven pr_debug("truncate(inode=%lu, oldsize=%llu, newsize=%llu)\n", 87508fe100dSGeert Uytterhoeven inode->i_ino, AFFS_I(inode)->mmu_private, inode->i_size); 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds last_blk = 0; 8781da177e4SLinus Torvalds ext = 0; 8791da177e4SLinus Torvalds if (inode->i_size) { 8801da177e4SLinus Torvalds last_blk = ((u32)inode->i_size - 1) / AFFS_SB(sb)->s_data_blksize; 8811da177e4SLinus Torvalds ext = last_blk / AFFS_SB(sb)->s_hashsize; 8821da177e4SLinus Torvalds } 8831da177e4SLinus Torvalds 8841da177e4SLinus Torvalds if (inode->i_size > AFFS_I(inode)->mmu_private) { 8851da177e4SLinus Torvalds struct address_space *mapping = inode->i_mapping; 8861da177e4SLinus Torvalds struct page *page; 887f2b6a16eSNick Piggin void *fsdata; 88873516aceSFabian Frederick loff_t isize = inode->i_size; 8891da177e4SLinus Torvalds int res; 8901da177e4SLinus Torvalds 8919d6b0cd7SMatthew Wilcox (Oracle) res = mapping->a_ops->write_begin(NULL, mapping, isize, 0, &page, &fsdata); 8921da177e4SLinus Torvalds if (!res) 89373516aceSFabian Frederick res = mapping->a_ops->write_end(NULL, mapping, isize, 0, 0, page, fsdata); 894dca3c336SRoman Zippel else 895dca3c336SRoman Zippel inode->i_size = AFFS_I(inode)->mmu_private; 8961da177e4SLinus Torvalds mark_inode_dirty(inode); 8971da177e4SLinus Torvalds return; 8981da177e4SLinus Torvalds } else if (inode->i_size == AFFS_I(inode)->mmu_private) 8991da177e4SLinus Torvalds return; 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds // lock cache 9021da177e4SLinus Torvalds ext_bh = affs_get_extblock(inode, ext); 9031da177e4SLinus Torvalds if (IS_ERR(ext_bh)) { 9041ee54b09SFabian Frederick affs_warning(sb, "truncate", 9051ee54b09SFabian Frederick "unexpected read error for ext block %u (%ld)", 90608fe100dSGeert Uytterhoeven ext, PTR_ERR(ext_bh)); 9071da177e4SLinus Torvalds return; 9081da177e4SLinus Torvalds } 9091da177e4SLinus Torvalds if (AFFS_I(inode)->i_lc) { 9101da177e4SLinus Torvalds /* clear linear cache */ 9111da177e4SLinus Torvalds i = (ext + 1) >> AFFS_I(inode)->i_lc_shift; 9121da177e4SLinus Torvalds if (AFFS_I(inode)->i_lc_size > i) { 9131da177e4SLinus Torvalds AFFS_I(inode)->i_lc_size = i; 9141da177e4SLinus Torvalds for (; i < AFFS_LC_SIZE; i++) 9151da177e4SLinus Torvalds AFFS_I(inode)->i_lc[i] = 0; 9161da177e4SLinus Torvalds } 9171da177e4SLinus Torvalds /* clear associative cache */ 9181da177e4SLinus Torvalds for (i = 0; i < AFFS_AC_SIZE; i++) 9191da177e4SLinus Torvalds if (AFFS_I(inode)->i_ac[i].ext >= ext) 9201da177e4SLinus Torvalds AFFS_I(inode)->i_ac[i].ext = 0; 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds blkcnt = AFFS_I(inode)->i_blkcnt; 9251da177e4SLinus Torvalds i = 0; 9261da177e4SLinus Torvalds blk = last_blk; 9271da177e4SLinus Torvalds if (inode->i_size) { 9281da177e4SLinus Torvalds i = last_blk % AFFS_SB(sb)->s_hashsize + 1; 9291da177e4SLinus Torvalds blk++; 9301da177e4SLinus Torvalds } else 9311da177e4SLinus Torvalds AFFS_HEAD(ext_bh)->first_data = 0; 932dca3c336SRoman Zippel AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i); 9331da177e4SLinus Torvalds size = AFFS_SB(sb)->s_hashsize; 9341da177e4SLinus Torvalds if (size > blkcnt - blk + i) 9351da177e4SLinus Torvalds size = blkcnt - blk + i; 9361da177e4SLinus Torvalds for (; i < size; i++, blk++) { 9371da177e4SLinus Torvalds affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i))); 9381da177e4SLinus Torvalds AFFS_BLOCK(sb, ext_bh, i) = 0; 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds AFFS_TAIL(sb, ext_bh)->extension = 0; 9411da177e4SLinus Torvalds affs_fix_checksum(sb, ext_bh); 9421da177e4SLinus Torvalds mark_buffer_dirty_inode(ext_bh, inode); 9431da177e4SLinus Torvalds affs_brelse(ext_bh); 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds if (inode->i_size) { 9461da177e4SLinus Torvalds AFFS_I(inode)->i_blkcnt = last_blk + 1; 9471da177e4SLinus Torvalds AFFS_I(inode)->i_extcnt = ext + 1; 94879bda4d5SFabian Frederick if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS)) { 9491da177e4SLinus Torvalds struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0); 9501da177e4SLinus Torvalds u32 tmp; 9510e45b67dSDan Carpenter if (IS_ERR(bh)) { 9521ee54b09SFabian Frederick affs_warning(sb, "truncate", 9531ee54b09SFabian Frederick "unexpected read error for last block %u (%ld)", 95408fe100dSGeert Uytterhoeven ext, PTR_ERR(bh)); 9551da177e4SLinus Torvalds return; 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next); 9581da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->next = 0; 9591da177e4SLinus Torvalds affs_adjust_checksum(bh, -tmp); 9601da177e4SLinus Torvalds affs_brelse(bh); 9611da177e4SLinus Torvalds } 9621da177e4SLinus Torvalds } else { 9631da177e4SLinus Torvalds AFFS_I(inode)->i_blkcnt = 0; 9641da177e4SLinus Torvalds AFFS_I(inode)->i_extcnt = 1; 9651da177e4SLinus Torvalds } 9661da177e4SLinus Torvalds AFFS_I(inode)->mmu_private = inode->i_size; 9671da177e4SLinus Torvalds // unlock cache 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds while (ext_key) { 9701da177e4SLinus Torvalds ext_bh = affs_bread(sb, ext_key); 9711da177e4SLinus Torvalds size = AFFS_SB(sb)->s_hashsize; 9721da177e4SLinus Torvalds if (size > blkcnt - blk) 9731da177e4SLinus Torvalds size = blkcnt - blk; 9741da177e4SLinus Torvalds for (i = 0; i < size; i++, blk++) 9751da177e4SLinus Torvalds affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i))); 9761da177e4SLinus Torvalds affs_free_block(sb, ext_key); 9771da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); 9781da177e4SLinus Torvalds affs_brelse(ext_bh); 9791da177e4SLinus Torvalds } 9801da177e4SLinus Torvalds affs_free_prealloc(inode); 9811da177e4SLinus Torvalds } 982c4758795SAl Viro 98302c24a82SJosef Bacik int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) 984c4758795SAl Viro { 9857ea80859SChristoph Hellwig struct inode *inode = filp->f_mapping->host; 986c4758795SAl Viro int ret, err; 987c4758795SAl Viro 9883b49c9a1SJeff Layton err = file_write_and_wait_range(filp, start, end); 98902c24a82SJosef Bacik if (err) 99002c24a82SJosef Bacik return err; 99102c24a82SJosef Bacik 9925955102cSAl Viro inode_lock(inode); 993c4758795SAl Viro ret = write_inode_now(inode, 0); 994c4758795SAl Viro err = sync_blockdev(inode->i_sb->s_bdev); 995c4758795SAl Viro if (!ret) 996c4758795SAl Viro ret = err; 9975955102cSAl Viro inode_unlock(inode); 998c4758795SAl Viro return ret; 999c4758795SAl Viro } 10007633978bSFabian Frederick const struct file_operations affs_file_operations = { 10017633978bSFabian Frederick .llseek = generic_file_llseek, 10027633978bSFabian Frederick .read_iter = generic_file_read_iter, 10037633978bSFabian Frederick .write_iter = generic_file_write_iter, 10047633978bSFabian Frederick .mmap = generic_file_mmap, 10057633978bSFabian Frederick .open = affs_file_open, 10067633978bSFabian Frederick .release = affs_file_release, 10077633978bSFabian Frederick .fsync = affs_file_fsync, 10087633978bSFabian Frederick .splice_read = generic_file_splice_read, 10097633978bSFabian Frederick }; 10107633978bSFabian Frederick 10117633978bSFabian Frederick const struct inode_operations affs_file_inode_operations = { 10127633978bSFabian Frederick .setattr = affs_notify_change, 10137633978bSFabian Frederick }; 1014