/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _BCACHEFS_FS_IO_H #define _BCACHEFS_FS_IO_H #ifndef NO_BCACHEFS_FS #include "buckets.h" #include "fs.h" #include "io_write_types.h" #include "quota.h" #include struct folio_vec { struct folio *fv_folio; size_t fv_offset; size_t fv_len; }; static inline struct folio_vec biovec_to_foliovec(struct bio_vec bv) { struct folio *folio = page_folio(bv.bv_page); size_t offset = (folio_page_idx(folio, bv.bv_page) << PAGE_SHIFT) + bv.bv_offset; size_t len = min_t(size_t, folio_size(folio) - offset, bv.bv_len); return (struct folio_vec) { .fv_folio = folio, .fv_offset = offset, .fv_len = len, }; } static inline struct folio_vec bio_iter_iovec_folio(struct bio *bio, struct bvec_iter iter) { return biovec_to_foliovec(bio_iter_iovec(bio, iter)); } #define __bio_for_each_folio(bvl, bio, iter, start) \ for (iter = (start); \ (iter).bi_size && \ ((bvl = bio_iter_iovec_folio((bio), (iter))), 1); \ bio_advance_iter_single((bio), &(iter), (bvl).fv_len)) /** * bio_for_each_folio - iterate over folios within a bio * * Like other non-_all versions, this iterates over what bio->bi_iter currently * points to. This version is for drivers, where the bio may have previously * been split or cloned. */ #define bio_for_each_folio(bvl, bio, iter) \ __bio_for_each_folio(bvl, bio, iter, (bio)->bi_iter) struct quota_res { u64 sectors; }; #ifdef CONFIG_BCACHEFS_QUOTA static inline void __bch2_quota_reservation_put(struct bch_fs *c, struct bch_inode_info *inode, struct quota_res *res) { BUG_ON(res->sectors > inode->ei_quota_reserved); bch2_quota_acct(c, inode->ei_qid, Q_SPC, -((s64) res->sectors), KEY_TYPE_QUOTA_PREALLOC); inode->ei_quota_reserved -= res->sectors; res->sectors = 0; } static inline void bch2_quota_reservation_put(struct bch_fs *c, struct bch_inode_info *inode, struct quota_res *res) { if (res->sectors) { mutex_lock(&inode->ei_quota_lock); __bch2_quota_reservation_put(c, inode, res); mutex_unlock(&inode->ei_quota_lock); } } static inline int bch2_quota_reservation_add(struct bch_fs *c, struct bch_inode_info *inode, struct quota_res *res, u64 sectors, bool check_enospc) { int ret; if (test_bit(EI_INODE_SNAPSHOT, &inode->ei_flags)) return 0; mutex_lock(&inode->ei_quota_lock); ret = bch2_quota_acct(c, inode->ei_qid, Q_SPC, sectors, check_enospc ? KEY_TYPE_QUOTA_PREALLOC : KEY_TYPE_QUOTA_NOCHECK); if (likely(!ret)) { inode->ei_quota_reserved += sectors; res->sectors += sectors; } mutex_unlock(&inode->ei_quota_lock); return ret; } #else static inline void __bch2_quota_reservation_put(struct bch_fs *c, struct bch_inode_info *inode, struct quota_res *res) {} static inline void bch2_quota_reservation_put(struct bch_fs *c, struct bch_inode_info *inode, struct quota_res *res) {} static inline int bch2_quota_reservation_add(struct bch_fs *c, struct bch_inode_info *inode, struct quota_res *res, unsigned sectors, bool check_enospc) { return 0; } #endif void __bch2_i_sectors_acct(struct bch_fs *, struct bch_inode_info *, struct quota_res *, s64); static inline void bch2_i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode, struct quota_res *quota_res, s64 sectors) { if (sectors) { mutex_lock(&inode->ei_quota_lock); __bch2_i_sectors_acct(c, inode, quota_res, sectors); mutex_unlock(&inode->ei_quota_lock); } } static inline struct address_space *faults_disabled_mapping(void) { return (void *) (((unsigned long) current->faults_disabled_mapping) & ~1UL); } static inline void set_fdm_dropped_locks(void) { current->faults_disabled_mapping = (void *) (((unsigned long) current->faults_disabled_mapping)|1); } static inline bool fdm_dropped_locks(void) { return ((unsigned long) current->faults_disabled_mapping) & 1; } void bch2_inode_flush_nocow_writes_async(struct bch_fs *, struct bch_inode_info *, struct closure *); int __must_check bch2_write_inode_size(struct bch_fs *, struct bch_inode_info *, loff_t, unsigned); int bch2_fsync(struct file *, loff_t, loff_t, int); int bchfs_truncate(struct mnt_idmap *, struct bch_inode_info *, struct iattr *); long bch2_fallocate_dispatch(struct file *, int, loff_t, loff_t); loff_t bch2_remap_file_range(struct file *, loff_t, struct file *, loff_t, loff_t, unsigned); loff_t bch2_llseek(struct file *, loff_t, int); void bch2_fs_fsio_exit(struct bch_fs *); int bch2_fs_fsio_init(struct bch_fs *); #else static inline void bch2_fs_fsio_exit(struct bch_fs *c) {} static inline int bch2_fs_fsio_init(struct bch_fs *c) { return 0; } #endif #endif /* _BCACHEFS_FS_IO_H */