Loading fs/ntfs/ChangeLog +4 −2 Original line number Diff line number Diff line Loading @@ -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. Loading fs/ntfs/attrib.c +48 −36 Original line number Diff line number Diff line Loading @@ -408,7 +408,7 @@ 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 * @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. Loading @@ -416,9 +416,22 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN 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. Loading @@ -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); Loading Loading @@ -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); 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 (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; } /* * -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) Loading Loading @@ -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 Loading fs/ntfs/attrib.h +1 −1 Original line number Diff line number Diff line Loading @@ -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, Loading fs/ntfs/lcnalloc.c +2 −2 Original line number Diff line number Diff line Loading @@ -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 " Loading Loading @@ -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) Loading fs/ntfs/mft.c +4 −3 Original line number Diff line number Diff line Loading @@ -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); /* Loading Loading @@ -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 " Loading Loading @@ -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 " Loading Loading
fs/ntfs/ChangeLog +4 −2 Original line number Diff line number Diff line Loading @@ -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. Loading
fs/ntfs/attrib.c +48 −36 Original line number Diff line number Diff line Loading @@ -408,7 +408,7 @@ 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 * @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. Loading @@ -416,9 +416,22 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN 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. Loading @@ -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); Loading Loading @@ -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); 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 (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; } /* * -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) Loading Loading @@ -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 Loading
fs/ntfs/attrib.h +1 −1 Original line number Diff line number Diff line Loading @@ -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, Loading
fs/ntfs/lcnalloc.c +2 −2 Original line number Diff line number Diff line Loading @@ -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 " Loading Loading @@ -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) Loading
fs/ntfs/mft.c +4 −3 Original line number Diff line number Diff line Loading @@ -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); /* Loading Loading @@ -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 " Loading Loading @@ -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 " Loading