ntfs_mft_record_alloc(): factor out ntfs_mft_record_init()
parent
436d36f933
commit
58987ffe0c
207
libntfs-3g/mft.c
207
libntfs-3g/mft.c
|
@ -1097,6 +1097,115 @@ undo_alloc:
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
|
||||
{
|
||||
int ret = -1;
|
||||
ntfs_attr *mft_na, *mftbmp_na;
|
||||
s64 old_data_initialized, old_data_size;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
/* NOTE: Caller must sanity check vol, vol->mft_na and vol->mftbmp_na */
|
||||
|
||||
mft_na = vol->mft_na;
|
||||
mftbmp_na = vol->mftbmp_na;
|
||||
|
||||
/*
|
||||
* The mft record is outside the initialized data. Extend the mft data
|
||||
* attribute until it covers the allocated record. The loop is only
|
||||
* actually traversed more than once when a freshly formatted volume
|
||||
* is first written to so it optimizes away nicely in the common case.
|
||||
*/
|
||||
ntfs_log_debug("Status of mft data before extension: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
while (size > mft_na->allocated_size) {
|
||||
if (ntfs_mft_data_extend_allocation(vol))
|
||||
goto out;
|
||||
ntfs_log_debug("Status of mft data after allocation extension: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
}
|
||||
|
||||
old_data_initialized = mft_na->initialized_size;
|
||||
old_data_size = mft_na->data_size;
|
||||
|
||||
/*
|
||||
* Extend mft data initialized size (and data size of course) to reach
|
||||
* the allocated mft record, formatting the mft records along the way.
|
||||
* Note: We only modify the ntfs_attr structure as that is all that is
|
||||
* needed by ntfs_mft_record_format(). We will update the attribute
|
||||
* record itself in one fell swoop later on.
|
||||
*/
|
||||
while (size > mft_na->initialized_size) {
|
||||
s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits;
|
||||
mft_na->initialized_size += vol->mft_record_size;
|
||||
if (mft_na->initialized_size > mft_na->data_size)
|
||||
mft_na->data_size = mft_na->initialized_size;
|
||||
ntfs_log_debug("Initializing mft record 0x%llx.\n", (long long)ll2);
|
||||
if (ntfs_mft_record_format(vol, ll2) < 0) {
|
||||
ntfs_log_error("Failed to format mft record.\n");
|
||||
goto undo_data_init;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the mft data attribute record to reflect the new sizes. */
|
||||
ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get search context.\n");
|
||||
goto undo_data_init;
|
||||
}
|
||||
if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,
|
||||
0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("Failed to find first attribute extent of "
|
||||
"mft data attribute.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
goto undo_data_init;
|
||||
}
|
||||
ctx->attr->initialized_size = cpu_to_sle64(mft_na->initialized_size);
|
||||
ctx->attr->data_size = cpu_to_sle64(mft_na->data_size);
|
||||
|
||||
/* Ensure the changes make it to disk. */
|
||||
ntfs_inode_mark_dirty(ctx->ntfs_ino);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ntfs_log_debug("Status of mft data after mft record initialization: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
|
||||
/* Sanity checks. */
|
||||
if (mft_na->data_size > mft_na->allocated_size ||
|
||||
mft_na->initialized_size > mft_na->data_size)
|
||||
NTFS_BUG("mft_na sanity checks failed");
|
||||
// BUG_ON(mft_na->initialized_size > mft_na->data_size);
|
||||
// BUG_ON(mft_na->data_size > mft_na->allocated_size);
|
||||
|
||||
/* Sync MFT to minimize data loss if there won't be clean unmount. */
|
||||
if (ntfs_inode_sync(mft_na->ni)) {
|
||||
ntfs_log_error("Failed to sync $MFT.");
|
||||
goto undo_data_init;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
|
||||
undo_data_init:
|
||||
mft_na->initialized_size = old_data_initialized;
|
||||
mft_na->data_size = old_data_size;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_alloc - allocate an mft record on an ntfs volume
|
||||
* @vol: volume on which to allocate the mft record
|
||||
|
@ -1182,11 +1291,9 @@ undo_alloc:
|
|||
*/
|
||||
ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
{
|
||||
s64 ll, bit, old_data_initialized, old_data_size;
|
||||
s64 ll, bit;
|
||||
ntfs_attr *mft_na, *mftbmp_na;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
MFT_RECORD *m;
|
||||
ATTR_RECORD *a;
|
||||
ntfs_inode *ni;
|
||||
int err;
|
||||
u16 seq_no, usn;
|
||||
|
@ -1201,6 +1308,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mft_na = vol->mft_na;
|
||||
mftbmp_na = vol->mftbmp_na;
|
||||
bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);
|
||||
|
@ -1268,99 +1376,18 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||
ntfs_log_debug("Found free record (#3), bit 0x%llx.\n", (long long)bit);
|
||||
found_free_rec:
|
||||
/* @bit is the found free mft record, allocate it in the mft bitmap. */
|
||||
ntfs_log_debug("At found_free_rec.\n");
|
||||
if (ntfs_bitmap_set_bit(mftbmp_na, bit)) {
|
||||
ntfs_log_error("Failed to allocate bit in mft bitmap.\n");
|
||||
goto err_out;
|
||||
}
|
||||
ntfs_log_debug("Set bit 0x%llx in mft bitmap.\n", (long long)bit);
|
||||
|
||||
/* The mft bitmap is now uptodate. Deal with mft data attribute now. */
|
||||
ll = (bit + 1) << vol->mft_record_size_bits;
|
||||
if (ll <= mft_na->initialized_size) {
|
||||
ntfs_log_debug("Allocated mft record already initialized.\n");
|
||||
goto mft_rec_already_initialized;
|
||||
}
|
||||
ntfs_log_debug("Initializing allocated mft record.\n");
|
||||
/*
|
||||
* The mft record is outside the initialized data. Extend the mft data
|
||||
* attribute until it covers the allocated record. The loop is only
|
||||
* actually traversed more than once when a freshly formatted volume is
|
||||
* first written to so it optimizes away nicely in the common case.
|
||||
*/
|
||||
ntfs_log_debug("Status of mft data before extension: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
while (ll > mft_na->allocated_size) {
|
||||
if (ntfs_mft_data_extend_allocation(vol))
|
||||
if (ll > mft_na->initialized_size)
|
||||
if (ntfs_mft_record_init(vol, ll) < 0)
|
||||
goto undo_mftbmp_alloc;
|
||||
ntfs_log_debug("Status of mft data after allocation extension: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
}
|
||||
old_data_initialized = mft_na->initialized_size;
|
||||
old_data_size = mft_na->data_size;
|
||||
/*
|
||||
* Extend mft data initialized size (and data size of course) to reach
|
||||
* the allocated mft record, formatting the mft records along the way.
|
||||
* Note: We only modify the ntfs_attr structure as that is all that is
|
||||
* needed by ntfs_mft_record_format(). We will update the attribute
|
||||
* record itself in one fell swoop later on.
|
||||
*/
|
||||
while (ll > mft_na->initialized_size) {
|
||||
s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits;
|
||||
mft_na->initialized_size += vol->mft_record_size;
|
||||
if (mft_na->initialized_size > mft_na->data_size)
|
||||
mft_na->data_size = mft_na->initialized_size;
|
||||
ntfs_log_debug("Initializing mft record 0x%llx.\n", (long long)ll2);
|
||||
err = ntfs_mft_record_format(vol, ll2);
|
||||
if (err) {
|
||||
ntfs_log_error("Failed to format mft record.\n");
|
||||
goto undo_data_init;
|
||||
}
|
||||
}
|
||||
/* Update the mft data attribute record to reflect the new sizes. */
|
||||
ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get search context.\n");
|
||||
goto undo_data_init;
|
||||
}
|
||||
if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,
|
||||
0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("Failed to find first attribute extent of "
|
||||
"mft data attribute.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
goto undo_data_init;
|
||||
}
|
||||
a = ctx->attr;
|
||||
a->initialized_size = cpu_to_sle64(mft_na->initialized_size);
|
||||
a->data_size = cpu_to_sle64(mft_na->data_size);
|
||||
/* Ensure the changes make it to disk. */
|
||||
ntfs_inode_mark_dirty(ctx->ntfs_ino);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ntfs_log_debug("Status of mft data after mft record initialization: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
/* Sanity checks. */
|
||||
if (mft_na->data_size > mft_na->allocated_size ||
|
||||
mft_na->initialized_size > mft_na->data_size)
|
||||
NTFS_BUG("mft_na sanity checks failed");
|
||||
// BUG_ON(mft_na->initialized_size > mft_na->data_size);
|
||||
// BUG_ON(mft_na->data_size > mft_na->allocated_size);
|
||||
/* Sync MFT to minimize data loss if there won't be clean unmount. */
|
||||
if (ntfs_inode_sync(mft_na->ni)) {
|
||||
ntfs_log_error("Failed to sync $MFT.");
|
||||
goto undo_data_init;
|
||||
}
|
||||
mft_rec_already_initialized:
|
||||
|
||||
/*
|
||||
* We now have allocated and initialized the mft record. Need to read
|
||||
* it from disk and re-format it, preserving the sequence number if it
|
||||
|
@ -1457,9 +1484,7 @@ mft_rec_already_initialized:
|
|||
ntfs_log_debug("Returning opened, allocated %sinode 0x%llx.\n",
|
||||
base_ni ? "extent " : "", (long long)bit);
|
||||
return ni;
|
||||
undo_data_init:
|
||||
mft_na->initialized_size = old_data_initialized;
|
||||
mft_na->data_size = old_data_size;
|
||||
|
||||
undo_mftbmp_alloc:
|
||||
err = errno;
|
||||
if (ntfs_bitmap_clear_bit(mftbmp_na, bit))
|
||||
|
|
Loading…
Reference in New Issue