a8cdf0ff46
folio_has_private() is an attractive nuisance; filesystem authors generally don't realise that it actually checks two flags (one of which is never set by bcachefs). There's no need to check the private flag at all; for folios owned by bcachefs, we know that folio->private is NULL when the private flag is clear and non-NULL when the private flag is set. Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
177 lines
4.7 KiB
C
177 lines
4.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _BCACHEFS_FS_IO_PAGECACHE_H
|
|
#define _BCACHEFS_FS_IO_PAGECACHE_H
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
typedef DARRAY(struct folio *) folios;
|
|
|
|
int bch2_filemap_get_contig_folios_d(struct address_space *, loff_t,
|
|
u64, fgf_t, gfp_t, folios *);
|
|
int bch2_write_invalidate_inode_pages_range(struct address_space *, loff_t, loff_t);
|
|
|
|
/*
|
|
* Use u64 for the end pos and sector helpers because if the folio covers the
|
|
* max supported range of the mapping, the start offset of the next folio
|
|
* overflows loff_t. This breaks much of the range based processing in the
|
|
* buffered write path.
|
|
*/
|
|
static inline u64 folio_end_pos(struct folio *folio)
|
|
{
|
|
return folio_pos(folio) + folio_size(folio);
|
|
}
|
|
|
|
static inline size_t folio_sectors(struct folio *folio)
|
|
{
|
|
return PAGE_SECTORS << folio_order(folio);
|
|
}
|
|
|
|
static inline loff_t folio_sector(struct folio *folio)
|
|
{
|
|
return folio_pos(folio) >> 9;
|
|
}
|
|
|
|
static inline u64 folio_end_sector(struct folio *folio)
|
|
{
|
|
return folio_end_pos(folio) >> 9;
|
|
}
|
|
|
|
#define BCH_FOLIO_SECTOR_STATE() \
|
|
x(unallocated) \
|
|
x(reserved) \
|
|
x(dirty) \
|
|
x(dirty_reserved) \
|
|
x(allocated)
|
|
|
|
enum bch_folio_sector_state {
|
|
#define x(n) SECTOR_##n,
|
|
BCH_FOLIO_SECTOR_STATE()
|
|
#undef x
|
|
};
|
|
|
|
struct bch_folio_sector {
|
|
/* Uncompressed, fully allocated replicas (or on disk reservation): */
|
|
u8 nr_replicas:4,
|
|
/* Owns PAGE_SECTORS * replicas_reserved sized in memory reservation: */
|
|
replicas_reserved:4;
|
|
u8 state;
|
|
};
|
|
|
|
struct bch_folio {
|
|
spinlock_t lock;
|
|
atomic_t write_count;
|
|
/*
|
|
* Is the sector state up to date with the btree?
|
|
* (Not the data itself)
|
|
*/
|
|
bool uptodate;
|
|
struct bch_folio_sector s[];
|
|
};
|
|
|
|
/* Helper for when we need to add debug instrumentation: */
|
|
static inline void bch2_folio_sector_set(struct folio *folio,
|
|
struct bch_folio *s,
|
|
unsigned i, unsigned n)
|
|
{
|
|
s->s[i].state = n;
|
|
}
|
|
|
|
/* file offset (to folio offset) to bch_folio_sector index */
|
|
static inline int folio_pos_to_s(struct folio *folio, loff_t pos)
|
|
{
|
|
u64 f_offset = pos - folio_pos(folio);
|
|
|
|
BUG_ON(pos < folio_pos(folio) || pos >= folio_end_pos(folio));
|
|
return f_offset >> SECTOR_SHIFT;
|
|
}
|
|
|
|
/* for newly allocated folios: */
|
|
static inline void __bch2_folio_release(struct folio *folio)
|
|
{
|
|
kfree(folio_detach_private(folio));
|
|
}
|
|
|
|
static inline void bch2_folio_release(struct folio *folio)
|
|
{
|
|
EBUG_ON(!folio_test_locked(folio));
|
|
__bch2_folio_release(folio);
|
|
}
|
|
|
|
static inline struct bch_folio *__bch2_folio(struct folio *folio)
|
|
{
|
|
return folio_get_private(folio);
|
|
}
|
|
|
|
static inline struct bch_folio *bch2_folio(struct folio *folio)
|
|
{
|
|
EBUG_ON(!folio_test_locked(folio));
|
|
|
|
return __bch2_folio(folio);
|
|
}
|
|
|
|
struct bch_folio *__bch2_folio_create(struct folio *, gfp_t);
|
|
struct bch_folio *bch2_folio_create(struct folio *, gfp_t);
|
|
|
|
struct bch2_folio_reservation {
|
|
struct disk_reservation disk;
|
|
struct quota_res quota;
|
|
};
|
|
|
|
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 inline void bch2_folio_reservation_init(struct bch_fs *c,
|
|
struct bch_inode_info *inode,
|
|
struct bch2_folio_reservation *res)
|
|
{
|
|
memset(res, 0, sizeof(*res));
|
|
|
|
res->disk.nr_replicas = inode_nr_replicas(c, inode);
|
|
}
|
|
|
|
int bch2_folio_set(struct bch_fs *, subvol_inum, struct folio **, unsigned);
|
|
void bch2_bio_page_state_set(struct bio *, struct bkey_s_c);
|
|
|
|
void bch2_mark_pagecache_unallocated(struct bch_inode_info *, u64, u64);
|
|
int bch2_mark_pagecache_reserved(struct bch_inode_info *, u64 *, u64, bool);
|
|
|
|
int bch2_get_folio_disk_reservation(struct bch_fs *,
|
|
struct bch_inode_info *,
|
|
struct folio *, bool);
|
|
|
|
void bch2_folio_reservation_put(struct bch_fs *,
|
|
struct bch_inode_info *,
|
|
struct bch2_folio_reservation *);
|
|
int bch2_folio_reservation_get(struct bch_fs *,
|
|
struct bch_inode_info *,
|
|
struct folio *,
|
|
struct bch2_folio_reservation *,
|
|
size_t, size_t);
|
|
ssize_t bch2_folio_reservation_get_partial(struct bch_fs *,
|
|
struct bch_inode_info *,
|
|
struct folio *,
|
|
struct bch2_folio_reservation *,
|
|
size_t, size_t);
|
|
|
|
void bch2_set_folio_dirty(struct bch_fs *,
|
|
struct bch_inode_info *,
|
|
struct folio *,
|
|
struct bch2_folio_reservation *,
|
|
unsigned, unsigned);
|
|
|
|
vm_fault_t bch2_page_fault(struct vm_fault *);
|
|
vm_fault_t bch2_page_mkwrite(struct vm_fault *);
|
|
void bch2_invalidate_folio(struct folio *, size_t, size_t);
|
|
bool bch2_release_folio(struct folio *, gfp_t);
|
|
|
|
loff_t bch2_seek_pagecache_data(struct inode *, loff_t, loff_t, unsigned, bool);
|
|
loff_t bch2_seek_pagecache_hole(struct inode *, loff_t, loff_t, unsigned, bool);
|
|
int bch2_clamp_data_hole(struct inode *, u64 *, u64 *, unsigned, bool);
|
|
|
|
#endif /* _BCACHEFS_FS_IO_PAGECACHE_H */
|