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 */
 |