NTFS: Change ntfs_attr_find_vcn_nolock() to also take an optional attribute
search context as argument. This allows calling it with the mft record mapped. Update all callers. Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
This commit is contained in:
parent
fd9d63678d
commit
69b41e3c02
|
@ -24,8 +24,10 @@ ToDo/Notes:
|
||||||
|
|
||||||
2.1.25-WIP
|
2.1.25-WIP
|
||||||
|
|
||||||
- Change ntfs_map_runlist_nolock() to also take an optional attribute
|
- Change ntfs_map_runlist_nolock() and ntfs_attr_find_vcn_nolock() to
|
||||||
search context. This allows calling it with the mft record mapped.
|
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.
|
2.1.24 - Lots of bug fixes and support more clean journal states.
|
||||||
|
|
||||||
|
|
|
@ -406,9 +406,9 @@ retry_remap:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode
|
* ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode
|
||||||
* @ni: ntfs inode describing the runlist to search
|
* @ni: ntfs inode describing the runlist to search
|
||||||
* @vcn: vcn to find
|
* @vcn: vcn to find
|
||||||
* @write_locked: true if the runlist is locked for writing
|
* @ctx: active attribute search context if present or NULL if not
|
||||||
*
|
*
|
||||||
* Find the virtual cluster number @vcn in the runlist described by the ntfs
|
* 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.
|
* inode @ni and return the address of the runlist element containing the @vcn.
|
||||||
|
@ -416,9 +416,22 @@ retry_remap:
|
||||||
* If the @vcn is not mapped yet, the attempt is made to map the attribute
|
* 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.
|
* 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 @ctx is specified, it is an active search context of @ni and its base mft
|
||||||
* if false for reading.
|
* 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
|
* 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
|
* being >= 0 and LCN_HOLE. In the later case you have to return zeroes on
|
||||||
* read and allocate clusters on write.
|
* read and allocate clusters on write.
|
||||||
|
@ -433,22 +446,31 @@ retry_remap:
|
||||||
* -ENOMEM - Not enough memory to map runlist.
|
* -ENOMEM - Not enough memory to map runlist.
|
||||||
* -EIO - Critical error (runlist/file is corrupt, i/o error, etc).
|
* -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.
|
* WARNING: If @ctx is supplied, regardless of whether success or failure is
|
||||||
* - If @write_locked is FALSE, i.e. the runlist is locked for reading,
|
* returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
|
||||||
* the lock may be dropped inside the function so you cannot rely on
|
* is no longer valid, i.e. you need to either call
|
||||||
* the runlist still being the same when this function returns.
|
* 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,
|
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;
|
unsigned long flags;
|
||||||
runlist_element *rl;
|
runlist_element *rl;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
BOOL is_retry = FALSE;
|
BOOL is_retry = FALSE;
|
||||||
|
|
||||||
ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.",
|
ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.",
|
||||||
ni->mft_no, (unsigned long long)vcn,
|
ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out");
|
||||||
write_locked ? "write" : "read");
|
|
||||||
BUG_ON(!ni);
|
BUG_ON(!ni);
|
||||||
BUG_ON(!NInoNonResident(ni));
|
BUG_ON(!NInoNonResident(ni));
|
||||||
BUG_ON(vcn < 0);
|
BUG_ON(vcn < 0);
|
||||||
|
@ -482,33 +504,22 @@ retry_remap:
|
||||||
}
|
}
|
||||||
if (!err && !is_retry) {
|
if (!err && !is_retry) {
|
||||||
/*
|
/*
|
||||||
* The @vcn is in an unmapped region, map the runlist and
|
* If the search context is invalid we cannot map the unmapped
|
||||||
* retry.
|
* region.
|
||||||
*/
|
*/
|
||||||
if (!write_locked) {
|
if (IS_ERR(ctx->mrec))
|
||||||
up_read(&ni->runlist.lock);
|
err = PTR_ERR(ctx->mrec);
|
||||||
down_write(&ni->runlist.lock);
|
else {
|
||||||
if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) !=
|
/*
|
||||||
LCN_RL_NOT_MAPPED)) {
|
* The @vcn is in an unmapped region, map the runlist
|
||||||
up_write(&ni->runlist.lock);
|
* and retry.
|
||||||
down_read(&ni->runlist.lock);
|
*/
|
||||||
|
err = ntfs_map_runlist_nolock(ni, vcn, ctx);
|
||||||
|
if (likely(!err)) {
|
||||||
|
is_retry = TRUE;
|
||||||
goto retry_remap;
|
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)
|
if (err == -EINVAL)
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
} else if (!err)
|
} else if (!err)
|
||||||
|
@ -1181,6 +1192,7 @@ int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
|
||||||
ntfs_inode *base_ni;
|
ntfs_inode *base_ni;
|
||||||
|
|
||||||
ntfs_debug("Entering.");
|
ntfs_debug("Entering.");
|
||||||
|
BUG_ON(IS_ERR(ctx->mrec));
|
||||||
if (ctx->base_ntfs_ino)
|
if (ctx->base_ntfs_ino)
|
||||||
base_ni = ctx->base_ntfs_ino;
|
base_ni = ctx->base_ntfs_ino;
|
||||||
else
|
else
|
||||||
|
|
|
@ -68,7 +68,7 @@ extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
|
||||||
const BOOL write_locked);
|
const BOOL write_locked);
|
||||||
|
|
||||||
extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni,
|
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,
|
int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
|
||||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||||
|
|
|
@ -839,7 +839,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count,
|
||||||
|
|
||||||
total_freed = real_freed = 0;
|
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_ERR(rl)) {
|
||||||
if (!is_rollback)
|
if (!is_rollback)
|
||||||
ntfs_error(vol->sb, "Failed to find first runlist "
|
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,
|
||||||
|
|
||||||
/* Attempt to map runlist. */
|
/* Attempt to map runlist. */
|
||||||
vcn = rl->vcn;
|
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)) {
|
if (IS_ERR(rl)) {
|
||||||
err = PTR_ERR(rl);
|
err = PTR_ERR(rl);
|
||||||
if (!is_rollback)
|
if (!is_rollback)
|
||||||
|
|
|
@ -49,7 +49,8 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
|
||||||
ntfs_volume *vol = ni->vol;
|
ntfs_volume *vol = ni->vol;
|
||||||
struct inode *mft_vi = vol->mft_ino;
|
struct inode *mft_vi = vol->mft_ino;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
unsigned long index, ofs, end_index;
|
unsigned long index, end_index;
|
||||||
|
unsigned ofs;
|
||||||
|
|
||||||
BUG_ON(ni->page);
|
BUG_ON(ni->page);
|
||||||
/*
|
/*
|
||||||
|
@ -1308,7 +1309,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol)
|
||||||
ll = mftbmp_ni->allocated_size;
|
ll = mftbmp_ni->allocated_size;
|
||||||
read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
|
read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
|
||||||
rl = ntfs_attr_find_vcn_nolock(mftbmp_ni,
|
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)) {
|
if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) {
|
||||||
up_write(&mftbmp_ni->runlist.lock);
|
up_write(&mftbmp_ni->runlist.lock);
|
||||||
ntfs_error(vol->sb, "Failed to determine last allocated "
|
ntfs_error(vol->sb, "Failed to determine last allocated "
|
||||||
|
@ -1738,7 +1739,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol)
|
||||||
ll = mft_ni->allocated_size;
|
ll = mft_ni->allocated_size;
|
||||||
read_unlock_irqrestore(&mft_ni->size_lock, flags);
|
read_unlock_irqrestore(&mft_ni->size_lock, flags);
|
||||||
rl = ntfs_attr_find_vcn_nolock(mft_ni,
|
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)) {
|
if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) {
|
||||||
up_write(&mft_ni->runlist.lock);
|
up_write(&mft_ni->runlist.lock);
|
||||||
ntfs_error(vol->sb, "Failed to determine last allocated "
|
ntfs_error(vol->sb, "Failed to determine last allocated "
|
||||||
|
|
Loading…
Reference in a new issue