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