diff options
-rw-r--r-- | fs/ntfs/ChangeLog | 6 | ||||
-rw-r--r-- | fs/ntfs/attrib.c | 84 | ||||
-rw-r--r-- | fs/ntfs/attrib.h | 2 | ||||
-rw-r--r-- | fs/ntfs/lcnalloc.c | 4 | ||||
-rw-r--r-- | fs/ntfs/mft.c | 7 |
5 files changed, 59 insertions, 44 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 85f797a2edad..0a361ddb3b45 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -24,8 +24,10 @@ ToDo/Notes: | |||
24 | 24 | ||
25 | 2.1.25-WIP | 25 | 2.1.25-WIP |
26 | 26 | ||
27 | - Change ntfs_map_runlist_nolock() to also take an optional attribute | 27 | - Change ntfs_map_runlist_nolock() and ntfs_attr_find_vcn_nolock() to |
28 | search context. This allows calling it with the mft record mapped. | 28 | also take an optional attribute search context as argument. This |
29 | allows calling these functions with the mft record mapped. Update | ||
30 | all callers. | ||
29 | 31 | ||
30 | 2.1.24 - Lots of bug fixes and support more clean journal states. | 32 | 2.1.24 - Lots of bug fixes and support more clean journal states. |
31 | 33 | ||
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index b194197b72f7..2aafc87e9601 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -406,9 +406,9 @@ retry_remap: | |||
406 | 406 | ||
407 | /** | 407 | /** |
408 | * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode | 408 | * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode |
409 | * @ni: ntfs inode describing the runlist to search | 409 | * @ni: ntfs inode describing the runlist to search |
410 | * @vcn: vcn to find | 410 | * @vcn: vcn to find |
411 | * @write_locked: true if the runlist is locked for writing | 411 | * @ctx: active attribute search context if present or NULL if not |
412 | * | 412 | * |
413 | * Find the virtual cluster number @vcn in the runlist described by the ntfs | 413 | * Find the virtual cluster number @vcn in the runlist described by the ntfs |
414 | * inode @ni and return the address of the runlist element containing the @vcn. | 414 | * inode @ni and return the address of the runlist element containing the @vcn. |
@@ -416,9 +416,22 @@ retry_remap: | |||
416 | * If the @vcn is not mapped yet, the attempt is made to map the attribute | 416 | * If the @vcn is not mapped yet, the attempt is made to map the attribute |
417 | * extent containing the @vcn and the vcn to lcn conversion is retried. | 417 | * extent containing the @vcn and the vcn to lcn conversion is retried. |
418 | * | 418 | * |
419 | * If @write_locked is true the caller has locked the runlist for writing and | 419 | * If @ctx is specified, it is an active search context of @ni and its base mft |
420 | * if false for reading. | 420 | * record. This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped |
421 | * runlist fragments and allows their mapping. If you do not have the mft | ||
422 | * record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock() | ||
423 | * will perform the necessary mapping and unmapping. | ||
421 | * | 424 | * |
425 | * Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and | ||
426 | * restores it before returning. Thus, @ctx will be left pointing to the same | ||
427 | * attribute on return as on entry. However, the actual pointers in @ctx may | ||
428 | * point to different memory locations on return, so you must remember to reset | ||
429 | * any cached pointers from the @ctx, i.e. after the call to | ||
430 | * ntfs_attr_find_vcn_nolock(), you will probably want to do: | ||
431 | * m = ctx->mrec; | ||
432 | * a = ctx->attr; | ||
433 | * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that | ||
434 | * you cache ctx->mrec in a variable @m of type MFT_RECORD *. | ||
422 | * Note you need to distinguish between the lcn of the returned runlist element | 435 | * Note you need to distinguish between the lcn of the returned runlist element |
423 | * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on | 436 | * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on |
424 | * read and allocate clusters on write. | 437 | * read and allocate clusters on write. |
@@ -433,22 +446,31 @@ retry_remap: | |||
433 | * -ENOMEM - Not enough memory to map runlist. | 446 | * -ENOMEM - Not enough memory to map runlist. |
434 | * -EIO - Critical error (runlist/file is corrupt, i/o error, etc). | 447 | * -EIO - Critical error (runlist/file is corrupt, i/o error, etc). |
435 | * | 448 | * |
436 | * Locking: - The runlist must be locked on entry and is left locked on return. | 449 | * WARNING: If @ctx is supplied, regardless of whether success or failure is |
437 | * - If @write_locked is FALSE, i.e. the runlist is locked for reading, | 450 | * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx |
438 | * the lock may be dropped inside the function so you cannot rely on | 451 | * is no longer valid, i.e. you need to either call |
439 | * the runlist still being the same when this function returns. | 452 | * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. |
453 | * In that case PTR_ERR(@ctx->mrec) will give you the error code for | ||
454 | * why the mapping of the old inode failed. | ||
455 | * | ||
456 | * Locking: - The runlist described by @ni must be locked for writing on entry | ||
457 | * and is locked on return. Note the runlist may be modified when | ||
458 | * needed runlist fragments need to be mapped. | ||
459 | * - If @ctx is NULL, the base mft record of @ni must not be mapped on | ||
460 | * entry and it will be left unmapped on return. | ||
461 | * - If @ctx is not NULL, the base mft record must be mapped on entry | ||
462 | * and it will be left mapped on return. | ||
440 | */ | 463 | */ |
441 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, | 464 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, |
442 | const BOOL write_locked) | 465 | ntfs_attr_search_ctx *ctx) |
443 | { | 466 | { |
444 | unsigned long flags; | 467 | unsigned long flags; |
445 | runlist_element *rl; | 468 | runlist_element *rl; |
446 | int err = 0; | 469 | int err = 0; |
447 | BOOL is_retry = FALSE; | 470 | BOOL is_retry = FALSE; |
448 | 471 | ||
449 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", | 472 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.", |
450 | ni->mft_no, (unsigned long long)vcn, | 473 | ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out"); |
451 | write_locked ? "write" : "read"); | ||
452 | BUG_ON(!ni); | 474 | BUG_ON(!ni); |
453 | BUG_ON(!NInoNonResident(ni)); | 475 | BUG_ON(!NInoNonResident(ni)); |
454 | BUG_ON(vcn < 0); | 476 | BUG_ON(vcn < 0); |
@@ -482,33 +504,22 @@ retry_remap: | |||
482 | } | 504 | } |
483 | if (!err && !is_retry) { | 505 | if (!err && !is_retry) { |
484 | /* | 506 | /* |
485 | * The @vcn is in an unmapped region, map the runlist and | 507 | * If the search context is invalid we cannot map the unmapped |
486 | * retry. | 508 | * region. |
487 | */ | 509 | */ |
488 | if (!write_locked) { | 510 | if (IS_ERR(ctx->mrec)) |
489 | up_read(&ni->runlist.lock); | 511 | err = PTR_ERR(ctx->mrec); |
490 | down_write(&ni->runlist.lock); | 512 | else { |
491 | if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) != | 513 | /* |
492 | LCN_RL_NOT_MAPPED)) { | 514 | * The @vcn is in an unmapped region, map the runlist |
493 | up_write(&ni->runlist.lock); | 515 | * and retry. |
494 | down_read(&ni->runlist.lock); | 516 | */ |
517 | err = ntfs_map_runlist_nolock(ni, vcn, ctx); | ||
518 | if (likely(!err)) { | ||
519 | is_retry = TRUE; | ||
495 | goto retry_remap; | 520 | goto retry_remap; |
496 | } | 521 | } |
497 | } | 522 | } |
498 | err = ntfs_map_runlist_nolock(ni, vcn, NULL); | ||
499 | if (!write_locked) { | ||
500 | up_write(&ni->runlist.lock); | ||
501 | down_read(&ni->runlist.lock); | ||
502 | } | ||
503 | if (likely(!err)) { | ||
504 | is_retry = TRUE; | ||
505 | goto retry_remap; | ||
506 | } | ||
507 | /* | ||
508 | * -EINVAL coming from a failed mapping attempt is equivalent | ||
509 | * to i/o error for us as it should not happen in our code | ||
510 | * paths. | ||
511 | */ | ||
512 | if (err == -EINVAL) | 523 | if (err == -EINVAL) |
513 | err = -EIO; | 524 | err = -EIO; |
514 | } else if (!err) | 525 | } else if (!err) |
@@ -1181,6 +1192,7 @@ int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, | |||
1181 | ntfs_inode *base_ni; | 1192 | ntfs_inode *base_ni; |
1182 | 1193 | ||
1183 | ntfs_debug("Entering."); | 1194 | ntfs_debug("Entering."); |
1195 | BUG_ON(IS_ERR(ctx->mrec)); | ||
1184 | if (ctx->base_ntfs_ino) | 1196 | if (ctx->base_ntfs_ino) |
1185 | base_ni = ctx->base_ntfs_ino; | 1197 | base_ni = ctx->base_ntfs_ino; |
1186 | else | 1198 | else |
diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h index eeca8e500971..62f76258d9c3 100644 --- a/fs/ntfs/attrib.h +++ b/fs/ntfs/attrib.h | |||
@@ -68,7 +68,7 @@ extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
68 | const BOOL write_locked); | 68 | const BOOL write_locked); |
69 | 69 | ||
70 | extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, | 70 | extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, |
71 | const VCN vcn, const BOOL write_locked); | 71 | const VCN vcn, ntfs_attr_search_ctx *ctx); |
72 | 72 | ||
73 | int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, | 73 | int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, |
74 | const u32 name_len, const IGNORE_CASE_BOOL ic, | 74 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c index 5af3bf0b7eee..8e60c47fafac 100644 --- a/fs/ntfs/lcnalloc.c +++ b/fs/ntfs/lcnalloc.c | |||
@@ -839,7 +839,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, | |||
839 | 839 | ||
840 | total_freed = real_freed = 0; | 840 | total_freed = real_freed = 0; |
841 | 841 | ||
842 | rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, TRUE); | 842 | rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, NULL); |
843 | if (IS_ERR(rl)) { | 843 | if (IS_ERR(rl)) { |
844 | if (!is_rollback) | 844 | if (!is_rollback) |
845 | ntfs_error(vol->sb, "Failed to find first runlist " | 845 | ntfs_error(vol->sb, "Failed to find first runlist " |
@@ -893,7 +893,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, | |||
893 | 893 | ||
894 | /* Attempt to map runlist. */ | 894 | /* Attempt to map runlist. */ |
895 | vcn = rl->vcn; | 895 | vcn = rl->vcn; |
896 | rl = ntfs_attr_find_vcn_nolock(ni, vcn, TRUE); | 896 | rl = ntfs_attr_find_vcn_nolock(ni, vcn, NULL); |
897 | if (IS_ERR(rl)) { | 897 | if (IS_ERR(rl)) { |
898 | err = PTR_ERR(rl); | 898 | err = PTR_ERR(rl); |
899 | if (!is_rollback) | 899 | if (!is_rollback) |
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index b011369b5956..15df34f62038 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c | |||
@@ -49,7 +49,8 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni) | |||
49 | ntfs_volume *vol = ni->vol; | 49 | ntfs_volume *vol = ni->vol; |
50 | struct inode *mft_vi = vol->mft_ino; | 50 | struct inode *mft_vi = vol->mft_ino; |
51 | struct page *page; | 51 | struct page *page; |
52 | unsigned long index, ofs, end_index; | 52 | unsigned long index, end_index; |
53 | unsigned ofs; | ||
53 | 54 | ||
54 | BUG_ON(ni->page); | 55 | BUG_ON(ni->page); |
55 | /* | 56 | /* |
@@ -1308,7 +1309,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol) | |||
1308 | ll = mftbmp_ni->allocated_size; | 1309 | ll = mftbmp_ni->allocated_size; |
1309 | read_unlock_irqrestore(&mftbmp_ni->size_lock, flags); | 1310 | read_unlock_irqrestore(&mftbmp_ni->size_lock, flags); |
1310 | rl = ntfs_attr_find_vcn_nolock(mftbmp_ni, | 1311 | rl = ntfs_attr_find_vcn_nolock(mftbmp_ni, |
1311 | (ll - 1) >> vol->cluster_size_bits, TRUE); | 1312 | (ll - 1) >> vol->cluster_size_bits, NULL); |
1312 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { | 1313 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { |
1313 | up_write(&mftbmp_ni->runlist.lock); | 1314 | up_write(&mftbmp_ni->runlist.lock); |
1314 | ntfs_error(vol->sb, "Failed to determine last allocated " | 1315 | ntfs_error(vol->sb, "Failed to determine last allocated " |
@@ -1738,7 +1739,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) | |||
1738 | ll = mft_ni->allocated_size; | 1739 | ll = mft_ni->allocated_size; |
1739 | read_unlock_irqrestore(&mft_ni->size_lock, flags); | 1740 | read_unlock_irqrestore(&mft_ni->size_lock, flags); |
1740 | rl = ntfs_attr_find_vcn_nolock(mft_ni, | 1741 | rl = ntfs_attr_find_vcn_nolock(mft_ni, |
1741 | (ll - 1) >> vol->cluster_size_bits, TRUE); | 1742 | (ll - 1) >> vol->cluster_size_bits, NULL); |
1742 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { | 1743 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { |
1743 | up_write(&mft_ni->runlist.lock); | 1744 | up_write(&mft_ni->runlist.lock); |
1744 | ntfs_error(vol->sb, "Failed to determine last allocated " | 1745 | ntfs_error(vol->sb, "Failed to determine last allocated " |