aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf/truncate.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/udf/truncate.c')
-rw-r--r--fs/udf/truncate.c159
1 files changed, 78 insertions, 81 deletions
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index ebd0f37f8b16..84191801f4c9 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -28,8 +28,8 @@
28#include "udf_i.h" 28#include "udf_i.h"
29#include "udf_sb.h" 29#include "udf_sb.h"
30 30
31static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffset, 31static void extent_trunc(struct inode * inode, struct extent_position *epos,
32 kernel_lb_addr eloc, int8_t etype, uint32_t elen, struct buffer_head *bh, uint32_t nelen) 32 kernel_lb_addr eloc, int8_t etype, uint32_t elen, uint32_t nelen)
33{ 33{
34 kernel_lb_addr neloc = { 0, 0 }; 34 kernel_lb_addr neloc = { 0, 0 };
35 int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; 35 int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
@@ -49,7 +49,7 @@ static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffse
49 49
50 if (elen != nelen) 50 if (elen != nelen)
51 { 51 {
52 udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0); 52 udf_write_aext(inode, epos, neloc, nelen, 0);
53 if (last_block - first_block > 0) 53 if (last_block - first_block > 0)
54 { 54 {
55 if (etype == (EXT_RECORDED_ALLOCATED >> 30)) 55 if (etype == (EXT_RECORDED_ALLOCATED >> 30))
@@ -63,18 +63,16 @@ static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffse
63 63
64void udf_discard_prealloc(struct inode * inode) 64void udf_discard_prealloc(struct inode * inode)
65{ 65{
66 kernel_lb_addr bloc, eloc; 66 struct extent_position epos = { NULL, 0, {0, 0}};
67 uint32_t extoffset = 0, elen, nelen; 67 kernel_lb_addr eloc;
68 uint32_t elen, nelen;
68 uint64_t lbcount = 0; 69 uint64_t lbcount = 0;
69 int8_t etype = -1, netype; 70 int8_t etype = -1, netype;
70 struct buffer_head *bh = NULL;
71 int adsize; 71 int adsize;
72 72
73 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB || 73 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
74 inode->i_size == UDF_I_LENEXTENTS(inode)) 74 inode->i_size == UDF_I_LENEXTENTS(inode))
75 {
76 return; 75 return;
77 }
78 76
79 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) 77 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
80 adsize = sizeof(short_ad); 78 adsize = sizeof(short_ad);
@@ -83,53 +81,55 @@ void udf_discard_prealloc(struct inode * inode)
83 else 81 else
84 adsize = 0; 82 adsize = 0;
85 83
86 bloc = UDF_I_LOCATION(inode); 84 epos.block = UDF_I_LOCATION(inode);
87 85
88 while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1) 86 /* Find the last extent in the file */
87 while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)
89 { 88 {
90 etype = netype; 89 etype = netype;
91 lbcount += elen; 90 lbcount += elen;
92 if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize) 91 if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize)
93 { 92 {
94 nelen = elen - (lbcount - inode->i_size); 93 nelen = elen - (lbcount - inode->i_size);
95 extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen); 94 epos.offset -= adsize;
95 extent_trunc(inode, &epos, eloc, etype, elen, nelen);
96 epos.offset += adsize;
96 lbcount = inode->i_size; 97 lbcount = inode->i_size;
97 } 98 }
98 } 99 }
99 if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) 100 if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
100 { 101 epos.offset -= adsize;
101 extoffset -= adsize;
102 lbcount -= elen; 102 lbcount -= elen;
103 extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0); 103 extent_trunc(inode, &epos, eloc, etype, elen, 0);
104 if (!bh) 104 if (!epos.bh)
105 { 105 {
106 UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode); 106 UDF_I_LENALLOC(inode) = epos.offset - udf_file_entry_alloc_offset(inode);
107 mark_inode_dirty(inode); 107 mark_inode_dirty(inode);
108 } 108 }
109 else 109 else
110 { 110 {
111 struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); 111 struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
112 aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc)); 112 aed->lengthAllocDescs = cpu_to_le32(epos.offset - sizeof(struct allocExtDesc));
113 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) 113 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
114 udf_update_tag(bh->b_data, extoffset); 114 udf_update_tag(epos.bh->b_data, epos.offset);
115 else 115 else
116 udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); 116 udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
117 mark_buffer_dirty_inode(bh, inode); 117 mark_buffer_dirty_inode(epos.bh, inode);
118 } 118 }
119 } 119 }
120 UDF_I_LENEXTENTS(inode) = lbcount; 120 UDF_I_LENEXTENTS(inode) = lbcount;
121 121
122 udf_release_data(bh); 122 udf_release_data(epos.bh);
123} 123}
124 124
125void udf_truncate_extents(struct inode * inode) 125void udf_truncate_extents(struct inode * inode)
126{ 126{
127 kernel_lb_addr bloc, eloc, neloc = { 0, 0 }; 127 struct extent_position epos;
128 uint32_t extoffset, elen, nelen = 0, lelen = 0, lenalloc; 128 kernel_lb_addr eloc, neloc = { 0, 0 };
129 uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
129 int8_t etype; 130 int8_t etype;
130 sector_t first_block = inode->i_size >> inode->i_sb->s_blocksize_bits, offset; 131 sector_t first_block = inode->i_size >> inode->i_sb->s_blocksize_bits, offset;
131 loff_t byte_offset; 132 loff_t byte_offset;
132 struct buffer_head *bh = NULL;
133 int adsize; 133 int adsize;
134 134
135 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) 135 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
@@ -137,102 +137,98 @@ void udf_truncate_extents(struct inode * inode)
137 else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) 137 else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
138 adsize = sizeof(long_ad); 138 adsize = sizeof(long_ad);
139 else 139 else
140 adsize = 0; 140 BUG();
141 141
142 etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh); 142 etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
143 byte_offset = (offset << inode->i_sb->s_blocksize_bits) + (inode->i_size & (inode->i_sb->s_blocksize-1)); 143 byte_offset = (offset << inode->i_sb->s_blocksize_bits) + (inode->i_size & (inode->i_sb->s_blocksize-1));
144 if (etype != -1) 144 if (etype != -1)
145 { 145 {
146 extoffset -= adsize; 146 epos.offset -= adsize;
147 extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, byte_offset); 147 extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
148 extoffset += adsize; 148 epos.offset += adsize;
149
150 if (byte_offset) 149 if (byte_offset)
151 lenalloc = extoffset; 150 lenalloc = epos.offset;
152 else 151 else
153 lenalloc = extoffset - adsize; 152 lenalloc = epos.offset - adsize;
154 153
155 if (!bh) 154 if (!epos.bh)
156 lenalloc -= udf_file_entry_alloc_offset(inode); 155 lenalloc -= udf_file_entry_alloc_offset(inode);
157 else 156 else
158 lenalloc -= sizeof(struct allocExtDesc); 157 lenalloc -= sizeof(struct allocExtDesc);
159 158
160 while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1) 159 while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1)
161 { 160 {
162 if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) 161 if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
163 { 162 {
164 udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0); 163 udf_write_aext(inode, &epos, neloc, nelen, 0);
165 extoffset = 0; 164 if (indirect_ext_len)
166 if (lelen)
167 { 165 {
168 if (!bh) 166 /* We managed to free all extents in the
167 * indirect extent - free it too */
168 if (!epos.bh)
169 BUG(); 169 BUG();
170 else 170 udf_free_blocks(inode->i_sb, inode, epos.block, 0, indirect_ext_len);
171 memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
172 udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
173 } 171 }
174 else 172 else
175 { 173 {
176 if (!bh) 174 if (!epos.bh)
177 { 175 {
178 UDF_I_LENALLOC(inode) = lenalloc; 176 UDF_I_LENALLOC(inode) = lenalloc;
179 mark_inode_dirty(inode); 177 mark_inode_dirty(inode);
180 } 178 }
181 else 179 else
182 { 180 {
183 struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); 181 struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
184 aed->lengthAllocDescs = cpu_to_le32(lenalloc); 182 aed->lengthAllocDescs = cpu_to_le32(lenalloc);
185 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) 183 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
186 udf_update_tag(bh->b_data, lenalloc + 184 udf_update_tag(epos.bh->b_data, lenalloc +
187 sizeof(struct allocExtDesc)); 185 sizeof(struct allocExtDesc));
188 else 186 else
189 udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); 187 udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
190 mark_buffer_dirty_inode(bh, inode); 188 mark_buffer_dirty_inode(epos.bh, inode);
191 } 189 }
192 } 190 }
193 191 brelse(epos.bh);
194 udf_release_data(bh); 192 epos.offset = sizeof(struct allocExtDesc);
195 extoffset = sizeof(struct allocExtDesc); 193 epos.block = eloc;
196 bloc = eloc; 194 epos.bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, eloc, 0));
197 bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, bloc, 0));
198 if (elen) 195 if (elen)
199 lelen = (elen + inode->i_sb->s_blocksize - 1) >> 196 indirect_ext_len = (elen +
197 inode->i_sb->s_blocksize - 1) >>
200 inode->i_sb->s_blocksize_bits; 198 inode->i_sb->s_blocksize_bits;
201 else 199 else
202 lelen = 1; 200 indirect_ext_len = 1;
203 } 201 }
204 else 202 else
205 { 203 {
206 extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0); 204 extent_trunc(inode, &epos, eloc, etype, elen, 0);
207 extoffset += adsize; 205 epos.offset += adsize;
208 } 206 }
209 } 207 }
210 208
211 if (lelen) 209 if (indirect_ext_len)
212 { 210 {
213 if (!bh) 211 if (!epos.bh)
214 BUG(); 212 BUG();
215 else 213 udf_free_blocks(inode->i_sb, inode, epos.block, 0, indirect_ext_len);
216 memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
217 udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
218 } 214 }
219 else 215 else
220 { 216 {
221 if (!bh) 217 if (!epos.bh)
222 { 218 {
223 UDF_I_LENALLOC(inode) = lenalloc; 219 UDF_I_LENALLOC(inode) = lenalloc;
224 mark_inode_dirty(inode); 220 mark_inode_dirty(inode);
225 } 221 }
226 else 222 else
227 { 223 {
228 struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); 224 struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
229 aed->lengthAllocDescs = cpu_to_le32(lenalloc); 225 aed->lengthAllocDescs = cpu_to_le32(lenalloc);
230 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) 226 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
231 udf_update_tag(bh->b_data, lenalloc + 227 udf_update_tag(epos.bh->b_data, lenalloc +
232 sizeof(struct allocExtDesc)); 228 sizeof(struct allocExtDesc));
233 else 229 else
234 udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); 230 udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
235 mark_buffer_dirty_inode(bh, inode); 231 mark_buffer_dirty_inode(epos.bh, inode);
236 } 232 }
237 } 233 }
238 } 234 }
@@ -245,50 +241,51 @@ void udf_truncate_extents(struct inode * inode)
245 * no extent above inode->i_size => truncate is 241 * no extent above inode->i_size => truncate is
246 * extending the file by 'offset'. 242 * extending the file by 'offset'.
247 */ 243 */
248 if ((!bh && extoffset == udf_file_entry_alloc_offset(inode)) || 244 if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
249 (bh && extoffset == sizeof(struct allocExtDesc))) { 245 (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
250 /* File has no extents at all! */ 246 /* File has no extents at all! */
251 memset(&eloc, 0x00, sizeof(kernel_lb_addr)); 247 memset(&eloc, 0x00, sizeof(kernel_lb_addr));
252 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | byte_offset; 248 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | byte_offset;
253 udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1); 249 udf_add_aext(inode, &epos, eloc, elen, 1);
254 } 250 }
255 else { 251 else {
256 extoffset -= adsize; 252 epos.offset -= adsize;
257 etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1); 253 etype = udf_next_aext(inode, &epos, &eloc, &elen, 1);
254
258 if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) 255 if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
259 { 256 {
260 extoffset -= adsize; 257 epos.offset -= adsize;
261 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + byte_offset); 258 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + byte_offset);
262 udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0); 259 udf_write_aext(inode, &epos, eloc, elen, 0);
263 } 260 }
264 else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) 261 else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
265 { 262 {
266 kernel_lb_addr neloc = { 0, 0 }; 263 kernel_lb_addr neloc = { 0, 0 };
267 extoffset -= adsize; 264 epos.offset -= adsize;
268 nelen = EXT_NOT_RECORDED_NOT_ALLOCATED | 265 nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
269 ((elen + byte_offset + inode->i_sb->s_blocksize - 1) & 266 ((elen + byte_offset + inode->i_sb->s_blocksize - 1) &
270 ~(inode->i_sb->s_blocksize - 1)); 267 ~(inode->i_sb->s_blocksize - 1));
271 udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1); 268 udf_write_aext(inode, &epos, neloc, nelen, 1);
272 udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1); 269 udf_add_aext(inode, &epos, eloc, (etype << 30) | elen, 1);
273 } 270 }
274 else 271 else
275 { 272 {
276 if (elen & (inode->i_sb->s_blocksize - 1)) 273 if (elen & (inode->i_sb->s_blocksize - 1))
277 { 274 {
278 extoffset -= adsize; 275 epos.offset -= adsize;
279 elen = EXT_RECORDED_ALLOCATED | 276 elen = EXT_RECORDED_ALLOCATED |
280 ((elen + inode->i_sb->s_blocksize - 1) & 277 ((elen + inode->i_sb->s_blocksize - 1) &
281 ~(inode->i_sb->s_blocksize - 1)); 278 ~(inode->i_sb->s_blocksize - 1));
282 udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1); 279 udf_write_aext(inode, &epos, eloc, elen, 1);
283 } 280 }
284 memset(&eloc, 0x00, sizeof(kernel_lb_addr)); 281 memset(&eloc, 0x00, sizeof(kernel_lb_addr));
285 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | byte_offset; 282 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | byte_offset;
286 udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1); 283 udf_add_aext(inode, &epos, eloc, elen, 1);
287 } 284 }
288 } 285 }
289 } 286 }
290 } 287 }
291 UDF_I_LENEXTENTS(inode) = inode->i_size; 288 UDF_I_LENEXTENTS(inode) = inode->i_size;
292 289
293 udf_release_data(bh); 290 udf_release_data(epos.bh);
294} 291}