aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ntfs/attrib.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ntfs/attrib.c')
-rw-r--r--fs/ntfs/attrib.c84
1 files changed, 48 insertions, 36 deletions
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