summaryrefslogtreecommitdiffstats
path: root/storage/innobase/fut/fut0lst.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--storage/innobase/fut/fut0lst.cc135
1 files changed, 82 insertions, 53 deletions
diff --git a/storage/innobase/fut/fut0lst.cc b/storage/innobase/fut/fut0lst.cc
index a52027f2..48e2fbe3 100644
--- a/storage/innobase/fut/fut0lst.cc
+++ b/storage/innobase/fut/fut0lst.cc
@@ -113,17 +113,18 @@ static void flst_add_to_empty(buf_block_t *base, uint16_t boffset,
}
/** Insert a node after another one.
-@param[in,out] base base node block
-@param[in] boffset byte offset of the base node
-@param[in,out] cur insert position block
-@param[in] coffset byte offset of the insert position
-@param[in,out] add block to be added
-@param[in] aoffset byte offset of the block to be added
-@param[in,out] mtr mini-transaction */
+@param base base node block
+@param boffset byte offset of the base node
+@param cur insert position block
+@param coffset byte offset of the insert position
+@param add block to be added
+@param aoffset byte offset of the block to be added
+@param limit fil_space_t::free_limit
+@param mtr mini-transaction */
static dberr_t flst_insert_after(buf_block_t *base, uint16_t boffset,
buf_block_t *cur, uint16_t coffset,
buf_block_t *add, uint16_t aoffset,
- mtr_t *mtr)
+ uint32_t limit, mtr_t *mtr)
{
ut_ad(base != cur || boffset != coffset);
ut_ad(base != add || boffset != aoffset);
@@ -139,6 +140,15 @@ static dberr_t flst_insert_after(buf_block_t *base, uint16_t boffset,
MTR_MEMO_PAGE_SX_FIX));
fil_addr_t next_addr= flst_get_next_addr(cur->page.frame + coffset);
+ if (next_addr.page >= limit)
+ {
+ if (UNIV_UNLIKELY(next_addr.page != FIL_NULL))
+ return DB_CORRUPTION;
+ }
+ else if (UNIV_UNLIKELY(next_addr.boffset < FIL_PAGE_DATA ||
+ next_addr.boffset >= base->physical_size() -
+ FIL_PAGE_DATA_END))
+ return DB_CORRUPTION;
flst_write_addr(*add, add->page.frame + aoffset + FLST_PREV,
cur->page.id().page_no(), coffset, mtr);
@@ -167,18 +177,19 @@ static dberr_t flst_insert_after(buf_block_t *base, uint16_t boffset,
}
/** Insert a node before another one.
-@param[in,out] base base node block
-@param[in] boffset byte offset of the base node
-@param[in,out] cur insert position block
-@param[in] coffset byte offset of the insert position
-@param[in,out] add block to be added
-@param[in] aoffset byte offset of the block to be added
-@param[in,out] mtr mini-transaction
+@param base base node block
+@param boffset byte offset of the base node
+@param cur insert position block
+@param coffset byte offset of the insert position
+@param add block to be added
+@param aoffset byte offset of the block to be added
+@param limit fil_space_t::free_limit
+@param mtr mini-transaction
@return error code */
static dberr_t flst_insert_before(buf_block_t *base, uint16_t boffset,
buf_block_t *cur, uint16_t coffset,
buf_block_t *add, uint16_t aoffset,
- mtr_t *mtr)
+ uint32_t limit, mtr_t *mtr)
{
ut_ad(base != cur || boffset != coffset);
ut_ad(base != add || boffset != aoffset);
@@ -194,6 +205,15 @@ static dberr_t flst_insert_before(buf_block_t *base, uint16_t boffset,
MTR_MEMO_PAGE_SX_FIX));
fil_addr_t prev_addr= flst_get_prev_addr(cur->page.frame + coffset);
+ if (prev_addr.page >= limit)
+ {
+ if (UNIV_UNLIKELY(prev_addr.page != FIL_NULL))
+ return DB_CORRUPTION;
+ }
+ else if (UNIV_UNLIKELY(prev_addr.boffset < FIL_PAGE_DATA ||
+ prev_addr.boffset >= base->physical_size() -
+ FIL_PAGE_DATA_END))
+ return DB_CORRUPTION;
flst_write_addr(*add, add->page.frame + aoffset + FLST_PREV,
prev_addr.page, prev_addr.boffset, mtr);
@@ -234,14 +254,9 @@ void flst_init(const buf_block_t& block, byte *base, mtr_t *mtr)
flst_zero_both(block, base + FLST_FIRST, mtr);
}
-/** Append a file list node to a list.
-@param[in,out] base base node block
-@param[in] boffset byte offset of the base node
-@param[in,out] add block to be added
-@param[in] aoffset byte offset of the node to be added
-@param[in,outr] mtr mini-transaction */
dberr_t flst_add_last(buf_block_t *base, uint16_t boffset,
- buf_block_t *add, uint16_t aoffset, mtr_t *mtr)
+ buf_block_t *add, uint16_t aoffset,
+ uint32_t limit, mtr_t *mtr)
{
ut_ad(base != add || boffset != aoffset);
ut_ad(boffset < base->physical_size());
@@ -258,6 +273,13 @@ dberr_t flst_add_last(buf_block_t *base, uint16_t boffset,
else
{
fil_addr_t addr= flst_get_last(base->page.frame + boffset);
+ if (UNIV_UNLIKELY(addr.page >= limit))
+ return DB_CORRUPTION;
+ else if (UNIV_UNLIKELY(addr.boffset < FIL_PAGE_DATA ||
+ addr.boffset >= base->physical_size() -
+ FIL_PAGE_DATA_END))
+ return DB_CORRUPTION;
+
buf_block_t *cur= add;
dberr_t err;
if (addr.page != add->page.id().page_no() &&
@@ -266,19 +288,13 @@ dberr_t flst_add_last(buf_block_t *base, uint16_t boffset,
BUF_GET_POSSIBLY_FREED, mtr, &err)))
return err;
return flst_insert_after(base, boffset, cur, addr.boffset,
- add, aoffset, mtr);
+ add, aoffset, limit, mtr);
}
}
-/** Prepend a file list node to a list.
-@param[in,out] base base node block
-@param[in] boffset byte offset of the base node
-@param[in,out] add block to be added
-@param[in] aoffset byte offset of the node to be added
-@param[in,out] mtr mini-transaction
-@return error code */
dberr_t flst_add_first(buf_block_t *base, uint16_t boffset,
- buf_block_t *add, uint16_t aoffset, mtr_t *mtr)
+ buf_block_t *add, uint16_t aoffset,
+ uint32_t limit, mtr_t *mtr)
{
ut_ad(base != add || boffset != aoffset);
ut_ad(boffset < base->physical_size());
@@ -296,6 +312,12 @@ dberr_t flst_add_first(buf_block_t *base, uint16_t boffset,
else
{
fil_addr_t addr= flst_get_first(base->page.frame + boffset);
+ if (UNIV_UNLIKELY(addr.page >= limit))
+ return DB_CORRUPTION;
+ else if (UNIV_UNLIKELY(addr.boffset < FIL_PAGE_DATA ||
+ addr.boffset >= base->physical_size() -
+ FIL_PAGE_DATA_END))
+ return DB_CORRUPTION;
buf_block_t *cur= add;
dberr_t err;
if (addr.page != add->page.id().page_no() &&
@@ -304,19 +326,13 @@ dberr_t flst_add_first(buf_block_t *base, uint16_t boffset,
BUF_GET_POSSIBLY_FREED, mtr, &err)))
return err;
return flst_insert_before(base, boffset, cur, addr.boffset,
- add, aoffset, mtr);
+ add, aoffset, limit, mtr);
}
}
-/** Remove a file list node.
-@param[in,out] base base node block
-@param[in] boffset byte offset of the base node
-@param[in,out] cur block to be removed
-@param[in] coffset byte offset of the current record to be removed
-@param[in,out] mtr mini-transaction
-@return error code */
dberr_t flst_remove(buf_block_t *base, uint16_t boffset,
- buf_block_t *cur, uint16_t coffset, mtr_t *mtr)
+ buf_block_t *cur, uint16_t coffset,
+ uint32_t limit, mtr_t *mtr)
{
ut_ad(boffset < base->physical_size());
ut_ad(coffset < cur->physical_size());
@@ -329,9 +345,27 @@ dberr_t flst_remove(buf_block_t *base, uint16_t boffset,
const fil_addr_t next_addr= flst_get_next_addr(cur->page.frame + coffset);
dberr_t err= DB_SUCCESS;
- if (prev_addr.page == FIL_NULL)
+ if (next_addr.page >= limit)
+ {
+ if (next_addr.page != FIL_NULL)
+ return DB_CORRUPTION;
+ }
+ else if (UNIV_UNLIKELY(next_addr.boffset < FIL_PAGE_DATA ||
+ next_addr.boffset >= base->physical_size() -
+ FIL_PAGE_DATA_END))
+ return DB_CORRUPTION;
+
+ if (prev_addr.page >= limit)
+ {
+ if (prev_addr.page != FIL_NULL)
+ return DB_CORRUPTION;
flst_write_addr(*base, base->page.frame + boffset + FLST_FIRST,
next_addr.page, next_addr.boffset, mtr);
+ }
+ else if (UNIV_UNLIKELY(prev_addr.boffset < FIL_PAGE_DATA ||
+ prev_addr.boffset >= base->physical_size() -
+ FIL_PAGE_DATA_END))
+ return DB_CORRUPTION;
else
{
buf_block_t *b= cur;
@@ -375,25 +409,19 @@ void flst_validate(const buf_block_t *base, uint16_t boffset, mtr_t *mtr)
ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX |
MTR_MEMO_PAGE_SX_FIX));
- /* We use two mini-transaction handles: the first is used to lock
- the base node, and prevent other threads from modifying the list.
- The second is used to traverse the list. We cannot run the second
- mtr without committing it at times, because if the list is long,
- the x-locked pages could fill the buffer, resulting in a deadlock. */
- mtr_t mtr2;
-
const uint32_t len= flst_get_len(base->page.frame + boffset);
fil_addr_t addr= flst_get_first(base->page.frame + boffset);
for (uint32_t i= len; i--; )
{
- mtr2.start();
+ ut_ad(addr.boffset >= FIL_PAGE_DATA);
+ ut_ad(addr.boffset < base->physical_size() - FIL_PAGE_DATA_END);
const buf_block_t *b=
buf_page_get_gen(page_id_t(base->page.id().space(), addr.page),
base->zip_size(), RW_SX_LATCH, nullptr, BUF_GET, mtr);
ut_ad(b);
addr= flst_get_next_addr(b->page.frame + addr.boffset);
- mtr2.commit();
+ mtr->release_last_page();
}
ut_ad(addr.page == FIL_NULL);
@@ -402,13 +430,14 @@ void flst_validate(const buf_block_t *base, uint16_t boffset, mtr_t *mtr)
for (uint32_t i= len; i--; )
{
- mtr2.start();
+ ut_ad(addr.boffset >= FIL_PAGE_DATA);
+ ut_ad(addr.boffset < base->physical_size() - FIL_PAGE_DATA_END);
const buf_block_t *b=
buf_page_get_gen(page_id_t(base->page.id().space(), addr.page),
base->zip_size(), RW_SX_LATCH, nullptr, BUF_GET, mtr);
ut_ad(b);
addr= flst_get_prev_addr(b->page.frame + addr.boffset);
- mtr2.commit();
+ mtr->release_last_page();
}
ut_ad(addr.page == FIL_NULL);