mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-01 06:33:07 +00:00
bcachefs: SECTOR_DIRTY_RESERVED
This fixes another i_sectors accounting bug - we need to differentiate between dirty writes that overwrite a reservation and dirty writes to unallocated space - dirty writes to unallocated space increase i_sectors, dirty writes over a reservation do not. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
This commit is contained in:
parent
b19d307dc1
commit
b44a66a641
1 changed files with 60 additions and 37 deletions
|
@ -231,6 +231,9 @@ static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode,
|
|||
return;
|
||||
|
||||
mutex_lock(&inode->ei_quota_lock);
|
||||
BUG_ON((s64) inode->v.i_blocks + sectors < 0);
|
||||
inode->v.i_blocks += sectors;
|
||||
|
||||
#ifdef CONFIG_BCACHEFS_QUOTA
|
||||
if (quota_res && sectors > 0) {
|
||||
BUG_ON(sectors > quota_res->sectors);
|
||||
|
@ -242,7 +245,6 @@ static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode,
|
|||
bch2_quota_acct(c, inode->ei_qid, Q_SPC, sectors, KEY_TYPE_QUOTA_WARN);
|
||||
}
|
||||
#endif
|
||||
inode->v.i_blocks += sectors;
|
||||
mutex_unlock(&inode->ei_quota_lock);
|
||||
}
|
||||
|
||||
|
@ -251,19 +253,20 @@ static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode,
|
|||
/* stored in page->private: */
|
||||
|
||||
struct bch_page_sector {
|
||||
/* Uncompressed, fully allocated replicas: */
|
||||
unsigned nr_replicas:3;
|
||||
/* Uncompressed, fully allocated replicas (or on disk reservation): */
|
||||
unsigned nr_replicas:4;
|
||||
|
||||
/* Owns PAGE_SECTORS * replicas_reserved sized reservation: */
|
||||
unsigned replicas_reserved:3;
|
||||
/* Owns PAGE_SECTORS * replicas_reserved sized in memory reservation: */
|
||||
unsigned replicas_reserved:4;
|
||||
|
||||
/* i_sectors: */
|
||||
enum {
|
||||
SECTOR_UNALLOCATED,
|
||||
SECTOR_RESERVED,
|
||||
SECTOR_DIRTY,
|
||||
SECTOR_DIRTY_RESERVED,
|
||||
SECTOR_ALLOCATED,
|
||||
} state:2;
|
||||
} state:8;
|
||||
};
|
||||
|
||||
struct bch_page_state {
|
||||
|
@ -319,6 +322,36 @@ static struct bch_page_state *bch2_page_state_create(struct page *page,
|
|||
return bch2_page_state(page) ?: __bch2_page_state_create(page, gfp);
|
||||
}
|
||||
|
||||
static unsigned bkey_to_sector_state(const struct bkey *k)
|
||||
{
|
||||
if (k->type == KEY_TYPE_reservation)
|
||||
return SECTOR_RESERVED;
|
||||
if (bkey_extent_is_allocation(k))
|
||||
return SECTOR_ALLOCATED;
|
||||
return SECTOR_UNALLOCATED;
|
||||
}
|
||||
|
||||
static void bch2_bio_page_state_set(struct bio *bio, struct bkey_s_c k)
|
||||
{
|
||||
struct bvec_iter iter;
|
||||
struct bio_vec bv;
|
||||
unsigned nr_ptrs = k.k->type == KEY_TYPE_reflink_v
|
||||
? 0 : bch2_bkey_nr_ptrs_fully_allocated(k);
|
||||
unsigned state = bkey_to_sector_state(k.k);
|
||||
|
||||
bio_for_each_segment(bv, bio, iter) {
|
||||
struct bch_page_state *s = bch2_page_state(bv.bv_page);
|
||||
unsigned i;
|
||||
|
||||
for (i = bv.bv_offset >> 9;
|
||||
i < (bv.bv_offset + bv.bv_len) >> 9;
|
||||
i++) {
|
||||
s->s[i].nr_replicas = nr_ptrs;
|
||||
s->s[i].state = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned inode_nr_replicas(struct bch_fs *c, struct bch_inode_info *inode)
|
||||
{
|
||||
/* XXX: this should not be open coded */
|
||||
|
@ -457,16 +490,23 @@ static void bch2_clear_page_bits(struct page *page)
|
|||
disk_res.sectors += s->s[i].replicas_reserved;
|
||||
s->s[i].replicas_reserved = 0;
|
||||
|
||||
if (s->s[i].state == SECTOR_DIRTY) {
|
||||
dirty_sectors++;
|
||||
switch (s->s[i].state) {
|
||||
case SECTOR_DIRTY:
|
||||
s->s[i].state = SECTOR_UNALLOCATED;
|
||||
--dirty_sectors;
|
||||
break;
|
||||
case SECTOR_DIRTY_RESERVED:
|
||||
s->s[i].state = SECTOR_RESERVED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bch2_disk_reservation_put(c, &disk_res);
|
||||
|
||||
if (dirty_sectors)
|
||||
i_sectors_acct(c, inode, NULL, -dirty_sectors);
|
||||
i_sectors_acct(c, inode, NULL, dirty_sectors);
|
||||
|
||||
bch2_page_state_release(page);
|
||||
}
|
||||
|
@ -499,10 +539,17 @@ static void bch2_set_page_dirty(struct bch_fs *c,
|
|||
s->s[i].replicas_reserved += sectors;
|
||||
res->disk.sectors -= sectors;
|
||||
|
||||
if (s->s[i].state == SECTOR_UNALLOCATED)
|
||||
switch (s->s[i].state) {
|
||||
case SECTOR_UNALLOCATED:
|
||||
s->s[i].state = SECTOR_DIRTY;
|
||||
dirty_sectors++;
|
||||
|
||||
s->s[i].state = max_t(unsigned, s->s[i].state, SECTOR_DIRTY);
|
||||
break;
|
||||
case SECTOR_RESERVED:
|
||||
s->s[i].state = SECTOR_DIRTY_RESERVED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&s->lock);
|
||||
|
@ -686,29 +733,6 @@ static inline struct page *readpage_iter_next(struct readpages_iter *iter)
|
|||
return iter->pages[iter->idx];
|
||||
}
|
||||
|
||||
static void bch2_add_page_sectors(struct bio *bio, struct bkey_s_c k)
|
||||
{
|
||||
struct bvec_iter iter;
|
||||
struct bio_vec bv;
|
||||
unsigned nr_ptrs = k.k->type == KEY_TYPE_reflink_v
|
||||
? 0 : bch2_bkey_nr_ptrs_fully_allocated(k);
|
||||
unsigned state = k.k->type == KEY_TYPE_reservation
|
||||
? SECTOR_RESERVED
|
||||
: SECTOR_ALLOCATED;
|
||||
|
||||
bio_for_each_segment(bv, bio, iter) {
|
||||
struct bch_page_state *s = bch2_page_state(bv.bv_page);
|
||||
unsigned i;
|
||||
|
||||
for (i = bv.bv_offset >> 9;
|
||||
i < (bv.bv_offset + bv.bv_len) >> 9;
|
||||
i++) {
|
||||
s->s[i].nr_replicas = nr_ptrs;
|
||||
s->s[i].state = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool extent_partial_reads_expensive(struct bkey_s_c k)
|
||||
{
|
||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
||||
|
@ -847,8 +871,7 @@ static void bchfs_read(struct btree_trans *trans,
|
|||
if (rbio->bio.bi_iter.bi_size == bytes)
|
||||
flags |= BCH_READ_LAST_FRAGMENT;
|
||||
|
||||
if (bkey_extent_is_allocation(k.k))
|
||||
bch2_add_page_sectors(&rbio->bio, k);
|
||||
bch2_bio_page_state_set(&rbio->bio, k);
|
||||
|
||||
bch2_read_extent(trans, rbio, iter.pos,
|
||||
data_btree, k, offset_into_extent, flags);
|
||||
|
|
Loading…
Reference in a new issue