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 151da177e4SLinus Torvalds #include "affs.h" 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #if PAGE_SIZE < 4096 181da177e4SLinus Torvalds #error PAGE_SIZE must be at least 4096 191da177e4SLinus Torvalds #endif 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds static int affs_grow_extcache(struct inode *inode, u32 lc_idx); 221da177e4SLinus Torvalds static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext); 231da177e4SLinus Torvalds static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext); 241da177e4SLinus Torvalds static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext); 251da177e4SLinus Torvalds static int affs_file_open(struct inode *inode, struct file *filp); 261da177e4SLinus Torvalds static int affs_file_release(struct inode *inode, struct file *filp); 271da177e4SLinus Torvalds 284b6f5d20SArjan van de Ven const struct file_operations affs_file_operations = { 291da177e4SLinus Torvalds .llseek = generic_file_llseek, 30543ade1fSBadari Pulavarty .read = do_sync_read, 31543ade1fSBadari Pulavarty .aio_read = generic_file_aio_read, 32543ade1fSBadari Pulavarty .write = do_sync_write, 33543ade1fSBadari Pulavarty .aio_write = generic_file_aio_write, 341da177e4SLinus Torvalds .mmap = generic_file_mmap, 351da177e4SLinus Torvalds .open = affs_file_open, 361da177e4SLinus Torvalds .release = affs_file_release, 371da177e4SLinus Torvalds .fsync = file_fsync, 381da177e4SLinus Torvalds .sendfile = generic_file_sendfile, 391da177e4SLinus Torvalds }; 401da177e4SLinus Torvalds 41754661f1SArjan van de Ven const struct inode_operations affs_file_inode_operations = { 421da177e4SLinus Torvalds .truncate = affs_truncate, 431da177e4SLinus Torvalds .setattr = affs_notify_change, 441da177e4SLinus Torvalds }; 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds static int 471da177e4SLinus Torvalds affs_file_open(struct inode *inode, struct file *filp) 481da177e4SLinus Torvalds { 491da177e4SLinus Torvalds if (atomic_read(&filp->f_count) != 1) 501da177e4SLinus Torvalds return 0; 511da177e4SLinus Torvalds pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt); 521da177e4SLinus Torvalds AFFS_I(inode)->i_opencnt++; 531da177e4SLinus Torvalds return 0; 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds static int 571da177e4SLinus Torvalds affs_file_release(struct inode *inode, struct file *filp) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds if (atomic_read(&filp->f_count) != 0) 601da177e4SLinus Torvalds return 0; 611da177e4SLinus Torvalds pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt); 621da177e4SLinus Torvalds AFFS_I(inode)->i_opencnt--; 631da177e4SLinus Torvalds if (!AFFS_I(inode)->i_opencnt) 641da177e4SLinus Torvalds affs_free_prealloc(inode); 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds return 0; 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds static int 701da177e4SLinus Torvalds affs_grow_extcache(struct inode *inode, u32 lc_idx) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 731da177e4SLinus Torvalds struct buffer_head *bh; 741da177e4SLinus Torvalds u32 lc_max; 751da177e4SLinus Torvalds int i, j, key; 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds if (!AFFS_I(inode)->i_lc) { 781da177e4SLinus Torvalds char *ptr = (char *)get_zeroed_page(GFP_NOFS); 791da177e4SLinus Torvalds if (!ptr) 801da177e4SLinus Torvalds return -ENOMEM; 811da177e4SLinus Torvalds AFFS_I(inode)->i_lc = (u32 *)ptr; 821da177e4SLinus Torvalds AFFS_I(inode)->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2); 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds lc_max = AFFS_LC_SIZE << AFFS_I(inode)->i_lc_shift; 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds if (AFFS_I(inode)->i_extcnt > lc_max) { 881da177e4SLinus Torvalds u32 lc_shift, lc_mask, tmp, off; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds /* need to recalculate linear cache, start from old size */ 911da177e4SLinus Torvalds lc_shift = AFFS_I(inode)->i_lc_shift; 921da177e4SLinus Torvalds tmp = (AFFS_I(inode)->i_extcnt / AFFS_LC_SIZE) >> lc_shift; 931da177e4SLinus Torvalds for (; tmp; tmp >>= 1) 941da177e4SLinus Torvalds lc_shift++; 951da177e4SLinus Torvalds lc_mask = (1 << lc_shift) - 1; 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds /* fix idx and old size to new shift */ 981da177e4SLinus Torvalds lc_idx >>= (lc_shift - AFFS_I(inode)->i_lc_shift); 991da177e4SLinus Torvalds AFFS_I(inode)->i_lc_size >>= (lc_shift - AFFS_I(inode)->i_lc_shift); 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds /* first shrink old cache to make more space */ 1021da177e4SLinus Torvalds off = 1 << (lc_shift - AFFS_I(inode)->i_lc_shift); 1031da177e4SLinus Torvalds for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off) 1041da177e4SLinus Torvalds AFFS_I(inode)->i_ac[i] = AFFS_I(inode)->i_ac[j]; 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds AFFS_I(inode)->i_lc_shift = lc_shift; 1071da177e4SLinus Torvalds AFFS_I(inode)->i_lc_mask = lc_mask; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds /* fill cache to the needed index */ 1111da177e4SLinus Torvalds i = AFFS_I(inode)->i_lc_size; 1121da177e4SLinus Torvalds AFFS_I(inode)->i_lc_size = lc_idx + 1; 1131da177e4SLinus Torvalds for (; i <= lc_idx; i++) { 1141da177e4SLinus Torvalds if (!i) { 1151da177e4SLinus Torvalds AFFS_I(inode)->i_lc[0] = inode->i_ino; 1161da177e4SLinus Torvalds continue; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds key = AFFS_I(inode)->i_lc[i - 1]; 1191da177e4SLinus Torvalds j = AFFS_I(inode)->i_lc_mask + 1; 1201da177e4SLinus Torvalds // unlock cache 1211da177e4SLinus Torvalds for (; j > 0; j--) { 1221da177e4SLinus Torvalds bh = affs_bread(sb, key); 1231da177e4SLinus Torvalds if (!bh) 1241da177e4SLinus Torvalds goto err; 1251da177e4SLinus Torvalds key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 1261da177e4SLinus Torvalds affs_brelse(bh); 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds // lock cache 1291da177e4SLinus Torvalds AFFS_I(inode)->i_lc[i] = key; 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds return 0; 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds err: 1351da177e4SLinus Torvalds // lock cache 1361da177e4SLinus Torvalds return -EIO; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds static struct buffer_head * 1401da177e4SLinus Torvalds affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext) 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 1431da177e4SLinus Torvalds struct buffer_head *new_bh; 1441da177e4SLinus Torvalds u32 blocknr, tmp; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds blocknr = affs_alloc_block(inode, bh->b_blocknr); 1471da177e4SLinus Torvalds if (!blocknr) 1481da177e4SLinus Torvalds return ERR_PTR(-ENOSPC); 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds new_bh = affs_getzeroblk(sb, blocknr); 1511da177e4SLinus Torvalds if (!new_bh) { 1521da177e4SLinus Torvalds affs_free_block(sb, blocknr); 1531da177e4SLinus Torvalds return ERR_PTR(-EIO); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST); 1571da177e4SLinus Torvalds AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr); 1581da177e4SLinus Torvalds AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE); 1591da177e4SLinus Torvalds AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino); 1601da177e4SLinus Torvalds affs_fix_checksum(sb, new_bh); 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds mark_buffer_dirty_inode(new_bh, inode); 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 1651da177e4SLinus Torvalds if (tmp) 1661da177e4SLinus Torvalds affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp); 1671da177e4SLinus Torvalds AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr); 1681da177e4SLinus Torvalds affs_adjust_checksum(bh, blocknr - tmp); 1691da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds AFFS_I(inode)->i_extcnt++; 1721da177e4SLinus Torvalds mark_inode_dirty(inode); 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds return new_bh; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds static inline struct buffer_head * 1781da177e4SLinus Torvalds affs_get_extblock(struct inode *inode, u32 ext) 1791da177e4SLinus Torvalds { 1801da177e4SLinus Torvalds /* inline the simplest case: same extended block as last time */ 1811da177e4SLinus Torvalds struct buffer_head *bh = AFFS_I(inode)->i_ext_bh; 1821da177e4SLinus Torvalds if (ext == AFFS_I(inode)->i_ext_last) 1831da177e4SLinus Torvalds atomic_inc(&bh->b_count); 1841da177e4SLinus Torvalds else 1851da177e4SLinus Torvalds /* we have to do more (not inlined) */ 1861da177e4SLinus Torvalds bh = affs_get_extblock_slow(inode, ext); 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds return bh; 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds static struct buffer_head * 1921da177e4SLinus Torvalds affs_get_extblock_slow(struct inode *inode, u32 ext) 1931da177e4SLinus Torvalds { 1941da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 1951da177e4SLinus Torvalds struct buffer_head *bh; 1961da177e4SLinus Torvalds u32 ext_key; 1971da177e4SLinus Torvalds u32 lc_idx, lc_off, ac_idx; 1981da177e4SLinus Torvalds u32 tmp, idx; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds if (ext == AFFS_I(inode)->i_ext_last + 1) { 2011da177e4SLinus Torvalds /* read the next extended block from the current one */ 2021da177e4SLinus Torvalds bh = AFFS_I(inode)->i_ext_bh; 2031da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 2041da177e4SLinus Torvalds if (ext < AFFS_I(inode)->i_extcnt) 2051da177e4SLinus Torvalds goto read_ext; 2061da177e4SLinus Torvalds if (ext > AFFS_I(inode)->i_extcnt) 2071da177e4SLinus Torvalds BUG(); 2081da177e4SLinus Torvalds bh = affs_alloc_extblock(inode, bh, ext); 2091da177e4SLinus Torvalds if (IS_ERR(bh)) 2101da177e4SLinus Torvalds return bh; 2111da177e4SLinus Torvalds goto store_ext; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds if (ext == 0) { 2151da177e4SLinus Torvalds /* we seek back to the file header block */ 2161da177e4SLinus Torvalds ext_key = inode->i_ino; 2171da177e4SLinus Torvalds goto read_ext; 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds if (ext >= AFFS_I(inode)->i_extcnt) { 2211da177e4SLinus Torvalds struct buffer_head *prev_bh; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds /* allocate a new extended block */ 2241da177e4SLinus Torvalds if (ext > AFFS_I(inode)->i_extcnt) 2251da177e4SLinus Torvalds BUG(); 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds /* get previous extended block */ 2281da177e4SLinus Torvalds prev_bh = affs_get_extblock(inode, ext - 1); 2291da177e4SLinus Torvalds if (IS_ERR(prev_bh)) 2301da177e4SLinus Torvalds return prev_bh; 2311da177e4SLinus Torvalds bh = affs_alloc_extblock(inode, prev_bh, ext); 2321da177e4SLinus Torvalds affs_brelse(prev_bh); 2331da177e4SLinus Torvalds if (IS_ERR(bh)) 2341da177e4SLinus Torvalds return bh; 2351da177e4SLinus Torvalds goto store_ext; 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds again: 2391da177e4SLinus Torvalds /* check if there is an extended cache and whether it's large enough */ 2401da177e4SLinus Torvalds lc_idx = ext >> AFFS_I(inode)->i_lc_shift; 2411da177e4SLinus Torvalds lc_off = ext & AFFS_I(inode)->i_lc_mask; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds if (lc_idx >= AFFS_I(inode)->i_lc_size) { 2441da177e4SLinus Torvalds int err; 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds err = affs_grow_extcache(inode, lc_idx); 2471da177e4SLinus Torvalds if (err) 2481da177e4SLinus Torvalds return ERR_PTR(err); 2491da177e4SLinus Torvalds goto again; 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds /* every n'th key we find in the linear cache */ 2531da177e4SLinus Torvalds if (!lc_off) { 2541da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_lc[lc_idx]; 2551da177e4SLinus Torvalds goto read_ext; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds /* maybe it's still in the associative cache */ 2591da177e4SLinus Torvalds ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK; 2601da177e4SLinus Torvalds if (AFFS_I(inode)->i_ac[ac_idx].ext == ext) { 2611da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_ac[ac_idx].key; 2621da177e4SLinus Torvalds goto read_ext; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds /* try to find one of the previous extended blocks */ 2661da177e4SLinus Torvalds tmp = ext; 2671da177e4SLinus Torvalds idx = ac_idx; 2681da177e4SLinus Torvalds while (--tmp, --lc_off > 0) { 2691da177e4SLinus Torvalds idx = (idx - 1) & AFFS_AC_MASK; 2701da177e4SLinus Torvalds if (AFFS_I(inode)->i_ac[idx].ext == tmp) { 2711da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_ac[idx].key; 2721da177e4SLinus Torvalds goto find_ext; 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds /* fall back to the linear cache */ 2771da177e4SLinus Torvalds ext_key = AFFS_I(inode)->i_lc[lc_idx]; 2781da177e4SLinus Torvalds find_ext: 2791da177e4SLinus Torvalds /* read all extended blocks until we find the one we need */ 2801da177e4SLinus Torvalds //unlock cache 2811da177e4SLinus Torvalds do { 2821da177e4SLinus Torvalds bh = affs_bread(sb, ext_key); 2831da177e4SLinus Torvalds if (!bh) 2841da177e4SLinus Torvalds goto err_bread; 2851da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); 2861da177e4SLinus Torvalds affs_brelse(bh); 2871da177e4SLinus Torvalds tmp++; 2881da177e4SLinus Torvalds } while (tmp < ext); 2891da177e4SLinus Torvalds //lock cache 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* store it in the associative cache */ 2921da177e4SLinus Torvalds // recalculate ac_idx? 2931da177e4SLinus Torvalds AFFS_I(inode)->i_ac[ac_idx].ext = ext; 2941da177e4SLinus Torvalds AFFS_I(inode)->i_ac[ac_idx].key = ext_key; 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds read_ext: 2971da177e4SLinus Torvalds /* finally read the right extended block */ 2981da177e4SLinus Torvalds //unlock cache 2991da177e4SLinus Torvalds bh = affs_bread(sb, ext_key); 3001da177e4SLinus Torvalds if (!bh) 3011da177e4SLinus Torvalds goto err_bread; 3021da177e4SLinus Torvalds //lock cache 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds store_ext: 3051da177e4SLinus Torvalds /* release old cached extended block and store the new one */ 3061da177e4SLinus Torvalds affs_brelse(AFFS_I(inode)->i_ext_bh); 3071da177e4SLinus Torvalds AFFS_I(inode)->i_ext_last = ext; 3081da177e4SLinus Torvalds AFFS_I(inode)->i_ext_bh = bh; 3091da177e4SLinus Torvalds atomic_inc(&bh->b_count); 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds return bh; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds err_bread: 3141da177e4SLinus Torvalds affs_brelse(bh); 3151da177e4SLinus Torvalds return ERR_PTR(-EIO); 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds static int 3191da177e4SLinus Torvalds affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create) 3201da177e4SLinus Torvalds { 3211da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 3221da177e4SLinus Torvalds struct buffer_head *ext_bh; 3231da177e4SLinus Torvalds u32 ext; 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block); 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds if (block > (sector_t)0x7fffffffUL) 3291da177e4SLinus Torvalds BUG(); 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds if (block >= AFFS_I(inode)->i_blkcnt) { 3321da177e4SLinus Torvalds if (block > AFFS_I(inode)->i_blkcnt || !create) 3331da177e4SLinus Torvalds goto err_big; 3341da177e4SLinus Torvalds } else 3351da177e4SLinus Torvalds create = 0; 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds //lock cache 3381da177e4SLinus Torvalds affs_lock_ext(inode); 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds ext = (u32)block / AFFS_SB(sb)->s_hashsize; 3411da177e4SLinus Torvalds block -= ext * AFFS_SB(sb)->s_hashsize; 3421da177e4SLinus Torvalds ext_bh = affs_get_extblock(inode, ext); 3431da177e4SLinus Torvalds if (IS_ERR(ext_bh)) 3441da177e4SLinus Torvalds goto err_ext; 3451da177e4SLinus Torvalds map_bh(bh_result, sb, (sector_t)be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block))); 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds if (create) { 3481da177e4SLinus Torvalds u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr); 3491da177e4SLinus Torvalds if (!blocknr) 3501da177e4SLinus Torvalds goto err_alloc; 3511da177e4SLinus Torvalds set_buffer_new(bh_result); 3521da177e4SLinus Torvalds AFFS_I(inode)->mmu_private += AFFS_SB(sb)->s_data_blksize; 3531da177e4SLinus Torvalds AFFS_I(inode)->i_blkcnt++; 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds /* store new block */ 3561da177e4SLinus Torvalds if (bh_result->b_blocknr) 3571da177e4SLinus Torvalds affs_warning(sb, "get_block", "block already set (%x)", bh_result->b_blocknr); 3581da177e4SLinus Torvalds AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr); 3591da177e4SLinus Torvalds AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1); 3601da177e4SLinus Torvalds affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1); 3611da177e4SLinus Torvalds bh_result->b_blocknr = blocknr; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds if (!block) { 3641da177e4SLinus Torvalds /* insert first block into header block */ 3651da177e4SLinus Torvalds u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data); 3661da177e4SLinus Torvalds if (tmp) 3671da177e4SLinus Torvalds affs_warning(sb, "get_block", "first block already set (%d)", tmp); 3681da177e4SLinus Torvalds AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr); 3691da177e4SLinus Torvalds affs_adjust_checksum(ext_bh, blocknr - tmp); 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds } 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds affs_brelse(ext_bh); 3741da177e4SLinus Torvalds //unlock cache 3751da177e4SLinus Torvalds affs_unlock_ext(inode); 3761da177e4SLinus Torvalds return 0; 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds err_big: 3791da177e4SLinus Torvalds affs_error(inode->i_sb,"get_block","strange block request %d", block); 3801da177e4SLinus Torvalds return -EIO; 3811da177e4SLinus Torvalds err_ext: 3821da177e4SLinus Torvalds // unlock cache 3831da177e4SLinus Torvalds affs_unlock_ext(inode); 3841da177e4SLinus Torvalds return PTR_ERR(ext_bh); 3851da177e4SLinus Torvalds err_alloc: 3861da177e4SLinus Torvalds brelse(ext_bh); 3871da177e4SLinus Torvalds clear_buffer_mapped(bh_result); 3881da177e4SLinus Torvalds bh_result->b_bdev = NULL; 3891da177e4SLinus Torvalds // unlock cache 3901da177e4SLinus Torvalds affs_unlock_ext(inode); 3911da177e4SLinus Torvalds return -ENOSPC; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds static int affs_writepage(struct page *page, struct writeback_control *wbc) 3951da177e4SLinus Torvalds { 3961da177e4SLinus Torvalds return block_write_full_page(page, affs_get_block, wbc); 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds static int affs_readpage(struct file *file, struct page *page) 3991da177e4SLinus Torvalds { 4001da177e4SLinus Torvalds return block_read_full_page(page, affs_get_block); 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) 4031da177e4SLinus Torvalds { 4041da177e4SLinus Torvalds return cont_prepare_write(page, from, to, affs_get_block, 4051da177e4SLinus Torvalds &AFFS_I(page->mapping->host)->mmu_private); 4061da177e4SLinus Torvalds } 4071da177e4SLinus Torvalds static sector_t _affs_bmap(struct address_space *mapping, sector_t block) 4081da177e4SLinus Torvalds { 4091da177e4SLinus Torvalds return generic_block_bmap(mapping,block,affs_get_block); 4101da177e4SLinus Torvalds } 411f5e54d6eSChristoph Hellwig const struct address_space_operations affs_aops = { 4121da177e4SLinus Torvalds .readpage = affs_readpage, 4131da177e4SLinus Torvalds .writepage = affs_writepage, 4141da177e4SLinus Torvalds .sync_page = block_sync_page, 4151da177e4SLinus Torvalds .prepare_write = affs_prepare_write, 4161da177e4SLinus Torvalds .commit_write = generic_commit_write, 4171da177e4SLinus Torvalds .bmap = _affs_bmap 4181da177e4SLinus Torvalds }; 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds static inline struct buffer_head * 4211da177e4SLinus Torvalds affs_bread_ino(struct inode *inode, int block, int create) 4221da177e4SLinus Torvalds { 4231da177e4SLinus Torvalds struct buffer_head *bh, tmp_bh; 4241da177e4SLinus Torvalds int err; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds tmp_bh.b_state = 0; 4271da177e4SLinus Torvalds err = affs_get_block(inode, block, &tmp_bh, create); 4281da177e4SLinus Torvalds if (!err) { 4291da177e4SLinus Torvalds bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr); 4301da177e4SLinus Torvalds if (bh) { 4311da177e4SLinus Torvalds bh->b_state |= tmp_bh.b_state; 4321da177e4SLinus Torvalds return bh; 4331da177e4SLinus Torvalds } 4341da177e4SLinus Torvalds err = -EIO; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds return ERR_PTR(err); 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds static inline struct buffer_head * 4401da177e4SLinus Torvalds affs_getzeroblk_ino(struct inode *inode, int block) 4411da177e4SLinus Torvalds { 4421da177e4SLinus Torvalds struct buffer_head *bh, tmp_bh; 4431da177e4SLinus Torvalds int err; 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds tmp_bh.b_state = 0; 4461da177e4SLinus Torvalds err = affs_get_block(inode, block, &tmp_bh, 1); 4471da177e4SLinus Torvalds if (!err) { 4481da177e4SLinus Torvalds bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr); 4491da177e4SLinus Torvalds if (bh) { 4501da177e4SLinus Torvalds bh->b_state |= tmp_bh.b_state; 4511da177e4SLinus Torvalds return bh; 4521da177e4SLinus Torvalds } 4531da177e4SLinus Torvalds err = -EIO; 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds return ERR_PTR(err); 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds static inline struct buffer_head * 4591da177e4SLinus Torvalds affs_getemptyblk_ino(struct inode *inode, int block) 4601da177e4SLinus Torvalds { 4611da177e4SLinus Torvalds struct buffer_head *bh, tmp_bh; 4621da177e4SLinus Torvalds int err; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds tmp_bh.b_state = 0; 4651da177e4SLinus Torvalds err = affs_get_block(inode, block, &tmp_bh, 1); 4661da177e4SLinus Torvalds if (!err) { 4671da177e4SLinus Torvalds bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr); 4681da177e4SLinus Torvalds if (bh) { 4691da177e4SLinus Torvalds bh->b_state |= tmp_bh.b_state; 4701da177e4SLinus Torvalds return bh; 4711da177e4SLinus Torvalds } 4721da177e4SLinus Torvalds err = -EIO; 4731da177e4SLinus Torvalds } 4741da177e4SLinus Torvalds return ERR_PTR(err); 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds static int 4781da177e4SLinus Torvalds affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to) 4791da177e4SLinus Torvalds { 4801da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 4811da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 4821da177e4SLinus Torvalds struct buffer_head *bh; 4831da177e4SLinus Torvalds char *data; 4841da177e4SLinus Torvalds u32 bidx, boff, bsize; 4851da177e4SLinus Torvalds u32 tmp; 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); 4881da177e4SLinus Torvalds if (from > to || to > PAGE_CACHE_SIZE) 4891da177e4SLinus Torvalds BUG(); 4901da177e4SLinus Torvalds kmap(page); 4911da177e4SLinus Torvalds data = page_address(page); 4921da177e4SLinus Torvalds bsize = AFFS_SB(sb)->s_data_blksize; 4931da177e4SLinus Torvalds tmp = (page->index << PAGE_CACHE_SHIFT) + from; 4941da177e4SLinus Torvalds bidx = tmp / bsize; 4951da177e4SLinus Torvalds boff = tmp % bsize; 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds while (from < to) { 4981da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 0); 4991da177e4SLinus Torvalds if (IS_ERR(bh)) 5001da177e4SLinus Torvalds return PTR_ERR(bh); 5011da177e4SLinus Torvalds tmp = min(bsize - boff, to - from); 5021da177e4SLinus Torvalds if (from + tmp > to || tmp > bsize) 5031da177e4SLinus Torvalds BUG(); 5041da177e4SLinus Torvalds memcpy(data + from, AFFS_DATA(bh) + boff, tmp); 5051da177e4SLinus Torvalds affs_brelse(bh); 5061da177e4SLinus Torvalds bidx++; 5071da177e4SLinus Torvalds from += tmp; 5081da177e4SLinus Torvalds boff = 0; 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds flush_dcache_page(page); 5111da177e4SLinus Torvalds kunmap(page); 5121da177e4SLinus Torvalds return 0; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds static int 5161da177e4SLinus Torvalds affs_extent_file_ofs(struct inode *inode, u32 newsize) 5171da177e4SLinus Torvalds { 5181da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 5191da177e4SLinus Torvalds struct buffer_head *bh, *prev_bh; 5201da177e4SLinus Torvalds u32 bidx, boff; 5211da177e4SLinus Torvalds u32 size, bsize; 5221da177e4SLinus Torvalds u32 tmp; 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize); 5251da177e4SLinus Torvalds bsize = AFFS_SB(sb)->s_data_blksize; 5261da177e4SLinus Torvalds bh = NULL; 5271da177e4SLinus Torvalds size = AFFS_I(inode)->mmu_private; 5281da177e4SLinus Torvalds bidx = size / bsize; 5291da177e4SLinus Torvalds boff = size % bsize; 5301da177e4SLinus Torvalds if (boff) { 5311da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 0); 5321da177e4SLinus Torvalds if (IS_ERR(bh)) 5331da177e4SLinus Torvalds return PTR_ERR(bh); 5341da177e4SLinus Torvalds tmp = min(bsize - boff, newsize - size); 5351da177e4SLinus Torvalds if (boff + tmp > bsize || tmp > bsize) 5361da177e4SLinus Torvalds BUG(); 5371da177e4SLinus Torvalds memset(AFFS_DATA(bh) + boff, 0, tmp); 5381da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp); 5391da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 5401da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 5411da177e4SLinus Torvalds size += tmp; 5421da177e4SLinus Torvalds bidx++; 5431da177e4SLinus Torvalds } else if (bidx) { 5441da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx - 1, 0); 5451da177e4SLinus Torvalds if (IS_ERR(bh)) 5461da177e4SLinus Torvalds return PTR_ERR(bh); 5471da177e4SLinus Torvalds } 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds while (size < newsize) { 5501da177e4SLinus Torvalds prev_bh = bh; 5511da177e4SLinus Torvalds bh = affs_getzeroblk_ino(inode, bidx); 5521da177e4SLinus Torvalds if (IS_ERR(bh)) 5531da177e4SLinus Torvalds goto out; 5541da177e4SLinus Torvalds tmp = min(bsize, newsize - size); 5551da177e4SLinus Torvalds if (tmp > bsize) 5561da177e4SLinus Torvalds BUG(); 5571da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 5581da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); 5591da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); 5601da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); 5611da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 5621da177e4SLinus Torvalds bh->b_state &= ~(1UL << BH_New); 5631da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 5641da177e4SLinus Torvalds if (prev_bh) { 5651da177e4SLinus Torvalds u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); 5661da177e4SLinus Torvalds if (tmp) 5671da177e4SLinus Torvalds affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp); 5681da177e4SLinus Torvalds AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); 5691da177e4SLinus Torvalds affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp); 5701da177e4SLinus Torvalds mark_buffer_dirty_inode(prev_bh, inode); 5711da177e4SLinus Torvalds affs_brelse(prev_bh); 5721da177e4SLinus Torvalds } 5731da177e4SLinus Torvalds size += bsize; 5741da177e4SLinus Torvalds bidx++; 5751da177e4SLinus Torvalds } 5761da177e4SLinus Torvalds affs_brelse(bh); 5771da177e4SLinus Torvalds inode->i_size = AFFS_I(inode)->mmu_private = newsize; 5781da177e4SLinus Torvalds return 0; 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds out: 5811da177e4SLinus Torvalds inode->i_size = AFFS_I(inode)->mmu_private = newsize; 5821da177e4SLinus Torvalds return PTR_ERR(bh); 5831da177e4SLinus Torvalds } 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds static int 5861da177e4SLinus Torvalds affs_readpage_ofs(struct file *file, struct page *page) 5871da177e4SLinus Torvalds { 5881da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 5891da177e4SLinus Torvalds u32 to; 5901da177e4SLinus Torvalds int err; 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds pr_debug("AFFS: read_page(%u, %ld)\n", (u32)inode->i_ino, page->index); 5931da177e4SLinus Torvalds to = PAGE_CACHE_SIZE; 5941da177e4SLinus Torvalds if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) { 5951da177e4SLinus Torvalds to = inode->i_size & ~PAGE_CACHE_MASK; 5961da177e4SLinus Torvalds memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to); 5971da177e4SLinus Torvalds } 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds err = affs_do_readpage_ofs(file, page, 0, to); 6001da177e4SLinus Torvalds if (!err) 6011da177e4SLinus Torvalds SetPageUptodate(page); 6021da177e4SLinus Torvalds unlock_page(page); 6031da177e4SLinus Torvalds return err; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to) 6071da177e4SLinus Torvalds { 6081da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 6091da177e4SLinus Torvalds u32 size, offset; 6101da177e4SLinus Torvalds u32 tmp; 6111da177e4SLinus Torvalds int err = 0; 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); 6141da177e4SLinus Torvalds offset = page->index << PAGE_CACHE_SHIFT; 6151da177e4SLinus Torvalds if (offset + from > AFFS_I(inode)->mmu_private) { 6161da177e4SLinus Torvalds err = affs_extent_file_ofs(inode, offset + from); 6171da177e4SLinus Torvalds if (err) 6181da177e4SLinus Torvalds return err; 6191da177e4SLinus Torvalds } 6201da177e4SLinus Torvalds size = inode->i_size; 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds if (PageUptodate(page)) 6231da177e4SLinus Torvalds return 0; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds if (from) { 6261da177e4SLinus Torvalds err = affs_do_readpage_ofs(file, page, 0, from); 6271da177e4SLinus Torvalds if (err) 6281da177e4SLinus Torvalds return err; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds if (to < PAGE_CACHE_SIZE) { 6311da177e4SLinus Torvalds char *kaddr = kmap_atomic(page, KM_USER0); 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); 6341da177e4SLinus Torvalds flush_dcache_page(page); 6351da177e4SLinus Torvalds kunmap_atomic(kaddr, KM_USER0); 6361da177e4SLinus Torvalds if (size > offset + to) { 6371da177e4SLinus Torvalds if (size < offset + PAGE_CACHE_SIZE) 6381da177e4SLinus Torvalds tmp = size & ~PAGE_CACHE_MASK; 6391da177e4SLinus Torvalds else 6401da177e4SLinus Torvalds tmp = PAGE_CACHE_SIZE; 6411da177e4SLinus Torvalds err = affs_do_readpage_ofs(file, page, to, tmp); 6421da177e4SLinus Torvalds } 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds return err; 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to) 6481da177e4SLinus Torvalds { 6491da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 6501da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 6511da177e4SLinus Torvalds struct buffer_head *bh, *prev_bh; 6521da177e4SLinus Torvalds char *data; 6531da177e4SLinus Torvalds u32 bidx, boff, bsize; 6541da177e4SLinus Torvalds u32 tmp; 6551da177e4SLinus Torvalds int written; 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds pr_debug("AFFS: commit_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); 6581da177e4SLinus Torvalds bsize = AFFS_SB(sb)->s_data_blksize; 6591da177e4SLinus Torvalds data = page_address(page); 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds bh = NULL; 6621da177e4SLinus Torvalds written = 0; 6631da177e4SLinus Torvalds tmp = (page->index << PAGE_CACHE_SHIFT) + from; 6641da177e4SLinus Torvalds bidx = tmp / bsize; 6651da177e4SLinus Torvalds boff = tmp % bsize; 6661da177e4SLinus Torvalds if (boff) { 6671da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 0); 6681da177e4SLinus Torvalds if (IS_ERR(bh)) 6691da177e4SLinus Torvalds return PTR_ERR(bh); 6701da177e4SLinus Torvalds tmp = min(bsize - boff, to - from); 6711da177e4SLinus Torvalds if (boff + tmp > bsize || tmp > bsize) 6721da177e4SLinus Torvalds BUG(); 6731da177e4SLinus Torvalds memcpy(AFFS_DATA(bh) + boff, data + from, tmp); 6741da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp); 6751da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 6761da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 6771da177e4SLinus Torvalds written += tmp; 6781da177e4SLinus Torvalds from += tmp; 6791da177e4SLinus Torvalds bidx++; 6801da177e4SLinus Torvalds } else if (bidx) { 6811da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx - 1, 0); 6821da177e4SLinus Torvalds if (IS_ERR(bh)) 6831da177e4SLinus Torvalds return PTR_ERR(bh); 6841da177e4SLinus Torvalds } 6851da177e4SLinus Torvalds while (from + bsize <= to) { 6861da177e4SLinus Torvalds prev_bh = bh; 6871da177e4SLinus Torvalds bh = affs_getemptyblk_ino(inode, bidx); 6881da177e4SLinus Torvalds if (IS_ERR(bh)) 6891da177e4SLinus Torvalds goto out; 6901da177e4SLinus Torvalds memcpy(AFFS_DATA(bh), data + from, bsize); 6911da177e4SLinus Torvalds if (buffer_new(bh)) { 6921da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 6931da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); 6941da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); 6951da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize); 6961da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->next = 0; 6971da177e4SLinus Torvalds bh->b_state &= ~(1UL << BH_New); 6981da177e4SLinus Torvalds if (prev_bh) { 6991da177e4SLinus Torvalds u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); 7001da177e4SLinus Torvalds if (tmp) 7011da177e4SLinus Torvalds affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp); 7021da177e4SLinus Torvalds AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); 7031da177e4SLinus Torvalds affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp); 7041da177e4SLinus Torvalds mark_buffer_dirty_inode(prev_bh, inode); 7051da177e4SLinus Torvalds } 7061da177e4SLinus Torvalds } 7071da177e4SLinus Torvalds affs_brelse(prev_bh); 7081da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 7091da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 7101da177e4SLinus Torvalds written += bsize; 7111da177e4SLinus Torvalds from += bsize; 7121da177e4SLinus Torvalds bidx++; 7131da177e4SLinus Torvalds } 7141da177e4SLinus Torvalds if (from < to) { 7151da177e4SLinus Torvalds prev_bh = bh; 7161da177e4SLinus Torvalds bh = affs_bread_ino(inode, bidx, 1); 7171da177e4SLinus Torvalds if (IS_ERR(bh)) 7181da177e4SLinus Torvalds goto out; 7191da177e4SLinus Torvalds tmp = min(bsize, to - from); 7201da177e4SLinus Torvalds if (tmp > bsize) 7211da177e4SLinus Torvalds BUG(); 7221da177e4SLinus Torvalds memcpy(AFFS_DATA(bh), data + from, tmp); 7231da177e4SLinus Torvalds if (buffer_new(bh)) { 7241da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 7251da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); 7261da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); 7271da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); 7281da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->next = 0; 7291da177e4SLinus Torvalds bh->b_state &= ~(1UL << BH_New); 7301da177e4SLinus Torvalds if (prev_bh) { 7311da177e4SLinus Torvalds u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); 7321da177e4SLinus Torvalds if (tmp) 7331da177e4SLinus Torvalds affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp); 7341da177e4SLinus Torvalds AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); 7351da177e4SLinus Torvalds affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp); 7361da177e4SLinus Torvalds mark_buffer_dirty_inode(prev_bh, inode); 7371da177e4SLinus Torvalds } 7381da177e4SLinus Torvalds } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp) 7391da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); 7401da177e4SLinus Torvalds affs_brelse(prev_bh); 7411da177e4SLinus Torvalds affs_fix_checksum(sb, bh); 7421da177e4SLinus Torvalds mark_buffer_dirty_inode(bh, inode); 7431da177e4SLinus Torvalds written += tmp; 7441da177e4SLinus Torvalds from += tmp; 7451da177e4SLinus Torvalds bidx++; 7461da177e4SLinus Torvalds } 7471da177e4SLinus Torvalds SetPageUptodate(page); 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds done: 7501da177e4SLinus Torvalds affs_brelse(bh); 7511da177e4SLinus Torvalds tmp = (page->index << PAGE_CACHE_SHIFT) + from; 7521da177e4SLinus Torvalds if (tmp > inode->i_size) 7531da177e4SLinus Torvalds inode->i_size = AFFS_I(inode)->mmu_private = tmp; 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds return written; 7561da177e4SLinus Torvalds 7571da177e4SLinus Torvalds out: 7581da177e4SLinus Torvalds bh = prev_bh; 7591da177e4SLinus Torvalds if (!written) 7601da177e4SLinus Torvalds written = PTR_ERR(bh); 7611da177e4SLinus Torvalds goto done; 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds 764f5e54d6eSChristoph Hellwig const struct address_space_operations affs_aops_ofs = { 7651da177e4SLinus Torvalds .readpage = affs_readpage_ofs, 7661da177e4SLinus Torvalds //.writepage = affs_writepage_ofs, 7671da177e4SLinus Torvalds //.sync_page = affs_sync_page_ofs, 7681da177e4SLinus Torvalds .prepare_write = affs_prepare_write_ofs, 7691da177e4SLinus Torvalds .commit_write = affs_commit_write_ofs 7701da177e4SLinus Torvalds }; 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds /* Free any preallocated blocks. */ 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds void 7751da177e4SLinus Torvalds affs_free_prealloc(struct inode *inode) 7761da177e4SLinus Torvalds { 7771da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino); 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds while (AFFS_I(inode)->i_pa_cnt) { 7821da177e4SLinus Torvalds AFFS_I(inode)->i_pa_cnt--; 7831da177e4SLinus Torvalds affs_free_block(sb, ++AFFS_I(inode)->i_lastalloc); 7841da177e4SLinus Torvalds } 7851da177e4SLinus Torvalds } 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds /* Truncate (or enlarge) a file to the requested size. */ 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds void 7901da177e4SLinus Torvalds affs_truncate(struct inode *inode) 7911da177e4SLinus Torvalds { 7921da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 7931da177e4SLinus Torvalds u32 ext, ext_key; 7941da177e4SLinus Torvalds u32 last_blk, blkcnt, blk; 7951da177e4SLinus Torvalds u32 size; 7961da177e4SLinus Torvalds struct buffer_head *ext_bh; 7971da177e4SLinus Torvalds int i; 7981da177e4SLinus Torvalds 7991da177e4SLinus Torvalds pr_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n", 8001da177e4SLinus Torvalds (u32)inode->i_ino, (u32)AFFS_I(inode)->mmu_private, (u32)inode->i_size); 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds last_blk = 0; 8031da177e4SLinus Torvalds ext = 0; 8041da177e4SLinus Torvalds if (inode->i_size) { 8051da177e4SLinus Torvalds last_blk = ((u32)inode->i_size - 1) / AFFS_SB(sb)->s_data_blksize; 8061da177e4SLinus Torvalds ext = last_blk / AFFS_SB(sb)->s_hashsize; 8071da177e4SLinus Torvalds } 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds if (inode->i_size > AFFS_I(inode)->mmu_private) { 8101da177e4SLinus Torvalds struct address_space *mapping = inode->i_mapping; 8111da177e4SLinus Torvalds struct page *page; 8121da177e4SLinus Torvalds u32 size = inode->i_size - 1; 8131da177e4SLinus Torvalds int res; 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT); 8161da177e4SLinus Torvalds if (!page) 8171da177e4SLinus Torvalds return; 8181da177e4SLinus Torvalds size = (size & (PAGE_CACHE_SIZE - 1)) + 1; 8191da177e4SLinus Torvalds res = mapping->a_ops->prepare_write(NULL, page, size, size); 8201da177e4SLinus Torvalds if (!res) 8211da177e4SLinus Torvalds res = mapping->a_ops->commit_write(NULL, page, size, size); 8221da177e4SLinus Torvalds unlock_page(page); 8231da177e4SLinus Torvalds page_cache_release(page); 8241da177e4SLinus Torvalds mark_inode_dirty(inode); 8251da177e4SLinus Torvalds return; 8261da177e4SLinus Torvalds } else if (inode->i_size == AFFS_I(inode)->mmu_private) 8271da177e4SLinus Torvalds return; 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds // lock cache 8301da177e4SLinus Torvalds ext_bh = affs_get_extblock(inode, ext); 8311da177e4SLinus Torvalds if (IS_ERR(ext_bh)) { 8321da177e4SLinus Torvalds affs_warning(sb, "truncate", "unexpected read error for ext block %u (%d)", 8331da177e4SLinus Torvalds ext, PTR_ERR(ext_bh)); 8341da177e4SLinus Torvalds return; 8351da177e4SLinus Torvalds } 8361da177e4SLinus Torvalds if (AFFS_I(inode)->i_lc) { 8371da177e4SLinus Torvalds /* clear linear cache */ 8381da177e4SLinus Torvalds i = (ext + 1) >> AFFS_I(inode)->i_lc_shift; 8391da177e4SLinus Torvalds if (AFFS_I(inode)->i_lc_size > i) { 8401da177e4SLinus Torvalds AFFS_I(inode)->i_lc_size = i; 8411da177e4SLinus Torvalds for (; i < AFFS_LC_SIZE; i++) 8421da177e4SLinus Torvalds AFFS_I(inode)->i_lc[i] = 0; 8431da177e4SLinus Torvalds } 8441da177e4SLinus Torvalds /* clear associative cache */ 8451da177e4SLinus Torvalds for (i = 0; i < AFFS_AC_SIZE; i++) 8461da177e4SLinus Torvalds if (AFFS_I(inode)->i_ac[i].ext >= ext) 8471da177e4SLinus Torvalds AFFS_I(inode)->i_ac[i].ext = 0; 8481da177e4SLinus Torvalds } 8491da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); 8501da177e4SLinus Torvalds 8511da177e4SLinus Torvalds blkcnt = AFFS_I(inode)->i_blkcnt; 8521da177e4SLinus Torvalds i = 0; 8531da177e4SLinus Torvalds blk = last_blk; 8541da177e4SLinus Torvalds if (inode->i_size) { 8551da177e4SLinus Torvalds i = last_blk % AFFS_SB(sb)->s_hashsize + 1; 8561da177e4SLinus Torvalds blk++; 8571da177e4SLinus Torvalds } else 8581da177e4SLinus Torvalds AFFS_HEAD(ext_bh)->first_data = 0; 8591da177e4SLinus Torvalds size = AFFS_SB(sb)->s_hashsize; 8601da177e4SLinus Torvalds if (size > blkcnt - blk + i) 8611da177e4SLinus Torvalds size = blkcnt - blk + i; 8621da177e4SLinus Torvalds for (; i < size; i++, blk++) { 8631da177e4SLinus Torvalds affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i))); 8641da177e4SLinus Torvalds AFFS_BLOCK(sb, ext_bh, i) = 0; 8651da177e4SLinus Torvalds } 8661da177e4SLinus Torvalds AFFS_TAIL(sb, ext_bh)->extension = 0; 8671da177e4SLinus Torvalds affs_fix_checksum(sb, ext_bh); 8681da177e4SLinus Torvalds mark_buffer_dirty_inode(ext_bh, inode); 8691da177e4SLinus Torvalds affs_brelse(ext_bh); 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds if (inode->i_size) { 8721da177e4SLinus Torvalds AFFS_I(inode)->i_blkcnt = last_blk + 1; 8731da177e4SLinus Torvalds AFFS_I(inode)->i_extcnt = ext + 1; 8741da177e4SLinus Torvalds if (AFFS_SB(sb)->s_flags & SF_OFS) { 8751da177e4SLinus Torvalds struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0); 8761da177e4SLinus Torvalds u32 tmp; 8771da177e4SLinus Torvalds if (IS_ERR(ext_bh)) { 8781da177e4SLinus Torvalds affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)", 8791da177e4SLinus Torvalds ext, PTR_ERR(ext_bh)); 8801da177e4SLinus Torvalds return; 8811da177e4SLinus Torvalds } 8821da177e4SLinus Torvalds tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next); 8831da177e4SLinus Torvalds AFFS_DATA_HEAD(bh)->next = 0; 8841da177e4SLinus Torvalds affs_adjust_checksum(bh, -tmp); 8851da177e4SLinus Torvalds affs_brelse(bh); 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds } else { 8881da177e4SLinus Torvalds AFFS_I(inode)->i_blkcnt = 0; 8891da177e4SLinus Torvalds AFFS_I(inode)->i_extcnt = 1; 8901da177e4SLinus Torvalds } 8911da177e4SLinus Torvalds AFFS_I(inode)->mmu_private = inode->i_size; 8921da177e4SLinus Torvalds // unlock cache 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds while (ext_key) { 8951da177e4SLinus Torvalds ext_bh = affs_bread(sb, ext_key); 8961da177e4SLinus Torvalds size = AFFS_SB(sb)->s_hashsize; 8971da177e4SLinus Torvalds if (size > blkcnt - blk) 8981da177e4SLinus Torvalds size = blkcnt - blk; 8991da177e4SLinus Torvalds for (i = 0; i < size; i++, blk++) 9001da177e4SLinus Torvalds affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i))); 9011da177e4SLinus Torvalds affs_free_block(sb, ext_key); 9021da177e4SLinus Torvalds ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); 9031da177e4SLinus Torvalds affs_brelse(ext_bh); 9041da177e4SLinus Torvalds } 9051da177e4SLinus Torvalds affs_free_prealloc(inode); 9061da177e4SLinus Torvalds } 907