aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ntfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ntfs')
-rw-r--r--fs/ntfs/ChangeLog6
-rw-r--r--fs/ntfs/attrib.c84
-rw-r--r--fs/ntfs/attrib.h2
-rw-r--r--fs/ntfs/lcnalloc.c4
-rw-r--r--fs/ntfs/mft.c7
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
252.1.25-WIP 252.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
302.1.24 - Lots of bug fixes and support more clean journal states. 322.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 */
441runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, 464runlist_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
70extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, 70extern 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
73int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, 73int 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 "