0001
0002
0003
0004
0005
0006
0007
0008 #define FSCACHE_DEBUG_LEVEL CACHE
0009 #include <linux/export.h>
0010 #include <linux/slab.h>
0011 #include "internal.h"
0012
0013 static LIST_HEAD(fscache_caches);
0014 DECLARE_RWSEM(fscache_addremove_sem);
0015 EXPORT_SYMBOL(fscache_addremove_sem);
0016 DECLARE_WAIT_QUEUE_HEAD(fscache_clearance_waiters);
0017 EXPORT_SYMBOL(fscache_clearance_waiters);
0018
0019 static atomic_t fscache_cache_debug_id;
0020
0021
0022
0023
0024 static struct fscache_cache *fscache_alloc_cache(const char *name)
0025 {
0026 struct fscache_cache *cache;
0027
0028 cache = kzalloc(sizeof(*cache), GFP_KERNEL);
0029 if (cache) {
0030 if (name) {
0031 cache->name = kstrdup(name, GFP_KERNEL);
0032 if (!cache->name) {
0033 kfree(cache);
0034 return NULL;
0035 }
0036 }
0037 refcount_set(&cache->ref, 1);
0038 INIT_LIST_HEAD(&cache->cache_link);
0039 cache->debug_id = atomic_inc_return(&fscache_cache_debug_id);
0040 }
0041 return cache;
0042 }
0043
0044 static bool fscache_get_cache_maybe(struct fscache_cache *cache,
0045 enum fscache_cache_trace where)
0046 {
0047 bool success;
0048 int ref;
0049
0050 success = __refcount_inc_not_zero(&cache->ref, &ref);
0051 if (success)
0052 trace_fscache_cache(cache->debug_id, ref + 1, where);
0053 return success;
0054 }
0055
0056
0057
0058
0059 struct fscache_cache *fscache_lookup_cache(const char *name, bool is_cache)
0060 {
0061 struct fscache_cache *candidate, *cache, *unnamed = NULL;
0062
0063
0064 down_read(&fscache_addremove_sem);
0065
0066 list_for_each_entry(cache, &fscache_caches, cache_link) {
0067 if (cache->name && name && strcmp(cache->name, name) == 0 &&
0068 fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0069 goto got_cache_r;
0070 if (!cache->name && !name &&
0071 fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0072 goto got_cache_r;
0073 }
0074
0075 if (!name) {
0076 list_for_each_entry(cache, &fscache_caches, cache_link) {
0077 if (cache->name &&
0078 fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0079 goto got_cache_r;
0080 }
0081 }
0082
0083 up_read(&fscache_addremove_sem);
0084
0085
0086 candidate = fscache_alloc_cache(name);
0087 if (!candidate)
0088 return ERR_PTR(-ENOMEM);
0089
0090
0091 down_write(&fscache_addremove_sem);
0092
0093 list_for_each_entry(cache, &fscache_caches, cache_link) {
0094 if (cache->name && name && strcmp(cache->name, name) == 0 &&
0095 fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0096 goto got_cache_w;
0097 if (!cache->name) {
0098 unnamed = cache;
0099 if (!name &&
0100 fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0101 goto got_cache_w;
0102 }
0103 }
0104
0105 if (unnamed && is_cache &&
0106 fscache_get_cache_maybe(unnamed, fscache_cache_get_acquire))
0107 goto use_unnamed_cache;
0108
0109 if (!name) {
0110 list_for_each_entry(cache, &fscache_caches, cache_link) {
0111 if (cache->name &&
0112 fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0113 goto got_cache_w;
0114 }
0115 }
0116
0117 list_add_tail(&candidate->cache_link, &fscache_caches);
0118 trace_fscache_cache(candidate->debug_id,
0119 refcount_read(&candidate->ref),
0120 fscache_cache_new_acquire);
0121 up_write(&fscache_addremove_sem);
0122 return candidate;
0123
0124 got_cache_r:
0125 up_read(&fscache_addremove_sem);
0126 return cache;
0127 use_unnamed_cache:
0128 cache = unnamed;
0129 cache->name = candidate->name;
0130 candidate->name = NULL;
0131 got_cache_w:
0132 up_write(&fscache_addremove_sem);
0133 kfree(candidate->name);
0134 kfree(candidate);
0135 return cache;
0136 }
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 struct fscache_cache *fscache_acquire_cache(const char *name)
0150 {
0151 struct fscache_cache *cache;
0152
0153 ASSERT(name);
0154 cache = fscache_lookup_cache(name, true);
0155 if (IS_ERR(cache))
0156 return cache;
0157
0158 if (!fscache_set_cache_state_maybe(cache,
0159 FSCACHE_CACHE_IS_NOT_PRESENT,
0160 FSCACHE_CACHE_IS_PREPARING)) {
0161 pr_warn("Cache tag %s in use\n", name);
0162 fscache_put_cache(cache, fscache_cache_put_cache);
0163 return ERR_PTR(-EBUSY);
0164 }
0165
0166 return cache;
0167 }
0168 EXPORT_SYMBOL(fscache_acquire_cache);
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179 void fscache_put_cache(struct fscache_cache *cache,
0180 enum fscache_cache_trace where)
0181 {
0182 unsigned int debug_id = cache->debug_id;
0183 bool zero;
0184 int ref;
0185
0186 if (IS_ERR_OR_NULL(cache))
0187 return;
0188
0189 zero = __refcount_dec_and_test(&cache->ref, &ref);
0190 trace_fscache_cache(debug_id, ref - 1, where);
0191
0192 if (zero) {
0193 down_write(&fscache_addremove_sem);
0194 list_del_init(&cache->cache_link);
0195 up_write(&fscache_addremove_sem);
0196 kfree(cache->name);
0197 kfree(cache);
0198 }
0199 }
0200
0201
0202
0203
0204
0205
0206
0207
0208 void fscache_relinquish_cache(struct fscache_cache *cache)
0209 {
0210 enum fscache_cache_trace where =
0211 (cache->state == FSCACHE_CACHE_IS_PREPARING) ?
0212 fscache_cache_put_prep_failed :
0213 fscache_cache_put_relinquish;
0214
0215 cache->ops = NULL;
0216 cache->cache_priv = NULL;
0217 fscache_set_cache_state(cache, FSCACHE_CACHE_IS_NOT_PRESENT);
0218 fscache_put_cache(cache, where);
0219 }
0220 EXPORT_SYMBOL(fscache_relinquish_cache);
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233 int fscache_add_cache(struct fscache_cache *cache,
0234 const struct fscache_cache_ops *ops,
0235 void *cache_priv)
0236 {
0237 int n_accesses;
0238
0239 _enter("{%s,%s}", ops->name, cache->name);
0240
0241 BUG_ON(fscache_cache_state(cache) != FSCACHE_CACHE_IS_PREPARING);
0242
0243
0244
0245
0246
0247 n_accesses = atomic_inc_return(&cache->n_accesses);
0248 trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
0249 n_accesses, fscache_access_cache_pin);
0250
0251 down_write(&fscache_addremove_sem);
0252
0253 cache->ops = ops;
0254 cache->cache_priv = cache_priv;
0255 fscache_set_cache_state(cache, FSCACHE_CACHE_IS_ACTIVE);
0256
0257 up_write(&fscache_addremove_sem);
0258 pr_notice("Cache \"%s\" added (type %s)\n", cache->name, ops->name);
0259 _leave(" = 0 [%s]", cache->name);
0260 return 0;
0261 }
0262 EXPORT_SYMBOL(fscache_add_cache);
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288 bool fscache_begin_cache_access(struct fscache_cache *cache, enum fscache_access_trace why)
0289 {
0290 int n_accesses;
0291
0292 if (!fscache_cache_is_live(cache))
0293 return false;
0294
0295 n_accesses = atomic_inc_return(&cache->n_accesses);
0296 smp_mb__after_atomic();
0297 trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
0298 n_accesses, why);
0299 if (!fscache_cache_is_live(cache)) {
0300 fscache_end_cache_access(cache, fscache_access_unlive);
0301 return false;
0302 }
0303 return true;
0304 }
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314 void fscache_end_cache_access(struct fscache_cache *cache, enum fscache_access_trace why)
0315 {
0316 int n_accesses;
0317
0318 smp_mb__before_atomic();
0319 n_accesses = atomic_dec_return(&cache->n_accesses);
0320 trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
0321 n_accesses, why);
0322 if (n_accesses == 0)
0323 wake_up_var(&cache->n_accesses);
0324 }
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336 void fscache_io_error(struct fscache_cache *cache)
0337 {
0338 if (fscache_set_cache_state_maybe(cache,
0339 FSCACHE_CACHE_IS_ACTIVE,
0340 FSCACHE_CACHE_GOT_IOERROR))
0341 pr_err("Cache '%s' stopped due to I/O error\n",
0342 cache->name);
0343 }
0344 EXPORT_SYMBOL(fscache_io_error);
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354 void fscache_withdraw_cache(struct fscache_cache *cache)
0355 {
0356 int n_accesses;
0357
0358 pr_notice("Withdrawing cache \"%s\" (%u objs)\n",
0359 cache->name, atomic_read(&cache->object_count));
0360
0361 fscache_set_cache_state(cache, FSCACHE_CACHE_IS_WITHDRAWN);
0362
0363
0364 n_accesses = atomic_dec_return(&cache->n_accesses);
0365 trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
0366 n_accesses, fscache_access_cache_unpin);
0367
0368 wait_var_event(&cache->n_accesses,
0369 atomic_read(&cache->n_accesses) == 0);
0370 }
0371 EXPORT_SYMBOL(fscache_withdraw_cache);
0372
0373 #ifdef CONFIG_PROC_FS
0374 static const char fscache_cache_states[NR__FSCACHE_CACHE_STATE] = "-PAEW";
0375
0376
0377
0378
0379 static int fscache_caches_seq_show(struct seq_file *m, void *v)
0380 {
0381 struct fscache_cache *cache;
0382
0383 if (v == &fscache_caches) {
0384 seq_puts(m,
0385 "CACHE REF VOLS OBJS ACCES S NAME\n"
0386 "======== ===== ===== ===== ===== = ===============\n"
0387 );
0388 return 0;
0389 }
0390
0391 cache = list_entry(v, struct fscache_cache, cache_link);
0392 seq_printf(m,
0393 "%08x %5d %5d %5d %5d %c %s\n",
0394 cache->debug_id,
0395 refcount_read(&cache->ref),
0396 atomic_read(&cache->n_volumes),
0397 atomic_read(&cache->object_count),
0398 atomic_read(&cache->n_accesses),
0399 fscache_cache_states[cache->state],
0400 cache->name ?: "-");
0401 return 0;
0402 }
0403
0404 static void *fscache_caches_seq_start(struct seq_file *m, loff_t *_pos)
0405 __acquires(fscache_addremove_sem)
0406 {
0407 down_read(&fscache_addremove_sem);
0408 return seq_list_start_head(&fscache_caches, *_pos);
0409 }
0410
0411 static void *fscache_caches_seq_next(struct seq_file *m, void *v, loff_t *_pos)
0412 {
0413 return seq_list_next(v, &fscache_caches, _pos);
0414 }
0415
0416 static void fscache_caches_seq_stop(struct seq_file *m, void *v)
0417 __releases(fscache_addremove_sem)
0418 {
0419 up_read(&fscache_addremove_sem);
0420 }
0421
0422 const struct seq_operations fscache_caches_seq_ops = {
0423 .start = fscache_caches_seq_start,
0424 .next = fscache_caches_seq_next,
0425 .stop = fscache_caches_seq_stop,
0426 .show = fscache_caches_seq_show,
0427 };
0428 #endif