| // SPDX-License-Identifier: GPL-2.0 | 
 | #ifndef NO_BCACHEFS_FS | 
 |  | 
 | #include "bcachefs.h" | 
 | #include "alloc_foreground.h" | 
 | #include "fs.h" | 
 | #include "fs-io.h" | 
 | #include "fs-io-direct.h" | 
 | #include "fs-io-pagecache.h" | 
 | #include "io_read.h" | 
 | #include "io_write.h" | 
 |  | 
 | #include <linux/kthread.h> | 
 | #include <linux/pagemap.h> | 
 | #include <linux/prefetch.h> | 
 | #include <linux/task_io_accounting_ops.h> | 
 |  | 
 | /* O_DIRECT reads */ | 
 |  | 
 | struct dio_read { | 
 | 	struct closure			cl; | 
 | 	struct kiocb			*req; | 
 | 	long				ret; | 
 | 	bool				should_dirty; | 
 | 	struct bch_read_bio		rbio; | 
 | }; | 
 |  | 
 | static void bio_check_or_release(struct bio *bio, bool check_dirty) | 
 | { | 
 | 	if (check_dirty) { | 
 | 		bio_check_pages_dirty(bio); | 
 | 	} else { | 
 | 		bio_release_pages(bio, false); | 
 | 		bio_put(bio); | 
 | 	} | 
 | } | 
 |  | 
 | static CLOSURE_CALLBACK(bch2_dio_read_complete) | 
 | { | 
 | 	closure_type(dio, struct dio_read, cl); | 
 |  | 
 | 	dio->req->ki_complete(dio->req, dio->ret); | 
 | 	bio_check_or_release(&dio->rbio.bio, dio->should_dirty); | 
 | } | 
 |  | 
 | static void bch2_direct_IO_read_endio(struct bio *bio) | 
 | { | 
 | 	struct dio_read *dio = bio->bi_private; | 
 |  | 
 | 	if (bio->bi_status) | 
 | 		dio->ret = blk_status_to_errno(bio->bi_status); | 
 |  | 
 | 	closure_put(&dio->cl); | 
 | } | 
 |  | 
 | static void bch2_direct_IO_read_split_endio(struct bio *bio) | 
 | { | 
 | 	struct dio_read *dio = bio->bi_private; | 
 | 	bool should_dirty = dio->should_dirty; | 
 |  | 
 | 	bch2_direct_IO_read_endio(bio); | 
 | 	bio_check_or_release(bio, should_dirty); | 
 | } | 
 |  | 
 | static int bch2_direct_IO_read(struct kiocb *req, struct iov_iter *iter) | 
 | { | 
 | 	struct file *file = req->ki_filp; | 
 | 	struct bch_inode_info *inode = file_bch_inode(file); | 
 | 	struct bch_fs *c = inode->v.i_sb->s_fs_info; | 
 | 	struct bch_io_opts opts; | 
 | 	struct dio_read *dio; | 
 | 	struct bio *bio; | 
 | 	loff_t offset = req->ki_pos; | 
 | 	bool sync = is_sync_kiocb(req); | 
 | 	size_t shorten; | 
 | 	ssize_t ret; | 
 |  | 
 | 	bch2_inode_opts_get(&opts, c, &inode->ei_inode); | 
 |  | 
 | 	/* bios must be 512 byte aligned: */ | 
 | 	if ((offset|iter->count) & (SECTOR_SIZE - 1)) | 
 | 		return -EINVAL; | 
 |  | 
 | 	ret = min_t(loff_t, iter->count, | 
 | 		    max_t(loff_t, 0, i_size_read(&inode->v) - offset)); | 
 |  | 
 | 	if (!ret) | 
 | 		return ret; | 
 |  | 
 | 	shorten = iov_iter_count(iter) - round_up(ret, block_bytes(c)); | 
 | 	if (shorten >= iter->count) | 
 | 		shorten = 0; | 
 | 	iter->count -= shorten; | 
 |  | 
 | 	bio = bio_alloc_bioset(NULL, | 
 | 			       bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS), | 
 | 			       REQ_OP_READ, | 
 | 			       GFP_KERNEL, | 
 | 			       &c->dio_read_bioset); | 
 |  | 
 | 	bio->bi_end_io = bch2_direct_IO_read_endio; | 
 |  | 
 | 	dio = container_of(bio, struct dio_read, rbio.bio); | 
 | 	closure_init(&dio->cl, NULL); | 
 |  | 
 | 	/* | 
 | 	 * this is a _really_ horrible hack just to avoid an atomic sub at the | 
 | 	 * end: | 
 | 	 */ | 
 | 	if (!sync) { | 
 | 		set_closure_fn(&dio->cl, bch2_dio_read_complete, NULL); | 
 | 		atomic_set(&dio->cl.remaining, | 
 | 			   CLOSURE_REMAINING_INITIALIZER - | 
 | 			   CLOSURE_RUNNING + | 
 | 			   CLOSURE_DESTRUCTOR); | 
 | 	} else { | 
 | 		atomic_set(&dio->cl.remaining, | 
 | 			   CLOSURE_REMAINING_INITIALIZER + 1); | 
 | 		dio->cl.closure_get_happened = true; | 
 | 	} | 
 |  | 
 | 	dio->req	= req; | 
 | 	dio->ret	= ret; | 
 | 	/* | 
 | 	 * This is one of the sketchier things I've encountered: we have to skip | 
 | 	 * the dirtying of requests that are internal from the kernel (i.e. from | 
 | 	 * loopback), because we'll deadlock on page_lock. | 
 | 	 */ | 
 | 	dio->should_dirty = iter_is_iovec(iter); | 
 |  | 
 | 	goto start; | 
 | 	while (iter->count) { | 
 | 		bio = bio_alloc_bioset(NULL, | 
 | 				       bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS), | 
 | 				       REQ_OP_READ, | 
 | 				       GFP_KERNEL, | 
 | 				       &c->bio_read); | 
 | 		bio->bi_end_io		= bch2_direct_IO_read_split_endio; | 
 | start: | 
 | 		bio->bi_opf		= REQ_OP_READ|REQ_SYNC; | 
 | 		bio->bi_iter.bi_sector	= offset >> 9; | 
 | 		bio->bi_private		= dio; | 
 |  | 
 | 		ret = bio_iov_iter_get_pages(bio, iter); | 
 | 		if (ret < 0) { | 
 | 			/* XXX: fault inject this path */ | 
 | 			bio->bi_status = BLK_STS_RESOURCE; | 
 | 			bio_endio(bio); | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		offset += bio->bi_iter.bi_size; | 
 |  | 
 | 		if (dio->should_dirty) | 
 | 			bio_set_pages_dirty(bio); | 
 |  | 
 | 		if (iter->count) | 
 | 			closure_get(&dio->cl); | 
 |  | 
 | 		bch2_read(c, rbio_init(bio, opts), inode_inum(inode)); | 
 | 	} | 
 |  | 
 | 	iter->count += shorten; | 
 |  | 
 | 	if (sync) { | 
 | 		closure_sync(&dio->cl); | 
 | 		closure_debug_destroy(&dio->cl); | 
 | 		ret = dio->ret; | 
 | 		bio_check_or_release(&dio->rbio.bio, dio->should_dirty); | 
 | 		return ret; | 
 | 	} else { | 
 | 		return -EIOCBQUEUED; | 
 | 	} | 
 | } | 
 |  | 
 | ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter) | 
 | { | 
 | 	struct file *file = iocb->ki_filp; | 
 | 	struct bch_inode_info *inode = file_bch_inode(file); | 
 | 	struct address_space *mapping = file->f_mapping; | 
 | 	size_t count = iov_iter_count(iter); | 
 | 	ssize_t ret = 0; | 
 |  | 
 | 	if (!count) | 
 | 		return 0; /* skip atime */ | 
 |  | 
 | 	if (iocb->ki_flags & IOCB_DIRECT) { | 
 | 		struct blk_plug plug; | 
 |  | 
 | 		if (unlikely(mapping->nrpages)) { | 
 | 			ret = filemap_write_and_wait_range(mapping, | 
 | 						iocb->ki_pos, | 
 | 						iocb->ki_pos + count - 1); | 
 | 			if (ret < 0) | 
 | 				goto out; | 
 | 		} | 
 |  | 
 | 		file_accessed(file); | 
 |  | 
 | 		blk_start_plug(&plug); | 
 | 		ret = bch2_direct_IO_read(iocb, iter); | 
 | 		blk_finish_plug(&plug); | 
 |  | 
 | 		if (ret >= 0) | 
 | 			iocb->ki_pos += ret; | 
 | 	} else { | 
 | 		bch2_pagecache_add_get(inode); | 
 | 		ret = filemap_read(iocb, iter, ret); | 
 | 		bch2_pagecache_add_put(inode); | 
 | 	} | 
 | out: | 
 | 	return bch2_err_class(ret); | 
 | } | 
 |  | 
 | /* O_DIRECT writes */ | 
 |  | 
 | struct dio_write { | 
 | 	struct kiocb			*req; | 
 | 	struct address_space		*mapping; | 
 | 	struct bch_inode_info		*inode; | 
 | 	struct mm_struct		*mm; | 
 | 	const struct iovec		*iov; | 
 | 	unsigned			loop:1, | 
 | 					extending:1, | 
 | 					sync:1, | 
 | 					flush:1; | 
 | 	struct quota_res		quota_res; | 
 | 	u64				written; | 
 |  | 
 | 	struct iov_iter			iter; | 
 | 	struct iovec			inline_vecs[2]; | 
 |  | 
 | 	/* must be last: */ | 
 | 	struct bch_write_op		op; | 
 | }; | 
 |  | 
 | static bool bch2_check_range_allocated(struct bch_fs *c, subvol_inum inum, | 
 | 				       u64 offset, u64 size, | 
 | 				       unsigned nr_replicas, bool compressed) | 
 | { | 
 | 	struct btree_trans *trans = bch2_trans_get(c); | 
 | 	struct btree_iter iter; | 
 | 	struct bkey_s_c k; | 
 | 	u64 end = offset + size; | 
 | 	u32 snapshot; | 
 | 	bool ret = true; | 
 | 	int err; | 
 | retry: | 
 | 	bch2_trans_begin(trans); | 
 |  | 
 | 	err = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot); | 
 | 	if (err) | 
 | 		goto err; | 
 |  | 
 | 	for_each_btree_key_norestart(trans, iter, BTREE_ID_extents, | 
 | 			   SPOS(inum.inum, offset, snapshot), | 
 | 			   BTREE_ITER_slots, k, err) { | 
 | 		if (bkey_ge(bkey_start_pos(k.k), POS(inum.inum, end))) | 
 | 			break; | 
 |  | 
 | 		if (k.k->p.snapshot != snapshot || | 
 | 		    nr_replicas > bch2_bkey_replicas(c, k) || | 
 | 		    (!compressed && bch2_bkey_sectors_compressed(k))) { | 
 | 			ret = false; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	offset = iter.pos.offset; | 
 | 	bch2_trans_iter_exit(trans, &iter); | 
 | err: | 
 | 	if (bch2_err_matches(err, BCH_ERR_transaction_restart)) | 
 | 		goto retry; | 
 | 	bch2_trans_put(trans); | 
 |  | 
 | 	return err ? false : ret; | 
 | } | 
 |  | 
 | static noinline bool bch2_dio_write_check_allocated(struct dio_write *dio) | 
 | { | 
 | 	struct bch_fs *c = dio->op.c; | 
 | 	struct bch_inode_info *inode = dio->inode; | 
 | 	struct bio *bio = &dio->op.wbio.bio; | 
 |  | 
 | 	return bch2_check_range_allocated(c, inode_inum(inode), | 
 | 				dio->op.pos.offset, bio_sectors(bio), | 
 | 				dio->op.opts.data_replicas, | 
 | 				dio->op.opts.compression != 0); | 
 | } | 
 |  | 
 | static void bch2_dio_write_loop_async(struct bch_write_op *); | 
 | static __always_inline long bch2_dio_write_done(struct dio_write *dio); | 
 |  | 
 | /* | 
 |  * We're going to return -EIOCBQUEUED, but we haven't finished consuming the | 
 |  * iov_iter yet, so we need to stash a copy of the iovec: it might be on the | 
 |  * caller's stack, we're not guaranteed that it will live for the duration of | 
 |  * the IO: | 
 |  */ | 
 | static noinline int bch2_dio_write_copy_iov(struct dio_write *dio) | 
 | { | 
 | 	struct iovec *iov = dio->inline_vecs; | 
 |  | 
 | 	/* | 
 | 	 * iov_iter has a single embedded iovec - nothing to do: | 
 | 	 */ | 
 | 	if (iter_is_ubuf(&dio->iter)) | 
 | 		return 0; | 
 |  | 
 | 	/* | 
 | 	 * We don't currently handle non-iovec iov_iters here - return an error, | 
 | 	 * and we'll fall back to doing the IO synchronously: | 
 | 	 */ | 
 | 	if (!iter_is_iovec(&dio->iter)) | 
 | 		return -1; | 
 |  | 
 | 	if (dio->iter.nr_segs > ARRAY_SIZE(dio->inline_vecs)) { | 
 | 		dio->iov = iov = kmalloc_array(dio->iter.nr_segs, sizeof(*iov), | 
 | 				    GFP_KERNEL); | 
 | 		if (unlikely(!iov)) | 
 | 			return -ENOMEM; | 
 | 	} | 
 |  | 
 | 	memcpy(iov, dio->iter.__iov, dio->iter.nr_segs * sizeof(*iov)); | 
 | 	dio->iter.__iov = iov; | 
 | 	return 0; | 
 | } | 
 |  | 
 | static CLOSURE_CALLBACK(bch2_dio_write_flush_done) | 
 | { | 
 | 	closure_type(dio, struct dio_write, op.cl); | 
 | 	struct bch_fs *c = dio->op.c; | 
 |  | 
 | 	closure_debug_destroy(cl); | 
 |  | 
 | 	dio->op.error = bch2_journal_error(&c->journal); | 
 |  | 
 | 	bch2_dio_write_done(dio); | 
 | } | 
 |  | 
 | static noinline void bch2_dio_write_flush(struct dio_write *dio) | 
 | { | 
 | 	struct bch_fs *c = dio->op.c; | 
 | 	struct bch_inode_unpacked inode; | 
 | 	int ret; | 
 |  | 
 | 	dio->flush = 0; | 
 |  | 
 | 	closure_init(&dio->op.cl, NULL); | 
 |  | 
 | 	if (!dio->op.error) { | 
 | 		ret = bch2_inode_find_by_inum(c, inode_inum(dio->inode), &inode); | 
 | 		if (ret) { | 
 | 			dio->op.error = ret; | 
 | 		} else { | 
 | 			bch2_journal_flush_seq_async(&c->journal, inode.bi_journal_seq, | 
 | 						     &dio->op.cl); | 
 | 			bch2_inode_flush_nocow_writes_async(c, dio->inode, &dio->op.cl); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if (dio->sync) { | 
 | 		closure_sync(&dio->op.cl); | 
 | 		closure_debug_destroy(&dio->op.cl); | 
 | 	} else { | 
 | 		continue_at(&dio->op.cl, bch2_dio_write_flush_done, NULL); | 
 | 	} | 
 | } | 
 |  | 
 | static __always_inline long bch2_dio_write_done(struct dio_write *dio) | 
 | { | 
 | 	struct bch_fs *c = dio->op.c; | 
 | 	struct kiocb *req = dio->req; | 
 | 	struct bch_inode_info *inode = dio->inode; | 
 | 	bool sync = dio->sync; | 
 | 	long ret; | 
 |  | 
 | 	if (unlikely(dio->flush)) { | 
 | 		bch2_dio_write_flush(dio); | 
 | 		if (!sync) | 
 | 			return -EIOCBQUEUED; | 
 | 	} | 
 |  | 
 | 	bch2_pagecache_block_put(inode); | 
 |  | 
 | 	kfree(dio->iov); | 
 |  | 
 | 	ret = dio->op.error ?: ((long) dio->written << 9); | 
 | 	bio_put(&dio->op.wbio.bio); | 
 |  | 
 | 	bch2_write_ref_put(c, BCH_WRITE_REF_dio_write); | 
 |  | 
 | 	/* inode->i_dio_count is our ref on inode and thus bch_fs */ | 
 | 	inode_dio_end(&inode->v); | 
 |  | 
 | 	if (ret < 0) | 
 | 		ret = bch2_err_class(ret); | 
 |  | 
 | 	if (!sync) { | 
 | 		req->ki_complete(req, ret); | 
 | 		ret = -EIOCBQUEUED; | 
 | 	} | 
 | 	return ret; | 
 | } | 
 |  | 
 | static __always_inline void bch2_dio_write_end(struct dio_write *dio) | 
 | { | 
 | 	struct bch_fs *c = dio->op.c; | 
 | 	struct kiocb *req = dio->req; | 
 | 	struct bch_inode_info *inode = dio->inode; | 
 | 	struct bio *bio = &dio->op.wbio.bio; | 
 |  | 
 | 	req->ki_pos	+= (u64) dio->op.written << 9; | 
 | 	dio->written	+= dio->op.written; | 
 |  | 
 | 	if (dio->extending) { | 
 | 		spin_lock(&inode->v.i_lock); | 
 | 		if (req->ki_pos > inode->v.i_size) | 
 | 			i_size_write(&inode->v, req->ki_pos); | 
 | 		spin_unlock(&inode->v.i_lock); | 
 | 	} | 
 |  | 
 | 	if (dio->op.i_sectors_delta || dio->quota_res.sectors) { | 
 | 		mutex_lock(&inode->ei_quota_lock); | 
 | 		__bch2_i_sectors_acct(c, inode, &dio->quota_res, dio->op.i_sectors_delta); | 
 | 		__bch2_quota_reservation_put(c, inode, &dio->quota_res); | 
 | 		mutex_unlock(&inode->ei_quota_lock); | 
 | 	} | 
 |  | 
 | 	bio_release_pages(bio, false); | 
 |  | 
 | 	if (unlikely(dio->op.error)) | 
 | 		set_bit(EI_INODE_ERROR, &inode->ei_flags); | 
 | } | 
 |  | 
 | static __always_inline long bch2_dio_write_loop(struct dio_write *dio) | 
 | { | 
 | 	struct bch_fs *c = dio->op.c; | 
 | 	struct kiocb *req = dio->req; | 
 | 	struct address_space *mapping = dio->mapping; | 
 | 	struct bch_inode_info *inode = dio->inode; | 
 | 	struct bch_io_opts opts; | 
 | 	struct bio *bio = &dio->op.wbio.bio; | 
 | 	unsigned unaligned, iter_count; | 
 | 	bool sync = dio->sync, dropped_locks; | 
 | 	long ret; | 
 |  | 
 | 	bch2_inode_opts_get(&opts, c, &inode->ei_inode); | 
 |  | 
 | 	while (1) { | 
 | 		iter_count = dio->iter.count; | 
 |  | 
 | 		EBUG_ON(current->faults_disabled_mapping); | 
 | 		current->faults_disabled_mapping = mapping; | 
 |  | 
 | 		ret = bio_iov_iter_get_pages(bio, &dio->iter); | 
 |  | 
 | 		dropped_locks = fdm_dropped_locks(); | 
 |  | 
 | 		current->faults_disabled_mapping = NULL; | 
 |  | 
 | 		/* | 
 | 		 * If the fault handler returned an error but also signalled | 
 | 		 * that it dropped & retook ei_pagecache_lock, we just need to | 
 | 		 * re-shoot down the page cache and retry: | 
 | 		 */ | 
 | 		if (dropped_locks && ret) | 
 | 			ret = 0; | 
 |  | 
 | 		if (unlikely(ret < 0)) | 
 | 			goto err; | 
 |  | 
 | 		if (unlikely(dropped_locks)) { | 
 | 			ret = bch2_write_invalidate_inode_pages_range(mapping, | 
 | 					req->ki_pos, | 
 | 					req->ki_pos + iter_count - 1); | 
 | 			if (unlikely(ret)) | 
 | 				goto err; | 
 |  | 
 | 			if (!bio->bi_iter.bi_size) | 
 | 				continue; | 
 | 		} | 
 |  | 
 | 		unaligned = bio->bi_iter.bi_size & (block_bytes(c) - 1); | 
 | 		bio->bi_iter.bi_size -= unaligned; | 
 | 		iov_iter_revert(&dio->iter, unaligned); | 
 |  | 
 | 		if (!bio->bi_iter.bi_size) { | 
 | 			/* | 
 | 			 * bio_iov_iter_get_pages was only able to get < | 
 | 			 * blocksize worth of pages: | 
 | 			 */ | 
 | 			ret = -EFAULT; | 
 | 			goto err; | 
 | 		} | 
 |  | 
 | 		bch2_write_op_init(&dio->op, c, opts); | 
 | 		dio->op.end_io		= sync | 
 | 			? NULL | 
 | 			: bch2_dio_write_loop_async; | 
 | 		dio->op.target		= dio->op.opts.foreground_target; | 
 | 		dio->op.write_point	= writepoint_hashed((unsigned long) current); | 
 | 		dio->op.nr_replicas	= dio->op.opts.data_replicas; | 
 | 		dio->op.subvol		= inode->ei_inum.subvol; | 
 | 		dio->op.pos		= POS(inode->v.i_ino, (u64) req->ki_pos >> 9); | 
 | 		dio->op.devs_need_flush	= &inode->ei_devs_need_flush; | 
 |  | 
 | 		if (sync) | 
 | 			dio->op.flags |= BCH_WRITE_SYNC; | 
 | 		dio->op.flags |= BCH_WRITE_CHECK_ENOSPC; | 
 |  | 
 | 		ret = bch2_quota_reservation_add(c, inode, &dio->quota_res, | 
 | 						 bio_sectors(bio), true); | 
 | 		if (unlikely(ret)) | 
 | 			goto err; | 
 |  | 
 | 		ret = bch2_disk_reservation_get(c, &dio->op.res, bio_sectors(bio), | 
 | 						dio->op.opts.data_replicas, 0); | 
 | 		if (unlikely(ret) && | 
 | 		    !bch2_dio_write_check_allocated(dio)) | 
 | 			goto err; | 
 |  | 
 | 		task_io_account_write(bio->bi_iter.bi_size); | 
 |  | 
 | 		if (unlikely(dio->iter.count) && | 
 | 		    !dio->sync && | 
 | 		    !dio->loop && | 
 | 		    bch2_dio_write_copy_iov(dio)) | 
 | 			dio->sync = sync = true; | 
 |  | 
 | 		dio->loop = true; | 
 | 		closure_call(&dio->op.cl, bch2_write, NULL, NULL); | 
 |  | 
 | 		if (!sync) | 
 | 			return -EIOCBQUEUED; | 
 |  | 
 | 		bch2_dio_write_end(dio); | 
 |  | 
 | 		if (likely(!dio->iter.count) || dio->op.error) | 
 | 			break; | 
 |  | 
 | 		bio_reset(bio, NULL, REQ_OP_WRITE | REQ_SYNC | REQ_IDLE); | 
 | 	} | 
 | out: | 
 | 	return bch2_dio_write_done(dio); | 
 | err: | 
 | 	dio->op.error = ret; | 
 |  | 
 | 	bio_release_pages(bio, false); | 
 |  | 
 | 	bch2_quota_reservation_put(c, inode, &dio->quota_res); | 
 | 	goto out; | 
 | } | 
 |  | 
 | static noinline __cold void bch2_dio_write_continue(struct dio_write *dio) | 
 | { | 
 | 	struct mm_struct *mm = dio->mm; | 
 |  | 
 | 	bio_reset(&dio->op.wbio.bio, NULL, REQ_OP_WRITE); | 
 |  | 
 | 	if (mm) | 
 | 		kthread_use_mm(mm); | 
 | 	bch2_dio_write_loop(dio); | 
 | 	if (mm) | 
 | 		kthread_unuse_mm(mm); | 
 | } | 
 |  | 
 | static void bch2_dio_write_loop_async(struct bch_write_op *op) | 
 | { | 
 | 	struct dio_write *dio = container_of(op, struct dio_write, op); | 
 |  | 
 | 	bch2_dio_write_end(dio); | 
 |  | 
 | 	if (likely(!dio->iter.count) || dio->op.error) | 
 | 		bch2_dio_write_done(dio); | 
 | 	else | 
 | 		bch2_dio_write_continue(dio); | 
 | } | 
 |  | 
 | ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter) | 
 | { | 
 | 	struct file *file = req->ki_filp; | 
 | 	struct address_space *mapping = file->f_mapping; | 
 | 	struct bch_inode_info *inode = file_bch_inode(file); | 
 | 	struct bch_fs *c = inode->v.i_sb->s_fs_info; | 
 | 	struct dio_write *dio; | 
 | 	struct bio *bio; | 
 | 	bool locked = true, extending; | 
 | 	ssize_t ret; | 
 |  | 
 | 	prefetch(&c->opts); | 
 | 	prefetch((void *) &c->opts + 64); | 
 | 	prefetch(&inode->ei_inode); | 
 | 	prefetch((void *) &inode->ei_inode + 64); | 
 |  | 
 | 	if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_dio_write)) | 
 | 		return -EROFS; | 
 |  | 
 | 	inode_lock(&inode->v); | 
 |  | 
 | 	ret = generic_write_checks(req, iter); | 
 | 	if (unlikely(ret <= 0)) | 
 | 		goto err_put_write_ref; | 
 |  | 
 | 	ret = file_remove_privs(file); | 
 | 	if (unlikely(ret)) | 
 | 		goto err_put_write_ref; | 
 |  | 
 | 	ret = file_update_time(file); | 
 | 	if (unlikely(ret)) | 
 | 		goto err_put_write_ref; | 
 |  | 
 | 	if (unlikely((req->ki_pos|iter->count) & (block_bytes(c) - 1))) { | 
 | 		ret = -EINVAL; | 
 | 		goto err_put_write_ref; | 
 | 	} | 
 |  | 
 | 	inode_dio_begin(&inode->v); | 
 | 	bch2_pagecache_block_get(inode); | 
 |  | 
 | 	extending = req->ki_pos + iter->count > inode->v.i_size; | 
 | 	if (!extending) { | 
 | 		inode_unlock(&inode->v); | 
 | 		locked = false; | 
 | 	} | 
 |  | 
 | 	bio = bio_alloc_bioset(NULL, | 
 | 			       bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS), | 
 | 			       REQ_OP_WRITE | REQ_SYNC | REQ_IDLE, | 
 | 			       GFP_KERNEL, | 
 | 			       &c->dio_write_bioset); | 
 | 	dio = container_of(bio, struct dio_write, op.wbio.bio); | 
 | 	dio->req		= req; | 
 | 	dio->mapping		= mapping; | 
 | 	dio->inode		= inode; | 
 | 	dio->mm			= current->mm; | 
 | 	dio->iov		= NULL; | 
 | 	dio->loop		= false; | 
 | 	dio->extending		= extending; | 
 | 	dio->sync		= is_sync_kiocb(req) || extending; | 
 | 	dio->flush		= iocb_is_dsync(req) && !c->opts.journal_flush_disabled; | 
 | 	dio->quota_res.sectors	= 0; | 
 | 	dio->written		= 0; | 
 | 	dio->iter		= *iter; | 
 | 	dio->op.c		= c; | 
 |  | 
 | 	if (unlikely(mapping->nrpages)) { | 
 | 		ret = bch2_write_invalidate_inode_pages_range(mapping, | 
 | 						req->ki_pos, | 
 | 						req->ki_pos + iter->count - 1); | 
 | 		if (unlikely(ret)) | 
 | 			goto err_put_bio; | 
 | 	} | 
 |  | 
 | 	ret = bch2_dio_write_loop(dio); | 
 | out: | 
 | 	if (locked) | 
 | 		inode_unlock(&inode->v); | 
 | 	return ret; | 
 | err_put_bio: | 
 | 	bch2_pagecache_block_put(inode); | 
 | 	bio_put(bio); | 
 | 	inode_dio_end(&inode->v); | 
 | err_put_write_ref: | 
 | 	bch2_write_ref_put(c, BCH_WRITE_REF_dio_write); | 
 | 	goto out; | 
 | } | 
 |  | 
 | void bch2_fs_fs_io_direct_exit(struct bch_fs *c) | 
 | { | 
 | 	bioset_exit(&c->dio_write_bioset); | 
 | 	bioset_exit(&c->dio_read_bioset); | 
 | } | 
 |  | 
 | int bch2_fs_fs_io_direct_init(struct bch_fs *c) | 
 | { | 
 | 	if (bioset_init(&c->dio_read_bioset, | 
 | 			4, offsetof(struct dio_read, rbio.bio), | 
 | 			BIOSET_NEED_BVECS)) | 
 | 		return -BCH_ERR_ENOMEM_dio_read_bioset_init; | 
 |  | 
 | 	if (bioset_init(&c->dio_write_bioset, | 
 | 			4, offsetof(struct dio_write, op.wbio.bio), | 
 | 			BIOSET_NEED_BVECS)) | 
 | 		return -BCH_ERR_ENOMEM_dio_write_bioset_init; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | #endif /* NO_BCACHEFS_FS */ |