]> asedeno.scripts.mit.edu Git - linux.git/blob - include/linux/iversion.h
fs: don't take the i_lock in inode_inc_iversion
[linux.git] / include / linux / iversion.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _LINUX_IVERSION_H
3 #define _LINUX_IVERSION_H
4
5 #include <linux/fs.h>
6
7 /*
8  * The change attribute (i_version) is mandated by NFSv4 and is mostly for
9  * knfsd, but is also used for other purposes (e.g. IMA). The i_version must
10  * appear different to observers if there was a change to the inode's data or
11  * metadata since it was last queried.
12  *
13  * Observers see the i_version as a 64-bit number that never decreases. If it
14  * remains the same since it was last checked, then nothing has changed in the
15  * inode. If it's different then something has changed. Observers cannot infer
16  * anything about the nature or magnitude of the changes from the value, only
17  * that the inode has changed in some fashion.
18  *
19  * Not all filesystems properly implement the i_version counter. Subsystems that
20  * want to use i_version field on an inode should first check whether the
21  * filesystem sets the SB_I_VERSION flag (usually via the IS_I_VERSION macro).
22  *
23  * Those that set SB_I_VERSION will automatically have their i_version counter
24  * incremented on writes to normal files. If the SB_I_VERSION is not set, then
25  * the VFS will not touch it on writes, and the filesystem can use it how it
26  * wishes. Note that the filesystem is always responsible for updating the
27  * i_version on namespace changes in directories (mkdir, rmdir, unlink, etc.).
28  * We consider these sorts of filesystems to have a kernel-managed i_version.
29  *
30  * It may be impractical for filesystems to keep i_version updates atomic with
31  * respect to the changes that cause them.  They should, however, guarantee
32  * that i_version updates are never visible before the changes that caused
33  * them.  Also, i_version updates should never be delayed longer than it takes
34  * the original change to reach disk.
35  *
36  * Note that some filesystems (e.g. NFS and AFS) just use the field to store
37  * a server-provided value (for the most part). For that reason, those
38  * filesystems do not set SB_I_VERSION. These filesystems are considered to
39  * have a self-managed i_version.
40  */
41
42 /**
43  * inode_set_iversion_raw - set i_version to the specified raw value
44  * @inode: inode to set
45  * @new: new i_version value to set
46  *
47  * Set @inode's i_version field to @new. This function is for use by
48  * filesystems that self-manage the i_version.
49  *
50  * For example, the NFS client stores its NFSv4 change attribute in this way,
51  * and the AFS client stores the data_version from the server here.
52  */
53 static inline void
54 inode_set_iversion_raw(struct inode *inode, u64 new)
55 {
56         inode->i_version = new;
57 }
58
59 /**
60  * inode_set_iversion - set i_version to a particular value
61  * @inode: inode to set
62  * @new: new i_version value to set
63  *
64  * Set @inode's i_version field to @new. This function is for filesystems with
65  * a kernel-managed i_version.
66  *
67  * For now, this just does the same thing as the _raw variant.
68  */
69 static inline void
70 inode_set_iversion(struct inode *inode, u64 new)
71 {
72         inode_set_iversion_raw(inode, new);
73 }
74
75 /**
76  * inode_set_iversion_queried - set i_version to a particular value and set
77  *                              flag to indicate that it has been viewed
78  * @inode: inode to set
79  * @new: new i_version value to set
80  *
81  * When loading in an i_version value from a backing store, we typically don't
82  * know whether it was previously viewed before being stored or not. Thus, we
83  * must assume that it was, to ensure that any changes will result in the
84  * value changing.
85  *
86  * This function will set the inode's i_version, and possibly flag the value
87  * as if it has already been viewed at least once.
88  *
89  * For now, this just does what inode_set_iversion does.
90  */
91 static inline void
92 inode_set_iversion_queried(struct inode *inode, u64 new)
93 {
94         inode_set_iversion(inode, new);
95 }
96
97 /**
98  * inode_maybe_inc_iversion - increments i_version
99  * @inode: inode with the i_version that should be updated
100  * @force: increment the counter even if it's not necessary
101  *
102  * Every time the inode is modified, the i_version field must be seen to have
103  * changed by any observer.
104  *
105  * In this implementation, we always increment it after taking the i_lock to
106  * ensure that we don't race with other incrementors.
107  *
108  * Returns true if counter was bumped, and false if it wasn't.
109  */
110 static inline bool
111 inode_maybe_inc_iversion(struct inode *inode, bool force)
112 {
113         atomic64_t *ivp = (atomic64_t *)&inode->i_version;
114
115         atomic64_inc(ivp);
116         return true;
117 }
118
119
120 /**
121  * inode_inc_iversion - forcibly increment i_version
122  * @inode: inode that needs to be updated
123  *
124  * Forcbily increment the i_version field. This always results in a change to
125  * the observable value.
126  */
127 static inline void
128 inode_inc_iversion(struct inode *inode)
129 {
130         inode_maybe_inc_iversion(inode, true);
131 }
132
133 /**
134  * inode_iversion_need_inc - is the i_version in need of being incremented?
135  * @inode: inode to check
136  *
137  * Returns whether the inode->i_version counter needs incrementing on the next
138  * change.
139  *
140  * For now, we assume that it always does.
141  */
142 static inline bool
143 inode_iversion_need_inc(struct inode *inode)
144 {
145         return true;
146 }
147
148 /**
149  * inode_peek_iversion_raw - grab a "raw" iversion value
150  * @inode: inode from which i_version should be read
151  *
152  * Grab a "raw" inode->i_version value and return it. The i_version is not
153  * flagged or converted in any way. This is mostly used to access a self-managed
154  * i_version.
155  *
156  * With those filesystems, we want to treat the i_version as an entirely
157  * opaque value.
158  */
159 static inline u64
160 inode_peek_iversion_raw(const struct inode *inode)
161 {
162         return inode->i_version;
163 }
164
165 /**
166  * inode_inc_iversion_raw - forcibly increment raw i_version
167  * @inode: inode that needs to be updated
168  *
169  * Forcbily increment the raw i_version field. This always results in a change
170  * to the raw value.
171  *
172  * NFS will use the i_version field to store the value from the server. It
173  * mostly treats it as opaque, but in the case where it holds a write
174  * delegation, it must increment the value itself. This function does that.
175  */
176 static inline void
177 inode_inc_iversion_raw(struct inode *inode)
178 {
179         inode_inc_iversion(inode);
180 }
181
182 /**
183  * inode_peek_iversion - read i_version without flagging it to be incremented
184  * @inode: inode from which i_version should be read
185  *
186  * Read the inode i_version counter for an inode without registering it as a
187  * query.
188  *
189  * This is typically used by local filesystems that need to store an i_version
190  * on disk. In that situation, it's not necessary to flag it as having been
191  * viewed, as the result won't be used to gauge changes from that point.
192  */
193 static inline u64
194 inode_peek_iversion(const struct inode *inode)
195 {
196         return inode_peek_iversion_raw(inode);
197 }
198
199 /**
200  * inode_query_iversion - read i_version for later use
201  * @inode: inode from which i_version should be read
202  *
203  * Read the inode i_version counter. This should be used by callers that wish
204  * to store the returned i_version for later comparison. This will guarantee
205  * that a later query of the i_version will result in a different value if
206  * anything has changed.
207  *
208  * This implementation just does a peek.
209  */
210 static inline u64
211 inode_query_iversion(struct inode *inode)
212 {
213         return inode_peek_iversion(inode);
214 }
215
216 /**
217  * inode_cmp_iversion_raw - check whether the raw i_version counter has changed
218  * @inode: inode to check
219  * @old: old value to check against its i_version
220  *
221  * Compare the current raw i_version counter with a previous one. Returns 0 if
222  * they are the same or non-zero if they are different.
223  */
224 static inline s64
225 inode_cmp_iversion_raw(const struct inode *inode, u64 old)
226 {
227         return (s64)inode_peek_iversion_raw(inode) - (s64)old;
228 }
229
230 /**
231  * inode_cmp_iversion - check whether the i_version counter has changed
232  * @inode: inode to check
233  * @old: old value to check against its i_version
234  *
235  * Compare an i_version counter with a previous one. Returns 0 if they are
236  * the same or non-zero if they are different.
237  */
238 static inline s64
239 inode_cmp_iversion(const struct inode *inode, u64 old)
240 {
241         return (s64)inode_peek_iversion(inode) - (s64)old;
242 }
243 #endif