11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/affs/file.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * (c) 1996 Hans-Joachim Widmaier - Rewritten 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * (C) 1991 Linus Torvalds - minix filesystem 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * affs regular file handling primitives 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 159abb4083SFabian Frederick #include <linux/aio.h> 161da177e4SLinus Torvalds #include "affs.h" 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext); 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds static int 211da177e4SLinus Torvalds affs_file_open(struct inode *inode, struct file *filp) 221da177e4SLinus Torvalds { 239606d9aaSFabian Frederick pr_debug("open(%lu,%d)\n", 24dca3c336SRoman Zippel inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); 25dca3c336SRoman Zippel atomic_inc(&AFFS_I(inode)->i_opencnt); 261da177e4SLinus Torvalds return 0; 271da177e4SLinus Torvalds } 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds static int 301da177e4SLinus Torvalds affs_file_release(struct inode *inode, struct file *filp) 311da177e4SLinus Torvalds { 329606d9aaSFabian Frederick pr_debug("release(%lu, %d)\n", 33dca3c336SRoman Zippel inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); 34dca3c336SRoman Zippel 35dca3c336SRoman Zippel if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) { 36dca3c336SRoman Zippel mutex_lock(&inode->i_mutex); 37dca3c336SRoman Zippel if (inode->i_size != AFFS_I(inode)->mmu_private) 38dca3c336SRoman Zippel affs_truncate(inode); 391da177e4SLinus Torvalds affs_free_prealloc(inode); 40dca3c336SRoman Zippel mutex_unlock(&inode->i_mutex); 41dca3c336SRoman Zippel } 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds return 0; 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds static int 471da177e4SLinus Torvalds affs_grow_extcache(struct inode *inode, u32 lc_idx) 481da177e4SLinus Torvalds { 491da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 501da177e4SLinus Torvalds struct buffer_head *bh; 511da177e4SLinus Torvalds u32 lc_max; 521da177e4SLinus Torvalds int i, j, key; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds if (!AFFS_I(inode)->i_lc) { 551da177e4SLinus Torvalds char *ptr = (char *)get_zeroed_page(GFP_NOFS); 561da177e4SLinus Torvalds if (!ptr) 571da177e4SLinus Torvalds return -ENOMEM; 581da177e4SLinus Torvalds AFFS_I(inode)->i_lc = (u32 *)ptr; 591da177e4SLinus Torvalds AFFS_I(inode)->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2); 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds lc_max = AFFS_LC_SIZE << AFFS_I(inode)->i_lc_shift; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds if (AFFS_I(inode)->i_extcnt > lc_max) { 651da177e4SLinus Torvalds u32 lc_shift, lc_mask, tmp, off; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /* need to recalculate linear cache, start from old size */ 681da177e4SLinus Torvalds lc_shift = AFFS_I(inode)->i_lc_shift; 691da177e4SLinus Torvalds tmp = (AFFS_I(inode)->i_extcnt / AFFS_LC_SIZE) >> lc_shift; 701da177e4SLinus Torvalds for (; tmp; tmp >>= 1) 711da177e4SLinus Torvalds lc_shift++; 721da177e4SLinus Torvalds lc_mask = (1 << lc_shift) - 1; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds /* fix idx and old size to new shift */ 751da177e4SLinus Torvalds lc_idx >>= (lc_shift - AFFS_I(inode)->i_lc_shift); 761da177e4SLinus Torvalds AFFS_I(inode)->i_lc_size >>= (lc_shift - AFFS_I(inode)->i_lc_shift); 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /* first shrink old cache to make more space */ 791da177e4SLinus Torvalds off = 1 << (lc_shift - AFFS_I(inode)->i_lc_shift); 801da177e4SLinus Torvalds for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off) 811da177e4SLinus Torvalds AFFS_I(inode)->i_ac[i] = AFFS_I(inode)->i_ac[j]; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds AFFS_I(inode)->i_lc_shift = lc_shift; 841da177e4SLinus Torvalds AFFS_I(inode)->i_lc_mask = lc_mask; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* fill cache to the needed index */ 881da177e4SLinus Torvalds i = AFFS_I(inode)->i_lc_size; 891da177e4SLinus Torvalds AFFS_I(inode)->i_lc_size = lc_idx + 1; 901da177e4SLinus Torvalds for (; i <= lc_idx; i++) { 911da177e4SLinus Torvalds if (!i) { 921da177e4SLinus Torvalds AFFS_I(inode)->i_lc[0] = inode->i_ino; 931da177e4SLinus Torvalds continue; 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds key = AFFS_I(inode)->i_lc[i - 1]; 961da177e4SLinus Torvalds j = AFFS_I(inode)->i_lc_mask + 1; 971da177e4SLinus Torvalds // unlock cache 981da177e4SLinus Torvalds for (; j > 0; j--) { 991da177e4SLinus Torvalds bh = affs_bread(sb, key); 1001da177e4SLinus Torvalds if (!bh) 1011da177e4SLinus Torvalds goto err; 1021da177e4SLinus Torvalds key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 1031da177e4SLinus Torvalds affs_brelse(bh); 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds // lock cache 1061da177e4SLinus Torvalds AFFS_I(inode)->i_lc[i] = key; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds return 0; 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds err: 1121da177e4SLinus Torvalds // lock cache 1131da177e4SLinus Torvalds return -EIO; 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds static struct buffer_head * 1171da177e4SLinus Torvalds affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext) 1181da177e4SLinus Torvalds { 1191da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 1201da177e4SLinus Torvalds struct buffer_head *new_bh; 1211da177e4SLinus Torvalds u32 blocknr, tmp; 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds blocknr = affs_alloc_block(inode, bh->b_blocknr); 1241da177e4SLinus Torvalds if (!blocknr) 1251da177e4SLinus Torvalds return ERR_PTR(-ENOSPC); 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds new_bh = affs_getzeroblk(sb, blocknr); 1281da177e4SLinus Torvalds if (!new_bh) { 1291da177e4SLinus Torvalds affs_free_block(sb, blocknr); 1301da177e4SLinus Torvalds return ERR_PTR(-EIO); 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST); 1341da177e4SLinus Torvalds AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr); 1351da177e4SLinus Torvalds AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE); 1361da177e4SLinus Torvalds AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino); 1371da177e4SLinus Torvalds affs_fix_checksum(sb, new_bh); 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds mark_buffer_dirty_inode(new_bh, inode); 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 1421da177e4SLinus Torvalds if (tmp) 1431da177e4SLinus Torvalds affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp); 1441da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr); 1451da177e4SLinus Torvalds affs_adjust_checksum(bh, blocknr - tmp); 1461da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds AFFS_I(inode)->i_extcnt++; 1491da177e4SLinus Torvalds mark_inode_dirty(inode); 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds return new_bh; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds static inline struct buffer_head * 1551da177e4SLinus Torvalds affs_get_extblock(struct inode *inode, u32 ext) 1561da177e4SLinus Torvalds { 1571da177e4SLinus Torvalds /* inline the simplest case: same extended block as last time */ 1581da177e4SLinus Torvalds struct buffer_head *bh = AFFS_I(inode)->i_ext_bh; 1591da177e4SLinus Torvalds if (ext == AFFS_I(inode)->i_ext_last) 160dca3c336SRoman Zippel get_bh(bh); 1611da177e4SLinus Torvalds else 1621da177e4SLinus Torvalds /* we have to do more (not inlined) */ 1631da177e4SLinus Torvalds bh = affs_get_extblock_slow(inode, ext); 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds return bh; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds static struct buffer_head * 1691da177e4SLinus Torvalds affs_get_extblock_slow(struct inode *inode, u32 ext) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 1721da177e4SLinus Torvalds struct buffer_head *bh; 1731da177e4SLinus Torvalds u32 ext_key; 1741da177e4SLinus Torvalds u32 lc_idx, lc_off, ac_idx; 1751da177e4SLinus Torvalds u32 tmp, idx; 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds if (ext == AFFS_I(inode)->i_ext_last + 1) { 1781da177e4SLinus Torvalds /* read the next extended block from the current one */ 1791da177e4SLinus Torvalds bh = AFFS_I(inode)->i_ext_bh; 1801da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 1811da177e4SLinus Torvalds if (ext < AFFS_I(inode)->i_extcnt) 1821da177e4SLinus Torvalds goto read_ext; 183afe305dcSFabian Frederick BUG_ON(ext > AFFS_I(inode)->i_extcnt); 1841da177e4SLinus Torvalds bh = affs_alloc_extblock(inode, bh, ext); 1851da177e4SLinus Torvalds if (IS_ERR(bh)) 1861da177e4SLinus Torvalds return bh; 1871da177e4SLinus Torvalds goto store_ext; 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds if (ext == 0) { 1911da177e4SLinus Torvalds /* we seek back to the file header block */ 1921da177e4SLinus Torvalds ext_key = inode->i_ino; 1931da177e4SLinus Torvalds goto read_ext; 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds if (ext >= AFFS_I(inode)->i_extcnt) { 1971da177e4SLinus Torvalds struct buffer_head *prev_bh; 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds /* allocate a new extended block */ 200afe305dcSFabian Frederick BUG_ON(ext > AFFS_I(inode)->i_extcnt); 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds /* get previous extended block */ 2031da177e4SLinus Torvalds prev_bh = affs_get_extblock(inode, ext - 1); 2041da177e4SLinus Torvalds if (IS_ERR(prev_bh)) 2051da177e4SLinus Torvalds return prev_bh; 2061da177e4SLinus Torvalds bh = affs_alloc_extblock(inode, prev_bh, ext); 2071da177e4SLinus Torvalds affs_brelse(prev_bh); 2081da177e4SLinus Torvalds if (IS_ERR(bh)) 2091da177e4SLinus Torvalds return bh; 2101da177e4SLinus Torvalds goto store_ext; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds again: 2141da177e4SLinus Torvalds /* check if there is an extended cache and whether it's large enough */ 2151da177e4SLinus Torvalds lc_idx = ext >> AFFS_I(inode)->i_lc_shift; 2161da177e4SLinus Torvalds lc_off = ext & AFFS_I(inode)->i_lc_mask; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds if (lc_idx >= AFFS_I(inode)->i_lc_size) { 2191da177e4SLinus Torvalds int err; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds err = affs_grow_extcache(inode, lc_idx); 2221da177e4SLinus Torvalds if (err) 2231da177e4SLinus Torvalds return ERR_PTR(err); 2241da177e4SLinus Torvalds goto again; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds /* every n'th key we find in the linear cache */ 2281da177e4SLinus Torvalds if (!lc_off) { 2291da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_lc[lc_idx]; 2301da177e4SLinus Torvalds goto read_ext; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /* maybe it's still in the associative cache */ 2341da177e4SLinus Torvalds ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK; 2351da177e4SLinus Torvalds if (AFFS_I(inode)->i_ac[ac_idx].ext == ext) { 2361da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_ac[ac_idx].key; 2371da177e4SLinus Torvalds goto read_ext; 2381da177e4SLinus Torvalds } 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /* try to find one of the previous extended blocks */ 2411da177e4SLinus Torvalds tmp = ext; 2421da177e4SLinus Torvalds idx = ac_idx; 2431da177e4SLinus Torvalds while (--tmp, --lc_off > 0) { 2441da177e4SLinus Torvalds idx = (idx - 1) & AFFS_AC_MASK; 2451da177e4SLinus Torvalds if (AFFS_I(inode)->i_ac[idx].ext == tmp) { 2461da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_ac[idx].key; 2471da177e4SLinus Torvalds goto find_ext; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds /* fall back to the linear cache */ 2521da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_lc[lc_idx]; 2531da177e4SLinus Torvalds find_ext: 2541da177e4SLinus Torvalds /* read all extended blocks until we find the one we need */ 2551da177e4SLinus Torvalds //unlock cache 2561da177e4SLinus Torvalds do { 2571da177e4SLinus Torvalds bh = affs_bread(sb, ext_key); 2581da177e4SLinus Torvalds if (!bh) 2591da177e4SLinus Torvalds goto err_bread; 2601da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 2611da177e4SLinus Torvalds affs_brelse(bh); 2621da177e4SLinus Torvalds tmp++; 2631da177e4SLinus Torvalds } while (tmp < ext); 2641da177e4SLinus Torvalds //lock cache 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /* store it in the associative cache */ 2671da177e4SLinus Torvalds // recalculate ac_idx? 2681da177e4SLinus Torvalds AFFS_I(inode)->i_ac[ac_idx].ext = ext; 2691da177e4SLinus Torvalds AFFS_I(inode)->i_ac[ac_idx].key = ext_key; 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds read_ext: 2721da177e4SLinus Torvalds /* finally read the right extended block */ 2731da177e4SLinus Torvalds //unlock cache 2741da177e4SLinus Torvalds bh = affs_bread(sb, ext_key); 2751da177e4SLinus Torvalds if (!bh) 2761da177e4SLinus Torvalds goto err_bread; 2771da177e4SLinus Torvalds //lock cache 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds store_ext: 2801da177e4SLinus Torvalds /* release old cached extended block and store the new one */ 2811da177e4SLinus Torvalds affs_brelse(AFFS_I(inode)->i_ext_bh); 2821da177e4SLinus Torvalds AFFS_I(inode)->i_ext_last = ext; 2831da177e4SLinus Torvalds AFFS_I(inode)->i_ext_bh = bh; 284dca3c336SRoman Zippel get_bh(bh); 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds return bh; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds err_bread: 2891da177e4SLinus Torvalds affs_brelse(bh); 2901da177e4SLinus Torvalds return ERR_PTR(-EIO); 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds static int 2941da177e4SLinus Torvalds affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create) 2951da177e4SLinus Torvalds { 2961da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2971da177e4SLinus Torvalds struct buffer_head *ext_bh; 2981da177e4SLinus Torvalds u32 ext; 2991da177e4SLinus Torvalds 30008fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %llu)\n", __func__, inode->i_ino, 30108fe100dSGeert Uytterhoeven (unsigned long long)block); 3021da177e4SLinus Torvalds 3038d4b6900SJulia Lawall BUG_ON(block > (sector_t)0x7fffffffUL); 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds if (block >= AFFS_I(inode)->i_blkcnt) { 3061da177e4SLinus Torvalds if (block > AFFS_I(inode)->i_blkcnt || !create) 3071da177e4SLinus Torvalds goto err_big; 3081da177e4SLinus Torvalds } else 3091da177e4SLinus Torvalds create = 0; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds //lock cache 3121da177e4SLinus Torvalds affs_lock_ext(inode); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds ext = (u32)block / AFFS_SB(sb)->s_hashsize; 3151da177e4SLinus Torvalds block -= ext * AFFS_SB(sb)->s_hashsize; 3161da177e4SLinus Torvalds ext_bh = affs_get_extblock(inode, ext); 3171da177e4SLinus Torvalds if (IS_ERR(ext_bh)) 3181da177e4SLinus Torvalds goto err_ext; 3191da177e4SLinus Torvalds map_bh(bh_result, sb, (sector_t)be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block))); 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds if (create) { 3221da177e4SLinus Torvalds u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr); 3231da177e4SLinus Torvalds if (!blocknr) 3241da177e4SLinus Torvalds goto err_alloc; 3251da177e4SLinus Torvalds set_buffer_new(bh_result); 3261da177e4SLinus Torvalds AFFS_I(inode)->mmu_private += AFFS_SB(sb)->s_data_blksize; 3271da177e4SLinus Torvalds AFFS_I(inode)->i_blkcnt++; 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds /* store new block */ 3301da177e4SLinus Torvalds if (bh_result->b_blocknr) 33108fe100dSGeert Uytterhoeven affs_warning(sb, "get_block", 33208fe100dSGeert Uytterhoeven "block already set (%llx)", 33308fe100dSGeert Uytterhoeven (unsigned long long)bh_result->b_blocknr); 3341da177e4SLinus Torvalds AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr); 3351da177e4SLinus Torvalds AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1); 3361da177e4SLinus Torvalds affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1); 3371da177e4SLinus Torvalds bh_result->b_blocknr = blocknr; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds if (!block) { 3401da177e4SLinus Torvalds /* insert first block into header block */ 3411da177e4SLinus Torvalds u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data); 3421da177e4SLinus Torvalds if (tmp) 3431da177e4SLinus Torvalds affs_warning(sb, "get_block", "first block already set (%d)", tmp); 3441da177e4SLinus Torvalds AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr); 3451da177e4SLinus Torvalds affs_adjust_checksum(ext_bh, blocknr - tmp); 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds affs_brelse(ext_bh); 3501da177e4SLinus Torvalds //unlock cache 3511da177e4SLinus Torvalds affs_unlock_ext(inode); 3521da177e4SLinus Torvalds return 0; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds err_big: 35508fe100dSGeert Uytterhoeven affs_error(inode->i_sb, "get_block", "strange block request %llu", 35608fe100dSGeert Uytterhoeven (unsigned long long)block); 3571da177e4SLinus Torvalds return -EIO; 3581da177e4SLinus Torvalds err_ext: 3591da177e4SLinus Torvalds // unlock cache 3601da177e4SLinus Torvalds affs_unlock_ext(inode); 3611da177e4SLinus Torvalds return PTR_ERR(ext_bh); 3621da177e4SLinus Torvalds err_alloc: 3631da177e4SLinus Torvalds brelse(ext_bh); 3641da177e4SLinus Torvalds clear_buffer_mapped(bh_result); 3651da177e4SLinus Torvalds bh_result->b_bdev = NULL; 3661da177e4SLinus Torvalds // unlock cache 3671da177e4SLinus Torvalds affs_unlock_ext(inode); 3681da177e4SLinus Torvalds return -ENOSPC; 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds static int affs_writepage(struct page *page, struct writeback_control *wbc) 3721da177e4SLinus Torvalds { 3731da177e4SLinus Torvalds return block_write_full_page(page, affs_get_block, wbc); 3741da177e4SLinus Torvalds } 375f2b6a16eSNick Piggin 3761da177e4SLinus Torvalds static int affs_readpage(struct file *file, struct page *page) 3771da177e4SLinus Torvalds { 3781da177e4SLinus Torvalds return block_read_full_page(page, affs_get_block); 3791da177e4SLinus Torvalds } 380f2b6a16eSNick Piggin 3811dc1834fSMarco Stornelli static void affs_write_failed(struct address_space *mapping, loff_t to) 3821dc1834fSMarco Stornelli { 3831dc1834fSMarco Stornelli struct inode *inode = mapping->host; 3841dc1834fSMarco Stornelli 3851dc1834fSMarco Stornelli if (to > inode->i_size) { 3867caef267SKirill A. Shutemov truncate_pagecache(inode, inode->i_size); 3871dc1834fSMarco Stornelli affs_truncate(inode); 3881dc1834fSMarco Stornelli } 3891dc1834fSMarco Stornelli } 3901dc1834fSMarco Stornelli 3919abb4083SFabian Frederick static ssize_t 3929abb4083SFabian Frederick affs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, 3939abb4083SFabian Frederick loff_t offset) 3949abb4083SFabian Frederick { 3959abb4083SFabian Frederick struct file *file = iocb->ki_filp; 3969abb4083SFabian Frederick struct address_space *mapping = file->f_mapping; 3979abb4083SFabian Frederick struct inode *inode = mapping->host; 3989abb4083SFabian Frederick size_t count = iov_iter_count(iter); 3999abb4083SFabian Frederick ssize_t ret; 4009abb4083SFabian Frederick 40192b20708SFabian Frederick if (rw == WRITE) { 40292b20708SFabian Frederick loff_t size = offset + count; 40392b20708SFabian Frederick 40492b20708SFabian Frederick if (AFFS_I(inode)->mmu_private < size) 40592b20708SFabian Frederick return 0; 40692b20708SFabian Frederick } 40792b20708SFabian Frederick 4089abb4083SFabian Frederick ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, affs_get_block); 4099abb4083SFabian Frederick if (ret < 0 && (rw & WRITE)) 4109abb4083SFabian Frederick affs_write_failed(mapping, offset + count); 4119abb4083SFabian Frederick return ret; 4129abb4083SFabian Frederick } 4139abb4083SFabian Frederick 414f2b6a16eSNick Piggin static int affs_write_begin(struct file *file, struct address_space *mapping, 415f2b6a16eSNick Piggin loff_t pos, unsigned len, unsigned flags, 416f2b6a16eSNick Piggin struct page **pagep, void **fsdata) 4171da177e4SLinus Torvalds { 418282dc178SChristoph Hellwig int ret; 419282dc178SChristoph Hellwig 420f2b6a16eSNick Piggin *pagep = NULL; 421282dc178SChristoph Hellwig ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, 422f2b6a16eSNick Piggin affs_get_block, 423f2b6a16eSNick Piggin &AFFS_I(mapping->host)->mmu_private); 4241dc1834fSMarco Stornelli if (unlikely(ret)) 4251dc1834fSMarco Stornelli affs_write_failed(mapping, pos + len); 426282dc178SChristoph Hellwig 427282dc178SChristoph Hellwig return ret; 4281da177e4SLinus Torvalds } 429f2b6a16eSNick Piggin 4301da177e4SLinus Torvalds static sector_t _affs_bmap(struct address_space *mapping, sector_t block) 4311da177e4SLinus Torvalds { 4321da177e4SLinus Torvalds return generic_block_bmap(mapping,block,affs_get_block); 4331da177e4SLinus Torvalds } 434f2b6a16eSNick Piggin 435f5e54d6eSChristoph Hellwig const struct address_space_operations affs_aops = { 4361da177e4SLinus Torvalds .readpage = affs_readpage, 4371da177e4SLinus Torvalds .writepage = affs_writepage, 438f2b6a16eSNick Piggin .write_begin = affs_write_begin, 439f2b6a16eSNick Piggin .write_end = generic_write_end, 4409abb4083SFabian Frederick .direct_IO = affs_direct_IO, 4411da177e4SLinus Torvalds .bmap = _affs_bmap 4421da177e4SLinus Torvalds }; 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds static inline struct buffer_head * 4451da177e4SLinus Torvalds affs_bread_ino(struct inode *inode, int block, int create) 4461da177e4SLinus Torvalds { 4471da177e4SLinus Torvalds struct buffer_head *bh, tmp_bh; 4481da177e4SLinus Torvalds int err; 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds tmp_bh.b_state = 0; 4511da177e4SLinus Torvalds err = affs_get_block(inode, block, &tmp_bh, create); 4521da177e4SLinus Torvalds if (!err) { 4531da177e4SLinus Torvalds bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr); 4541da177e4SLinus Torvalds if (bh) { 4551da177e4SLinus Torvalds bh->b_state |= tmp_bh.b_state; 4561da177e4SLinus Torvalds return bh; 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds err = -EIO; 4591da177e4SLinus Torvalds } 4601da177e4SLinus Torvalds return ERR_PTR(err); 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds static inline struct buffer_head * 4641da177e4SLinus Torvalds affs_getzeroblk_ino(struct inode *inode, int block) 4651da177e4SLinus Torvalds { 4661da177e4SLinus Torvalds struct buffer_head *bh, tmp_bh; 4671da177e4SLinus Torvalds int err; 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds tmp_bh.b_state = 0; 4701da177e4SLinus Torvalds err = affs_get_block(inode, block, &tmp_bh, 1); 4711da177e4SLinus Torvalds if (!err) { 4721da177e4SLinus Torvalds bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr); 4731da177e4SLinus Torvalds if (bh) { 4741da177e4SLinus Torvalds bh->b_state |= tmp_bh.b_state; 4751da177e4SLinus Torvalds return bh; 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds err = -EIO; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds return ERR_PTR(err); 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds static inline struct buffer_head * 4831da177e4SLinus Torvalds affs_getemptyblk_ino(struct inode *inode, int block) 4841da177e4SLinus Torvalds { 4851da177e4SLinus Torvalds struct buffer_head *bh, tmp_bh; 4861da177e4SLinus Torvalds int err; 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds tmp_bh.b_state = 0; 4891da177e4SLinus Torvalds err = affs_get_block(inode, block, &tmp_bh, 1); 4901da177e4SLinus Torvalds if (!err) { 4911da177e4SLinus Torvalds bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr); 4921da177e4SLinus Torvalds if (bh) { 4931da177e4SLinus Torvalds bh->b_state |= tmp_bh.b_state; 4941da177e4SLinus Torvalds return bh; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds err = -EIO; 4971da177e4SLinus Torvalds } 4981da177e4SLinus Torvalds return ERR_PTR(err); 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds 5011da177e4SLinus Torvalds static int 5020c89d670SFabian Frederick affs_do_readpage_ofs(struct page *page, unsigned to) 5031da177e4SLinus Torvalds { 5041da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 5051da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 5061da177e4SLinus Torvalds struct buffer_head *bh; 5071da177e4SLinus Torvalds char *data; 5080c89d670SFabian Frederick unsigned pos = 0; 5091da177e4SLinus Torvalds u32 bidx, boff, bsize; 5101da177e4SLinus Torvalds u32 tmp; 5111da177e4SLinus Torvalds 51208fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %ld, 0, %d)\n", __func__, inode->i_ino, 5130c89d670SFabian Frederick page->index, to); 5140c89d670SFabian Frederick BUG_ON(to > PAGE_CACHE_SIZE); 5151da177e4SLinus Torvalds kmap(page); 5161da177e4SLinus Torvalds data = page_address(page); 5171da177e4SLinus Torvalds bsize = AFFS_SB(sb)->s_data_blksize; 5180c89d670SFabian Frederick tmp = page->index << PAGE_CACHE_SHIFT; 5191da177e4SLinus Torvalds bidx = tmp / bsize; 5201da177e4SLinus Torvalds boff = tmp % bsize; 5211da177e4SLinus Torvalds 5220c89d670SFabian Frederick while (pos < to) { 5231da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 0); 5241da177e4SLinus Torvalds if (IS_ERR(bh)) 5251da177e4SLinus Torvalds return PTR_ERR(bh); 5260c89d670SFabian Frederick tmp = min(bsize - boff, to - pos); 5270c89d670SFabian Frederick BUG_ON(pos + tmp > to || tmp > bsize); 5280c89d670SFabian Frederick memcpy(data + pos, AFFS_DATA(bh) + boff, tmp); 5291da177e4SLinus Torvalds affs_brelse(bh); 5301da177e4SLinus Torvalds bidx++; 5310c89d670SFabian Frederick pos += tmp; 5321da177e4SLinus Torvalds boff = 0; 5331da177e4SLinus Torvalds } 5341da177e4SLinus Torvalds flush_dcache_page(page); 5351da177e4SLinus Torvalds kunmap(page); 5361da177e4SLinus Torvalds return 0; 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds static int 5401da177e4SLinus Torvalds affs_extent_file_ofs(struct inode *inode, u32 newsize) 5411da177e4SLinus Torvalds { 5421da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 5431da177e4SLinus Torvalds struct buffer_head *bh, *prev_bh; 5441da177e4SLinus Torvalds u32 bidx, boff; 5451da177e4SLinus Torvalds u32 size, bsize; 5461da177e4SLinus Torvalds u32 tmp; 5471da177e4SLinus Torvalds 54808fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %d)\n", __func__, inode->i_ino, newsize); 5491da177e4SLinus Torvalds bsize = AFFS_SB(sb)->s_data_blksize; 5501da177e4SLinus Torvalds bh = NULL; 5511da177e4SLinus Torvalds size = AFFS_I(inode)->mmu_private; 5521da177e4SLinus Torvalds bidx = size / bsize; 5531da177e4SLinus Torvalds boff = size % bsize; 5541da177e4SLinus Torvalds if (boff) { 5551da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 0); 5561da177e4SLinus Torvalds if (IS_ERR(bh)) 5571da177e4SLinus Torvalds return PTR_ERR(bh); 5581da177e4SLinus Torvalds tmp = min(bsize - boff, newsize - size); 5598d4b6900SJulia Lawall BUG_ON(boff + tmp > bsize || tmp > bsize); 5601da177e4SLinus Torvalds memset(AFFS_DATA(bh) + boff, 0, tmp); 5616369a4abSMarcin Slusarz be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp); 5621da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 5631da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 5641da177e4SLinus Torvalds size += tmp; 5651da177e4SLinus Torvalds bidx++; 5661da177e4SLinus Torvalds } else if (bidx) { 5671da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx - 1, 0); 5681da177e4SLinus Torvalds if (IS_ERR(bh)) 5691da177e4SLinus Torvalds return PTR_ERR(bh); 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds while (size < newsize) { 5731da177e4SLinus Torvalds prev_bh = bh; 5741da177e4SLinus Torvalds bh = affs_getzeroblk_ino(inode, bidx); 5751da177e4SLinus Torvalds if (IS_ERR(bh)) 5761da177e4SLinus Torvalds goto out; 5771da177e4SLinus Torvalds tmp = min(bsize, newsize - size); 5788d4b6900SJulia Lawall BUG_ON(tmp > bsize); 5791da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 5801da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); 5811da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); 5821da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); 5831da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 5841da177e4SLinus Torvalds bh->b_state &= ~(1UL << BH_New); 5851da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 5861da177e4SLinus Torvalds if (prev_bh) { 58773516aceSFabian Frederick u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); 58873516aceSFabian Frederick 58973516aceSFabian Frederick if (tmp_next) 59073516aceSFabian Frederick affs_warning(sb, "extent_file_ofs", 59173516aceSFabian Frederick "next block already set for %d (%d)", 59273516aceSFabian Frederick bidx, tmp_next); 5931da177e4SLinus Torvalds AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); 59473516aceSFabian Frederick affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next); 5951da177e4SLinus Torvalds mark_buffer_dirty_inode(prev_bh, inode); 5961da177e4SLinus Torvalds affs_brelse(prev_bh); 5971da177e4SLinus Torvalds } 5981da177e4SLinus Torvalds size += bsize; 5991da177e4SLinus Torvalds bidx++; 6001da177e4SLinus Torvalds } 6011da177e4SLinus Torvalds affs_brelse(bh); 6021da177e4SLinus Torvalds inode->i_size = AFFS_I(inode)->mmu_private = newsize; 6031da177e4SLinus Torvalds return 0; 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds out: 6061da177e4SLinus Torvalds inode->i_size = AFFS_I(inode)->mmu_private = newsize; 6071da177e4SLinus Torvalds return PTR_ERR(bh); 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds static int 6111da177e4SLinus Torvalds affs_readpage_ofs(struct file *file, struct page *page) 6121da177e4SLinus Torvalds { 6131da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 6141da177e4SLinus Torvalds u32 to; 6151da177e4SLinus Torvalds int err; 6161da177e4SLinus Torvalds 61708fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %ld)\n", __func__, inode->i_ino, page->index); 6181da177e4SLinus Torvalds to = PAGE_CACHE_SIZE; 6191da177e4SLinus Torvalds if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) { 6201da177e4SLinus Torvalds to = inode->i_size & ~PAGE_CACHE_MASK; 6211da177e4SLinus Torvalds memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to); 6221da177e4SLinus Torvalds } 6231da177e4SLinus Torvalds 6240c89d670SFabian Frederick err = affs_do_readpage_ofs(page, to); 6251da177e4SLinus Torvalds if (!err) 6261da177e4SLinus Torvalds SetPageUptodate(page); 6271da177e4SLinus Torvalds unlock_page(page); 6281da177e4SLinus Torvalds return err; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds 631f2b6a16eSNick Piggin static int affs_write_begin_ofs(struct file *file, struct address_space *mapping, 632f2b6a16eSNick Piggin loff_t pos, unsigned len, unsigned flags, 633f2b6a16eSNick Piggin struct page **pagep, void **fsdata) 6341da177e4SLinus Torvalds { 635f2b6a16eSNick Piggin struct inode *inode = mapping->host; 636f2b6a16eSNick Piggin struct page *page; 637f2b6a16eSNick Piggin pgoff_t index; 6381da177e4SLinus Torvalds int err = 0; 6391da177e4SLinus Torvalds 64008fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos, 64108fe100dSGeert Uytterhoeven pos + len); 642f2b6a16eSNick Piggin if (pos > AFFS_I(inode)->mmu_private) { 643f2b6a16eSNick Piggin /* XXX: this probably leaves a too-big i_size in case of 644f2b6a16eSNick Piggin * failure. Should really be updating i_size at write_end time 645f2b6a16eSNick Piggin */ 646f2b6a16eSNick Piggin err = affs_extent_file_ofs(inode, pos); 6471da177e4SLinus Torvalds if (err) 6481da177e4SLinus Torvalds return err; 6491da177e4SLinus Torvalds } 650f2b6a16eSNick Piggin 651f2b6a16eSNick Piggin index = pos >> PAGE_CACHE_SHIFT; 65254566b2cSNick Piggin page = grab_cache_page_write_begin(mapping, index, flags); 653f2b6a16eSNick Piggin if (!page) 654f2b6a16eSNick Piggin return -ENOMEM; 655f2b6a16eSNick Piggin *pagep = page; 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds if (PageUptodate(page)) 6581da177e4SLinus Torvalds return 0; 6591da177e4SLinus Torvalds 660f2b6a16eSNick Piggin /* XXX: inefficient but safe in the face of short writes */ 6610c89d670SFabian Frederick err = affs_do_readpage_ofs(page, PAGE_CACHE_SIZE); 662f2b6a16eSNick Piggin if (err) { 663f2b6a16eSNick Piggin unlock_page(page); 664f2b6a16eSNick Piggin page_cache_release(page); 6651da177e4SLinus Torvalds } 6661da177e4SLinus Torvalds return err; 6671da177e4SLinus Torvalds } 6681da177e4SLinus Torvalds 669f2b6a16eSNick Piggin static int affs_write_end_ofs(struct file *file, struct address_space *mapping, 670f2b6a16eSNick Piggin loff_t pos, unsigned len, unsigned copied, 671f2b6a16eSNick Piggin struct page *page, void *fsdata) 6721da177e4SLinus Torvalds { 673f2b6a16eSNick Piggin struct inode *inode = mapping->host; 6741da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 6751da177e4SLinus Torvalds struct buffer_head *bh, *prev_bh; 6761da177e4SLinus Torvalds char *data; 6771da177e4SLinus Torvalds u32 bidx, boff, bsize; 678f2b6a16eSNick Piggin unsigned from, to; 6791da177e4SLinus Torvalds u32 tmp; 6801da177e4SLinus Torvalds int written; 6811da177e4SLinus Torvalds 682f2b6a16eSNick Piggin from = pos & (PAGE_CACHE_SIZE - 1); 683f2b6a16eSNick Piggin to = pos + len; 684f2b6a16eSNick Piggin /* 685f2b6a16eSNick Piggin * XXX: not sure if this can handle short copies (len < copied), but 686f2b6a16eSNick Piggin * we don't have to, because the page should always be uptodate here, 687f2b6a16eSNick Piggin * due to write_begin. 688f2b6a16eSNick Piggin */ 689f2b6a16eSNick Piggin 69008fe100dSGeert Uytterhoeven pr_debug("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos, 69108fe100dSGeert Uytterhoeven pos + len); 6921da177e4SLinus Torvalds bsize = AFFS_SB(sb)->s_data_blksize; 6931da177e4SLinus Torvalds data = page_address(page); 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds bh = NULL; 6961da177e4SLinus Torvalds written = 0; 6971da177e4SLinus Torvalds tmp = (page->index << PAGE_CACHE_SHIFT) + from; 6981da177e4SLinus Torvalds bidx = tmp / bsize; 6991da177e4SLinus Torvalds boff = tmp % bsize; 7001da177e4SLinus Torvalds if (boff) { 7011da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 0); 7021da177e4SLinus Torvalds if (IS_ERR(bh)) 7031da177e4SLinus Torvalds return PTR_ERR(bh); 7041da177e4SLinus Torvalds tmp = min(bsize - boff, to - from); 7058d4b6900SJulia Lawall BUG_ON(boff + tmp > bsize || tmp > bsize); 7061da177e4SLinus Torvalds memcpy(AFFS_DATA(bh) + boff, data + from, tmp); 7076369a4abSMarcin Slusarz be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp); 7081da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 7091da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 7101da177e4SLinus Torvalds written += tmp; 7111da177e4SLinus Torvalds from += tmp; 7121da177e4SLinus Torvalds bidx++; 7131da177e4SLinus Torvalds } else if (bidx) { 7141da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx - 1, 0); 7151da177e4SLinus Torvalds if (IS_ERR(bh)) 7161da177e4SLinus Torvalds return PTR_ERR(bh); 7171da177e4SLinus Torvalds } 7181da177e4SLinus Torvalds while (from + bsize <= to) { 7191da177e4SLinus Torvalds prev_bh = bh; 7201da177e4SLinus Torvalds bh = affs_getemptyblk_ino(inode, bidx); 7211da177e4SLinus Torvalds if (IS_ERR(bh)) 7221da177e4SLinus Torvalds goto out; 7231da177e4SLinus Torvalds memcpy(AFFS_DATA(bh), data + from, bsize); 7241da177e4SLinus Torvalds if (buffer_new(bh)) { 7251da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 7261da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); 7271da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); 7281da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize); 7291da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->next = 0; 7301da177e4SLinus Torvalds bh->b_state &= ~(1UL << BH_New); 7311da177e4SLinus Torvalds if (prev_bh) { 73273516aceSFabian Frederick u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); 73373516aceSFabian Frederick 73473516aceSFabian Frederick if (tmp_next) 73573516aceSFabian Frederick affs_warning(sb, "commit_write_ofs", 73673516aceSFabian Frederick "next block already set for %d (%d)", 73773516aceSFabian Frederick bidx, tmp_next); 7381da177e4SLinus Torvalds AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); 73973516aceSFabian Frederick affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next); 7401da177e4SLinus Torvalds mark_buffer_dirty_inode(prev_bh, inode); 7411da177e4SLinus Torvalds } 7421da177e4SLinus Torvalds } 7431da177e4SLinus Torvalds affs_brelse(prev_bh); 7441da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 7451da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 7461da177e4SLinus Torvalds written += bsize; 7471da177e4SLinus Torvalds from += bsize; 7481da177e4SLinus Torvalds bidx++; 7491da177e4SLinus Torvalds } 7501da177e4SLinus Torvalds if (from < to) { 7511da177e4SLinus Torvalds prev_bh = bh; 7521da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 1); 7531da177e4SLinus Torvalds if (IS_ERR(bh)) 7541da177e4SLinus Torvalds goto out; 7551da177e4SLinus Torvalds tmp = min(bsize, to - from); 7568d4b6900SJulia Lawall BUG_ON(tmp > bsize); 7571da177e4SLinus Torvalds memcpy(AFFS_DATA(bh), data + from, tmp); 7581da177e4SLinus Torvalds if (buffer_new(bh)) { 7591da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 7601da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); 7611da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); 7621da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); 7631da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->next = 0; 7641da177e4SLinus Torvalds bh->b_state &= ~(1UL << BH_New); 7651da177e4SLinus Torvalds if (prev_bh) { 76673516aceSFabian Frederick u32 tmp_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); 76773516aceSFabian Frederick 76873516aceSFabian Frederick if (tmp_next) 76973516aceSFabian Frederick affs_warning(sb, "commit_write_ofs", 77073516aceSFabian Frederick "next block already set for %d (%d)", 77173516aceSFabian Frederick bidx, tmp_next); 7721da177e4SLinus Torvalds AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); 77373516aceSFabian Frederick affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next); 7741da177e4SLinus Torvalds mark_buffer_dirty_inode(prev_bh, inode); 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp) 7771da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); 7781da177e4SLinus Torvalds affs_brelse(prev_bh); 7791da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 7801da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 7811da177e4SLinus Torvalds written += tmp; 7821da177e4SLinus Torvalds from += tmp; 7831da177e4SLinus Torvalds bidx++; 7841da177e4SLinus Torvalds } 7851da177e4SLinus Torvalds SetPageUptodate(page); 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds done: 7881da177e4SLinus Torvalds affs_brelse(bh); 7891da177e4SLinus Torvalds tmp = (page->index << PAGE_CACHE_SHIFT) + from; 7901da177e4SLinus Torvalds if (tmp > inode->i_size) 7911da177e4SLinus Torvalds inode->i_size = AFFS_I(inode)->mmu_private = tmp; 7921da177e4SLinus Torvalds 793f2b6a16eSNick Piggin unlock_page(page); 794f2b6a16eSNick Piggin page_cache_release(page); 795f2b6a16eSNick Piggin 7961da177e4SLinus Torvalds return written; 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds out: 7991da177e4SLinus Torvalds bh = prev_bh; 8001da177e4SLinus Torvalds if (!written) 8011da177e4SLinus Torvalds written = PTR_ERR(bh); 8021da177e4SLinus Torvalds goto done; 8031da177e4SLinus Torvalds } 8041da177e4SLinus Torvalds 805f5e54d6eSChristoph Hellwig const struct address_space_operations affs_aops_ofs = { 8061da177e4SLinus Torvalds .readpage = affs_readpage_ofs, 8071da177e4SLinus Torvalds //.writepage = affs_writepage_ofs, 808f2b6a16eSNick Piggin .write_begin = affs_write_begin_ofs, 809f2b6a16eSNick Piggin .write_end = affs_write_end_ofs 8101da177e4SLinus Torvalds }; 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds /* Free any preallocated blocks. */ 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds void 8151da177e4SLinus Torvalds affs_free_prealloc(struct inode *inode) 8161da177e4SLinus Torvalds { 8171da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 8181da177e4SLinus Torvalds 8199606d9aaSFabian Frederick pr_debug("free_prealloc(ino=%lu)\n", inode->i_ino); 8201da177e4SLinus Torvalds 8211da177e4SLinus Torvalds while (AFFS_I(inode)->i_pa_cnt) { 8221da177e4SLinus Torvalds AFFS_I(inode)->i_pa_cnt--; 8231da177e4SLinus Torvalds affs_free_block(sb, ++AFFS_I(inode)->i_lastalloc); 8241da177e4SLinus Torvalds } 8251da177e4SLinus Torvalds } 8261da177e4SLinus Torvalds 8271da177e4SLinus Torvalds /* Truncate (or enlarge) a file to the requested size. */ 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds void 8301da177e4SLinus Torvalds affs_truncate(struct inode *inode) 8311da177e4SLinus Torvalds { 8321da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 8331da177e4SLinus Torvalds u32 ext, ext_key; 8341da177e4SLinus Torvalds u32 last_blk, blkcnt, blk; 8351da177e4SLinus Torvalds u32 size; 8361da177e4SLinus Torvalds struct buffer_head *ext_bh; 8371da177e4SLinus Torvalds int i; 8381da177e4SLinus Torvalds 83908fe100dSGeert Uytterhoeven pr_debug("truncate(inode=%lu, oldsize=%llu, newsize=%llu)\n", 84008fe100dSGeert Uytterhoeven inode->i_ino, AFFS_I(inode)->mmu_private, inode->i_size); 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds last_blk = 0; 8431da177e4SLinus Torvalds ext = 0; 8441da177e4SLinus Torvalds if (inode->i_size) { 8451da177e4SLinus Torvalds last_blk = ((u32)inode->i_size - 1) / AFFS_SB(sb)->s_data_blksize; 8461da177e4SLinus Torvalds ext = last_blk / AFFS_SB(sb)->s_hashsize; 8471da177e4SLinus Torvalds } 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds if (inode->i_size > AFFS_I(inode)->mmu_private) { 8501da177e4SLinus Torvalds struct address_space *mapping = inode->i_mapping; 8511da177e4SLinus Torvalds struct page *page; 852f2b6a16eSNick Piggin void *fsdata; 85373516aceSFabian Frederick loff_t isize = inode->i_size; 8541da177e4SLinus Torvalds int res; 8551da177e4SLinus Torvalds 85673516aceSFabian Frederick res = mapping->a_ops->write_begin(NULL, mapping, isize, 0, 0, &page, &fsdata); 8571da177e4SLinus Torvalds if (!res) 85873516aceSFabian Frederick res = mapping->a_ops->write_end(NULL, mapping, isize, 0, 0, page, fsdata); 859dca3c336SRoman Zippel else 860dca3c336SRoman Zippel inode->i_size = AFFS_I(inode)->mmu_private; 8611da177e4SLinus Torvalds mark_inode_dirty(inode); 8621da177e4SLinus Torvalds return; 8631da177e4SLinus Torvalds } else if (inode->i_size == AFFS_I(inode)->mmu_private) 8641da177e4SLinus Torvalds return; 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds // lock cache 8671da177e4SLinus Torvalds ext_bh = affs_get_extblock(inode, ext); 8681da177e4SLinus Torvalds if (IS_ERR(ext_bh)) { 8691ee54b09SFabian Frederick affs_warning(sb, "truncate", 8701ee54b09SFabian Frederick "unexpected read error for ext block %u (%ld)", 87108fe100dSGeert Uytterhoeven ext, PTR_ERR(ext_bh)); 8721da177e4SLinus Torvalds return; 8731da177e4SLinus Torvalds } 8741da177e4SLinus Torvalds if (AFFS_I(inode)->i_lc) { 8751da177e4SLinus Torvalds /* clear linear cache */ 8761da177e4SLinus Torvalds i = (ext + 1) >> AFFS_I(inode)->i_lc_shift; 8771da177e4SLinus Torvalds if (AFFS_I(inode)->i_lc_size > i) { 8781da177e4SLinus Torvalds AFFS_I(inode)->i_lc_size = i; 8791da177e4SLinus Torvalds for (; i < AFFS_LC_SIZE; i++) 8801da177e4SLinus Torvalds AFFS_I(inode)->i_lc[i] = 0; 8811da177e4SLinus Torvalds } 8821da177e4SLinus Torvalds /* clear associative cache */ 8831da177e4SLinus Torvalds for (i = 0; i < AFFS_AC_SIZE; i++) 8841da177e4SLinus Torvalds if (AFFS_I(inode)->i_ac[i].ext >= ext) 8851da177e4SLinus Torvalds AFFS_I(inode)->i_ac[i].ext = 0; 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds blkcnt = AFFS_I(inode)->i_blkcnt; 8901da177e4SLinus Torvalds i = 0; 8911da177e4SLinus Torvalds blk = last_blk; 8921da177e4SLinus Torvalds if (inode->i_size) { 8931da177e4SLinus Torvalds i = last_blk % AFFS_SB(sb)->s_hashsize + 1; 8941da177e4SLinus Torvalds blk++; 8951da177e4SLinus Torvalds } else 8961da177e4SLinus Torvalds AFFS_HEAD(ext_bh)->first_data = 0; 897dca3c336SRoman Zippel AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i); 8981da177e4SLinus Torvalds size = AFFS_SB(sb)->s_hashsize; 8991da177e4SLinus Torvalds if (size > blkcnt - blk + i) 9001da177e4SLinus Torvalds size = blkcnt - blk + i; 9011da177e4SLinus Torvalds for (; i < size; i++, blk++) { 9021da177e4SLinus Torvalds affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i))); 9031da177e4SLinus Torvalds AFFS_BLOCK(sb, ext_bh, i) = 0; 9041da177e4SLinus Torvalds } 9051da177e4SLinus Torvalds AFFS_TAIL(sb, ext_bh)->extension = 0; 9061da177e4SLinus Torvalds affs_fix_checksum(sb, ext_bh); 9071da177e4SLinus Torvalds mark_buffer_dirty_inode(ext_bh, inode); 9081da177e4SLinus Torvalds affs_brelse(ext_bh); 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds if (inode->i_size) { 9111da177e4SLinus Torvalds AFFS_I(inode)->i_blkcnt = last_blk + 1; 9121da177e4SLinus Torvalds AFFS_I(inode)->i_extcnt = ext + 1; 9131da177e4SLinus Torvalds if (AFFS_SB(sb)->s_flags & SF_OFS) { 9141da177e4SLinus Torvalds struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0); 9151da177e4SLinus Torvalds u32 tmp; 9160e45b67dSDan Carpenter if (IS_ERR(bh)) { 9171ee54b09SFabian Frederick affs_warning(sb, "truncate", 9181ee54b09SFabian Frederick "unexpected read error for last block %u (%ld)", 91908fe100dSGeert Uytterhoeven ext, PTR_ERR(bh)); 9201da177e4SLinus Torvalds return; 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next); 9231da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->next = 0; 9241da177e4SLinus Torvalds affs_adjust_checksum(bh, -tmp); 9251da177e4SLinus Torvalds affs_brelse(bh); 9261da177e4SLinus Torvalds } 9271da177e4SLinus Torvalds } else { 9281da177e4SLinus Torvalds AFFS_I(inode)->i_blkcnt = 0; 9291da177e4SLinus Torvalds AFFS_I(inode)->i_extcnt = 1; 9301da177e4SLinus Torvalds } 9311da177e4SLinus Torvalds AFFS_I(inode)->mmu_private = inode->i_size; 9321da177e4SLinus Torvalds // unlock cache 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds while (ext_key) { 9351da177e4SLinus Torvalds ext_bh = affs_bread(sb, ext_key); 9361da177e4SLinus Torvalds size = AFFS_SB(sb)->s_hashsize; 9371da177e4SLinus Torvalds if (size > blkcnt - blk) 9381da177e4SLinus Torvalds size = blkcnt - blk; 9391da177e4SLinus Torvalds for (i = 0; i < size; i++, blk++) 9401da177e4SLinus Torvalds affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i))); 9411da177e4SLinus Torvalds affs_free_block(sb, ext_key); 9421da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); 9431da177e4SLinus Torvalds affs_brelse(ext_bh); 9441da177e4SLinus Torvalds } 9451da177e4SLinus Torvalds affs_free_prealloc(inode); 9461da177e4SLinus Torvalds } 947c4758795SAl Viro 94802c24a82SJosef Bacik int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) 949c4758795SAl Viro { 9507ea80859SChristoph Hellwig struct inode *inode = filp->f_mapping->host; 951c4758795SAl Viro int ret, err; 952c4758795SAl Viro 95302c24a82SJosef Bacik err = filemap_write_and_wait_range(inode->i_mapping, start, end); 95402c24a82SJosef Bacik if (err) 95502c24a82SJosef Bacik return err; 95602c24a82SJosef Bacik 95702c24a82SJosef Bacik mutex_lock(&inode->i_mutex); 958c4758795SAl Viro ret = write_inode_now(inode, 0); 959c4758795SAl Viro err = sync_blockdev(inode->i_sb->s_bdev); 960c4758795SAl Viro if (!ret) 961c4758795SAl Viro ret = err; 96202c24a82SJosef Bacik mutex_unlock(&inode->i_mutex); 963c4758795SAl Viro return ret; 964c4758795SAl Viro } 9657633978bSFabian Frederick const struct file_operations affs_file_operations = { 9667633978bSFabian Frederick .llseek = generic_file_llseek, 9677633978bSFabian Frederick .read = new_sync_read, 9687633978bSFabian Frederick .read_iter = generic_file_read_iter, 9697633978bSFabian Frederick .write = new_sync_write, 9707633978bSFabian Frederick .write_iter = generic_file_write_iter, 9717633978bSFabian Frederick .mmap = generic_file_mmap, 9727633978bSFabian Frederick .open = affs_file_open, 9737633978bSFabian Frederick .release = affs_file_release, 9747633978bSFabian Frederick .fsync = affs_file_fsync, 9757633978bSFabian Frederick .splice_read = generic_file_splice_read, 9767633978bSFabian Frederick }; 9777633978bSFabian Frederick 9787633978bSFabian Frederick const struct inode_operations affs_file_inode_operations = { 9797633978bSFabian Frederick .setattr = affs_notify_change, 9807633978bSFabian Frederick }; 981