Skip to content

Commit ec5fc72

Browse files
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 <[email protected]>
1 parent 60ce8df commit ec5fc72

File tree

4 files changed

+81
-44
lines changed

4 files changed

+81
-44
lines changed

fs/ntfs3/bitmap.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,44 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
800800
return err;
801801
}
802802

803+
/*
804+
* wnd_set_used_safe - Mark the bits range from bit to bit + bits as used.
805+
*
806+
* Unlikely wnd_set_used/wnd_set_free this function is not full trusted.
807+
* It scans every bit in bitmap and marks free bit as used.
808+
* @done - how many bits were marked as used.
809+
*
810+
* NOTE: normally *done should be 0.
811+
*/
812+
int wnd_set_used_safe(struct wnd_bitmap *wnd, size_t bit, size_t bits,
813+
size_t *done)
814+
{
815+
size_t i, from = 0, len = 0;
816+
int err = 0;
817+
818+
*done = 0;
819+
for (i = 0; i < bits; i++) {
820+
if (wnd_is_free(wnd, bit + i, 1)) {
821+
if (!len)
822+
from = bit + i;
823+
len += 1;
824+
} else if (len) {
825+
err = wnd_set_used(wnd, from, len);
826+
*done += len;
827+
len = 0;
828+
if (err)
829+
break;
830+
}
831+
}
832+
833+
if (len) {
834+
/* last fragment. */
835+
err = wnd_set_used(wnd, from, len);
836+
*done += len;
837+
}
838+
return err;
839+
}
840+
803841
/*
804842
* wnd_is_free_hlp
805843
*

fs/ntfs3/ntfs_fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,8 @@ static inline size_t wnd_zeroes(const struct wnd_bitmap *wnd)
828828
int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits);
829829
int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits);
830830
int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits);
831+
int wnd_set_used_safe(struct wnd_bitmap *wnd, size_t bit, size_t bits,
832+
size_t *done);
831833
bool wnd_is_free(struct wnd_bitmap *wnd, size_t bit, size_t bits);
832834
bool wnd_is_used(struct wnd_bitmap *wnd, size_t bit, size_t bits);
833835

fs/ntfs3/run.c

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,25 +1096,8 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
10961096

10971097
if (down_write_trylock(&wnd->rw_lock)) {
10981098
/* Mark all zero bits as used in range [lcn, lcn+len). */
1099-
CLST i, lcn_f = 0, len_f = 0;
1100-
1101-
err = 0;
1102-
for (i = 0; i < len; i++) {
1103-
if (wnd_is_free(wnd, lcn + i, 1)) {
1104-
if (!len_f)
1105-
lcn_f = lcn + i;
1106-
len_f += 1;
1107-
} else if (len_f) {
1108-
err = wnd_set_used(wnd, lcn_f, len_f);
1109-
len_f = 0;
1110-
if (err)
1111-
break;
1112-
}
1113-
}
1114-
1115-
if (len_f)
1116-
err = wnd_set_used(wnd, lcn_f, len_f);
1117-
1099+
size_t done;
1100+
err = wnd_set_used_safe(wnd, lcn, len, &done);
11181101
up_write(&wnd->rw_lock);
11191102
if (err)
11201103
return err;

fs/ntfs3/super.c

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
930930
struct block_device *bdev = sb->s_bdev;
931931
struct inode *inode;
932932
struct ntfs_inode *ni;
933-
size_t i, tt;
933+
size_t i, tt, bad_len, bad_frags;
934934
CLST vcn, lcn, len;
935935
struct ATTRIB *attr;
936936
const struct VOLUME_INFO *info;
@@ -1100,30 +1100,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
11001100

11011101
sbi->mft.ni = ni;
11021102

1103-
/* Load $BadClus. */
1104-
ref.low = cpu_to_le32(MFT_REC_BADCLUST);
1105-
ref.seq = cpu_to_le16(MFT_REC_BADCLUST);
1106-
inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS);
1107-
if (IS_ERR(inode)) {
1108-
ntfs_err(sb, "Failed to load $BadClus.");
1109-
err = PTR_ERR(inode);
1110-
goto out;
1111-
}
1112-
1113-
ni = ntfs_i(inode);
1114-
1115-
for (i = 0; run_get_entry(&ni->file.run, i, &vcn, &lcn, &len); i++) {
1116-
if (lcn == SPARSE_LCN)
1117-
continue;
1118-
1119-
if (!sbi->bad_clusters)
1120-
ntfs_notice(sb, "Volume contains bad blocks");
1121-
1122-
sbi->bad_clusters += len;
1123-
}
1124-
1125-
iput(inode);
1126-
11271103
/* Load $Bitmap. */
11281104
ref.low = cpu_to_le32(MFT_REC_BITMAP);
11291105
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)
11611137
if (err)
11621138
goto out;
11631139

1140+
/* Load $BadClus. */
1141+
ref.low = cpu_to_le32(MFT_REC_BADCLUST);
1142+
ref.seq = cpu_to_le16(MFT_REC_BADCLUST);
1143+
inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS);
1144+
if (IS_ERR(inode)) {
1145+
err = PTR_ERR(inode);
1146+
ntfs_err(sb, "Failed to load $BadClus (%d).", err);
1147+
goto out;
1148+
}
1149+
1150+
ni = ntfs_i(inode);
1151+
bad_len = bad_frags = 0;
1152+
for (i = 0; run_get_entry(&ni->file.run, i, &vcn, &lcn, &len); i++) {
1153+
if (lcn == SPARSE_LCN)
1154+
continue;
1155+
1156+
bad_len += len;
1157+
bad_frags += 1;
1158+
if (sb_rdonly(sb))
1159+
continue;
1160+
1161+
if (wnd_set_used_safe(&sbi->used.bitmap, lcn, len, &tt) || tt) {
1162+
/* Bad blocks marked as free in bitmap. */
1163+
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
1164+
}
1165+
}
1166+
if (bad_len) {
1167+
/*
1168+
* Notice about bad blocks.
1169+
* In normal cases these blocks are marked as used in bitmap.
1170+
* And we never allocate space in it.
1171+
*/
1172+
ntfs_notice(sb,
1173+
"Volume contains %zu bad blocks in %zu fragments.",
1174+
bad_len, bad_frags);
1175+
}
1176+
iput(inode);
1177+
11641178
/* Load $AttrDef. */
11651179
ref.low = cpu_to_le32(MFT_REC_ATTR);
11661180
ref.seq = cpu_to_le16(MFT_REC_ATTR);

0 commit comments

Comments
 (0)