Skip to content

Commit

Permalink
NTFS: Change ntfs_attr_find_vcn_nolock() to also take an optional att…
Browse files Browse the repository at this point in the history
…ribute

      search context as argument.  This allows calling it with the mft
      record mapped.  Update all callers.

Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
  • Loading branch information
Anton Altaparmakov committed Oct 4, 2005
1 parent fd9d636 commit 69b41e3
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 44 deletions.
6 changes: 4 additions & 2 deletions fs/ntfs/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ ToDo/Notes:

2.1.25-WIP

- Change ntfs_map_runlist_nolock() to also take an optional attribute
search context. This allows calling it with the mft record mapped.
- Change ntfs_map_runlist_nolock() and ntfs_attr_find_vcn_nolock() to
also take an optional attribute search context as argument. This
allows calling these functions with the mft record mapped. Update
all callers.

2.1.24 - Lots of bug fixes and support more clean journal states.

Expand Down
84 changes: 48 additions & 36 deletions fs/ntfs/attrib.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,19 +406,32 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,

/**
* ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode
* @ni: ntfs inode describing the runlist to search
* @vcn: vcn to find
* @write_locked: true if the runlist is locked for writing
* @ni: ntfs inode describing the runlist to search
* @vcn: vcn to find
* @ctx: active attribute search context if present or NULL if not
*
* Find the virtual cluster number @vcn in the runlist described by the ntfs
* inode @ni and return the address of the runlist element containing the @vcn.
*
* If the @vcn is not mapped yet, the attempt is made to map the attribute
* extent containing the @vcn and the vcn to lcn conversion is retried.
*
* If @write_locked is true the caller has locked the runlist for writing and
* if false for reading.
* If @ctx is specified, it is an active search context of @ni and its base mft
* record. This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped
* runlist fragments and allows their mapping. If you do not have the mft
* record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock()
* will perform the necessary mapping and unmapping.
*
* Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and
* restores it before returning. Thus, @ctx will be left pointing to the same
* attribute on return as on entry. However, the actual pointers in @ctx may
* point to different memory locations on return, so you must remember to reset
* any cached pointers from the @ctx, i.e. after the call to
* ntfs_attr_find_vcn_nolock(), you will probably want to do:
* m = ctx->mrec;
* a = ctx->attr;
* Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
* you cache ctx->mrec in a variable @m of type MFT_RECORD *.
* Note you need to distinguish between the lcn of the returned runlist element
* being >= 0 and LCN_HOLE. In the later case you have to return zeroes on
* read and allocate clusters on write.
Expand All @@ -433,22 +446,31 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
* -ENOMEM - Not enough memory to map runlist.
* -EIO - Critical error (runlist/file is corrupt, i/o error, etc).
*
* Locking: - The runlist must be locked on entry and is left locked on return.
* - If @write_locked is FALSE, i.e. the runlist is locked for reading,
* the lock may be dropped inside the function so you cannot rely on
* the runlist still being the same when this function returns.
* WARNING: If @ctx is supplied, regardless of whether success or failure is
* returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
* is no longer valid, i.e. you need to either call
* ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
* In that case PTR_ERR(@ctx->mrec) will give you the error code for
* why the mapping of the old inode failed.
*
* Locking: - The runlist described by @ni must be locked for writing on entry
* and is locked on return. Note the runlist may be modified when
* needed runlist fragments need to be mapped.
* - If @ctx is NULL, the base mft record of @ni must not be mapped on
* entry and it will be left unmapped on return.
* - If @ctx is not NULL, the base mft record must be mapped on entry
* and it will be left mapped on return.
*/
runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,
const BOOL write_locked)
ntfs_attr_search_ctx *ctx)
{
unsigned long flags;
runlist_element *rl;
int err = 0;
BOOL is_retry = FALSE;

ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.",
ni->mft_no, (unsigned long long)vcn,
write_locked ? "write" : "read");
ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.",
ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out");
BUG_ON(!ni);
BUG_ON(!NInoNonResident(ni));
BUG_ON(vcn < 0);
Expand Down Expand Up @@ -482,33 +504,22 @@ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,
}
if (!err && !is_retry) {
/*
* The @vcn is in an unmapped region, map the runlist and
* retry.
* If the search context is invalid we cannot map the unmapped
* region.
*/
if (!write_locked) {
up_read(&ni->runlist.lock);
down_write(&ni->runlist.lock);
if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) !=
LCN_RL_NOT_MAPPED)) {
up_write(&ni->runlist.lock);
down_read(&ni->runlist.lock);
if (IS_ERR(ctx->mrec))
err = PTR_ERR(ctx->mrec);
else {
/*
* The @vcn is in an unmapped region, map the runlist
* and retry.
*/
err = ntfs_map_runlist_nolock(ni, vcn, ctx);
if (likely(!err)) {
is_retry = TRUE;
goto retry_remap;
}
}
err = ntfs_map_runlist_nolock(ni, vcn, NULL);
if (!write_locked) {
up_write(&ni->runlist.lock);
down_read(&ni->runlist.lock);
}
if (likely(!err)) {
is_retry = TRUE;
goto retry_remap;
}
/*
* -EINVAL coming from a failed mapping attempt is equivalent
* to i/o error for us as it should not happen in our code
* paths.
*/
if (err == -EINVAL)
err = -EIO;
} else if (!err)
Expand Down Expand Up @@ -1181,6 +1192,7 @@ int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
ntfs_inode *base_ni;

ntfs_debug("Entering.");
BUG_ON(IS_ERR(ctx->mrec));
if (ctx->base_ntfs_ino)
base_ni = ctx->base_ntfs_ino;
else
Expand Down
2 changes: 1 addition & 1 deletion fs/ntfs/attrib.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
const BOOL write_locked);

extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni,
const VCN vcn, const BOOL write_locked);
const VCN vcn, ntfs_attr_search_ctx *ctx);

int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
const u32 name_len, const IGNORE_CASE_BOOL ic,
Expand Down
4 changes: 2 additions & 2 deletions fs/ntfs/lcnalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count,

total_freed = real_freed = 0;

rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, TRUE);
rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, NULL);
if (IS_ERR(rl)) {
if (!is_rollback)
ntfs_error(vol->sb, "Failed to find first runlist "
Expand Down Expand Up @@ -893,7 +893,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count,

/* Attempt to map runlist. */
vcn = rl->vcn;
rl = ntfs_attr_find_vcn_nolock(ni, vcn, TRUE);
rl = ntfs_attr_find_vcn_nolock(ni, vcn, NULL);
if (IS_ERR(rl)) {
err = PTR_ERR(rl);
if (!is_rollback)
Expand Down
7 changes: 4 additions & 3 deletions fs/ntfs/mft.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
ntfs_volume *vol = ni->vol;
struct inode *mft_vi = vol->mft_ino;
struct page *page;
unsigned long index, ofs, end_index;
unsigned long index, end_index;
unsigned ofs;

BUG_ON(ni->page);
/*
Expand Down Expand Up @@ -1308,7 +1309,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol)
ll = mftbmp_ni->allocated_size;
read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
rl = ntfs_attr_find_vcn_nolock(mftbmp_ni,
(ll - 1) >> vol->cluster_size_bits, TRUE);
(ll - 1) >> vol->cluster_size_bits, NULL);
if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) {
up_write(&mftbmp_ni->runlist.lock);
ntfs_error(vol->sb, "Failed to determine last allocated "
Expand Down Expand Up @@ -1738,7 +1739,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol)
ll = mft_ni->allocated_size;
read_unlock_irqrestore(&mft_ni->size_lock, flags);
rl = ntfs_attr_find_vcn_nolock(mft_ni,
(ll - 1) >> vol->cluster_size_bits, TRUE);
(ll - 1) >> vol->cluster_size_bits, NULL);
if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) {
up_write(&mft_ni->runlist.lock);
ntfs_error(vol->sb, "Failed to determine last allocated "
Expand Down

0 comments on commit 69b41e3

Please sign in to comment.