diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-02-03 00:22:47 -0900 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2017-01-18 21:38:26 -0900 |
commit | f0e5fe448e8fd34a881fb0f081122c44004b2ef2 (patch) | |
tree | 552324787b364397013a5c98af30bf591f3cb099 | |
parent | 4c78450d3785a4fca3e15b35316745c0f0916407 (diff) |
bcachefs: verify i_size/i_size_dirty in various places
-rw-r--r-- | drivers/md/bcache/fs-io.c | 52 | ||||
-rw-r--r-- | drivers/md/bcache/fs-io.h | 3 |
2 files changed, 50 insertions, 5 deletions
diff --git a/drivers/md/bcache/fs-io.c b/drivers/md/bcache/fs-io.c index 282d58897321..ba92857f3056 100644 --- a/drivers/md/bcache/fs-io.c +++ b/drivers/md/bcache/fs-io.c @@ -204,6 +204,10 @@ static void i_sectors_hook_fn(struct btree_insert_hook *hook, struct i_sectors_hook *h = container_of(hook, struct i_sectors_hook, hook); + EBUG_ON(h->ei->vfs_inode.i_ino != insert->k.p.inode); + EBUG_ON(!(h->ei->i_flags & BCH_INODE_I_SECTORS_DIRTY)); + EBUG_ON(!atomic_long_read(&h->ei->i_sectors_dirty_count)); + if (k.k) { if (!bkey_extent_is_allocation(k.k)) return; @@ -229,6 +233,22 @@ static void i_sectors_hook_fn(struct btree_insert_hook *hook, if (!bkey_extent_is_allocation(&insert->k)) return; +#ifdef CONFIG_BCACHE_DEBUG + if (!(insert->k.type == BCH_RESERVATION)) { + struct bch_inode_info *ei = h->ei; + unsigned seq; + bool bad_write; + + do { + seq = read_seqcount_begin(&ei->shadow_i_size_lock); + bad_write = !(ei->i_flags & BCH_INODE_I_SIZE_DIRTY) && + insert->k.p.offset > + (round_up(ei->i_size, PAGE_SIZE) >> 9); + } while (read_seqcount_retry(&ei->shadow_i_size_lock, seq)); + + BUG_ON(bad_write); + } +#endif h->sectors += insert->k.size; } } @@ -298,6 +318,9 @@ static int __must_check i_sectors_dirty_get(struct bch_inode_info *ei, h->hook.fn = i_sectors_hook_fn; h->sectors = 0; +#ifdef CONFIG_BCACHE_DEBUG + h->ei = ei; +#endif if (atomic_long_inc_not_zero(&ei->i_sectors_dirty_count)) return 0; @@ -484,6 +507,25 @@ int bch_set_page_dirty(struct page *page) { struct bch_page_state old, new; +#ifdef CONFIG_BCACHE_DEBUG + { + struct bch_inode_info *ei = to_bch_ei(page->mapping->host); + unsigned seq, i_flags; + u64 i_size; + + do { + seq = read_seqcount_begin(&ei->shadow_i_size_lock); + i_size = ei->i_size; + i_flags = ei->i_flags; + } while (read_seqcount_retry(&ei->shadow_i_size_lock, seq)); + + BUG_ON(((page_offset(page) + PAGE_SIZE) > + round_up(i_size, PAGE_SIZE)) && + !(i_flags & BCH_INODE_I_SIZE_DIRTY) && + !atomic_long_read(&ei->i_size_dirty_count)); + } +#endif + old = page_state_cmpxchg(page_state(page), new, new.dirty_sectors = PAGE_SECTORS - new.sectors; ); @@ -1132,11 +1174,6 @@ int bch_write_end(struct file *filp, struct address_space *mapping, goto out; } - if (!PageUptodate(page)) - SetPageUptodate(page); - if (!PageDirty(page)) - set_page_dirty(page); - if (pos + copied > inode->i_size) { struct bch_page_state old, new; struct i_size_update *u; @@ -1172,6 +1209,11 @@ int bch_write_end(struct file *filp, struct address_space *mapping, bch_i_size_write(inode, pos + copied); mutex_unlock(&ei->update_lock); } + + if (!PageUptodate(page)) + SetPageUptodate(page); + if (!PageDirty(page)) + set_page_dirty(page); out: unlock_page(page); put_page(page); diff --git a/drivers/md/bcache/fs-io.h b/drivers/md/bcache/fs-io.h index f7b9b7b57e88..28fc4a64132b 100644 --- a/drivers/md/bcache/fs-io.h +++ b/drivers/md/bcache/fs-io.h @@ -35,6 +35,9 @@ int bch_migrate_page(struct address_space *, struct page *, struct i_sectors_hook { struct btree_insert_hook hook; s64 sectors; +#ifdef CONFIG_BCACHE_DEBUG + struct bch_inode_info *ei; +#endif }; struct bch_writepage_io { |