1 /* 2 * truncate.c 3 * 4 * PURPOSE 5 * Truncate handling routines for the OSTA-UDF(tm) filesystem. 6 * 7 * CONTACTS 8 * E-mail regarding any portion of the Linux UDF file system should be 9 * directed to the development team mailing list (run by majordomo): 10 * linux_udf@hpesjro.fc.hp.com 11 * 12 * COPYRIGHT 13 * This file is distributed under the terms of the GNU General Public 14 * License (GPL). Copies of the GPL can be obtained from: 15 * ftp://prep.ai.mit.edu/pub/gnu/GPL 16 * Each contributing author retains all rights to their own work. 17 * 18 * (C) 1999-2004 Ben Fennema 19 * (C) 1999 Stelias Computing Inc 20 * 21 * HISTORY 22 * 23 * 02/24/99 blf Created. 24 * 25 */ 26 27 #include "udfdecl.h" 28 #include <linux/fs.h> 29 #include <linux/mm.h> 30 #include <linux/udf_fs.h> 31 #include <linux/buffer_head.h> 32 33 #include "udf_i.h" 34 #include "udf_sb.h" 35 36 static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffset, 37 kernel_lb_addr eloc, int8_t etype, uint32_t elen, struct buffer_head *bh, uint32_t nelen) 38 { 39 kernel_lb_addr neloc = { 0, 0 }; 40 int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; 41 int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; 42 43 if (nelen) 44 { 45 if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) 46 { 47 udf_free_blocks(inode->i_sb, inode, eloc, 0, last_block); 48 etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30); 49 } 50 else 51 neloc = eloc; 52 nelen = (etype << 30) | nelen; 53 } 54 55 if (elen != nelen) 56 { 57 udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0); 58 if (last_block - first_block > 0) 59 { 60 if (etype == (EXT_RECORDED_ALLOCATED >> 30)) 61 mark_inode_dirty(inode); 62 63 if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) 64 udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block); 65 } 66 } 67 } 68 69 void udf_discard_prealloc(struct inode * inode) 70 { 71 kernel_lb_addr bloc, eloc; 72 uint32_t extoffset = 0, elen, nelen; 73 uint64_t lbcount = 0; 74 int8_t etype = -1, netype; 75 struct buffer_head *bh = NULL; 76 int adsize; 77 78 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB || 79 inode->i_size == UDF_I_LENEXTENTS(inode)) 80 { 81 return; 82 } 83 84 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) 85 adsize = sizeof(short_ad); 86 else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) 87 adsize = sizeof(long_ad); 88 else 89 adsize = 0; 90 91 bloc = UDF_I_LOCATION(inode); 92 93 while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1) 94 { 95 etype = netype; 96 lbcount += elen; 97 if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize) 98 { 99 nelen = elen - (lbcount - inode->i_size); 100 extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen); 101 lbcount = inode->i_size; 102 } 103 } 104 if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) 105 { 106 extoffset -= adsize; 107 lbcount -= elen; 108 extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0); 109 if (!bh) 110 { 111 UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode); 112 mark_inode_dirty(inode); 113 } 114 else 115 { 116 struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); 117 aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc)); 118 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) 119 udf_update_tag(bh->b_data, extoffset); 120 else 121 udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); 122 mark_buffer_dirty_inode(bh, inode); 123 } 124 } 125 UDF_I_LENEXTENTS(inode) = lbcount; 126 127 udf_release_data(bh); 128 } 129 130 void udf_truncate_extents(struct inode * inode) 131 { 132 kernel_lb_addr bloc, eloc, neloc = { 0, 0 }; 133 uint32_t extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc; 134 int8_t etype; 135 int first_block = inode->i_size >> inode->i_sb->s_blocksize_bits; 136 struct buffer_head *bh = NULL; 137 int adsize; 138 139 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) 140 adsize = sizeof(short_ad); 141 else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) 142 adsize = sizeof(long_ad); 143 else 144 adsize = 0; 145 146 etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh); 147 offset += (inode->i_size & (inode->i_sb->s_blocksize - 1)); 148 if (etype != -1) 149 { 150 extoffset -= adsize; 151 extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, offset); 152 extoffset += adsize; 153 154 if (offset) 155 lenalloc = extoffset; 156 else 157 lenalloc = extoffset - adsize; 158 159 if (!bh) 160 lenalloc -= udf_file_entry_alloc_offset(inode); 161 else 162 lenalloc -= sizeof(struct allocExtDesc); 163 164 while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1) 165 { 166 if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) 167 { 168 udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0); 169 extoffset = 0; 170 if (lelen) 171 { 172 if (!bh) 173 BUG(); 174 else 175 memset(bh->b_data, 0x00, sizeof(struct allocExtDesc)); 176 udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen); 177 } 178 else 179 { 180 if (!bh) 181 { 182 UDF_I_LENALLOC(inode) = lenalloc; 183 mark_inode_dirty(inode); 184 } 185 else 186 { 187 struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); 188 aed->lengthAllocDescs = cpu_to_le32(lenalloc); 189 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) 190 udf_update_tag(bh->b_data, lenalloc + 191 sizeof(struct allocExtDesc)); 192 else 193 udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); 194 mark_buffer_dirty_inode(bh, inode); 195 } 196 } 197 198 udf_release_data(bh); 199 extoffset = sizeof(struct allocExtDesc); 200 bloc = eloc; 201 bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, bloc, 0)); 202 if (elen) 203 lelen = (elen + inode->i_sb->s_blocksize - 1) >> 204 inode->i_sb->s_blocksize_bits; 205 else 206 lelen = 1; 207 } 208 else 209 { 210 extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0); 211 extoffset += adsize; 212 } 213 } 214 215 if (lelen) 216 { 217 if (!bh) 218 BUG(); 219 else 220 memset(bh->b_data, 0x00, sizeof(struct allocExtDesc)); 221 udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen); 222 } 223 else 224 { 225 if (!bh) 226 { 227 UDF_I_LENALLOC(inode) = lenalloc; 228 mark_inode_dirty(inode); 229 } 230 else 231 { 232 struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); 233 aed->lengthAllocDescs = cpu_to_le32(lenalloc); 234 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) 235 udf_update_tag(bh->b_data, lenalloc + 236 sizeof(struct allocExtDesc)); 237 else 238 udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); 239 mark_buffer_dirty_inode(bh, inode); 240 } 241 } 242 } 243 else if (inode->i_size) 244 { 245 if (offset) 246 { 247 extoffset -= adsize; 248 etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1); 249 if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) 250 { 251 extoffset -= adsize; 252 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset); 253 udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0); 254 } 255 else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) 256 { 257 kernel_lb_addr neloc = { 0, 0 }; 258 extoffset -= adsize; 259 nelen = EXT_NOT_RECORDED_NOT_ALLOCATED | 260 ((elen + offset + inode->i_sb->s_blocksize - 1) & 261 ~(inode->i_sb->s_blocksize - 1)); 262 udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1); 263 udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1); 264 } 265 else 266 { 267 if (elen & (inode->i_sb->s_blocksize - 1)) 268 { 269 extoffset -= adsize; 270 elen = EXT_RECORDED_ALLOCATED | 271 ((elen + inode->i_sb->s_blocksize - 1) & 272 ~(inode->i_sb->s_blocksize - 1)); 273 udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1); 274 } 275 memset(&eloc, 0x00, sizeof(kernel_lb_addr)); 276 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset; 277 udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1); 278 } 279 } 280 } 281 UDF_I_LENEXTENTS(inode) = inode->i_size; 282 283 udf_release_data(bh); 284 } 285