static int ufs_trunc_tindirect(struct inode *inode) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct ufs_inode_info *ufsi = UFS_I(inode); struct ufs_buffer_head * tind_bh; u64 tindirect_block, tmp, i; void *tind, *p; int retry; UFSD("ENTER: ino %lu\n", inode->i_ino); retry = 0; tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0; p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) return 0; tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); if (tmp != ufs_data_ptr_to_cpu(sb, p)) { ubh_brelse (tind_bh); return 1; } if (!tind_bh) { ufs_data_ptr_clear(uspi, p); return 0; } for (i = tindirect_block ; i < uspi->s_apb ; i++) { tind = ubh_get_data_ptr(uspi, tind_bh, i); retry |= ufs_trunc_dindirect(inode, UFS_NDADDR + uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); ubh_mark_buffer_dirty(tind_bh); } for (i = 0; i < uspi->s_apb; i++) if (!ufs_is_data_ptr_zero(uspi, ubh_get_data_ptr(uspi, tind_bh, i))) break; if (i >= uspi->s_apb) { tmp = ufs_data_ptr_to_cpu(sb, p); ufs_data_ptr_clear(uspi, p); ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); ubh_bforget(tind_bh); tind_bh = NULL; } if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) { ubh_ll_rw_block(SWRITE, tind_bh); ubh_wait_on_buffer (tind_bh); } ubh_brelse (tind_bh); UFSD("EXIT: ino %lu\n", inode->i_ino); return retry; }
static int ufs_trunc_tindirect (struct inode * inode) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_buffer_head * tind_bh; unsigned tindirect_block, tmp, i; __fs32 * tind, * p; int retry; UFSD("ENTER\n"); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; retry = 0; tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0; p = ufsi->i_u1.i_data + UFS_TIND_BLOCK; if (!(tmp = fs32_to_cpu(sb, *p))) return 0; tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); if (tmp != fs32_to_cpu(sb, *p)) { ubh_brelse (tind_bh); return 1; } if (!tind_bh) { *p = 0; return 0; } for (i = tindirect_block ; i < uspi->s_apb ; i++) { tind = ubh_get_addr32 (tind_bh, i); retry |= ufs_trunc_dindirect(inode, UFS_NDADDR + uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); ubh_mark_buffer_dirty(tind_bh); } for (i = 0; i < uspi->s_apb; i++) if (*ubh_get_addr32 (tind_bh, i)) break; if (i >= uspi->s_apb) { tmp = fs32_to_cpu(sb, *p); *p = 0; ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); ubh_bforget(tind_bh); tind_bh = NULL; } if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) { ubh_ll_rw_block(SWRITE, tind_bh); ubh_wait_on_buffer (tind_bh); } ubh_brelse (tind_bh); UFSD("EXIT\n"); return retry; }
int ufs_truncate(struct inode *inode, loff_t old_i_size) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; int retry, err = 0; UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", inode->i_ino, (unsigned long long)i_size_read(inode), (unsigned long long)old_i_size); if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return -EINVAL; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return -EPERM; err = ufs_alloc_lastblock(inode); if (err) { i_size_write(inode, old_i_size); goto out; } block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); lock_kernel(); while (1) { retry = ufs_trunc_direct(inode); retry |= ufs_trunc_indirect(inode, UFS_IND_BLOCK, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); retry |= ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); retry |= ufs_trunc_tindirect (inode); if (!retry) break; if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) ufs_sync_inode (inode); blk_run_address_space(inode->i_mapping); yield(); } inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; ufsi->i_lastfrag = DIRECT_FRAGMENT; unlock_kernel(); mark_inode_dirty(inode); out: UFSD("EXIT: err %d\n", err); return err; }