mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
fs/ntfs3: Improve checking of bad clusters
Added new function wnd_set_used_safe. Load $BadClus before $AttrDef instead of before $Bitmap. Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
This commit is contained in:
parent
60ce8dfde0
commit
ec5fc72013
@ -800,6 +800,44 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* wnd_set_used_safe - Mark the bits range from bit to bit + bits as used.
|
||||
*
|
||||
* Unlikely wnd_set_used/wnd_set_free this function is not full trusted.
|
||||
* It scans every bit in bitmap and marks free bit as used.
|
||||
* @done - how many bits were marked as used.
|
||||
*
|
||||
* NOTE: normally *done should be 0.
|
||||
*/
|
||||
int wnd_set_used_safe(struct wnd_bitmap *wnd, size_t bit, size_t bits,
|
||||
size_t *done)
|
||||
{
|
||||
size_t i, from = 0, len = 0;
|
||||
int err = 0;
|
||||
|
||||
*done = 0;
|
||||
for (i = 0; i < bits; i++) {
|
||||
if (wnd_is_free(wnd, bit + i, 1)) {
|
||||
if (!len)
|
||||
from = bit + i;
|
||||
len += 1;
|
||||
} else if (len) {
|
||||
err = wnd_set_used(wnd, from, len);
|
||||
*done += len;
|
||||
len = 0;
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len) {
|
||||
/* last fragment. */
|
||||
err = wnd_set_used(wnd, from, len);
|
||||
*done += len;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* wnd_is_free_hlp
|
||||
*
|
||||
|
@ -828,6 +828,8 @@ static inline size_t wnd_zeroes(const struct wnd_bitmap *wnd)
|
||||
int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits);
|
||||
int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits);
|
||||
int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits);
|
||||
int wnd_set_used_safe(struct wnd_bitmap *wnd, size_t bit, size_t bits,
|
||||
size_t *done);
|
||||
bool wnd_is_free(struct wnd_bitmap *wnd, size_t bit, size_t bits);
|
||||
bool wnd_is_used(struct wnd_bitmap *wnd, size_t bit, size_t bits);
|
||||
|
||||
|
@ -1096,25 +1096,8 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
|
||||
if (down_write_trylock(&wnd->rw_lock)) {
|
||||
/* Mark all zero bits as used in range [lcn, lcn+len). */
|
||||
CLST i, lcn_f = 0, len_f = 0;
|
||||
|
||||
err = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (wnd_is_free(wnd, lcn + i, 1)) {
|
||||
if (!len_f)
|
||||
lcn_f = lcn + i;
|
||||
len_f += 1;
|
||||
} else if (len_f) {
|
||||
err = wnd_set_used(wnd, lcn_f, len_f);
|
||||
len_f = 0;
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len_f)
|
||||
err = wnd_set_used(wnd, lcn_f, len_f);
|
||||
|
||||
size_t done;
|
||||
err = wnd_set_used_safe(wnd, lcn, len, &done);
|
||||
up_write(&wnd->rw_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -930,7 +930,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
struct block_device *bdev = sb->s_bdev;
|
||||
struct inode *inode;
|
||||
struct ntfs_inode *ni;
|
||||
size_t i, tt;
|
||||
size_t i, tt, bad_len, bad_frags;
|
||||
CLST vcn, lcn, len;
|
||||
struct ATTRIB *attr;
|
||||
const struct VOLUME_INFO *info;
|
||||
@ -1100,30 +1100,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
|
||||
sbi->mft.ni = ni;
|
||||
|
||||
/* Load $BadClus. */
|
||||
ref.low = cpu_to_le32(MFT_REC_BADCLUST);
|
||||
ref.seq = cpu_to_le16(MFT_REC_BADCLUST);
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS);
|
||||
if (IS_ERR(inode)) {
|
||||
ntfs_err(sb, "Failed to load $BadClus.");
|
||||
err = PTR_ERR(inode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ni = ntfs_i(inode);
|
||||
|
||||
for (i = 0; run_get_entry(&ni->file.run, i, &vcn, &lcn, &len); i++) {
|
||||
if (lcn == SPARSE_LCN)
|
||||
continue;
|
||||
|
||||
if (!sbi->bad_clusters)
|
||||
ntfs_notice(sb, "Volume contains bad blocks");
|
||||
|
||||
sbi->bad_clusters += len;
|
||||
}
|
||||
|
||||
iput(inode);
|
||||
|
||||
/* Load $Bitmap. */
|
||||
ref.low = cpu_to_le32(MFT_REC_BITMAP);
|
||||
ref.seq = cpu_to_le16(MFT_REC_BITMAP);
|
||||
@ -1161,6 +1137,44 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Load $BadClus. */
|
||||
ref.low = cpu_to_le32(MFT_REC_BADCLUST);
|
||||
ref.seq = cpu_to_le16(MFT_REC_BADCLUST);
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load $BadClus (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ni = ntfs_i(inode);
|
||||
bad_len = bad_frags = 0;
|
||||
for (i = 0; run_get_entry(&ni->file.run, i, &vcn, &lcn, &len); i++) {
|
||||
if (lcn == SPARSE_LCN)
|
||||
continue;
|
||||
|
||||
bad_len += len;
|
||||
bad_frags += 1;
|
||||
if (sb_rdonly(sb))
|
||||
continue;
|
||||
|
||||
if (wnd_set_used_safe(&sbi->used.bitmap, lcn, len, &tt) || tt) {
|
||||
/* Bad blocks marked as free in bitmap. */
|
||||
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
|
||||
}
|
||||
}
|
||||
if (bad_len) {
|
||||
/*
|
||||
* Notice about bad blocks.
|
||||
* In normal cases these blocks are marked as used in bitmap.
|
||||
* And we never allocate space in it.
|
||||
*/
|
||||
ntfs_notice(sb,
|
||||
"Volume contains %zu bad blocks in %zu fragments.",
|
||||
bad_len, bad_frags);
|
||||
}
|
||||
iput(inode);
|
||||
|
||||
/* Load $AttrDef. */
|
||||
ref.low = cpu_to_le32(MFT_REC_ATTR);
|
||||
ref.seq = cpu_to_le16(MFT_REC_ATTR);
|
||||
|
Loading…
Reference in New Issue
Block a user