Commit e1036a2a authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Always touch page state with page locked

This will mean we don't have to use cmpxchg for modifying page state,
which will simplify a fair amount of code
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent a6f4d5bb
......@@ -500,11 +500,6 @@ static inline struct bch_io_opts io_opts(struct bch_fs *c, struct bch_inode_info
/* stored in page->private: */
/*
* bch_page_state has to (unfortunately) be manipulated with cmpxchg - we could
* almost protected it with the page lock, except that bch2_writepage_io_done has
* to update the sector counts (and from interrupt/bottom half context).
*/
struct bch_page_state {
union { struct {
/* existing data: */
......@@ -550,6 +545,7 @@ static inline struct bch_page_state *page_state(struct page *page)
{
struct bch_page_state *s = (void *) &page->private;
EBUG_ON(!PageLocked(page));
BUILD_BUG_ON(sizeof(*s) > sizeof(page->private));
if (!PagePrivate(page))
......@@ -589,15 +585,20 @@ static void bch2_put_page_reservation(struct bch_fs *c, struct bch_inode_info *i
__bch2_put_page_reservation(c, inode, s);
}
static inline unsigned inode_nr_replicas(struct bch_fs *c, struct bch_inode_info *inode)
{
/* XXX: this should not be open coded */
return inode->ei_inode.bi_data_replicas
? inode->ei_inode.bi_data_replicas - 1
: c->opts.data_replicas;
}
static int bch2_get_page_reservation(struct bch_fs *c, struct bch_inode_info *inode,
struct page *page, bool check_enospc)
{
struct bch_page_state *s = page_state(page), new;
/* XXX: this should not be open coded */
unsigned nr_replicas = inode->ei_inode.bi_data_replicas
? inode->ei_inode.bi_data_replicas - 1
: c->opts.data_replicas;
unsigned nr_replicas = inode_nr_replicas(c, inode);
struct disk_reservation disk_res;
struct quota_res quota_res = { 0 };
int ret;
......@@ -655,7 +656,7 @@ static void bch2_clear_page_bits(struct page *page)
__bch2_put_page_reservation(c, inode, s);
}
bool bch2_dirty_folio(struct address_space *mapping, struct folio *folio)
static void __bch2_set_page_dirty(struct address_space *mapping, struct folio *folio)
{
struct bch_inode_info *inode = to_bch_ei(mapping->host);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
......@@ -673,8 +674,14 @@ bool bch2_dirty_folio(struct address_space *mapping, struct folio *folio)
i_sectors_acct(c, inode, &quota_res,
new.dirty_sectors - old.dirty_sectors);
bch2_quota_reservation_put(c, inode, &quota_res);
}
static void bch2_set_page_dirty(struct address_space *mapping, struct page *page)
{
struct folio *folio = page_folio(page);
return filemap_dirty_folio(mapping, folio);
__bch2_set_page_dirty(mapping, folio);
filemap_dirty_folio(mapping, folio);
}
vm_fault_t bch2_page_fault(struct vm_fault *vmf)
......@@ -725,7 +732,7 @@ vm_fault_t bch2_page_mkwrite(struct vm_fault *vmf)
}
if (!PageDirty(page))
set_page_dirty(page);
bch2_set_page_dirty(mapping, page);
wait_for_stable_page(page);
out:
bch2_pagecache_add_put(&inode->ei_pagecache_lock);
......@@ -1210,10 +1217,12 @@ static int __bch2_writepage(struct folio *folio,
struct bch_inode_info *inode = to_bch_ei(page->mapping->host);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
struct bch_writepage_state *w = data;
struct bch_page_state new, old;
struct bch_page_state *s;
unsigned offset, nr_replicas_this_write;
unsigned dirty_sectors, replicas_reserved;
loff_t i_size = i_size_read(&inode->v);
pgoff_t end_index = i_size >> PAGE_SHIFT;
int ret;
EBUG_ON(!PageUptodate(page));
......@@ -1237,33 +1246,37 @@ static int __bch2_writepage(struct folio *folio,
*/
zero_user_segment(page, offset, PAGE_SIZE);
do_io:
EBUG_ON(!PageLocked(page));
s = page_state(page);
/* Before unlocking the page, transfer reservation to w->io: */
old = page_state_cmpxchg(page_state(page), new, {
/*
* If we didn't get a reservation, we can only write out the
* number of (fully allocated) replicas that currently exist,
* and only if the entire page has been written:
*/
nr_replicas_this_write =
max_t(unsigned,
new.replicas_reserved,
(new.sectors == PAGE_SECTORS
? new.nr_replicas : 0));
ret = bch2_get_page_reservation(c, inode, page, true);
if (ret) {
SetPageError(page);
mapping_set_error(page->mapping, ret);
unlock_page(page);
return 0;
}
BUG_ON(!nr_replicas_this_write);
__bch2_set_page_dirty(page->mapping, page_folio(page));
new.nr_replicas = w->opts.compression
? 0
: nr_replicas_this_write;
nr_replicas_this_write =
max_t(unsigned,
s->replicas_reserved,
(s->sectors == PAGE_SECTORS
? s->nr_replicas : 0));
new.replicas_reserved = 0;
s->nr_replicas = w->opts.compression
? 0
: nr_replicas_this_write;
new.sectors += new.dirty_sectors;
BUG_ON(new.sectors != PAGE_SECTORS);
new.dirty_sectors = 0;
});
/* Before unlocking the page, transfer reservation to w->io: */
replicas_reserved = s->replicas_reserved;
s->replicas_reserved = 0;
dirty_sectors = s->dirty_sectors;
s->dirty_sectors = 0;
s->sectors += dirty_sectors;
BUG_ON(s->sectors != PAGE_SECTORS);
BUG_ON(PageWriteback(page));
set_page_writeback(page);
......@@ -1278,12 +1291,12 @@ static int __bch2_writepage(struct folio *folio,
bch2_writepage_io_alloc(c, w, inode, page,
nr_replicas_this_write);
w->io->new_sectors += new.sectors - old.sectors;
w->io->new_sectors += dirty_sectors;
BUG_ON(inode != w->io->op.inode);
BUG_ON(bio_add_page_contig(&w->io->op.op.wbio.bio, page));
w->io->op.op.res.sectors += old.replicas_reserved * PAGE_SECTORS;
w->io->op.op.res.sectors += replicas_reserved * PAGE_SECTORS;
w->io->op.new_i_size = i_size;
if (wbc->sync_mode == WB_SYNC_ALL)
......@@ -1421,7 +1434,7 @@ int bch2_write_end(struct file *file, struct address_space *mapping,
if (!PageUptodate(page))
SetPageUptodate(page);
if (!PageDirty(page))
set_page_dirty(page);
bch2_set_page_dirty(mapping, page);
inode->ei_last_dirtied = (unsigned long) current;
} else {
......@@ -1538,7 +1551,7 @@ static int __bch2_buffered_write(struct bch_inode_info *inode,
if (!PageUptodate(pages[i]))
SetPageUptodate(pages[i]);
if (!PageDirty(pages[i]))
set_page_dirty(pages[i]);
bch2_set_page_dirty(mapping, pages[i]);
unlock_page(pages[i]);
put_page(pages[i]);
}
......@@ -2212,7 +2225,7 @@ static int __bch2_truncate_page(struct bch_inode_info *inode,
zero_user_segment(page, 0, end_offset);
if (!PageDirty(page))
set_page_dirty(page);
bch2_set_page_dirty(mapping, page);
unlock:
unlock_page(page);
put_page(page);
......
......@@ -9,8 +9,6 @@
#include <linux/uio.h>
bool bch2_dirty_folio(struct address_space *, struct folio *);
int bch2_writepage(struct page *, struct writeback_control *);
int bch2_read_folio(struct file *, struct folio *);
......
......@@ -1349,7 +1349,7 @@ static const struct address_space_operations bch_address_space_operations = {
.read_folio = bch2_read_folio,
.writepages = bch2_writepages,
.readahead = bch2_readahead,
.dirty_folio = bch2_dirty_folio,
.dirty_folio = filemap_dirty_folio,
.write_begin = bch2_write_begin,
.write_end = bch2_write_end,
.invalidate_folio = bch2_invalidate_folio,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment