1321fe13cSJeff Layton // SPDX-License-Identifier: GPL-2.0
2321fe13cSJeff Layton /*
3321fe13cSJeff Layton * Copyright (c) 2016 Trond Myklebust
4321fe13cSJeff Layton * Copyright (c) 2019 Jeff Layton
5321fe13cSJeff Layton *
6321fe13cSJeff Layton * I/O and data path helper functionality.
7321fe13cSJeff Layton *
8321fe13cSJeff Layton * Heavily borrowed from equivalent code in fs/nfs/io.c
9321fe13cSJeff Layton */
10321fe13cSJeff Layton
11321fe13cSJeff Layton #include <linux/ceph/ceph_debug.h>
12321fe13cSJeff Layton
13321fe13cSJeff Layton #include <linux/types.h>
14321fe13cSJeff Layton #include <linux/kernel.h>
15321fe13cSJeff Layton #include <linux/rwsem.h>
16321fe13cSJeff Layton #include <linux/fs.h>
17321fe13cSJeff Layton
18321fe13cSJeff Layton #include "super.h"
19321fe13cSJeff Layton #include "io.h"
20321fe13cSJeff Layton
21321fe13cSJeff Layton /* Call with exclusively locked inode->i_rwsem */
ceph_block_o_direct(struct ceph_inode_info * ci,struct inode * inode)22321fe13cSJeff Layton static void ceph_block_o_direct(struct ceph_inode_info *ci, struct inode *inode)
23321fe13cSJeff Layton {
24321fe13cSJeff Layton lockdep_assert_held_write(&inode->i_rwsem);
25321fe13cSJeff Layton
26321fe13cSJeff Layton if (READ_ONCE(ci->i_ceph_flags) & CEPH_I_ODIRECT) {
27321fe13cSJeff Layton spin_lock(&ci->i_ceph_lock);
28321fe13cSJeff Layton ci->i_ceph_flags &= ~CEPH_I_ODIRECT;
29321fe13cSJeff Layton spin_unlock(&ci->i_ceph_lock);
30321fe13cSJeff Layton inode_dio_wait(inode);
31321fe13cSJeff Layton }
32321fe13cSJeff Layton }
33321fe13cSJeff Layton
34321fe13cSJeff Layton /**
35321fe13cSJeff Layton * ceph_start_io_read - declare the file is being used for buffered reads
36321fe13cSJeff Layton * @inode: file inode
37321fe13cSJeff Layton *
38321fe13cSJeff Layton * Declare that a buffered read operation is about to start, and ensure
39321fe13cSJeff Layton * that we block all direct I/O.
40321fe13cSJeff Layton * On exit, the function ensures that the CEPH_I_ODIRECT flag is unset,
41321fe13cSJeff Layton * and holds a shared lock on inode->i_rwsem to ensure that the flag
42321fe13cSJeff Layton * cannot be changed.
43321fe13cSJeff Layton * In practice, this means that buffered read operations are allowed to
44321fe13cSJeff Layton * execute in parallel, thanks to the shared lock, whereas direct I/O
45321fe13cSJeff Layton * operations need to wait to grab an exclusive lock in order to set
46321fe13cSJeff Layton * CEPH_I_ODIRECT.
47321fe13cSJeff Layton * Note that buffered writes and truncates both take a write lock on
48321fe13cSJeff Layton * inode->i_rwsem, meaning that those are serialised w.r.t. the reads.
49321fe13cSJeff Layton */
50321fe13cSJeff Layton void
ceph_start_io_read(struct inode * inode)51321fe13cSJeff Layton ceph_start_io_read(struct inode *inode)
52321fe13cSJeff Layton {
53321fe13cSJeff Layton struct ceph_inode_info *ci = ceph_inode(inode);
54321fe13cSJeff Layton
55321fe13cSJeff Layton /* Be an optimist! */
56321fe13cSJeff Layton down_read(&inode->i_rwsem);
57321fe13cSJeff Layton if (!(READ_ONCE(ci->i_ceph_flags) & CEPH_I_ODIRECT))
58321fe13cSJeff Layton return;
59321fe13cSJeff Layton up_read(&inode->i_rwsem);
60321fe13cSJeff Layton /* Slow path.... */
61321fe13cSJeff Layton down_write(&inode->i_rwsem);
62321fe13cSJeff Layton ceph_block_o_direct(ci, inode);
63321fe13cSJeff Layton downgrade_write(&inode->i_rwsem);
64321fe13cSJeff Layton }
65321fe13cSJeff Layton
66321fe13cSJeff Layton /**
67321fe13cSJeff Layton * ceph_end_io_read - declare that the buffered read operation is done
68321fe13cSJeff Layton * @inode: file inode
69321fe13cSJeff Layton *
70321fe13cSJeff Layton * Declare that a buffered read operation is done, and release the shared
71321fe13cSJeff Layton * lock on inode->i_rwsem.
72321fe13cSJeff Layton */
73321fe13cSJeff Layton void
ceph_end_io_read(struct inode * inode)74321fe13cSJeff Layton ceph_end_io_read(struct inode *inode)
75321fe13cSJeff Layton {
76321fe13cSJeff Layton up_read(&inode->i_rwsem);
77321fe13cSJeff Layton }
78321fe13cSJeff Layton
79321fe13cSJeff Layton /**
80321fe13cSJeff Layton * ceph_start_io_write - declare the file is being used for buffered writes
81321fe13cSJeff Layton * @inode: file inode
82321fe13cSJeff Layton *
83321fe13cSJeff Layton * Declare that a buffered write operation is about to start, and ensure
84321fe13cSJeff Layton * that we block all direct I/O.
85321fe13cSJeff Layton */
86321fe13cSJeff Layton void
ceph_start_io_write(struct inode * inode)87321fe13cSJeff Layton ceph_start_io_write(struct inode *inode)
88321fe13cSJeff Layton {
89321fe13cSJeff Layton down_write(&inode->i_rwsem);
90321fe13cSJeff Layton ceph_block_o_direct(ceph_inode(inode), inode);
91321fe13cSJeff Layton }
92321fe13cSJeff Layton
93321fe13cSJeff Layton /**
94321fe13cSJeff Layton * ceph_end_io_write - declare that the buffered write operation is done
95321fe13cSJeff Layton * @inode: file inode
96321fe13cSJeff Layton *
97321fe13cSJeff Layton * Declare that a buffered write operation is done, and release the
98321fe13cSJeff Layton * lock on inode->i_rwsem.
99321fe13cSJeff Layton */
100321fe13cSJeff Layton void
ceph_end_io_write(struct inode * inode)101321fe13cSJeff Layton ceph_end_io_write(struct inode *inode)
102321fe13cSJeff Layton {
103321fe13cSJeff Layton up_write(&inode->i_rwsem);
104321fe13cSJeff Layton }
105321fe13cSJeff Layton
106321fe13cSJeff Layton /* Call with exclusively locked inode->i_rwsem */
ceph_block_buffered(struct ceph_inode_info * ci,struct inode * inode)107321fe13cSJeff Layton static void ceph_block_buffered(struct ceph_inode_info *ci, struct inode *inode)
108321fe13cSJeff Layton {
109321fe13cSJeff Layton lockdep_assert_held_write(&inode->i_rwsem);
110321fe13cSJeff Layton
111321fe13cSJeff Layton if (!(READ_ONCE(ci->i_ceph_flags) & CEPH_I_ODIRECT)) {
112321fe13cSJeff Layton spin_lock(&ci->i_ceph_lock);
113321fe13cSJeff Layton ci->i_ceph_flags |= CEPH_I_ODIRECT;
114321fe13cSJeff Layton spin_unlock(&ci->i_ceph_lock);
115321fe13cSJeff Layton /* FIXME: unmap_mapping_range? */
116321fe13cSJeff Layton filemap_write_and_wait(inode->i_mapping);
117321fe13cSJeff Layton }
118321fe13cSJeff Layton }
119321fe13cSJeff Layton
120321fe13cSJeff Layton /**
121*54b026b4SJeff Layton * ceph_start_io_direct - declare the file is being used for direct i/o
122321fe13cSJeff Layton * @inode: file inode
123321fe13cSJeff Layton *
124321fe13cSJeff Layton * Declare that a direct I/O operation is about to start, and ensure
125321fe13cSJeff Layton * that we block all buffered I/O.
126321fe13cSJeff Layton * On exit, the function ensures that the CEPH_I_ODIRECT flag is set,
127321fe13cSJeff Layton * and holds a shared lock on inode->i_rwsem to ensure that the flag
128321fe13cSJeff Layton * cannot be changed.
129321fe13cSJeff Layton * In practice, this means that direct I/O operations are allowed to
130321fe13cSJeff Layton * execute in parallel, thanks to the shared lock, whereas buffered I/O
131321fe13cSJeff Layton * operations need to wait to grab an exclusive lock in order to clear
132321fe13cSJeff Layton * CEPH_I_ODIRECT.
133321fe13cSJeff Layton * Note that buffered writes and truncates both take a write lock on
134321fe13cSJeff Layton * inode->i_rwsem, meaning that those are serialised w.r.t. O_DIRECT.
135321fe13cSJeff Layton */
136321fe13cSJeff Layton void
ceph_start_io_direct(struct inode * inode)137321fe13cSJeff Layton ceph_start_io_direct(struct inode *inode)
138321fe13cSJeff Layton {
139321fe13cSJeff Layton struct ceph_inode_info *ci = ceph_inode(inode);
140321fe13cSJeff Layton
141321fe13cSJeff Layton /* Be an optimist! */
142321fe13cSJeff Layton down_read(&inode->i_rwsem);
143321fe13cSJeff Layton if (READ_ONCE(ci->i_ceph_flags) & CEPH_I_ODIRECT)
144321fe13cSJeff Layton return;
145321fe13cSJeff Layton up_read(&inode->i_rwsem);
146321fe13cSJeff Layton /* Slow path.... */
147321fe13cSJeff Layton down_write(&inode->i_rwsem);
148321fe13cSJeff Layton ceph_block_buffered(ci, inode);
149321fe13cSJeff Layton downgrade_write(&inode->i_rwsem);
150321fe13cSJeff Layton }
151321fe13cSJeff Layton
152321fe13cSJeff Layton /**
153321fe13cSJeff Layton * ceph_end_io_direct - declare that the direct i/o operation is done
154321fe13cSJeff Layton * @inode: file inode
155321fe13cSJeff Layton *
156321fe13cSJeff Layton * Declare that a direct I/O operation is done, and release the shared
157321fe13cSJeff Layton * lock on inode->i_rwsem.
158321fe13cSJeff Layton */
159321fe13cSJeff Layton void
ceph_end_io_direct(struct inode * inode)160321fe13cSJeff Layton ceph_end_io_direct(struct inode *inode)
161321fe13cSJeff Layton {
162321fe13cSJeff Layton up_read(&inode->i_rwsem);
163321fe13cSJeff Layton }
164