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