Blame view
fs/hfsplus/extents.c
15.5 KB
b24413180
|
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c
|
2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* * 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
|
15 16 17 18 19 |
#include "hfsplus_fs.h" #include "hfsplus_raw.h" /* Compare two extents keys, returns 0 on same, pos/neg for difference */ |
2179d372d
|
20 21 |
int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, const hfsplus_btree_key *k2) |
1da177e4c
|
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 85 |
{ __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); } |
d7a475d0c
|
86 |
static int __hfsplus_ext_write_extent(struct inode *inode, |
2753cc281
|
87 |
struct hfs_find_data *fd) |
1da177e4c
|
88 |
{ |
6af502de2
|
89 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c
|
90 |
int res; |
7fcc99f4f
|
91 |
WARN_ON(!mutex_is_locked(&hip->extents_lock)); |
6af502de2
|
92 93 94 |
hfsplus_ext_build_key(fd->search_key, inode->i_ino, hip->cached_start, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); |
324ef39a8
|
95 |
res = hfs_brec_find(fd, hfs_find_rec_by_key); |
b33b7921d
|
96 |
if (hip->extent_state & HFSPLUS_EXT_NEW) { |
1da177e4c
|
97 |
if (res != -ENOENT) |
d7a475d0c
|
98 |
return res; |
d92915c35
|
99 100 101 102 |
/* Fail early and avoid ENOSPC during the btree operation */ res = hfs_bmap_reserve(fd->tree, fd->tree->depth + 1); if (res) return res; |
6af502de2
|
103 104 |
hfs_brec_insert(fd, hip->cached_extents, sizeof(hfsplus_extent_rec)); |
b33b7921d
|
105 |
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); |
1da177e4c
|
106 107 |
} else { if (res) |
d7a475d0c
|
108 |
return res; |
6af502de2
|
109 110 |
hfs_bnode_write(fd->bnode, hip->cached_extents, fd->entryoffset, fd->entrylength); |
b33b7921d
|
111 |
hip->extent_state &= ~HFSPLUS_EXT_DIRTY; |
1da177e4c
|
112 |
} |
e34947056
|
113 114 115 116 117 118 119 120 |
/* * 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); |
d7a475d0c
|
121 122 |
return 0; |
1da177e4c
|
123 |
} |
dd7f3d545
|
124 |
static int hfsplus_ext_write_extent_locked(struct inode *inode) |
1da177e4c
|
125 |
{ |
d7a475d0c
|
126 |
int res = 0; |
dd7f3d545
|
127 |
|
b33b7921d
|
128 |
if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) { |
1da177e4c
|
129 |
struct hfs_find_data fd; |
dd7f3d545
|
130 131 132 |
res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); if (res) return res; |
d7a475d0c
|
133 |
res = __hfsplus_ext_write_extent(inode, &fd); |
dd7f3d545
|
134 |
hfs_find_exit(&fd); |
1da177e4c
|
135 |
} |
d7a475d0c
|
136 |
return res; |
1da177e4c
|
137 |
} |
dd7f3d545
|
138 |
int hfsplus_ext_write_extent(struct inode *inode) |
7fcc99f4f
|
139 |
{ |
dd7f3d545
|
140 |
int res; |
7fcc99f4f
|
141 |
mutex_lock(&HFSPLUS_I(inode)->extents_lock); |
dd7f3d545
|
142 |
res = hfsplus_ext_write_extent_locked(inode); |
7fcc99f4f
|
143 |
mutex_unlock(&HFSPLUS_I(inode)->extents_lock); |
dd7f3d545
|
144 145 |
return res; |
7fcc99f4f
|
146 |
} |
1da177e4c
|
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; |
324ef39a8
|
155 |
res = hfs_brec_find(fd, hfs_find_rec_by_key); |
1da177e4c
|
156 157 158 159 160 161 162 |
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
|
163 164 |
hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfsplus_extent_rec)); |
1da177e4c
|
165 166 |
return 0; } |
2753cc281
|
167 168 |
static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block) |
1da177e4c
|
169 |
{ |
6af502de2
|
170 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c
|
171 |
int res; |
7fcc99f4f
|
172 |
WARN_ON(!mutex_is_locked(&hip->extents_lock)); |
d7a475d0c
|
173 174 175 176 177 |
if (hip->extent_state & HFSPLUS_EXT_DIRTY) { res = __hfsplus_ext_write_extent(inode, fd); if (res) return res; } |
1da177e4c
|
178 |
|
6af502de2
|
179 180 181 182 |
res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino, block, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); |
1da177e4c
|
183 |
if (!res) { |
6af502de2
|
184 |
hip->cached_start = be32_to_cpu(fd->key->ext.start_block); |
2753cc281
|
185 186 |
hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents); |
1da177e4c
|
187 |
} else { |
6af502de2
|
188 |
hip->cached_start = hip->cached_blocks = 0; |
b33b7921d
|
189 |
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); |
1da177e4c
|
190 191 192 193 194 195 |
} return res; } static int hfsplus_ext_read_extent(struct inode *inode, u32 block) { |
6af502de2
|
196 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c
|
197 198 |
struct hfs_find_data fd; int res; |
6af502de2
|
199 200 |
if (block >= hip->cached_start && block < hip->cached_start + hip->cached_blocks) |
1da177e4c
|
201 |
return 0; |
5bd9d99d1
|
202 203 204 205 206 |
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
|
207 208 209 210 211 212 213 |
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
|
214 215 |
struct super_block *sb = inode->i_sb; struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); |
6af502de2
|
216 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c
|
217 218 |
int res = -EIO; u32 ablock, dblock, mask; |
bf1a1b31f
|
219 |
sector_t sector; |
e34947056
|
220 |
int was_dirty = 0; |
1da177e4c
|
221 |
|
1da177e4c
|
222 |
/* Convert inode block to disk allocation block */ |
dd73a01a3
|
223 |
ablock = iblock >> sbi->fs_shift; |
1da177e4c
|
224 |
|
6af502de2
|
225 |
if (iblock >= hip->fs_blocks) { |
839c3a6a5
|
226 227 228 |
if (!create) return 0; if (iblock > hip->fs_blocks) |
1da177e4c
|
229 |
return -EIO; |
6af502de2
|
230 |
if (ablock >= hip->alloc_blocks) { |
2cd282a1b
|
231 |
res = hfsplus_file_extend(inode, false); |
1da177e4c
|
232 233 234 235 236 |
if (res) return res; } } else create = 0; |
6af502de2
|
237 238 |
if (ablock < hip->first_blocks) { dblock = hfsplus_ext_find_block(hip->first_extents, ablock); |
1da177e4c
|
239 240 |
goto done; } |
248736c2a
|
241 242 |
if (inode->i_ino == HFSPLUS_EXT_CNID) return -EIO; |
6af502de2
|
243 |
mutex_lock(&hip->extents_lock); |
e34947056
|
244 245 246 247 248 249 250 |
/* * 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
|
251 |
res = hfsplus_ext_read_extent(inode, ablock); |
e34947056
|
252 |
if (res) { |
6af502de2
|
253 |
mutex_unlock(&hip->extents_lock); |
1da177e4c
|
254 255 |
return -EIO; } |
e34947056
|
256 257 |
dblock = hfsplus_ext_find_block(hip->cached_extents, ablock - hip->cached_start); |
6af502de2
|
258 |
mutex_unlock(&hip->extents_lock); |
1da177e4c
|
259 260 |
done: |
c2b3e1f76
|
261 262 |
hfs_dbg(EXTENT, "get_block(%lu): %llu - %u ", |
2753cc281
|
263 |
inode->i_ino, (long long)iblock, dblock); |
bf1a1b31f
|
264 |
|
dd73a01a3
|
265 |
mask = (1 << sbi->fs_shift) - 1; |
bf1a1b31f
|
266 267 268 |
sector = ((sector_t)dblock << sbi->fs_shift) + sbi->blockoffset + (iblock & mask); map_bh(bh_result, sb, sector); |
1da177e4c
|
269 270 |
if (create) { set_buffer_new(bh_result); |
6af502de2
|
271 272 |
hip->phys_size += sb->s_blocksize; hip->fs_blocks++; |
1da177e4c
|
273 |
inode_add_bytes(inode, sb->s_blocksize); |
1da177e4c
|
274 |
} |
e34947056
|
275 276 |
if (create || was_dirty) mark_inode_dirty(inode); |
1da177e4c
|
277 278 279 280 281 282 |
return 0; } static void hfsplus_dump_extent(struct hfsplus_extent *extent) { int i; |
c2b3e1f76
|
283 |
hfs_dbg(EXTENT, " "); |
1da177e4c
|
284 |
for (i = 0; i < 8; i++) |
c2b3e1f76
|
285 286 287 288 289 |
hfs_dbg_cont(EXTENT, " %u:%u", be32_to_cpu(extent[i].start_block), be32_to_cpu(extent[i].block_count)); hfs_dbg_cont(EXTENT, " "); |
1da177e4c
|
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 |
} 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; |
1b243fd39
|
326 |
int err = 0; |
1da177e4c
|
327 |
|
31651c607
|
328 329 |
/* Mapping the allocation file may lock the extent tree */ WARN_ON(mutex_is_locked(&HFSPLUS_SB(sb)->ext_tree->tree_lock)); |
1da177e4c
|
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
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) { |
1b243fd39
|
345 346 |
err = hfsplus_block_free(sb, start, count); if (err) { |
d61426732
|
347 348 |
pr_err("can't free extent "); |
c2b3e1f76
|
349 350 |
hfs_dbg(EXTENT, " start: %u count: %u ", |
1b243fd39
|
351 352 |
start, count); } |
1da177e4c
|
353 354 355 356 357 |
extent->block_count = 0; extent->start_block = 0; block_nr -= count; } else { count -= block_nr; |
1b243fd39
|
358 359 |
err = hfsplus_block_free(sb, start + count, block_nr); if (err) { |
d61426732
|
360 361 |
pr_err("can't free extent "); |
c2b3e1f76
|
362 363 |
hfs_dbg(EXTENT, " start: %u count: %u ", |
1b243fd39
|
364 365 |
start, count); } |
1da177e4c
|
366 367 368 |
extent->block_count = cpu_to_be32(count); block_nr = 0; } |
1b243fd39
|
369 370 371 372 373 374 375 |
if (!block_nr || !i) { /* * Try to free all extents and * return only last error */ return err; } |
1da177e4c
|
376 377 378 379 380 |
i--; extent--; count = be32_to_cpu(extent->block_count); } } |
2753cc281
|
381 382 |
int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw *fork, int type) |
1da177e4c
|
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
{ 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
|
402 403 404 |
res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); if (res) return res; |
1da177e4c
|
405 406 407 408 409 410 |
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); |
1da177e4c
|
411 |
hfs_brec_remove(&fd); |
31651c607
|
412 413 414 415 |
mutex_unlock(&fd.tree->tree_lock); hfsplus_free_extents(sb, ext_entry, total_blocks - start, total_blocks); |
1da177e4c
|
416 |
total_blocks = start; |
31651c607
|
417 |
mutex_lock(&fd.tree->tree_lock); |
1da177e4c
|
418 419 420 421 422 |
} while (total_blocks > blocks); hfs_find_exit(&fd); return res; } |
2cd282a1b
|
423 |
int hfsplus_file_extend(struct inode *inode, bool zeroout) |
1da177e4c
|
424 425 |
{ struct super_block *sb = inode->i_sb; |
dd73a01a3
|
426 |
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); |
6af502de2
|
427 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c
|
428 429 |
u32 start, len, goal; int res; |
1065348d4
|
430 431 |
if (sbi->alloc_file->i_size * 8 < sbi->total_blocks - sbi->free_blocks + 8) { |
21f2296a5
|
432 |
/* extend alloc file */ |
b73f3d0e7
|
433 434 435 436 |
pr_err("extend alloc file! (%llu,%u,%u) ", sbi->alloc_file->i_size * 8, sbi->total_blocks, sbi->free_blocks); |
1da177e4c
|
437 |
return -ENOSPC; |
1da177e4c
|
438 |
} |
6af502de2
|
439 440 441 |
mutex_lock(&hip->extents_lock); if (hip->alloc_blocks == hip->first_blocks) goal = hfsplus_ext_lastblock(hip->first_extents); |
1da177e4c
|
442 |
else { |
6af502de2
|
443 |
res = hfsplus_ext_read_extent(inode, hip->alloc_blocks); |
1da177e4c
|
444 445 |
if (res) goto out; |
6af502de2
|
446 |
goal = hfsplus_ext_lastblock(hip->cached_extents); |
1da177e4c
|
447 |
} |
6af502de2
|
448 |
len = hip->clump_blocks; |
dd73a01a3
|
449 450 |
start = hfsplus_block_allocate(sb, sbi->total_blocks, goal, &len); if (start >= sbi->total_blocks) { |
1da177e4c
|
451 452 453 454 455 456 |
start = hfsplus_block_allocate(sb, goal, 0, &len); if (start >= goal) { res = -ENOSPC; goto out; } } |
2cd282a1b
|
457 458 459 460 461 |
if (zeroout) { res = sb_issue_zeroout(sb, start, len, GFP_NOFS); if (res) goto out; } |
c2b3e1f76
|
462 463 |
hfs_dbg(EXTENT, "extend %lu: %u,%u ", inode->i_ino, start, len); |
6af502de2
|
464 465 466 |
if (hip->alloc_blocks <= hip->first_blocks) { if (!hip->first_blocks) { |
c2b3e1f76
|
467 468 |
hfs_dbg(EXTENT, "first extents "); |
1da177e4c
|
469 |
/* no extents yet */ |
6af502de2
|
470 471 |
hip->first_extents[0].start_block = cpu_to_be32(start); hip->first_extents[0].block_count = cpu_to_be32(len); |
1da177e4c
|
472 473 474 |
res = 0; } else { /* try to append to extents in inode */ |
6af502de2
|
475 476 |
res = hfsplus_add_extent(hip->first_extents, hip->alloc_blocks, |
1da177e4c
|
477 478 479 480 481 |
start, len); if (res == -ENOSPC) goto insert_extent; } if (!res) { |
6af502de2
|
482 483 |
hfsplus_dump_extent(hip->first_extents); hip->first_blocks += len; |
1da177e4c
|
484 485 |
} } else { |
6af502de2
|
486 487 |
res = hfsplus_add_extent(hip->cached_extents, hip->alloc_blocks - hip->cached_start, |
1da177e4c
|
488 489 |
start, len); if (!res) { |
6af502de2
|
490 |
hfsplus_dump_extent(hip->cached_extents); |
b33b7921d
|
491 |
hip->extent_state |= HFSPLUS_EXT_DIRTY; |
6af502de2
|
492 |
hip->cached_blocks += len; |
1da177e4c
|
493 494 495 496 |
} else if (res == -ENOSPC) goto insert_extent; } out: |
1da177e4c
|
497 |
if (!res) { |
6af502de2
|
498 |
hip->alloc_blocks += len; |
d7bdb996a
|
499 |
mutex_unlock(&hip->extents_lock); |
e34947056
|
500 |
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); |
d7bdb996a
|
501 |
return 0; |
1da177e4c
|
502 |
} |
d7bdb996a
|
503 |
mutex_unlock(&hip->extents_lock); |
1da177e4c
|
504 505 506 |
return res; insert_extent: |
c2b3e1f76
|
507 508 |
hfs_dbg(EXTENT, "insert new extent "); |
dd7f3d545
|
509 510 511 |
res = hfsplus_ext_write_extent_locked(inode); if (res) goto out; |
1da177e4c
|
512 |
|
6af502de2
|
513 514 515 516 |
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
|
517 |
hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW; |
6af502de2
|
518 519 |
hip->cached_start = hip->alloc_blocks; hip->cached_blocks = len; |
1da177e4c
|
520 521 522 523 524 525 526 527 |
res = 0; goto out; } void hfsplus_file_truncate(struct inode *inode) { struct super_block *sb = inode->i_sb; |
6af502de2
|
528 |
struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
1da177e4c
|
529 530 531 |
struct hfs_find_data fd; u32 alloc_cnt, blk_cnt, start; int res; |
c2b3e1f76
|
532 533 534 |
hfs_dbg(INODE, "truncate: %lu, %llu -> %llu ", inode->i_ino, (long long)hip->phys_size, inode->i_size); |
6af502de2
|
535 536 |
if (inode->i_size > hip->phys_size) { |
1da177e4c
|
537 538 |
struct address_space *mapping = inode->i_mapping; struct page *page; |
7c0efc627
|
539 |
void *fsdata; |
12f267a20
|
540 |
loff_t size = inode->i_size; |
1da177e4c
|
541 |
|
c718a9751
|
542 543 |
res = pagecache_write_begin(NULL, mapping, size, 0, 0, &page, &fsdata); |
1da177e4c
|
544 |
if (res) |
7c0efc627
|
545 |
return; |
2753cc281
|
546 547 |
res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata); |
7c0efc627
|
548 549 |
if (res < 0) return; |
1da177e4c
|
550 551 |
mark_inode_dirty(inode); return; |
6af502de2
|
552 |
} else if (inode->i_size == hip->phys_size) |
f76d28d23
|
553 |
return; |
dd73a01a3
|
554 555 |
blk_cnt = (inode->i_size + HFSPLUS_SB(sb)->alloc_blksz - 1) >> HFSPLUS_SB(sb)->alloc_blksz_shift; |
d7bdb996a
|
556 557 |
mutex_lock(&hip->extents_lock); |
6af502de2
|
558 |
alloc_cnt = hip->alloc_blocks; |
1da177e4c
|
559 |
if (blk_cnt == alloc_cnt) |
d7bdb996a
|
560 |
goto out_unlock; |
1da177e4c
|
561 |
|
5bd9d99d1
|
562 563 564 565 566 567 |
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
|
568 |
while (1) { |
6af502de2
|
569 |
if (alloc_cnt == hip->first_blocks) { |
31651c607
|
570 |
mutex_unlock(&fd.tree->tree_lock); |
6af502de2
|
571 |
hfsplus_free_extents(sb, hip->first_extents, |
1da177e4c
|
572 |
alloc_cnt, alloc_cnt - blk_cnt); |
6af502de2
|
573 574 |
hfsplus_dump_extent(hip->first_extents); hip->first_blocks = blk_cnt; |
31651c607
|
575 |
mutex_lock(&fd.tree->tree_lock); |
1da177e4c
|
576 577 578 579 580 |
break; } res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt); if (res) break; |
31651c607
|
581 582 583 |
hfs_brec_remove(&fd); mutex_unlock(&fd.tree->tree_lock); |
6af502de2
|
584 585 |
start = hip->cached_start; hfsplus_free_extents(sb, hip->cached_extents, |
1da177e4c
|
586 |
alloc_cnt - start, alloc_cnt - blk_cnt); |
6af502de2
|
587 |
hfsplus_dump_extent(hip->cached_extents); |
1da177e4c
|
588 |
if (blk_cnt > start) { |
b33b7921d
|
589 |
hip->extent_state |= HFSPLUS_EXT_DIRTY; |
1da177e4c
|
590 591 592 |
break; } alloc_cnt = start; |
6af502de2
|
593 |
hip->cached_start = hip->cached_blocks = 0; |
b33b7921d
|
594 |
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); |
31651c607
|
595 |
mutex_lock(&fd.tree->tree_lock); |
1da177e4c
|
596 597 |
} hfs_find_exit(&fd); |
1da177e4c
|
598 |
|
6af502de2
|
599 |
hip->alloc_blocks = blk_cnt; |
d7bdb996a
|
600 601 |
out_unlock: mutex_unlock(&hip->extents_lock); |
6af502de2
|
602 |
hip->phys_size = inode->i_size; |
2753cc281
|
603 604 |
hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; |
6af502de2
|
605 |
inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); |
e34947056
|
606 |
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); |
1da177e4c
|
607 |
} |