mirror of
https://github.com/torvalds/linux.git
synced 2026-11-10 17:11:02 +01:00
ntfs: write MFT records through containing I/O units
Use the configured MFT I/O unit for direct writes, mirror updates, and
generic folio writeback. On native 4Kn devices, multiple MFT records can
share a device block, so submit complete containing units while preserving
unselected neighboring records.
Track selected records separately from records owned by direct inode
writeback, and retain the existing runlist and cluster-boundary checks.
Force direct MFT writes to complete synchronously when the I/O unit is
larger than an individual record. the following patch restores
caller-controlled completion.
Fixes: 115380f9a2 ("ntfs: update mft operations")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
1df655bcdd
commit
4437d9d787
|
|
@ -597,13 +597,18 @@ static int ntfs_sync_mft_mirror_unit(struct ntfs_volume *vol,
|
|||
static int ntfs_sync_mft_mirror_record(struct ntfs_volume *vol,
|
||||
struct folio *source, const u64 mft_no)
|
||||
{
|
||||
u64 mirror_file_ofs = (u64)mft_no * vol->mft_record_size;
|
||||
struct ntfs_mft_io_unit unit = {
|
||||
.folio_ofs = NTFS_MFT_NR_TO_POFS(vol, mft_no),
|
||||
.len = vol->mft_record_size,
|
||||
};
|
||||
|
||||
return ntfs_sync_mft_mirror_unit(vol, source,
|
||||
(u64)mft_no * vol->mft_record_size, &unit);
|
||||
mirror_file_ofs =
|
||||
round_down(mirror_file_ofs, (u64)vol->mft_io_unit_size);
|
||||
unit.folio_ofs = round_down(unit.folio_ofs, vol->mft_io_unit_size);
|
||||
unit.len = vol->mft_io_unit_size;
|
||||
|
||||
return ntfs_sync_mft_mirror_unit(vol, source, mirror_file_ofs, &unit);
|
||||
}
|
||||
|
||||
static int ntfs_prepare_mft_record_io_units(struct ntfs_inode *ni,
|
||||
|
|
@ -623,6 +628,18 @@ static int ntfs_prepare_mft_record_io_units(struct ntfs_inode *ni,
|
|||
return -EIO;
|
||||
|
||||
cluster_ofs = ntfs_bytes_to_cluster_off(vol, record_byte);
|
||||
if (vol->mft_io_unit_size > vol->mft_record_size) {
|
||||
cluster_ofs = round_down(cluster_ofs, vol->mft_io_unit_size);
|
||||
disk_byte = NTFS_CLU_TO_B(vol, ni->mft_lcn[0]) + cluster_ofs;
|
||||
units[0] = (struct ntfs_mft_io_unit){
|
||||
.sector = ntfs_bytes_to_bio_sector(disk_byte),
|
||||
.folio_ofs = round_down(ni->folio_ofs,
|
||||
vol->mft_io_unit_size),
|
||||
.len = vol->mft_io_unit_size,
|
||||
};
|
||||
return 1;
|
||||
}
|
||||
|
||||
disk_byte = NTFS_CLU_TO_B(vol, ni->mft_lcn[0]) + cluster_ofs;
|
||||
units[0] = (struct ntfs_mft_io_unit){
|
||||
.sector = ntfs_bytes_to_bio_sector(disk_byte),
|
||||
|
|
@ -676,6 +693,8 @@ int write_mft_record_nolock(struct ntfs_inode *ni, struct mft_record *m, int syn
|
|||
WARN_ON(NInoAttr(ni));
|
||||
WARN_ON(!folio_test_locked(folio));
|
||||
|
||||
if (vol->mft_io_unit_size > vol->mft_record_size)
|
||||
sync = 1;
|
||||
if (folio_test_writeback(folio))
|
||||
folio_wait_writeback(folio);
|
||||
|
||||
|
|
@ -3063,7 +3082,7 @@ static int ntfs_map_mft_io_for_folio(struct ntfs_inode *ni, u64 folio_byte,
|
|||
|
||||
static int ntfs_prepare_mft_folio_units(struct ntfs_inode *ni, u64 folio_byte,
|
||||
u64 file_limit,
|
||||
const unsigned long *record_writable,
|
||||
const unsigned long *record_selected,
|
||||
struct ntfs_mft_io_unit *units,
|
||||
unsigned int *nr_units,
|
||||
unsigned int max_units, bool *defer)
|
||||
|
|
@ -3075,28 +3094,37 @@ static int ntfs_prepare_mft_folio_units(struct ntfs_inode *ni, u64 folio_byte,
|
|||
while (unit_byte < folio_end && unit_byte < file_limit) {
|
||||
struct ntfs_mft_io_unit unit;
|
||||
u64 record_byte;
|
||||
u64 cluster_end = ntfs_cluster_to_bytes(
|
||||
vol, ntfs_bytes_to_cluster(vol, unit_byte) + 1);
|
||||
u64 record_end =
|
||||
round_down(unit_byte, (u64)vol->mft_record_size) +
|
||||
vol->mft_record_size;
|
||||
u64 unit_end = min3(record_end, cluster_end, folio_end);
|
||||
bool writable = false;
|
||||
u64 unit_end;
|
||||
u64 io_unit_end;
|
||||
u64 cluster_end;
|
||||
bool selected = false;
|
||||
int err;
|
||||
|
||||
io_unit_end =
|
||||
round_down(unit_byte, (u64)vol->mft_io_unit_size) +
|
||||
vol->mft_io_unit_size;
|
||||
cluster_end = ntfs_cluster_to_bytes(
|
||||
vol, ntfs_bytes_to_cluster(vol, unit_byte) + 1);
|
||||
unit_end = min3(io_unit_end, cluster_end, folio_end);
|
||||
|
||||
record_byte = round_down(unit_byte, (u64)vol->mft_record_size);
|
||||
while (record_byte < min(unit_end, file_limit)) {
|
||||
unsigned int record;
|
||||
|
||||
record = div_u64(record_byte - folio_byte,
|
||||
vol->mft_record_size);
|
||||
if (test_bit(record, record_writable)) {
|
||||
writable = true;
|
||||
if (test_bit(record, record_selected)) {
|
||||
selected = true;
|
||||
break;
|
||||
}
|
||||
record_byte += vol->mft_record_size;
|
||||
}
|
||||
if (!writable)
|
||||
/*
|
||||
* Direct inode writeback owns unselected records. Their folio
|
||||
* images are stable while this folio is locked, so a containing
|
||||
* unit can preserve them when writing a selected record.
|
||||
*/
|
||||
if (!selected)
|
||||
goto next;
|
||||
|
||||
unit = (struct ntfs_mft_io_unit){
|
||||
|
|
@ -3153,7 +3181,7 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w
|
|||
struct bio *parent = NULL, *child = NULL;
|
||||
struct ntfs_mft_write_ctx *ctx = NULL;
|
||||
u8 *kaddr = NULL;
|
||||
DECLARE_BITMAP(record_writable, PAGE_SIZE / NTFS_BLOCK_SIZE) = {};
|
||||
DECLARE_BITMAP(record_selected, PAGE_SIZE / NTFS_BLOCK_SIZE) = {};
|
||||
u64 folio_byte, file_limit, folio_end, mirror_size;
|
||||
unsigned int nr_records, nr_units = 0, max_units;
|
||||
unsigned int nr_locked_nis = 0, nr_ref_inos = 0;
|
||||
|
|
@ -3221,11 +3249,11 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w
|
|||
tni->ext.base_ntfs_ino == NTFS_I(vol->mft_ino))
|
||||
continue;
|
||||
}
|
||||
__set_bit(record, record_writable);
|
||||
__set_bit(record, record_selected);
|
||||
}
|
||||
|
||||
err = ntfs_prepare_mft_folio_units(ni, folio_byte, file_limit,
|
||||
record_writable, units, &nr_units,
|
||||
record_selected, units, &nr_units,
|
||||
max_units, &defer);
|
||||
if (err)
|
||||
goto out_noio;
|
||||
|
|
@ -3309,6 +3337,7 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w
|
|||
submit_bio(parent);
|
||||
ntfs_release_mft_write_refs(locked_nis, nr_locked_nis, ref_inos,
|
||||
nr_ref_inos);
|
||||
|
||||
return 0;
|
||||
|
||||
out_noio:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user