11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * truncate.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * PURPOSE 51da177e4SLinus Torvalds * Truncate handling routines for the OSTA-UDF(tm) filesystem. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * COPYRIGHT 81da177e4SLinus Torvalds * This file is distributed under the terms of the GNU General Public 91da177e4SLinus Torvalds * License (GPL). Copies of the GPL can be obtained from: 101da177e4SLinus Torvalds * ftp://prep.ai.mit.edu/pub/gnu/GPL 111da177e4SLinus Torvalds * Each contributing author retains all rights to their own work. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * (C) 1999-2004 Ben Fennema 141da177e4SLinus Torvalds * (C) 1999 Stelias Computing Inc 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * HISTORY 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * 02/24/99 blf Created. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include "udfdecl.h" 231da177e4SLinus Torvalds #include <linux/fs.h> 241da177e4SLinus Torvalds #include <linux/mm.h> 251da177e4SLinus Torvalds #include <linux/udf_fs.h> 261da177e4SLinus Torvalds #include <linux/buffer_head.h> 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include "udf_i.h" 291da177e4SLinus Torvalds #include "udf_sb.h" 301da177e4SLinus Torvalds 31ff116fc8SJan Kara static void extent_trunc(struct inode *inode, struct extent_position *epos, 32cb00ea35SCyrill Gorcunov kernel_lb_addr eloc, int8_t etype, uint32_t elen, 33cb00ea35SCyrill Gorcunov uint32_t nelen) 341da177e4SLinus Torvalds { 3528de7948SCyrill Gorcunov kernel_lb_addr neloc = {}; 3628de7948SCyrill Gorcunov int last_block = (elen + inode->i_sb->s_blocksize - 1) >> 3728de7948SCyrill Gorcunov inode->i_sb->s_blocksize_bits; 3828de7948SCyrill Gorcunov int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> 3928de7948SCyrill Gorcunov inode->i_sb->s_blocksize_bits; 401da177e4SLinus Torvalds 41cb00ea35SCyrill Gorcunov if (nelen) { 42cb00ea35SCyrill Gorcunov if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { 43cb00ea35SCyrill Gorcunov udf_free_blocks(inode->i_sb, inode, eloc, 0, 44cb00ea35SCyrill Gorcunov last_block); 451da177e4SLinus Torvalds etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30); 46cb00ea35SCyrill Gorcunov } else 471da177e4SLinus Torvalds neloc = eloc; 481da177e4SLinus Torvalds nelen = (etype << 30) | nelen; 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds 51cb00ea35SCyrill Gorcunov if (elen != nelen) { 52ff116fc8SJan Kara udf_write_aext(inode, epos, neloc, nelen, 0); 53cb00ea35SCyrill Gorcunov if (last_block - first_block > 0) { 541da177e4SLinus Torvalds if (etype == (EXT_RECORDED_ALLOCATED >> 30)) 551da177e4SLinus Torvalds mark_inode_dirty(inode); 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) 58cb00ea35SCyrill Gorcunov udf_free_blocks(inode->i_sb, inode, eloc, 59cb00ea35SCyrill Gorcunov first_block, 60cb00ea35SCyrill Gorcunov last_block - first_block); 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 6574584ae5SJan Kara /* 6674584ae5SJan Kara * Truncate the last extent to match i_size. This function assumes 6774584ae5SJan Kara * that preallocation extent is already truncated. 6874584ae5SJan Kara */ 6974584ae5SJan Kara void udf_truncate_tail_extent(struct inode *inode) 701da177e4SLinus Torvalds { 7128de7948SCyrill Gorcunov struct extent_position epos = {}; 72ff116fc8SJan Kara kernel_lb_addr eloc; 73ff116fc8SJan Kara uint32_t elen, nelen; 741da177e4SLinus Torvalds uint64_t lbcount = 0; 751da177e4SLinus Torvalds int8_t etype = -1, netype; 761da177e4SLinus Torvalds int adsize; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB || 791da177e4SLinus Torvalds inode->i_size == UDF_I_LENEXTENTS(inode)) 801da177e4SLinus Torvalds return; 8174584ae5SJan Kara /* Are we going to delete the file anyway? */ 8274584ae5SJan Kara if (inode->i_nlink == 0) 8374584ae5SJan Kara return; 8474584ae5SJan Kara 8574584ae5SJan Kara if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) 8674584ae5SJan Kara adsize = sizeof(short_ad); 8774584ae5SJan Kara else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) 8874584ae5SJan Kara adsize = sizeof(long_ad); 8974584ae5SJan Kara else 9074584ae5SJan Kara BUG(); 9174584ae5SJan Kara 9274584ae5SJan Kara /* Find the last extent in the file */ 93cb00ea35SCyrill Gorcunov while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { 9474584ae5SJan Kara etype = netype; 9574584ae5SJan Kara lbcount += elen; 9674584ae5SJan Kara if (lbcount > inode->i_size) { 9774584ae5SJan Kara if (lbcount - inode->i_size >= inode->i_sb->s_blocksize) 9874584ae5SJan Kara printk(KERN_WARNING 9974584ae5SJan Kara "udf_truncate_tail_extent(): Too long " 10074584ae5SJan Kara "extent after EOF in inode %u: i_size: " 10174584ae5SJan Kara "%Ld lbcount: %Ld extent %u+%u\n", 10274584ae5SJan Kara (unsigned)inode->i_ino, 10374584ae5SJan Kara (long long)inode->i_size, 10474584ae5SJan Kara (long long)lbcount, 10574584ae5SJan Kara (unsigned)eloc.logicalBlockNum, 10674584ae5SJan Kara (unsigned)elen); 10774584ae5SJan Kara nelen = elen - (lbcount - inode->i_size); 10874584ae5SJan Kara epos.offset -= adsize; 10974584ae5SJan Kara extent_trunc(inode, &epos, eloc, etype, elen, nelen); 11074584ae5SJan Kara epos.offset += adsize; 11174584ae5SJan Kara if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1) 11274584ae5SJan Kara printk(KERN_ERR "udf_truncate_tail_extent(): " 11374584ae5SJan Kara "Extent after EOF in inode %u.\n", 11474584ae5SJan Kara (unsigned)inode->i_ino); 11574584ae5SJan Kara break; 11674584ae5SJan Kara } 11774584ae5SJan Kara } 11874584ae5SJan Kara /* This inode entry is in-memory only and thus we don't have to mark 11974584ae5SJan Kara * the inode dirty */ 12074584ae5SJan Kara UDF_I_LENEXTENTS(inode) = inode->i_size; 12174584ae5SJan Kara brelse(epos.bh); 12274584ae5SJan Kara } 12374584ae5SJan Kara 12474584ae5SJan Kara void udf_discard_prealloc(struct inode *inode) 12574584ae5SJan Kara { 12674584ae5SJan Kara struct extent_position epos = { NULL, 0, {0, 0} }; 12774584ae5SJan Kara kernel_lb_addr eloc; 12874584ae5SJan Kara uint32_t elen; 12974584ae5SJan Kara uint64_t lbcount = 0; 13074584ae5SJan Kara int8_t etype = -1, netype; 13174584ae5SJan Kara int adsize; 13274584ae5SJan Kara 13374584ae5SJan Kara if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB || 13474584ae5SJan Kara inode->i_size == UDF_I_LENEXTENTS(inode)) 13574584ae5SJan Kara return; 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) 1381da177e4SLinus Torvalds adsize = sizeof(short_ad); 1391da177e4SLinus Torvalds else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) 1401da177e4SLinus Torvalds adsize = sizeof(long_ad); 1411da177e4SLinus Torvalds else 1421da177e4SLinus Torvalds adsize = 0; 1431da177e4SLinus Torvalds 144ff116fc8SJan Kara epos.block = UDF_I_LOCATION(inode); 1451da177e4SLinus Torvalds 146ff116fc8SJan Kara /* Find the last extent in the file */ 14774584ae5SJan Kara while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { 1481da177e4SLinus Torvalds etype = netype; 1491da177e4SLinus Torvalds lbcount += elen; 1501da177e4SLinus Torvalds } 151ff116fc8SJan Kara if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { 152ff116fc8SJan Kara epos.offset -= adsize; 1531da177e4SLinus Torvalds lbcount -= elen; 154ff116fc8SJan Kara extent_trunc(inode, &epos, eloc, etype, elen, 0); 15574584ae5SJan Kara if (!epos.bh) { 156cb00ea35SCyrill Gorcunov UDF_I_LENALLOC(inode) = 1574b11111aSMarcin Slusarz epos.offset - 1584b11111aSMarcin Slusarz udf_file_entry_alloc_offset(inode); 1591da177e4SLinus Torvalds mark_inode_dirty(inode); 16074584ae5SJan Kara } else { 161cb00ea35SCyrill Gorcunov struct allocExtDesc *aed = 162cb00ea35SCyrill Gorcunov (struct allocExtDesc *)(epos.bh->b_data); 163cb00ea35SCyrill Gorcunov aed->lengthAllocDescs = 164cb00ea35SCyrill Gorcunov cpu_to_le32(epos.offset - 165cb00ea35SCyrill Gorcunov sizeof(struct allocExtDesc)); 16628de7948SCyrill Gorcunov if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || 1676c79e987SMarcin Slusarz UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) 168ff116fc8SJan Kara udf_update_tag(epos.bh->b_data, epos.offset); 1691da177e4SLinus Torvalds else 170cb00ea35SCyrill Gorcunov udf_update_tag(epos.bh->b_data, 171cb00ea35SCyrill Gorcunov sizeof(struct allocExtDesc)); 172ff116fc8SJan Kara mark_buffer_dirty_inode(epos.bh, inode); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds } 17574584ae5SJan Kara /* This inode entry is in-memory only and thus we don't have to mark 17674584ae5SJan Kara * the inode dirty */ 1771da177e4SLinus Torvalds UDF_I_LENEXTENTS(inode) = lbcount; 1783bf25cb4SJan Kara brelse(epos.bh); 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds void udf_truncate_extents(struct inode *inode) 1821da177e4SLinus Torvalds { 183ff116fc8SJan Kara struct extent_position epos; 18428de7948SCyrill Gorcunov kernel_lb_addr eloc, neloc = {}; 185ff116fc8SJan Kara uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc; 1861da177e4SLinus Torvalds int8_t etype; 18731170b6aSJan Kara struct super_block *sb = inode->i_sb; 1886c79e987SMarcin Slusarz struct udf_sb_info *sbi = UDF_SB(sb); 18931170b6aSJan Kara sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset; 19060448b1dSJan Kara loff_t byte_offset; 1911da177e4SLinus Torvalds int adsize; 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) 1941da177e4SLinus Torvalds adsize = sizeof(short_ad); 1951da177e4SLinus Torvalds else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) 1961da177e4SLinus Torvalds adsize = sizeof(long_ad); 1971da177e4SLinus Torvalds else 198ff116fc8SJan Kara BUG(); 1991da177e4SLinus Torvalds 200ff116fc8SJan Kara etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); 20128de7948SCyrill Gorcunov byte_offset = (offset << sb->s_blocksize_bits) + 202cb00ea35SCyrill Gorcunov (inode->i_size & (sb->s_blocksize - 1)); 203cb00ea35SCyrill Gorcunov if (etype != -1) { 204ff116fc8SJan Kara epos.offset -= adsize; 205ff116fc8SJan Kara extent_trunc(inode, &epos, eloc, etype, elen, byte_offset); 206ff116fc8SJan Kara epos.offset += adsize; 20760448b1dSJan Kara if (byte_offset) 208ff116fc8SJan Kara lenalloc = epos.offset; 2091da177e4SLinus Torvalds else 210ff116fc8SJan Kara lenalloc = epos.offset - adsize; 2111da177e4SLinus Torvalds 212ff116fc8SJan Kara if (!epos.bh) 2131da177e4SLinus Torvalds lenalloc -= udf_file_entry_alloc_offset(inode); 2141da177e4SLinus Torvalds else 2151da177e4SLinus Torvalds lenalloc -= sizeof(struct allocExtDesc); 2161da177e4SLinus Torvalds 2174b11111aSMarcin Slusarz while ((etype = udf_current_aext(inode, &epos, &eloc, 2184b11111aSMarcin Slusarz &elen, 0)) != -1) { 219cb00ea35SCyrill Gorcunov if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { 220ff116fc8SJan Kara udf_write_aext(inode, &epos, neloc, nelen, 0); 221cb00ea35SCyrill Gorcunov if (indirect_ext_len) { 222ff116fc8SJan Kara /* We managed to free all extents in the 223ff116fc8SJan Kara * indirect extent - free it too */ 224ff116fc8SJan Kara if (!epos.bh) 2251da177e4SLinus Torvalds BUG(); 226cb00ea35SCyrill Gorcunov udf_free_blocks(sb, inode, epos.block, 227cb00ea35SCyrill Gorcunov 0, indirect_ext_len); 228cb00ea35SCyrill Gorcunov } else { 229cb00ea35SCyrill Gorcunov if (!epos.bh) { 2304b11111aSMarcin Slusarz UDF_I_LENALLOC(inode) = 2314b11111aSMarcin Slusarz lenalloc; 2321da177e4SLinus Torvalds mark_inode_dirty(inode); 233cb00ea35SCyrill Gorcunov } else { 234cb00ea35SCyrill Gorcunov struct allocExtDesc *aed = 2354b11111aSMarcin Slusarz (struct allocExtDesc *) 2364b11111aSMarcin Slusarz (epos.bh->b_data); 2374b11111aSMarcin Slusarz int len = 2384b11111aSMarcin Slusarz sizeof(struct allocExtDesc); 2394b11111aSMarcin Slusarz 240cb00ea35SCyrill Gorcunov aed->lengthAllocDescs = 241cb00ea35SCyrill Gorcunov cpu_to_le32(lenalloc); 2424b11111aSMarcin Slusarz if (!UDF_QUERY_FLAG(sb, 2434b11111aSMarcin Slusarz UDF_FLAG_STRICT) || 2446c79e987SMarcin Slusarz sbi->s_udfrev >= 0x0201) 2454b11111aSMarcin Slusarz len += lenalloc; 2464b11111aSMarcin Slusarz 24728de7948SCyrill Gorcunov udf_update_tag(epos.bh->b_data, 2484b11111aSMarcin Slusarz len); 2494b11111aSMarcin Slusarz mark_buffer_dirty_inode( 2504b11111aSMarcin Slusarz epos.bh, inode); 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds } 253ff116fc8SJan Kara brelse(epos.bh); 254ff116fc8SJan Kara epos.offset = sizeof(struct allocExtDesc); 255ff116fc8SJan Kara epos.block = eloc; 2564b11111aSMarcin Slusarz epos.bh = udf_tread(sb, 2574b11111aSMarcin Slusarz udf_get_lb_pblock(sb, eloc, 0)); 2581da177e4SLinus Torvalds if (elen) 2594b11111aSMarcin Slusarz indirect_ext_len = 2604b11111aSMarcin Slusarz (elen + sb->s_blocksize - 1) >> 26128de7948SCyrill Gorcunov sb->s_blocksize_bits; 2621da177e4SLinus Torvalds else 263ff116fc8SJan Kara indirect_ext_len = 1; 264cb00ea35SCyrill Gorcunov } else { 2654b11111aSMarcin Slusarz extent_trunc(inode, &epos, eloc, etype, 2664b11111aSMarcin Slusarz elen, 0); 267ff116fc8SJan Kara epos.offset += adsize; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 271cb00ea35SCyrill Gorcunov if (indirect_ext_len) { 272ff116fc8SJan Kara if (!epos.bh) 2731da177e4SLinus Torvalds BUG(); 274cb00ea35SCyrill Gorcunov udf_free_blocks(sb, inode, epos.block, 0, 275cb00ea35SCyrill Gorcunov indirect_ext_len); 276cb00ea35SCyrill Gorcunov } else { 277cb00ea35SCyrill Gorcunov if (!epos.bh) { 2781da177e4SLinus Torvalds UDF_I_LENALLOC(inode) = lenalloc; 2791da177e4SLinus Torvalds mark_inode_dirty(inode); 280cb00ea35SCyrill Gorcunov } else { 281cb00ea35SCyrill Gorcunov struct allocExtDesc *aed = 282cb00ea35SCyrill Gorcunov (struct allocExtDesc *)(epos.bh->b_data); 2831da177e4SLinus Torvalds aed->lengthAllocDescs = cpu_to_le32(lenalloc); 28428de7948SCyrill Gorcunov if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || 2856c79e987SMarcin Slusarz sbi->s_udfrev >= 0x0201) 286cb00ea35SCyrill Gorcunov udf_update_tag(epos.bh->b_data, 2874b11111aSMarcin Slusarz lenalloc + 2884b11111aSMarcin Slusarz sizeof(struct allocExtDesc)); 2891da177e4SLinus Torvalds else 290cb00ea35SCyrill Gorcunov udf_update_tag(epos.bh->b_data, 29128de7948SCyrill Gorcunov sizeof(struct allocExtDesc)); 292ff116fc8SJan Kara mark_buffer_dirty_inode(epos.bh, inode); 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds } 295cb00ea35SCyrill Gorcunov } else if (inode->i_size) { 296cb00ea35SCyrill Gorcunov if (byte_offset) { 29731170b6aSJan Kara kernel_long_ad extent; 29831170b6aSJan Kara 29900a2b0f6SJan Kara /* 30000a2b0f6SJan Kara * OK, there is not extent covering inode->i_size and 30100a2b0f6SJan Kara * no extent above inode->i_size => truncate is 30231170b6aSJan Kara * extending the file by 'offset' blocks. 30300a2b0f6SJan Kara */ 30428de7948SCyrill Gorcunov if ((!epos.bh && 3054b11111aSMarcin Slusarz epos.offset == 3064b11111aSMarcin Slusarz udf_file_entry_alloc_offset(inode)) || 3074b11111aSMarcin Slusarz (epos.bh && epos.offset == 3084b11111aSMarcin Slusarz sizeof(struct allocExtDesc))) { 30931170b6aSJan Kara /* File has no extents at all or has empty last 31031170b6aSJan Kara * indirect extent! Create a fake extent... */ 31131170b6aSJan Kara extent.extLocation.logicalBlockNum = 0; 31231170b6aSJan Kara extent.extLocation.partitionReferenceNum = 0; 3134b11111aSMarcin Slusarz extent.extLength = 3144b11111aSMarcin Slusarz EXT_NOT_RECORDED_NOT_ALLOCATED; 315cb00ea35SCyrill Gorcunov } else { 316ff116fc8SJan Kara epos.offset -= adsize; 31731170b6aSJan Kara etype = udf_next_aext(inode, &epos, 318cb00ea35SCyrill Gorcunov &extent.extLocation, 319cb00ea35SCyrill Gorcunov &extent.extLength, 0); 32031170b6aSJan Kara extent.extLength |= etype << 30; 3211da177e4SLinus Torvalds } 322cb00ea35SCyrill Gorcunov udf_extend_file(inode, &epos, &extent, 3234b11111aSMarcin Slusarz offset + 3244b11111aSMarcin Slusarz ((inode->i_size & 3254b11111aSMarcin Slusarz (sb->s_blocksize - 1)) != 0)); 3261da177e4SLinus Torvalds } 32700a2b0f6SJan Kara } 3281da177e4SLinus Torvalds UDF_I_LENEXTENTS(inode) = inode->i_size; 3291da177e4SLinus Torvalds 3303bf25cb4SJan Kara brelse(epos.bh); 3311da177e4SLinus Torvalds } 332