summaryrefslogtreecommitdiff
path: root/include/linux/fscache.h
blob: 0f36d1fac23730c3a5beffc40a4fe9c5efd63d0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* General filesystem caching interface
 *
 * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * NOTE!!! See:
 *
 *	Documentation/filesystems/caching/netfs-api.rst
 *
 * for a description of the network filesystem interface declared here.
 */

#ifndef _LINUX_FSCACHE_H
#define _LINUX_FSCACHE_H

#include <linux/fs.h>
#include <linux/netfs.h>

#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
#define __fscache_available (1)
#define fscache_available() (1)
#define fscache_volume_valid(volume) (volume)
#define fscache_cookie_valid(cookie) (cookie)
#define fscache_resources_valid(cres) ((cres)->cache_priv)
#define fscache_cookie_enabled(cookie) (cookie && !test_bit(FSCACHE_COOKIE_DISABLED, &cookie->flags))
#else
#define __fscache_available (0)
#define fscache_available() (0)
#define fscache_volume_valid(volume) (0)
#define fscache_cookie_valid(cookie) (0)
#define fscache_resources_valid(cres) (false)
#define fscache_cookie_enabled(cookie) (0)
#endif

struct fscache_cookie;

#define FSCACHE_ADV_SINGLE_CHUNK	0x01 /* The object is a single chunk of data */
#define FSCACHE_ADV_WRITE_CACHE		0x00 /* Do cache if written to locally */
#define FSCACHE_ADV_WRITE_NOCACHE	0x02 /* Don't cache if written to locally */

#define FSCACHE_INVAL_DIO_WRITE		0x01 /* Invalidate due to DIO write */

/*
 * Data object state.
 */
enum fscache_cookie_state {
	FSCACHE_COOKIE_STATE_QUIESCENT,		/* The cookie is uncached */
	FSCACHE_COOKIE_STATE_LOOKING_UP,	/* The cache object is being looked up */
	FSCACHE_COOKIE_STATE_CREATING,		/* The cache object is being created */
	FSCACHE_COOKIE_STATE_ACTIVE,		/* The cache is active, readable and writable */
	FSCACHE_COOKIE_STATE_INVALIDATING,	/* The cache is being invalidated */
	FSCACHE_COOKIE_STATE_FAILED,		/* The cache failed, withdraw to clear */
	FSCACHE_COOKIE_STATE_LRU_DISCARDING,	/* The cookie is being discarded by the LRU */
	FSCACHE_COOKIE_STATE_WITHDRAWING,	/* The cookie is being withdrawn */
	FSCACHE_COOKIE_STATE_RELINQUISHING,	/* The cookie is being relinquished */
	FSCACHE_COOKIE_STATE_DROPPED,		/* The cookie has been dropped */
#define FSCACHE_COOKIE_STATE__NR (FSCACHE_COOKIE_STATE_DROPPED + 1)
} __attribute__((mode(byte)));

/*
 * Volume representation cookie.
 */
struct fscache_volume {
	refcount_t			ref;
	atomic_t			n_cookies;	/* Number of data cookies in volume */
	atomic_t			n_accesses;	/* Number of cache accesses in progress */
	unsigned int			debug_id;
	unsigned int			key_hash;	/* Hash of key string */
	char				*key;		/* Volume ID, eg. "afs@example.com@1234" */
	struct list_head		proc_link;	/* Link in /proc/fs/fscache/volumes */
	struct hlist_bl_node		hash_link;	/* Link in hash table */
	struct work_struct		work;
	struct fscache_cache		*cache;		/* The cache in which this resides */
	void				*cache_priv;	/* Cache private data */
	spinlock_t			lock;
	unsigned long			flags;
#define FSCACHE_VOLUME_RELINQUISHED	0	/* Volume is being cleaned up */
#define FSCACHE_VOLUME_INVALIDATE	1	/* Volume was invalidated */
#define FSCACHE_VOLUME_COLLIDED_WITH	2	/* Volume was collided with */
#define FSCACHE_VOLUME_ACQUIRE_PENDING	3	/* Volume is waiting to complete acquisition */
#define FSCACHE_VOLUME_CREATING		4	/* Volume is being created on disk */
};

/*
 * Data file representation cookie.
 * - a file will only appear in one cache
 * - a request to cache a file may or may not be honoured, subject to
 *   constraints such as disk space
 * - indices are created on disk just-in-time
 */
struct fscache_cookie {
	refcount_t			ref;
	atomic_t			n_active;	/* number of active users of cookie */
	atomic_t			n_accesses;	/* Number of cache accesses in progress */
	unsigned int			debug_id;
	unsigned int			inval_counter;	/* Number of invalidations made */
	spinlock_t			lock;
	struct fscache_volume		*volume;	/* Parent volume of this file. */
	void				*cache_priv;	/* Cache-side representation */
	struct hlist_bl_node		hash_link;	/* Link in hash table */
	struct list_head		proc_link;	/* Link in proc list */
	struct list_head		commit_link;	/* Link in commit queue */
	struct work_struct		work;		/* Commit/relinq/withdraw work */
	loff_t				object_size;	/* Size of the netfs object */
	unsigned long			unused_at;	/* Time at which unused (jiffies) */
	unsigned long			flags;
#define FSCACHE_COOKIE_RELINQUISHED	0		/* T if cookie has been relinquished */
#define FSCACHE_COOKIE_RETIRED		1		/* T if this cookie has retired on relinq */
#define FSCACHE_COOKIE_IS_CACHING	2		/* T if this cookie is cached */
#define FSCACHE_COOKIE_NO_DATA_TO_READ	3		/* T if this cookie has nothing to read */
#define FSCACHE_COOKIE_NEEDS_UPDATE	4		/* T if attrs have been updated */
#define FSCACHE_COOKIE_HAS_BEEN_CACHED	5		/* T if cookie needs withdraw-on-relinq */
#define FSCACHE_COOKIE_DISABLED		6		/* T if cookie has been disabled */
#define FSCACHE_COOKIE_LOCAL_WRITE	7		/* T if cookie has been modified locally */
#define FSCACHE_COOKIE_NO_ACCESS_WAKE	8		/* T if no wake when n_accesses goes 0 */
#define FSCACHE_COOKIE_DO_RELINQUISH	9		/* T if this cookie needs relinquishment */
#define FSCACHE_COOKIE_DO_WITHDRAW	10		/* T if this cookie needs withdrawing */
#define FSCACHE_COOKIE_DO_LRU_DISCARD	11		/* T if this cookie needs LRU discard */
#define FSCACHE_COOKIE_DO_PREP_TO_WRITE	12		/* T if cookie needs write preparation */
#define FSCACHE_COOKIE_HAVE_DATA	13		/* T if this cookie has data stored */
#define FSCACHE_COOKIE_IS_HASHED	14		/* T if this cookie is hashed */

	enum fscache_cookie_state	state;
	u8				advice;		/* FSCACHE_ADV_* */
	u8				key_len;	/* Length of index key */
	u8				aux_len;	/* Length of auxiliary data */
	u32				key_hash;	/* Hash of volume, key, len */
	union {
		void			*key;		/* Index key */
		u8			inline_key[16];	/* - If the key is short enough */
	};
	union {
		void			*aux;		/* Auxiliary data */
		u8			inline_aux[8];	/* - If the aux data is short enough */
	};
};

/*
 * slow-path functions for when there is actually caching available, and the
 * netfs does actually have a valid token
 * - these are not to be called directly
 * - these are undefined symbols when FS-Cache is not configured and the
 *   optimiser takes care of not using them
 */
extern struct fscache_volume *__fscache_acquire_volume(const char *, const char *,
						       const void *, size_t);
extern void __fscache_relinquish_volume(struct fscache_volume *, const void *, bool);

extern struct fscache_cookie *__fscache_acquire_cookie(
	struct fscache_volume *,
	u8,
	const void *, size_t,
	const void *, size_t,
	loff_t);
extern void __fscache_use_cookie(struct fscache_cookie *, bool);
extern void __fscache_unuse_cookie(struct fscache_cookie *, const void *, const loff_t *);
extern void __fscache_relinquish_cookie(struct fscache_cookie *, bool);
extern void __fscache_invalidate(struct fscache_cookie *, const void *, loff_t, unsigned int);

/**
 * fscache_acquire_volume - Register a volume as desiring caching services
 * @volume_key: An identification string for the volume
 * @cache_name: The name of the cache to use (or NULL for the default)
 * @coherency_data: Piece of arbitrary coherency data to check (or NULL)
 * @coherency_len: The size of the coherency data
 *
 * Register a volume as desiring caching services if they're available.  The
 * caller must provide an identifier for the volume and may also indicate which
 * cache it should be in.  If a preexisting volume entry is found in the cache,
 * the coherency data must match otherwise the entry will be invalidated.
 *
 * Returns a cookie pointer on success, -ENOMEM if out of memory or -EBUSY if a
 * cache volume of that name is already acquired.  Note that "NULL" is a valid
 * cookie pointer and can be returned if caching is refused.
 */
static inline
struct fscache_volume *fscache_acquire_volume(const char *volume_key,
					      const char *cache_name,
					      const void *coherency_data,
					      size_t coherency_len)
{
	if (!fscache_available())
		return NULL;
	return __fscache_acquire_volume(volume_key, cache_name,
					coherency_data, coherency_len);
}

/**
 * fscache_relinquish_volume - Cease caching a volume
 * @volume: The volume cookie
 * @coherency_data: Piece of arbitrary coherency data to set (or NULL)
 * @invalidate: True if the volume should be invalidated
 *
 * Indicate that a filesystem no longer desires caching services for a volume.
 * The caller must have relinquished all file cookies prior to calling this.
 * The stored coherency data is updated.
 */
static inline
void fscache_relinquish_volume(struct fscache_volume *volume,
			       const void *coherency_data,
			       bool invalidate)
{
	if (fscache_volume_valid(volume))
		__fscache_relinquish_volume(volume, coherency_data, invalidate);
}

/**
 * fscache_acquire_cookie - Acquire a cookie to represent a cache object
 * @volume: The volume in which to locate/create this cookie
 * @advice: Advice flags (FSCACHE_COOKIE_ADV_*)
 * @index_key: The index key for this cookie
 * @index_key_len: Size of the index key
 * @aux_data: The auxiliary data for the cookie (may be NULL)
 * @aux_data_len: Size of the auxiliary data buffer
 * @object_size: The initial size of object
 *
 * Acquire a cookie to represent a data file within the given cache volume.
 *
 * See Documentation/filesystems/caching/netfs-api.rst for a complete
 * description.
 */
static inline
struct fscache_cookie *fscache_acquire_cookie(struct fscache_volume *volume,
					      u8 advice,
					      const void *index_key,
					      size_t index_key_len,
					      const void *aux_data,
					      size_t aux_data_len,
					      loff_t object_size)
{
	if (!fscache_volume_valid(volume))
		return NULL;
	return __fscache_acquire_cookie(volume, advice,
					index_key, index_key_len,
					aux_data, aux_data_len,
					object_size);
}

/**
 * fscache_use_cookie - Request usage of cookie attached to an object
 * @object: Object description
 * @will_modify: If cache is expected to be modified locally
 *
 * Request usage of the cookie attached to an object.  The caller should tell
 * the cache if the object's contents are about to be modified locally and then
 * the cache can apply the policy that has been set to handle this case.
 */
static inline void fscache_use_cookie(struct fscache_cookie *cookie,
				      bool will_modify)
{
	if (fscache_cookie_valid(cookie))
		__fscache_use_cookie(cookie, will_modify);
}

/**
 * fscache_unuse_cookie - Cease usage of cookie attached to an object
 * @object: Object description
 * @aux_data: Updated auxiliary data (or NULL)
 * @object_size: Revised size of the object (or NULL)
 *
 * Cease usage of the cookie attached to an object.  When the users count
 * reaches zero then the cookie relinquishment will be permitted to proceed.
 */
static inline void fscache_unuse_cookie(struct fscache_cookie *cookie,
					const void *aux_data,
					const loff_t *object_size)
{
	if (fscache_cookie_valid(cookie))
		__fscache_unuse_cookie(cookie, aux_data, object_size);
}

/**
 * fscache_relinquish_cookie - Return the cookie to the cache, maybe discarding
 * it
 * @cookie: The cookie being returned
 * @retire: True if the cache object the cookie represents is to be discarded
 *
 * This function returns a cookie to the cache, forcibly discarding the
 * associated cache object if retire is set to true.
 *
 * See Documentation/filesystems/caching/netfs-api.rst for a complete
 * description.
 */
static inline
void fscache_relinquish_cookie(struct fscache_cookie *cookie, bool retire)
{
	if (fscache_cookie_valid(cookie))
		__fscache_relinquish_cookie(cookie, retire);
}

/*
 * Find the auxiliary data on a cookie.
 */
static inline void *fscache_get_aux(struct fscache_cookie *cookie)
{
	if (cookie->aux_len <= sizeof(cookie->inline_aux))
		return cookie->inline_aux;
	else
		return cookie->aux;
}

/*
 * Update the auxiliary data on a cookie.
 */
static inline
void fscache_update_aux(struct fscache_cookie *cookie,
			const void *aux_data, const loff_t *object_size)
{
	void *p = fscache_get_aux(cookie);

	if (aux_data && p)
		memcpy(p, aux_data, cookie->aux_len);
	if (object_size)
		cookie->object_size = *object_size;
}

#ifdef CONFIG_FSCACHE_STATS
extern atomic_t fscache_n_updates;
#endif

static inline
void __fscache_update_cookie(struct fscache_cookie *cookie, const void *aux_data,
			     const loff_t *object_size)
{
#ifdef CONFIG_FSCACHE_STATS
	atomic_inc(&fscache_n_updates);
#endif
	fscache_update_aux(cookie, aux_data, object_size);
	smp_wmb();
	set_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &cookie->flags);
}

/**
 * fscache_invalidate - Notify cache that an object needs invalidation
 * @cookie: The cookie representing the cache object
 * @aux_data: The updated auxiliary data for the cookie (may be NULL)
 * @size: The revised size of the object.
 * @flags: Invalidation flags (FSCACHE_INVAL_*)
 *
 * Notify the cache that an object is needs to be invalidated and that it
 * should abort any retrievals or stores it is doing on the cache.  This
 * increments inval_counter on the cookie which can be used by the caller to
 * reconsider I/O requests as they complete.
 *
 * If @flags has FSCACHE_INVAL_DIO_WRITE set, this indicates that this is due
 * to a direct I/O write and will cause caching to be disabled on this cookie
 * until it is completely unused.
 *
 * See Documentation/filesystems/caching/netfs-api.rst for a complete
 * description.
 */
static inline
void fscache_invalidate(struct fscache_cookie *cookie,
			const void *aux_data, loff_t size, unsigned int flags)
{
	if (fscache_cookie_enabled(cookie))
		__fscache_invalidate(cookie, aux_data, size, flags);
}

#endif /* _LINUX_FSCACHE_H */