diff options
-rw-r--r-- | fs/ntfs/ChangeLog | 20 | ||||
-rw-r--r-- | fs/ntfs/inode.c | 491 |
2 files changed, 468 insertions, 43 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 6c5bdfbb7bbf..70ad4be7a7fe 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -3,16 +3,14 @@ ToDo/Notes: | |||
3 | - In between ntfs_prepare/commit_write, need exclusion between | 3 | - In between ntfs_prepare/commit_write, need exclusion between |
4 | simultaneous file extensions. This is given to us by holding i_sem | 4 | simultaneous file extensions. This is given to us by holding i_sem |
5 | on the inode. The only places in the kernel when a file is resized | 5 | on the inode. The only places in the kernel when a file is resized |
6 | are prepare/commit write and truncate for both of which i_sem is | 6 | are prepare/commit write and ntfs_truncate() for both of which i_sem |
7 | held. Just have to be careful in readpage/writepage and all other | 7 | is held. Just have to be careful in read-/writepage and other helpers |
8 | helpers not running under i_sem that we play nice... | 8 | not running under i_sem that we play nice... Also need to be careful |
9 | Also need to be careful with initialized_size extention in | 9 | with initialized_size extention in ntfs_prepare_write and writepage. |
10 | ntfs_prepare_write. Basically, just be _very_ careful in this code... | 10 | UPDATE: The only things that need to be checked are |
11 | UPDATE: The only things that need to be checked are read/writepage | 11 | prepare/commit_write as well as the compressed write and the other |
12 | which do not hold i_sem. Note writepage cannot change i_size but it | 12 | attribute resize/write cases like index attributes, etc. For now |
13 | needs to cope with a concurrent i_size change, just like readpage. | 13 | none of these are implemented so are safe. |
14 | Also both need to cope with concurrent changes to the other sizes, | ||
15 | i.e. initialized/allocated/compressed size, as well. | ||
16 | - Implement mft.c::sync_mft_mirror_umount(). We currently will just | 14 | - Implement mft.c::sync_mft_mirror_umount(). We currently will just |
17 | leave the volume dirty on umount if the final iput(vol->mft_ino) | 15 | leave the volume dirty on umount if the final iput(vol->mft_ino) |
18 | causes a write of any mirrored mft records due to the mft mirror | 16 | causes a write of any mirrored mft records due to the mft mirror |
@@ -50,6 +48,8 @@ ToDo/Notes: | |||
50 | - Add fs/ntfs/attrib.[hc]::ntfs_attr_extend_allocation(), a function to | 48 | - Add fs/ntfs/attrib.[hc]::ntfs_attr_extend_allocation(), a function to |
51 | extend the allocation of an attributes. Optionally, the data size, | 49 | extend the allocation of an attributes. Optionally, the data size, |
52 | but not the initialized size can be extended, too. | 50 | but not the initialized size can be extended, too. |
51 | - Implement fs/ntfs/inode.[hc]::ntfs_truncate(). It only supports | ||
52 | uncompressed and unencrypted files. | ||
53 | 53 | ||
54 | 2.1.24 - Lots of bug fixes and support more clean journal states. | 54 | 2.1.24 - Lots of bug fixes and support more clean journal states. |
55 | 55 | ||
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 7ec045131808..a1682342baa6 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "debug.h" | 30 | #include "debug.h" |
31 | #include "inode.h" | 31 | #include "inode.h" |
32 | #include "attrib.h" | 32 | #include "attrib.h" |
33 | #include "lcnalloc.h" | ||
33 | #include "malloc.h" | 34 | #include "malloc.h" |
34 | #include "mft.h" | 35 | #include "mft.h" |
35 | #include "time.h" | 36 | #include "time.h" |
@@ -2291,11 +2292,16 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt) | |||
2291 | 2292 | ||
2292 | #ifdef NTFS_RW | 2293 | #ifdef NTFS_RW |
2293 | 2294 | ||
2295 | static const char *es = " Leaving inconsistent metadata. Unmount and run " | ||
2296 | "chkdsk."; | ||
2297 | |||
2294 | /** | 2298 | /** |
2295 | * ntfs_truncate - called when the i_size of an ntfs inode is changed | 2299 | * ntfs_truncate - called when the i_size of an ntfs inode is changed |
2296 | * @vi: inode for which the i_size was changed | 2300 | * @vi: inode for which the i_size was changed |
2297 | * | 2301 | * |
2298 | * We do not support i_size changes yet. | 2302 | * We only support i_size changes for normal files at present, i.e. not |
2303 | * compressed and not encrypted. This is enforced in ntfs_setattr(), see | ||
2304 | * below. | ||
2299 | * | 2305 | * |
2300 | * The kernel guarantees that @vi is a regular file (S_ISREG() is true) and | 2306 | * The kernel guarantees that @vi is a regular file (S_ISREG() is true) and |
2301 | * that the change is allowed. | 2307 | * that the change is allowed. |
@@ -2306,80 +2312,499 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt) | |||
2306 | * Returns 0 on success or -errno on error. | 2312 | * Returns 0 on success or -errno on error. |
2307 | * | 2313 | * |
2308 | * Called with ->i_sem held. In all but one case ->i_alloc_sem is held for | 2314 | * Called with ->i_sem held. In all but one case ->i_alloc_sem is held for |
2309 | * writing. The only case where ->i_alloc_sem is not held is | 2315 | * writing. The only case in the kernel where ->i_alloc_sem is not held is |
2310 | * mm/filemap.c::generic_file_buffered_write() where vmtruncate() is called | 2316 | * mm/filemap.c::generic_file_buffered_write() where vmtruncate() is called |
2311 | * with the current i_size as the offset which means that it is a noop as far | 2317 | * with the current i_size as the offset. The analogous place in NTFS is in |
2312 | * as ntfs_truncate() is concerned. | 2318 | * fs/ntfs/file.c::ntfs_file_buffered_write() where we call vmtruncate() again |
2319 | * without holding ->i_alloc_sem. | ||
2313 | */ | 2320 | */ |
2314 | int ntfs_truncate(struct inode *vi) | 2321 | int ntfs_truncate(struct inode *vi) |
2315 | { | 2322 | { |
2316 | ntfs_inode *ni = NTFS_I(vi); | 2323 | s64 new_size, old_size, nr_freed, new_alloc_size, old_alloc_size; |
2324 | VCN highest_vcn; | ||
2325 | unsigned long flags; | ||
2326 | ntfs_inode *base_ni, *ni = NTFS_I(vi); | ||
2317 | ntfs_volume *vol = ni->vol; | 2327 | ntfs_volume *vol = ni->vol; |
2318 | ntfs_attr_search_ctx *ctx; | 2328 | ntfs_attr_search_ctx *ctx; |
2319 | MFT_RECORD *m; | 2329 | MFT_RECORD *m; |
2320 | ATTR_RECORD *a; | 2330 | ATTR_RECORD *a; |
2321 | const char *te = " Leaving file length out of sync with i_size."; | 2331 | const char *te = " Leaving file length out of sync with i_size."; |
2322 | int err; | 2332 | int err, mp_size, size_change, alloc_change; |
2333 | u32 attr_len; | ||
2323 | 2334 | ||
2324 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); | 2335 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); |
2325 | BUG_ON(NInoAttr(ni)); | 2336 | BUG_ON(NInoAttr(ni)); |
2337 | BUG_ON(S_ISDIR(vi->i_mode)); | ||
2338 | BUG_ON(NInoMstProtected(ni)); | ||
2326 | BUG_ON(ni->nr_extents < 0); | 2339 | BUG_ON(ni->nr_extents < 0); |
2327 | m = map_mft_record(ni); | 2340 | retry_truncate: |
2341 | /* | ||
2342 | * Lock the runlist for writing and map the mft record to ensure it is | ||
2343 | * safe to mess with the attribute runlist and sizes. | ||
2344 | */ | ||
2345 | down_write(&ni->runlist.lock); | ||
2346 | if (!NInoAttr(ni)) | ||
2347 | base_ni = ni; | ||
2348 | else | ||
2349 | base_ni = ni->ext.base_ntfs_ino; | ||
2350 | m = map_mft_record(base_ni); | ||
2328 | if (IS_ERR(m)) { | 2351 | if (IS_ERR(m)) { |
2329 | err = PTR_ERR(m); | 2352 | err = PTR_ERR(m); |
2330 | ntfs_error(vi->i_sb, "Failed to map mft record for inode 0x%lx " | 2353 | ntfs_error(vi->i_sb, "Failed to map mft record for inode 0x%lx " |
2331 | "(error code %d).%s", vi->i_ino, err, te); | 2354 | "(error code %d).%s", vi->i_ino, err, te); |
2332 | ctx = NULL; | 2355 | ctx = NULL; |
2333 | m = NULL; | 2356 | m = NULL; |
2334 | goto err_out; | 2357 | goto old_bad_out; |
2335 | } | 2358 | } |
2336 | ctx = ntfs_attr_get_search_ctx(ni, m); | 2359 | ctx = ntfs_attr_get_search_ctx(base_ni, m); |
2337 | if (unlikely(!ctx)) { | 2360 | if (unlikely(!ctx)) { |
2338 | ntfs_error(vi->i_sb, "Failed to allocate a search context for " | 2361 | ntfs_error(vi->i_sb, "Failed to allocate a search context for " |
2339 | "inode 0x%lx (not enough memory).%s", | 2362 | "inode 0x%lx (not enough memory).%s", |
2340 | vi->i_ino, te); | 2363 | vi->i_ino, te); |
2341 | err = -ENOMEM; | 2364 | err = -ENOMEM; |
2342 | goto err_out; | 2365 | goto old_bad_out; |
2343 | } | 2366 | } |
2344 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | 2367 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, |
2345 | CASE_SENSITIVE, 0, NULL, 0, ctx); | 2368 | CASE_SENSITIVE, 0, NULL, 0, ctx); |
2346 | if (unlikely(err)) { | 2369 | if (unlikely(err)) { |
2347 | if (err == -ENOENT) | 2370 | if (err == -ENOENT) { |
2348 | ntfs_error(vi->i_sb, "Open attribute is missing from " | 2371 | ntfs_error(vi->i_sb, "Open attribute is missing from " |
2349 | "mft record. Inode 0x%lx is corrupt. " | 2372 | "mft record. Inode 0x%lx is corrupt. " |
2350 | "Run chkdsk.", vi->i_ino); | 2373 | "Run chkdsk.%s", vi->i_ino, te); |
2351 | else | 2374 | err = -EIO; |
2375 | } else | ||
2352 | ntfs_error(vi->i_sb, "Failed to lookup attribute in " | 2376 | ntfs_error(vi->i_sb, "Failed to lookup attribute in " |
2353 | "inode 0x%lx (error code %d).", | 2377 | "inode 0x%lx (error code %d).%s", |
2354 | vi->i_ino, err); | 2378 | vi->i_ino, err, te); |
2355 | goto err_out; | 2379 | goto old_bad_out; |
2356 | } | 2380 | } |
2381 | m = ctx->mrec; | ||
2357 | a = ctx->attr; | 2382 | a = ctx->attr; |
2358 | /* If the size has not changed there is nothing to do. */ | 2383 | /* |
2359 | if (ntfs_attr_size(a) == i_size_read(vi)) | 2384 | * The i_size of the vfs inode is the new size for the attribute value. |
2360 | goto done; | 2385 | */ |
2361 | // TODO: Implement the truncate... | 2386 | new_size = i_size_read(vi); |
2362 | ntfs_error(vi->i_sb, "Inode size has changed but this is not " | 2387 | /* The current size of the attribute value is the old size. */ |
2363 | "implemented yet. Resetting inode size to old value. " | 2388 | old_size = ntfs_attr_size(a); |
2364 | " This is most likely a bug in the ntfs driver!"); | 2389 | /* Calculate the new allocated size. */ |
2365 | i_size_write(vi, ntfs_attr_size(a)); | 2390 | if (NInoNonResident(ni)) |
2366 | done: | 2391 | new_alloc_size = (new_size + vol->cluster_size - 1) & |
2392 | ~(s64)vol->cluster_size_mask; | ||
2393 | else | ||
2394 | new_alloc_size = (new_size + 7) & ~7; | ||
2395 | /* The current allocated size is the old allocated size. */ | ||
2396 | read_lock_irqsave(&ni->size_lock, flags); | ||
2397 | old_alloc_size = ni->allocated_size; | ||
2398 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
2399 | /* | ||
2400 | * The change in the file size. This will be 0 if no change, >0 if the | ||
2401 | * size is growing, and <0 if the size is shrinking. | ||
2402 | */ | ||
2403 | size_change = -1; | ||
2404 | if (new_size - old_size >= 0) { | ||
2405 | size_change = 1; | ||
2406 | if (new_size == old_size) | ||
2407 | size_change = 0; | ||
2408 | } | ||
2409 | /* As above for the allocated size. */ | ||
2410 | alloc_change = -1; | ||
2411 | if (new_alloc_size - old_alloc_size >= 0) { | ||
2412 | alloc_change = 1; | ||
2413 | if (new_alloc_size == old_alloc_size) | ||
2414 | alloc_change = 0; | ||
2415 | } | ||
2416 | /* | ||
2417 | * If neither the size nor the allocation are being changed there is | ||
2418 | * nothing to do. | ||
2419 | */ | ||
2420 | if (!size_change && !alloc_change) | ||
2421 | goto unm_done; | ||
2422 | /* If the size is changing, check if new size is allowed in $AttrDef. */ | ||
2423 | if (size_change) { | ||
2424 | err = ntfs_attr_size_bounds_check(vol, ni->type, new_size); | ||
2425 | if (unlikely(err)) { | ||
2426 | if (err == -ERANGE) { | ||
2427 | ntfs_error(vol->sb, "Truncate would cause the " | ||
2428 | "inode 0x%lx to %simum size " | ||
2429 | "for its attribute type " | ||
2430 | "(0x%x). Aborting truncate.", | ||
2431 | vi->i_ino, | ||
2432 | new_size > old_size ? "exceed " | ||
2433 | "the max" : "go under the min", | ||
2434 | le32_to_cpu(ni->type)); | ||
2435 | err = -EFBIG; | ||
2436 | } else { | ||
2437 | ntfs_error(vol->sb, "Inode 0x%lx has unknown " | ||
2438 | "attribute type 0x%x. " | ||
2439 | "Aborting truncate.", | ||
2440 | vi->i_ino, | ||
2441 | le32_to_cpu(ni->type)); | ||
2442 | err = -EIO; | ||
2443 | } | ||
2444 | /* Reset the vfs inode size to the old size. */ | ||
2445 | i_size_write(vi, old_size); | ||
2446 | goto err_out; | ||
2447 | } | ||
2448 | } | ||
2449 | if (NInoCompressed(ni) || NInoEncrypted(ni)) { | ||
2450 | ntfs_warning(vi->i_sb, "Changes in inode size are not " | ||
2451 | "supported yet for %s files, ignoring.", | ||
2452 | NInoCompressed(ni) ? "compressed" : | ||
2453 | "encrypted"); | ||
2454 | err = -EOPNOTSUPP; | ||
2455 | goto bad_out; | ||
2456 | } | ||
2457 | if (a->non_resident) | ||
2458 | goto do_non_resident_truncate; | ||
2459 | BUG_ON(NInoNonResident(ni)); | ||
2460 | /* Resize the attribute record to best fit the new attribute size. */ | ||
2461 | if (new_size < vol->mft_record_size && | ||
2462 | !ntfs_resident_attr_value_resize(m, a, new_size)) { | ||
2463 | unsigned long flags; | ||
2464 | |||
2465 | /* The resize succeeded! */ | ||
2466 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2467 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2468 | write_lock_irqsave(&ni->size_lock, flags); | ||
2469 | /* Update the sizes in the ntfs inode and all is done. */ | ||
2470 | ni->allocated_size = le32_to_cpu(a->length) - | ||
2471 | le16_to_cpu(a->data.resident.value_offset); | ||
2472 | /* | ||
2473 | * Note ntfs_resident_attr_value_resize() has already done any | ||
2474 | * necessary data clearing in the attribute record. When the | ||
2475 | * file is being shrunk vmtruncate() will already have cleared | ||
2476 | * the top part of the last partial page, i.e. since this is | ||
2477 | * the resident case this is the page with index 0. However, | ||
2478 | * when the file is being expanded, the page cache page data | ||
2479 | * between the old data_size, i.e. old_size, and the new_size | ||
2480 | * has not been zeroed. Fortunately, we do not need to zero it | ||
2481 | * either since on one hand it will either already be zero due | ||
2482 | * to both readpage and writepage clearing partial page data | ||
2483 | * beyond i_size in which case there is nothing to do or in the | ||
2484 | * case of the file being mmap()ped at the same time, POSIX | ||
2485 | * specifies that the behaviour is unspecified thus we do not | ||
2486 | * have to do anything. This means that in our implementation | ||
2487 | * in the rare case that the file is mmap()ped and a write | ||
2488 | * occured into the mmap()ped region just beyond the file size | ||
2489 | * and writepage has not yet been called to write out the page | ||
2490 | * (which would clear the area beyond the file size) and we now | ||
2491 | * extend the file size to incorporate this dirty region | ||
2492 | * outside the file size, a write of the page would result in | ||
2493 | * this data being written to disk instead of being cleared. | ||
2494 | * Given both POSIX and the Linux mmap(2) man page specify that | ||
2495 | * this corner case is undefined, we choose to leave it like | ||
2496 | * that as this is much simpler for us as we cannot lock the | ||
2497 | * relevant page now since we are holding too many ntfs locks | ||
2498 | * which would result in a lock reversal deadlock. | ||
2499 | */ | ||
2500 | ni->initialized_size = new_size; | ||
2501 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2502 | goto unm_done; | ||
2503 | } | ||
2504 | /* If the above resize failed, this must be an attribute extension. */ | ||
2505 | BUG_ON(size_change < 0); | ||
2506 | /* | ||
2507 | * We have to drop all the locks so we can call | ||
2508 | * ntfs_attr_make_non_resident(). This could be optimised by try- | ||
2509 | * locking the first page cache page and only if that fails dropping | ||
2510 | * the locks, locking the page, and redoing all the locking and | ||
2511 | * lookups. While this would be a huge optimisation, it is not worth | ||
2512 | * it as this is definitely a slow code path as it only ever can happen | ||
2513 | * once for any given file. | ||
2514 | */ | ||
2367 | ntfs_attr_put_search_ctx(ctx); | 2515 | ntfs_attr_put_search_ctx(ctx); |
2368 | unmap_mft_record(ni); | 2516 | unmap_mft_record(base_ni); |
2369 | NInoClearTruncateFailed(ni); | 2517 | up_write(&ni->runlist.lock); |
2370 | ntfs_debug("Done."); | 2518 | /* |
2371 | return 0; | 2519 | * Not enough space in the mft record, try to make the attribute |
2372 | err_out: | 2520 | * non-resident and if successful restart the truncation process. |
2373 | if (err != -ENOMEM) { | 2521 | */ |
2522 | err = ntfs_attr_make_non_resident(ni, old_size); | ||
2523 | if (likely(!err)) | ||
2524 | goto retry_truncate; | ||
2525 | /* | ||
2526 | * Could not make non-resident. If this is due to this not being | ||
2527 | * permitted for this attribute type or there not being enough space, | ||
2528 | * try to make other attributes non-resident. Otherwise fail. | ||
2529 | */ | ||
2530 | if (unlikely(err != -EPERM && err != -ENOSPC)) { | ||
2531 | ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, attribute " | ||
2532 | "type 0x%x, because the conversion from " | ||
2533 | "resident to non-resident attribute failed " | ||
2534 | "with error code %i.", vi->i_ino, | ||
2535 | (unsigned)le32_to_cpu(ni->type), err); | ||
2536 | if (err != -ENOMEM) | ||
2537 | err = -EIO; | ||
2538 | goto conv_err_out; | ||
2539 | } | ||
2540 | /* TODO: Not implemented from here, abort. */ | ||
2541 | if (err == -ENOSPC) | ||
2542 | ntfs_error(vol->sb, "Not enough space in the mft record/on " | ||
2543 | "disk for the non-resident attribute value. " | ||
2544 | "This case is not implemented yet."); | ||
2545 | else /* if (err == -EPERM) */ | ||
2546 | ntfs_error(vol->sb, "This attribute type may not be " | ||
2547 | "non-resident. This case is not implemented " | ||
2548 | "yet."); | ||
2549 | err = -EOPNOTSUPP; | ||
2550 | goto conv_err_out; | ||
2551 | #if 0 | ||
2552 | // TODO: Attempt to make other attributes non-resident. | ||
2553 | if (!err) | ||
2554 | goto do_resident_extend; | ||
2555 | /* | ||
2556 | * Both the attribute list attribute and the standard information | ||
2557 | * attribute must remain in the base inode. Thus, if this is one of | ||
2558 | * these attributes, we have to try to move other attributes out into | ||
2559 | * extent mft records instead. | ||
2560 | */ | ||
2561 | if (ni->type == AT_ATTRIBUTE_LIST || | ||
2562 | ni->type == AT_STANDARD_INFORMATION) { | ||
2563 | // TODO: Attempt to move other attributes into extent mft | ||
2564 | // records. | ||
2565 | err = -EOPNOTSUPP; | ||
2566 | if (!err) | ||
2567 | goto do_resident_extend; | ||
2568 | goto err_out; | ||
2569 | } | ||
2570 | // TODO: Attempt to move this attribute to an extent mft record, but | ||
2571 | // only if it is not already the only attribute in an mft record in | ||
2572 | // which case there would be nothing to gain. | ||
2573 | err = -EOPNOTSUPP; | ||
2574 | if (!err) | ||
2575 | goto do_resident_extend; | ||
2576 | /* There is nothing we can do to make enough space. )-: */ | ||
2577 | goto err_out; | ||
2578 | #endif | ||
2579 | do_non_resident_truncate: | ||
2580 | BUG_ON(!NInoNonResident(ni)); | ||
2581 | if (alloc_change < 0) { | ||
2582 | highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); | ||
2583 | if (highest_vcn > 0 && | ||
2584 | old_alloc_size >> vol->cluster_size_bits > | ||
2585 | highest_vcn + 1) { | ||
2586 | /* | ||
2587 | * This attribute has multiple extents. Not yet | ||
2588 | * supported. | ||
2589 | */ | ||
2590 | ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, " | ||
2591 | "attribute type 0x%x, because the " | ||
2592 | "attribute is highly fragmented (it " | ||
2593 | "consists of multiple extents) and " | ||
2594 | "this case is not implemented yet.", | ||
2595 | vi->i_ino, | ||
2596 | (unsigned)le32_to_cpu(ni->type)); | ||
2597 | err = -EOPNOTSUPP; | ||
2598 | goto bad_out; | ||
2599 | } | ||
2600 | } | ||
2601 | /* | ||
2602 | * If the size is shrinking, need to reduce the initialized_size and | ||
2603 | * the data_size before reducing the allocation. | ||
2604 | */ | ||
2605 | if (size_change < 0) { | ||
2606 | /* | ||
2607 | * Make the valid size smaller (i_size is already up-to-date). | ||
2608 | */ | ||
2609 | write_lock_irqsave(&ni->size_lock, flags); | ||
2610 | if (new_size < ni->initialized_size) { | ||
2611 | ni->initialized_size = new_size; | ||
2612 | a->data.non_resident.initialized_size = | ||
2613 | cpu_to_sle64(new_size); | ||
2614 | } | ||
2615 | a->data.non_resident.data_size = cpu_to_sle64(new_size); | ||
2616 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2617 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2618 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2619 | /* If the allocated size is not changing, we are done. */ | ||
2620 | if (!alloc_change) | ||
2621 | goto unm_done; | ||
2622 | /* | ||
2623 | * If the size is shrinking it makes no sense for the | ||
2624 | * allocation to be growing. | ||
2625 | */ | ||
2626 | BUG_ON(alloc_change > 0); | ||
2627 | } else /* if (size_change >= 0) */ { | ||
2628 | /* | ||
2629 | * The file size is growing or staying the same but the | ||
2630 | * allocation can be shrinking, growing or staying the same. | ||
2631 | */ | ||
2632 | if (alloc_change > 0) { | ||
2633 | /* | ||
2634 | * We need to extend the allocation and possibly update | ||
2635 | * the data size. If we are updating the data size, | ||
2636 | * since we are not touching the initialized_size we do | ||
2637 | * not need to worry about the actual data on disk. | ||
2638 | * And as far as the page cache is concerned, there | ||
2639 | * will be no pages beyond the old data size and any | ||
2640 | * partial region in the last page between the old and | ||
2641 | * new data size (or the end of the page if the new | ||
2642 | * data size is outside the page) does not need to be | ||
2643 | * modified as explained above for the resident | ||
2644 | * attribute truncate case. To do this, we simply drop | ||
2645 | * the locks we hold and leave all the work to our | ||
2646 | * friendly helper ntfs_attr_extend_allocation(). | ||
2647 | */ | ||
2648 | ntfs_attr_put_search_ctx(ctx); | ||
2649 | unmap_mft_record(base_ni); | ||
2650 | up_write(&ni->runlist.lock); | ||
2651 | err = ntfs_attr_extend_allocation(ni, new_size, | ||
2652 | size_change > 0 ? new_size : -1, -1); | ||
2653 | /* | ||
2654 | * ntfs_attr_extend_allocation() will have done error | ||
2655 | * output already. | ||
2656 | */ | ||
2657 | goto done; | ||
2658 | } | ||
2659 | if (!alloc_change) | ||
2660 | goto alloc_done; | ||
2661 | } | ||
2662 | /* alloc_change < 0 */ | ||
2663 | /* Free the clusters. */ | ||
2664 | nr_freed = ntfs_cluster_free(ni, new_alloc_size >> | ||
2665 | vol->cluster_size_bits, -1, ctx); | ||
2666 | m = ctx->mrec; | ||
2667 | a = ctx->attr; | ||
2668 | if (unlikely(nr_freed < 0)) { | ||
2669 | ntfs_error(vol->sb, "Failed to release cluster(s) (error code " | ||
2670 | "%lli). Unmount and run chkdsk to recover " | ||
2671 | "the lost cluster(s).", (long long)nr_freed); | ||
2374 | NVolSetErrors(vol); | 2672 | NVolSetErrors(vol); |
2673 | nr_freed = 0; | ||
2674 | } | ||
2675 | /* Truncate the runlist. */ | ||
2676 | err = ntfs_rl_truncate_nolock(vol, &ni->runlist, | ||
2677 | new_alloc_size >> vol->cluster_size_bits); | ||
2678 | /* | ||
2679 | * If the runlist truncation failed and/or the search context is no | ||
2680 | * longer valid, we cannot resize the attribute record or build the | ||
2681 | * mapping pairs array thus we mark the inode bad so that no access to | ||
2682 | * the freed clusters can happen. | ||
2683 | */ | ||
2684 | if (unlikely(err || IS_ERR(m))) { | ||
2685 | ntfs_error(vol->sb, "Failed to %s (error code %li).%s", | ||
2686 | IS_ERR(m) ? | ||
2687 | "restore attribute search context" : | ||
2688 | "truncate attribute runlist", | ||
2689 | IS_ERR(m) ? PTR_ERR(m) : err, es); | ||
2690 | err = -EIO; | ||
2691 | goto bad_out; | ||
2692 | } | ||
2693 | /* Get the size for the shrunk mapping pairs array for the runlist. */ | ||
2694 | mp_size = ntfs_get_size_for_mapping_pairs(vol, ni->runlist.rl, 0, -1); | ||
2695 | if (unlikely(mp_size <= 0)) { | ||
2696 | ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, " | ||
2697 | "attribute type 0x%x, because determining the " | ||
2698 | "size for the mapping pairs failed with error " | ||
2699 | "code %i.%s", vi->i_ino, | ||
2700 | (unsigned)le32_to_cpu(ni->type), mp_size, es); | ||
2701 | err = -EIO; | ||
2702 | goto bad_out; | ||
2703 | } | ||
2704 | /* | ||
2705 | * Shrink the attribute record for the new mapping pairs array. Note, | ||
2706 | * this cannot fail since we are making the attribute smaller thus by | ||
2707 | * definition there is enough space to do so. | ||
2708 | */ | ||
2709 | attr_len = le32_to_cpu(a->length); | ||
2710 | err = ntfs_attr_record_resize(m, a, mp_size + | ||
2711 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset)); | ||
2712 | BUG_ON(err); | ||
2713 | /* | ||
2714 | * Generate the mapping pairs array directly into the attribute record. | ||
2715 | */ | ||
2716 | err = ntfs_mapping_pairs_build(vol, (u8*)a + | ||
2717 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset), | ||
2718 | mp_size, ni->runlist.rl, 0, -1, NULL); | ||
2719 | if (unlikely(err)) { | ||
2720 | ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, " | ||
2721 | "attribute type 0x%x, because building the " | ||
2722 | "mapping pairs failed with error code %i.%s", | ||
2723 | vi->i_ino, (unsigned)le32_to_cpu(ni->type), | ||
2724 | err, es); | ||
2725 | err = -EIO; | ||
2726 | goto bad_out; | ||
2727 | } | ||
2728 | /* Update the allocated/compressed size as well as the highest vcn. */ | ||
2729 | a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >> | ||
2730 | vol->cluster_size_bits) - 1); | ||
2731 | write_lock_irqsave(&ni->size_lock, flags); | ||
2732 | ni->allocated_size = new_alloc_size; | ||
2733 | a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size); | ||
2734 | if (NInoSparse(ni) || NInoCompressed(ni)) { | ||
2735 | if (nr_freed) { | ||
2736 | ni->itype.compressed.size -= nr_freed << | ||
2737 | vol->cluster_size_bits; | ||
2738 | BUG_ON(ni->itype.compressed.size < 0); | ||
2739 | a->data.non_resident.compressed_size = cpu_to_sle64( | ||
2740 | ni->itype.compressed.size); | ||
2741 | vi->i_blocks = ni->itype.compressed.size >> 9; | ||
2742 | } | ||
2743 | } else | ||
2744 | vi->i_blocks = new_alloc_size >> 9; | ||
2745 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2746 | /* | ||
2747 | * We have shrunk the allocation. If this is a shrinking truncate we | ||
2748 | * have already dealt with the initialized_size and the data_size above | ||
2749 | * and we are done. If the truncate is only changing the allocation | ||
2750 | * and not the data_size, we are also done. If this is an extending | ||
2751 | * truncate, need to extend the data_size now which is ensured by the | ||
2752 | * fact that @size_change is positive. | ||
2753 | */ | ||
2754 | alloc_done: | ||
2755 | /* | ||
2756 | * If the size is growing, need to update it now. If it is shrinking, | ||
2757 | * we have already updated it above (before the allocation change). | ||
2758 | */ | ||
2759 | if (size_change > 0) | ||
2760 | a->data.non_resident.data_size = cpu_to_sle64(new_size); | ||
2761 | /* Ensure the modified mft record is written out. */ | ||
2762 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2763 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2764 | unm_done: | ||
2765 | ntfs_attr_put_search_ctx(ctx); | ||
2766 | unmap_mft_record(base_ni); | ||
2767 | up_write(&ni->runlist.lock); | ||
2768 | done: | ||
2769 | /* Update the mtime and ctime on the base inode. */ | ||
2770 | inode_update_time(VFS_I(base_ni), 1); | ||
2771 | if (likely(!err)) { | ||
2772 | NInoClearTruncateFailed(ni); | ||
2773 | ntfs_debug("Done."); | ||
2774 | } | ||
2775 | return err; | ||
2776 | old_bad_out: | ||
2777 | old_size = -1; | ||
2778 | bad_out: | ||
2779 | if (err != -ENOMEM && err != -EOPNOTSUPP) { | ||
2375 | make_bad_inode(vi); | 2780 | make_bad_inode(vi); |
2781 | make_bad_inode(VFS_I(base_ni)); | ||
2782 | NVolSetErrors(vol); | ||
2376 | } | 2783 | } |
2784 | if (err != -EOPNOTSUPP) | ||
2785 | NInoSetTruncateFailed(ni); | ||
2786 | else if (old_size >= 0) | ||
2787 | i_size_write(vi, old_size); | ||
2788 | err_out: | ||
2377 | if (ctx) | 2789 | if (ctx) |
2378 | ntfs_attr_put_search_ctx(ctx); | 2790 | ntfs_attr_put_search_ctx(ctx); |
2379 | if (m) | 2791 | if (m) |
2380 | unmap_mft_record(ni); | 2792 | unmap_mft_record(base_ni); |
2381 | NInoSetTruncateFailed(ni); | 2793 | up_write(&ni->runlist.lock); |
2794 | out: | ||
2795 | ntfs_debug("Failed. Returning error code %i.", err); | ||
2382 | return err; | 2796 | return err; |
2797 | conv_err_out: | ||
2798 | if (err != -ENOMEM && err != -EOPNOTSUPP) { | ||
2799 | make_bad_inode(vi); | ||
2800 | make_bad_inode(VFS_I(base_ni)); | ||
2801 | NVolSetErrors(vol); | ||
2802 | } | ||
2803 | if (err != -EOPNOTSUPP) | ||
2804 | NInoSetTruncateFailed(ni); | ||
2805 | else | ||
2806 | i_size_write(vi, old_size); | ||
2807 | goto out; | ||
2383 | } | 2808 | } |
2384 | 2809 | ||
2385 | /** | 2810 | /** |