Blame view
fs/hfsplus/extents.c
14.5 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * linux/fs/hfsplus/extents.c * * Copyright (C) 2001 * Brad Boyer (flar@allandria.com) * (C) 2003 Ardis Technologies <roman@ardistech.com> * * Handling of Extents both in catalog and extents overflow trees */ #include <linux/errno.h> #include <linux/fs.h> #include <linux/pagemap.h> |
1da177e4c Linux-2.6.12-rc2 |
14 15 16 17 18 |
#include "hfsplus_fs.h" #include "hfsplus_raw.h" /* Compare two extents keys, returns 0 on same, pos/neg for difference */ |
2179d372d [PATCH] hfs: add ... |
19 20 |
int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, const hfsplus_btree_key *k2) |
1da177e4c Linux-2.6.12-rc2 |
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
{ __be32 k1id, k2id; __be32 k1s, k2s; k1id = k1->ext.cnid; k2id = k2->ext.cnid; if (k1id != k2id) return be32_to_cpu(k1id) < be32_to_cpu(k2id) ? -1 : 1; if (k1->ext.fork_type != k2->ext.fork_type) return k1->ext.fork_type < k2->ext.fork_type ? -1 : 1; k1s = k1->ext.start_block; k2s = k2->ext.start_block; if (k1s == k2s) return 0; return be32_to_cpu(k1s) < be32_to_cpu(k2s) ? -1 : 1; } static void hfsplus_ext_build_key(hfsplus_btree_key *key, u32 cnid, u32 block, u8 type) { key->key_len = cpu_to_be16(HFSPLUS_EXT_KEYLEN - 2); key->ext.cnid = cpu_to_be32(cnid); key->ext.start_block = cpu_to_be32(block); key->ext.fork_type = type; key->ext.pad = 0; } static u32 hfsplus_ext_find_block(struct hfsplus_extent *ext, u32 off) { int i; u32 count; for (i = 0; i < 8; ext++, i++) { count = be32_to_cpu(ext->block_count); if (off < count) return be32_to_cpu(ext->start_block) + off; off -= count; } /* panic? */ return 0; } static int hfsplus_ext_block_count(struct hfsplus_extent *ext) { int i; u32 count = 0; for (i = 0; i < 8; ext++, i++) count += be32_to_cpu(ext->block_count); return count; } static u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext) { int i; ext += 7; for (i = 0; i < 7; ext--, i++) if (ext->block_count) break; return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count); } |
2753cc281 hfsplus: over 80 ... |
85 86 |
static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) |
1da177e4c Linux-2.6.12-rc2 |
87 |
{ |
6af502de2 hfsplus: fix HFSP... |
88 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c Linux-2.6.12-rc2 |
89 |
int res; |
7fcc99f4f hfsplus: add miss... |
90 |
WARN_ON(!mutex_is_locked(&hip->extents_lock)); |
6af502de2 hfsplus: fix HFSP... |
91 92 93 |
hfsplus_ext_build_key(fd->search_key, inode->i_ino, hip->cached_start, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); |
1da177e4c Linux-2.6.12-rc2 |
94 |
res = hfs_brec_find(fd); |
b33b7921d hfsplus: split up... |
95 |
if (hip->extent_state & HFSPLUS_EXT_NEW) { |
1da177e4c Linux-2.6.12-rc2 |
96 97 |
if (res != -ENOENT) return; |
6af502de2 hfsplus: fix HFSP... |
98 99 |
hfs_brec_insert(fd, hip->cached_extents, sizeof(hfsplus_extent_rec)); |
b33b7921d hfsplus: split up... |
100 |
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); |
1da177e4c Linux-2.6.12-rc2 |
101 102 103 |
} else { if (res) return; |
6af502de2 hfsplus: fix HFSP... |
104 105 |
hfs_bnode_write(fd->bnode, hip->cached_extents, fd->entryoffset, fd->entrylength); |
b33b7921d hfsplus: split up... |
106 |
hip->extent_state &= ~HFSPLUS_EXT_DIRTY; |
1da177e4c Linux-2.6.12-rc2 |
107 |
} |
e34947056 hfsplus: optimize... |
108 109 110 111 112 113 114 115 |
/* * We can't just use hfsplus_mark_inode_dirty here, because we * also get called from hfsplus_write_inode, which should not * redirty the inode. Instead the callers have to be careful * to explicily mark the inode dirty, too. */ set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags); |
1da177e4c Linux-2.6.12-rc2 |
116 |
} |
dd7f3d545 hfsplus: Add erro... |
117 |
static int hfsplus_ext_write_extent_locked(struct inode *inode) |
1da177e4c Linux-2.6.12-rc2 |
118 |
{ |
dd7f3d545 hfsplus: Add erro... |
119 |
int res; |
b33b7921d hfsplus: split up... |
120 |
if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) { |
1da177e4c Linux-2.6.12-rc2 |
121 |
struct hfs_find_data fd; |
dd7f3d545 hfsplus: Add erro... |
122 123 124 125 126 |
res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); if (res) return res; __hfsplus_ext_write_extent(inode, &fd); hfs_find_exit(&fd); |
1da177e4c Linux-2.6.12-rc2 |
127 |
} |
dd7f3d545 hfsplus: Add erro... |
128 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
129 |
} |
dd7f3d545 hfsplus: Add erro... |
130 |
int hfsplus_ext_write_extent(struct inode *inode) |
7fcc99f4f hfsplus: add miss... |
131 |
{ |
dd7f3d545 hfsplus: Add erro... |
132 |
int res; |
7fcc99f4f hfsplus: add miss... |
133 |
mutex_lock(&HFSPLUS_I(inode)->extents_lock); |
dd7f3d545 hfsplus: Add erro... |
134 |
res = hfsplus_ext_write_extent_locked(inode); |
7fcc99f4f hfsplus: add miss... |
135 |
mutex_unlock(&HFSPLUS_I(inode)->extents_lock); |
dd7f3d545 hfsplus: Add erro... |
136 137 |
return res; |
7fcc99f4f hfsplus: add miss... |
138 |
} |
1da177e4c Linux-2.6.12-rc2 |
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, struct hfsplus_extent *extent, u32 cnid, u32 block, u8 type) { int res; hfsplus_ext_build_key(fd->search_key, cnid, block, type); fd->key->ext.cnid = 0; res = hfs_brec_find(fd); if (res && res != -ENOENT) return res; if (fd->key->ext.cnid != fd->search_key->ext.cnid || fd->key->ext.fork_type != fd->search_key->ext.fork_type) return -ENOENT; if (fd->entrylength != sizeof(hfsplus_extent_rec)) return -EIO; |
2753cc281 hfsplus: over 80 ... |
155 156 |
hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfsplus_extent_rec)); |
1da177e4c Linux-2.6.12-rc2 |
157 158 |
return 0; } |
2753cc281 hfsplus: over 80 ... |
159 160 |
static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block) |
1da177e4c Linux-2.6.12-rc2 |
161 |
{ |
6af502de2 hfsplus: fix HFSP... |
162 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c Linux-2.6.12-rc2 |
163 |
int res; |
7fcc99f4f hfsplus: add miss... |
164 |
WARN_ON(!mutex_is_locked(&hip->extents_lock)); |
b33b7921d hfsplus: split up... |
165 |
if (hip->extent_state & HFSPLUS_EXT_DIRTY) |
1da177e4c Linux-2.6.12-rc2 |
166 |
__hfsplus_ext_write_extent(inode, fd); |
6af502de2 hfsplus: fix HFSP... |
167 168 169 170 |
res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino, block, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); |
1da177e4c Linux-2.6.12-rc2 |
171 |
if (!res) { |
6af502de2 hfsplus: fix HFSP... |
172 |
hip->cached_start = be32_to_cpu(fd->key->ext.start_block); |
2753cc281 hfsplus: over 80 ... |
173 174 |
hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents); |
1da177e4c Linux-2.6.12-rc2 |
175 |
} else { |
6af502de2 hfsplus: fix HFSP... |
176 |
hip->cached_start = hip->cached_blocks = 0; |
b33b7921d hfsplus: split up... |
177 |
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); |
1da177e4c Linux-2.6.12-rc2 |
178 179 180 181 182 183 |
} return res; } static int hfsplus_ext_read_extent(struct inode *inode, u32 block) { |
6af502de2 hfsplus: fix HFSP... |
184 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c Linux-2.6.12-rc2 |
185 186 |
struct hfs_find_data fd; int res; |
6af502de2 hfsplus: fix HFSP... |
187 188 |
if (block >= hip->cached_start && block < hip->cached_start + hip->cached_blocks) |
1da177e4c Linux-2.6.12-rc2 |
189 |
return 0; |
5bd9d99d1 hfsplus: add erro... |
190 191 192 193 194 |
res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); if (!res) { res = __hfsplus_ext_cache_extent(&fd, inode, block); hfs_find_exit(&fd); } |
1da177e4c Linux-2.6.12-rc2 |
195 196 197 198 199 200 201 |
return res; } /* Get a block at iblock for inode, possibly allocating if create */ int hfsplus_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { |
dd73a01a3 hfsplus: fix HFSP... |
202 203 |
struct super_block *sb = inode->i_sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); |
6af502de2 hfsplus: fix HFSP... |
204 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c Linux-2.6.12-rc2 |
205 206 |
int res = -EIO; u32 ablock, dblock, mask; |
bf1a1b31f hfsplus: fix over... |
207 |
sector_t sector; |
e34947056 hfsplus: optimize... |
208 |
int was_dirty = 0; |
1da177e4c Linux-2.6.12-rc2 |
209 |
int shift; |
1da177e4c Linux-2.6.12-rc2 |
210 |
/* Convert inode block to disk allocation block */ |
dd73a01a3 hfsplus: fix HFSP... |
211 212 |
shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits; ablock = iblock >> sbi->fs_shift; |
1da177e4c Linux-2.6.12-rc2 |
213 |
|
6af502de2 hfsplus: fix HFSP... |
214 215 |
if (iblock >= hip->fs_blocks) { if (iblock > hip->fs_blocks || !create) |
1da177e4c Linux-2.6.12-rc2 |
216 |
return -EIO; |
6af502de2 hfsplus: fix HFSP... |
217 |
if (ablock >= hip->alloc_blocks) { |
1da177e4c Linux-2.6.12-rc2 |
218 219 220 221 222 223 |
res = hfsplus_file_extend(inode); if (res) return res; } } else create = 0; |
6af502de2 hfsplus: fix HFSP... |
224 225 |
if (ablock < hip->first_blocks) { dblock = hfsplus_ext_find_block(hip->first_extents, ablock); |
1da177e4c Linux-2.6.12-rc2 |
226 227 |
goto done; } |
248736c2a hfsplus: fix poss... |
228 229 |
if (inode->i_ino == HFSPLUS_EXT_CNID) return -EIO; |
6af502de2 hfsplus: fix HFSP... |
230 |
mutex_lock(&hip->extents_lock); |
e34947056 hfsplus: optimize... |
231 232 233 234 235 236 237 |
/* * hfsplus_ext_read_extent will write out a cached extent into * the extents btree. In that case we may have to mark the inode * dirty even for a pure read of an extent here. */ was_dirty = (hip->extent_state & HFSPLUS_EXT_DIRTY); |
1da177e4c Linux-2.6.12-rc2 |
238 |
res = hfsplus_ext_read_extent(inode, ablock); |
e34947056 hfsplus: optimize... |
239 |
if (res) { |
6af502de2 hfsplus: fix HFSP... |
240 |
mutex_unlock(&hip->extents_lock); |
1da177e4c Linux-2.6.12-rc2 |
241 242 |
return -EIO; } |
e34947056 hfsplus: optimize... |
243 244 |
dblock = hfsplus_ext_find_block(hip->cached_extents, ablock - hip->cached_start); |
6af502de2 hfsplus: fix HFSP... |
245 |
mutex_unlock(&hip->extents_lock); |
1da177e4c Linux-2.6.12-rc2 |
246 247 |
done: |
2753cc281 hfsplus: over 80 ... |
248 249 250 |
dprint(DBG_EXTENT, "get_block(%lu): %llu - %u ", inode->i_ino, (long long)iblock, dblock); |
bf1a1b31f hfsplus: fix over... |
251 |
|
dd73a01a3 hfsplus: fix HFSP... |
252 |
mask = (1 << sbi->fs_shift) - 1; |
bf1a1b31f hfsplus: fix over... |
253 254 255 |
sector = ((sector_t)dblock << sbi->fs_shift) + sbi->blockoffset + (iblock & mask); map_bh(bh_result, sb, sector); |
1da177e4c Linux-2.6.12-rc2 |
256 257 |
if (create) { set_buffer_new(bh_result); |
6af502de2 hfsplus: fix HFSP... |
258 259 |
hip->phys_size += sb->s_blocksize; hip->fs_blocks++; |
1da177e4c Linux-2.6.12-rc2 |
260 |
inode_add_bytes(inode, sb->s_blocksize); |
1da177e4c Linux-2.6.12-rc2 |
261 |
} |
e34947056 hfsplus: optimize... |
262 263 |
if (create || was_dirty) mark_inode_dirty(inode); |
1da177e4c Linux-2.6.12-rc2 |
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
return 0; } static void hfsplus_dump_extent(struct hfsplus_extent *extent) { int i; dprint(DBG_EXTENT, " "); for (i = 0; i < 8; i++) dprint(DBG_EXTENT, " %u:%u", be32_to_cpu(extent[i].start_block), be32_to_cpu(extent[i].block_count)); dprint(DBG_EXTENT, " "); } static int hfsplus_add_extent(struct hfsplus_extent *extent, u32 offset, u32 alloc_block, u32 block_count) { u32 count, start; int i; hfsplus_dump_extent(extent); for (i = 0; i < 8; extent++, i++) { count = be32_to_cpu(extent->block_count); if (offset == count) { start = be32_to_cpu(extent->start_block); if (alloc_block != start + count) { if (++i >= 8) return -ENOSPC; extent++; extent->start_block = cpu_to_be32(alloc_block); } else block_count += count; extent->block_count = cpu_to_be32(block_count); return 0; } else if (offset < count) break; offset -= count; } /* panic? */ return -EIO; } static int hfsplus_free_extents(struct super_block *sb, struct hfsplus_extent *extent, u32 offset, u32 block_nr) { u32 count, start; int i; hfsplus_dump_extent(extent); for (i = 0; i < 8; extent++, i++) { count = be32_to_cpu(extent->block_count); if (offset == count) goto found; else if (offset < count) break; offset -= count; } /* panic? */ return -EIO; found: for (;;) { start = be32_to_cpu(extent->start_block); if (count <= block_nr) { hfsplus_block_free(sb, start, count); extent->block_count = 0; extent->start_block = 0; block_nr -= count; } else { count -= block_nr; hfsplus_block_free(sb, start + count, block_nr); extent->block_count = cpu_to_be32(count); block_nr = 0; } if (!block_nr || !i) return 0; i--; extent--; count = be32_to_cpu(extent->block_count); } } |
2753cc281 hfsplus: over 80 ... |
346 347 |
int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw *fork, int type) |
1da177e4c Linux-2.6.12-rc2 |
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
{ struct hfs_find_data fd; hfsplus_extent_rec ext_entry; u32 total_blocks, blocks, start; int res, i; total_blocks = be32_to_cpu(fork->total_blocks); if (!total_blocks) return 0; blocks = 0; for (i = 0; i < 8; i++) blocks += be32_to_cpu(fork->extents[i].block_count); res = hfsplus_free_extents(sb, fork->extents, blocks, blocks); if (res) return res; if (total_blocks == blocks) return 0; |
5bd9d99d1 hfsplus: add erro... |
367 368 369 |
res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); if (res) return res; |
1da177e4c Linux-2.6.12-rc2 |
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
do { res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, total_blocks, type); if (res) break; start = be32_to_cpu(fd.key->ext.start_block); hfsplus_free_extents(sb, ext_entry, total_blocks - start, total_blocks); hfs_brec_remove(&fd); total_blocks = start; } while (total_blocks > blocks); hfs_find_exit(&fd); return res; } int hfsplus_file_extend(struct inode *inode) { struct super_block *sb = inode->i_sb; |
dd73a01a3 hfsplus: fix HFSP... |
390 |
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); |
6af502de2 hfsplus: fix HFSP... |
391 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c Linux-2.6.12-rc2 |
392 393 |
u32 start, len, goal; int res; |
1065348d4 hfsplus: fix up a... |
394 395 |
if (sbi->alloc_file->i_size * 8 < sbi->total_blocks - sbi->free_blocks + 8) { |
21f2296a5 hfsplus: C99 comm... |
396 |
/* extend alloc file */ |
b2837fcf4 hfsplus: %L-to-%l... |
397 398 399 400 401 |
printk(KERN_ERR "hfs: extend alloc file! " "(%llu,%u,%u) ", sbi->alloc_file->i_size * 8, sbi->total_blocks, sbi->free_blocks); |
1da177e4c Linux-2.6.12-rc2 |
402 |
return -ENOSPC; |
1da177e4c Linux-2.6.12-rc2 |
403 |
} |
6af502de2 hfsplus: fix HFSP... |
404 405 406 |
mutex_lock(&hip->extents_lock); if (hip->alloc_blocks == hip->first_blocks) goal = hfsplus_ext_lastblock(hip->first_extents); |
1da177e4c Linux-2.6.12-rc2 |
407 |
else { |
6af502de2 hfsplus: fix HFSP... |
408 |
res = hfsplus_ext_read_extent(inode, hip->alloc_blocks); |
1da177e4c Linux-2.6.12-rc2 |
409 410 |
if (res) goto out; |
6af502de2 hfsplus: fix HFSP... |
411 |
goal = hfsplus_ext_lastblock(hip->cached_extents); |
1da177e4c Linux-2.6.12-rc2 |
412 |
} |
6af502de2 hfsplus: fix HFSP... |
413 |
len = hip->clump_blocks; |
dd73a01a3 hfsplus: fix HFSP... |
414 415 |
start = hfsplus_block_allocate(sb, sbi->total_blocks, goal, &len); if (start >= sbi->total_blocks) { |
1da177e4c Linux-2.6.12-rc2 |
416 417 418 419 420 421 422 423 424 |
start = hfsplus_block_allocate(sb, goal, 0, &len); if (start >= goal) { res = -ENOSPC; goto out; } } dprint(DBG_EXTENT, "extend %lu: %u,%u ", inode->i_ino, start, len); |
6af502de2 hfsplus: fix HFSP... |
425 426 427 |
if (hip->alloc_blocks <= hip->first_blocks) { if (!hip->first_blocks) { |
1da177e4c Linux-2.6.12-rc2 |
428 429 430 |
dprint(DBG_EXTENT, "first extents "); /* no extents yet */ |
6af502de2 hfsplus: fix HFSP... |
431 432 |
hip->first_extents[0].start_block = cpu_to_be32(start); hip->first_extents[0].block_count = cpu_to_be32(len); |
1da177e4c Linux-2.6.12-rc2 |
433 434 435 |
res = 0; } else { /* try to append to extents in inode */ |
6af502de2 hfsplus: fix HFSP... |
436 437 |
res = hfsplus_add_extent(hip->first_extents, hip->alloc_blocks, |
1da177e4c Linux-2.6.12-rc2 |
438 439 440 441 442 |
start, len); if (res == -ENOSPC) goto insert_extent; } if (!res) { |
6af502de2 hfsplus: fix HFSP... |
443 444 |
hfsplus_dump_extent(hip->first_extents); hip->first_blocks += len; |
1da177e4c Linux-2.6.12-rc2 |
445 446 |
} } else { |
6af502de2 hfsplus: fix HFSP... |
447 448 |
res = hfsplus_add_extent(hip->cached_extents, hip->alloc_blocks - hip->cached_start, |
1da177e4c Linux-2.6.12-rc2 |
449 450 |
start, len); if (!res) { |
6af502de2 hfsplus: fix HFSP... |
451 |
hfsplus_dump_extent(hip->cached_extents); |
b33b7921d hfsplus: split up... |
452 |
hip->extent_state |= HFSPLUS_EXT_DIRTY; |
6af502de2 hfsplus: fix HFSP... |
453 |
hip->cached_blocks += len; |
1da177e4c Linux-2.6.12-rc2 |
454 455 456 457 |
} else if (res == -ENOSPC) goto insert_extent; } out: |
6af502de2 hfsplus: fix HFSP... |
458 |
mutex_unlock(&hip->extents_lock); |
1da177e4c Linux-2.6.12-rc2 |
459 |
if (!res) { |
6af502de2 hfsplus: fix HFSP... |
460 |
hip->alloc_blocks += len; |
e34947056 hfsplus: optimize... |
461 |
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); |
1da177e4c Linux-2.6.12-rc2 |
462 463 464 465 466 467 |
} return res; insert_extent: dprint(DBG_EXTENT, "insert new extent "); |
dd7f3d545 hfsplus: Add erro... |
468 469 470 |
res = hfsplus_ext_write_extent_locked(inode); if (res) goto out; |
1da177e4c Linux-2.6.12-rc2 |
471 |
|
6af502de2 hfsplus: fix HFSP... |
472 473 474 475 |
memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); hip->cached_extents[0].start_block = cpu_to_be32(start); hip->cached_extents[0].block_count = cpu_to_be32(len); hfsplus_dump_extent(hip->cached_extents); |
b33b7921d hfsplus: split up... |
476 |
hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW; |
6af502de2 hfsplus: fix HFSP... |
477 478 |
hip->cached_start = hip->alloc_blocks; hip->cached_blocks = len; |
1da177e4c Linux-2.6.12-rc2 |
479 480 481 482 483 484 485 486 |
res = 0; goto out; } void hfsplus_file_truncate(struct inode *inode) { struct super_block *sb = inode->i_sb; |
6af502de2 hfsplus: fix HFSP... |
487 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c Linux-2.6.12-rc2 |
488 489 490 |
struct hfs_find_data fd; u32 alloc_cnt, blk_cnt, start; int res; |
b2837fcf4 hfsplus: %L-to-%l... |
491 492 493 494 |
dprint(DBG_INODE, "truncate: %lu, %llu -> %llu ", inode->i_ino, (long long)hip->phys_size, inode->i_size); |
6af502de2 hfsplus: fix HFSP... |
495 496 |
if (inode->i_size > hip->phys_size) { |
1da177e4c Linux-2.6.12-rc2 |
497 498 |
struct address_space *mapping = inode->i_mapping; struct page *page; |
7c0efc627 hfsplus: convert ... |
499 500 |
void *fsdata; u32 size = inode->i_size; |
1da177e4c Linux-2.6.12-rc2 |
501 |
|
7c0efc627 hfsplus: convert ... |
502 503 504 |
res = pagecache_write_begin(NULL, mapping, size, 0, AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); |
1da177e4c Linux-2.6.12-rc2 |
505 |
if (res) |
7c0efc627 hfsplus: convert ... |
506 |
return; |
2753cc281 hfsplus: over 80 ... |
507 508 |
res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata); |
7c0efc627 hfsplus: convert ... |
509 510 |
if (res < 0) return; |
1da177e4c Linux-2.6.12-rc2 |
511 512 |
mark_inode_dirty(inode); return; |
6af502de2 hfsplus: fix HFSP... |
513 |
} else if (inode->i_size == hip->phys_size) |
f76d28d23 [PATCH] hfs: don'... |
514 |
return; |
dd73a01a3 hfsplus: fix HFSP... |
515 516 |
blk_cnt = (inode->i_size + HFSPLUS_SB(sb)->alloc_blksz - 1) >> HFSPLUS_SB(sb)->alloc_blksz_shift; |
6af502de2 hfsplus: fix HFSP... |
517 |
alloc_cnt = hip->alloc_blocks; |
1da177e4c Linux-2.6.12-rc2 |
518 519 |
if (blk_cnt == alloc_cnt) goto out; |
6af502de2 hfsplus: fix HFSP... |
520 |
mutex_lock(&hip->extents_lock); |
5bd9d99d1 hfsplus: add erro... |
521 522 523 524 525 526 |
res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); if (res) { mutex_unlock(&hip->extents_lock); /* XXX: We lack error handling of hfsplus_file_truncate() */ return; } |
1da177e4c Linux-2.6.12-rc2 |
527 |
while (1) { |
6af502de2 hfsplus: fix HFSP... |
528 529 |
if (alloc_cnt == hip->first_blocks) { hfsplus_free_extents(sb, hip->first_extents, |
1da177e4c Linux-2.6.12-rc2 |
530 |
alloc_cnt, alloc_cnt - blk_cnt); |
6af502de2 hfsplus: fix HFSP... |
531 532 |
hfsplus_dump_extent(hip->first_extents); hip->first_blocks = blk_cnt; |
1da177e4c Linux-2.6.12-rc2 |
533 534 535 536 537 |
break; } res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt); if (res) break; |
6af502de2 hfsplus: fix HFSP... |
538 539 |
start = hip->cached_start; hfsplus_free_extents(sb, hip->cached_extents, |
1da177e4c Linux-2.6.12-rc2 |
540 |
alloc_cnt - start, alloc_cnt - blk_cnt); |
6af502de2 hfsplus: fix HFSP... |
541 |
hfsplus_dump_extent(hip->cached_extents); |
1da177e4c Linux-2.6.12-rc2 |
542 |
if (blk_cnt > start) { |
b33b7921d hfsplus: split up... |
543 |
hip->extent_state |= HFSPLUS_EXT_DIRTY; |
1da177e4c Linux-2.6.12-rc2 |
544 545 546 |
break; } alloc_cnt = start; |
6af502de2 hfsplus: fix HFSP... |
547 |
hip->cached_start = hip->cached_blocks = 0; |
b33b7921d hfsplus: split up... |
548 |
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); |
1da177e4c Linux-2.6.12-rc2 |
549 550 551 |
hfs_brec_remove(&fd); } hfs_find_exit(&fd); |
6af502de2 hfsplus: fix HFSP... |
552 |
mutex_unlock(&hip->extents_lock); |
1da177e4c Linux-2.6.12-rc2 |
553 |
|
6af502de2 hfsplus: fix HFSP... |
554 |
hip->alloc_blocks = blk_cnt; |
1da177e4c Linux-2.6.12-rc2 |
555 |
out: |
6af502de2 hfsplus: fix HFSP... |
556 |
hip->phys_size = inode->i_size; |
2753cc281 hfsplus: over 80 ... |
557 558 |
hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; |
6af502de2 hfsplus: fix HFSP... |
559 |
inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); |
e34947056 hfsplus: optimize... |
560 |
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); |
1da177e4c Linux-2.6.12-rc2 |
561 |
} |