Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Manage high-level VFS aspects of a cache.
0003  *
0004  * Copyright (C) 2007, 2021 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/slab.h>
0009 #include <linux/statfs.h>
0010 #include <linux/namei.h>
0011 #include "internal.h"
0012 
0013 /*
0014  * Bring a cache online.
0015  */
0016 int cachefiles_add_cache(struct cachefiles_cache *cache)
0017 {
0018     struct fscache_cache *cache_cookie;
0019     struct path path;
0020     struct kstatfs stats;
0021     struct dentry *graveyard, *cachedir, *root;
0022     const struct cred *saved_cred;
0023     int ret;
0024 
0025     _enter("");
0026 
0027     cache_cookie = fscache_acquire_cache(cache->tag);
0028     if (IS_ERR(cache_cookie))
0029         return PTR_ERR(cache_cookie);
0030 
0031     /* we want to work under the module's security ID */
0032     ret = cachefiles_get_security_ID(cache);
0033     if (ret < 0)
0034         goto error_getsec;
0035 
0036     cachefiles_begin_secure(cache, &saved_cred);
0037 
0038     /* look up the directory at the root of the cache */
0039     ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path);
0040     if (ret < 0)
0041         goto error_open_root;
0042 
0043     cache->mnt = path.mnt;
0044     root = path.dentry;
0045 
0046     ret = -EINVAL;
0047     if (is_idmapped_mnt(path.mnt)) {
0048         pr_warn("File cache on idmapped mounts not supported");
0049         goto error_unsupported;
0050     }
0051 
0052     /* Check features of the backing filesystem:
0053      * - Directories must support looking up and directory creation
0054      * - We create tmpfiles to handle invalidation
0055      * - We use xattrs to store metadata
0056      * - We need to be able to query the amount of space available
0057      * - We want to be able to sync the filesystem when stopping the cache
0058      * - We use DIO to/from pages, so the blocksize mustn't be too big.
0059      */
0060     ret = -EOPNOTSUPP;
0061     if (d_is_negative(root) ||
0062         !d_backing_inode(root)->i_op->lookup ||
0063         !d_backing_inode(root)->i_op->mkdir ||
0064         !d_backing_inode(root)->i_op->tmpfile ||
0065         !(d_backing_inode(root)->i_opflags & IOP_XATTR) ||
0066         !root->d_sb->s_op->statfs ||
0067         !root->d_sb->s_op->sync_fs ||
0068         root->d_sb->s_blocksize > PAGE_SIZE)
0069         goto error_unsupported;
0070 
0071     ret = -EROFS;
0072     if (sb_rdonly(root->d_sb))
0073         goto error_unsupported;
0074 
0075     /* determine the security of the on-disk cache as this governs
0076      * security ID of files we create */
0077     ret = cachefiles_determine_cache_security(cache, root, &saved_cred);
0078     if (ret < 0)
0079         goto error_unsupported;
0080 
0081     /* get the cache size and blocksize */
0082     ret = vfs_statfs(&path, &stats);
0083     if (ret < 0)
0084         goto error_unsupported;
0085 
0086     ret = -ERANGE;
0087     if (stats.f_bsize <= 0)
0088         goto error_unsupported;
0089 
0090     ret = -EOPNOTSUPP;
0091     if (stats.f_bsize > PAGE_SIZE)
0092         goto error_unsupported;
0093 
0094     cache->bsize = stats.f_bsize;
0095     cache->bshift = ilog2(stats.f_bsize);
0096 
0097     _debug("blksize %u (shift %u)",
0098            cache->bsize, cache->bshift);
0099 
0100     _debug("size %llu, avail %llu",
0101            (unsigned long long) stats.f_blocks,
0102            (unsigned long long) stats.f_bavail);
0103 
0104     /* set up caching limits */
0105     do_div(stats.f_files, 100);
0106     cache->fstop = stats.f_files * cache->fstop_percent;
0107     cache->fcull = stats.f_files * cache->fcull_percent;
0108     cache->frun  = stats.f_files * cache->frun_percent;
0109 
0110     _debug("limits {%llu,%llu,%llu} files",
0111            (unsigned long long) cache->frun,
0112            (unsigned long long) cache->fcull,
0113            (unsigned long long) cache->fstop);
0114 
0115     do_div(stats.f_blocks, 100);
0116     cache->bstop = stats.f_blocks * cache->bstop_percent;
0117     cache->bcull = stats.f_blocks * cache->bcull_percent;
0118     cache->brun  = stats.f_blocks * cache->brun_percent;
0119 
0120     _debug("limits {%llu,%llu,%llu} blocks",
0121            (unsigned long long) cache->brun,
0122            (unsigned long long) cache->bcull,
0123            (unsigned long long) cache->bstop);
0124 
0125     /* get the cache directory and check its type */
0126     cachedir = cachefiles_get_directory(cache, root, "cache", NULL);
0127     if (IS_ERR(cachedir)) {
0128         ret = PTR_ERR(cachedir);
0129         goto error_unsupported;
0130     }
0131 
0132     cache->store = cachedir;
0133 
0134     /* get the graveyard directory */
0135     graveyard = cachefiles_get_directory(cache, root, "graveyard", NULL);
0136     if (IS_ERR(graveyard)) {
0137         ret = PTR_ERR(graveyard);
0138         goto error_unsupported;
0139     }
0140 
0141     cache->graveyard = graveyard;
0142     cache->cache = cache_cookie;
0143 
0144     ret = fscache_add_cache(cache_cookie, &cachefiles_cache_ops, cache);
0145     if (ret < 0)
0146         goto error_add_cache;
0147 
0148     /* done */
0149     set_bit(CACHEFILES_READY, &cache->flags);
0150     dput(root);
0151 
0152     pr_info("File cache on %s registered\n", cache_cookie->name);
0153 
0154     /* check how much space the cache has */
0155     cachefiles_has_space(cache, 0, 0, cachefiles_has_space_check);
0156     cachefiles_end_secure(cache, saved_cred);
0157     _leave(" = 0 [%px]", cache->cache);
0158     return 0;
0159 
0160 error_add_cache:
0161     cachefiles_put_directory(cache->graveyard);
0162     cache->graveyard = NULL;
0163 error_unsupported:
0164     cachefiles_put_directory(cache->store);
0165     cache->store = NULL;
0166     mntput(cache->mnt);
0167     cache->mnt = NULL;
0168     dput(root);
0169 error_open_root:
0170     cachefiles_end_secure(cache, saved_cred);
0171 error_getsec:
0172     fscache_relinquish_cache(cache_cookie);
0173     cache->cache = NULL;
0174     pr_err("Failed to register: %d\n", ret);
0175     return ret;
0176 }
0177 
0178 /*
0179  * See if we have space for a number of pages and/or a number of files in the
0180  * cache
0181  */
0182 int cachefiles_has_space(struct cachefiles_cache *cache,
0183              unsigned fnr, unsigned bnr,
0184              enum cachefiles_has_space_for reason)
0185 {
0186     struct kstatfs stats;
0187     u64 b_avail, b_writing;
0188     int ret;
0189 
0190     struct path path = {
0191         .mnt    = cache->mnt,
0192         .dentry = cache->mnt->mnt_root,
0193     };
0194 
0195     //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u",
0196     //       (unsigned long long) cache->frun,
0197     //       (unsigned long long) cache->fcull,
0198     //       (unsigned long long) cache->fstop,
0199     //       (unsigned long long) cache->brun,
0200     //       (unsigned long long) cache->bcull,
0201     //       (unsigned long long) cache->bstop,
0202     //       fnr, bnr);
0203 
0204     /* find out how many pages of blockdev are available */
0205     memset(&stats, 0, sizeof(stats));
0206 
0207     ret = vfs_statfs(&path, &stats);
0208     if (ret < 0) {
0209         trace_cachefiles_vfs_error(NULL, d_inode(path.dentry), ret,
0210                        cachefiles_trace_statfs_error);
0211         if (ret == -EIO)
0212             cachefiles_io_error(cache, "statfs failed");
0213         _leave(" = %d", ret);
0214         return ret;
0215     }
0216 
0217     b_avail = stats.f_bavail;
0218     b_writing = atomic_long_read(&cache->b_writing);
0219     if (b_avail > b_writing)
0220         b_avail -= b_writing;
0221     else
0222         b_avail = 0;
0223 
0224     //_debug("avail %llu,%llu",
0225     //       (unsigned long long)stats.f_ffree,
0226     //       (unsigned long long)b_avail);
0227 
0228     /* see if there is sufficient space */
0229     if (stats.f_ffree > fnr)
0230         stats.f_ffree -= fnr;
0231     else
0232         stats.f_ffree = 0;
0233 
0234     if (b_avail > bnr)
0235         b_avail -= bnr;
0236     else
0237         b_avail = 0;
0238 
0239     ret = -ENOBUFS;
0240     if (stats.f_ffree < cache->fstop ||
0241         b_avail < cache->bstop)
0242         goto stop_and_begin_cull;
0243 
0244     ret = 0;
0245     if (stats.f_ffree < cache->fcull ||
0246         b_avail < cache->bcull)
0247         goto begin_cull;
0248 
0249     if (test_bit(CACHEFILES_CULLING, &cache->flags) &&
0250         stats.f_ffree >= cache->frun &&
0251         b_avail >= cache->brun &&
0252         test_and_clear_bit(CACHEFILES_CULLING, &cache->flags)
0253         ) {
0254         _debug("cease culling");
0255         cachefiles_state_changed(cache);
0256     }
0257 
0258     //_leave(" = 0");
0259     return 0;
0260 
0261 stop_and_begin_cull:
0262     switch (reason) {
0263     case cachefiles_has_space_for_write:
0264         fscache_count_no_write_space();
0265         break;
0266     case cachefiles_has_space_for_create:
0267         fscache_count_no_create_space();
0268         break;
0269     default:
0270         break;
0271     }
0272 begin_cull:
0273     if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) {
0274         _debug("### CULL CACHE ###");
0275         cachefiles_state_changed(cache);
0276     }
0277 
0278     _leave(" = %d", ret);
0279     return ret;
0280 }
0281 
0282 /*
0283  * Mark all the objects as being out of service and queue them all for cleanup.
0284  */
0285 static void cachefiles_withdraw_objects(struct cachefiles_cache *cache)
0286 {
0287     struct cachefiles_object *object;
0288     unsigned int count = 0;
0289 
0290     _enter("");
0291 
0292     spin_lock(&cache->object_list_lock);
0293 
0294     while (!list_empty(&cache->object_list)) {
0295         object = list_first_entry(&cache->object_list,
0296                       struct cachefiles_object, cache_link);
0297         cachefiles_see_object(object, cachefiles_obj_see_withdrawal);
0298         list_del_init(&object->cache_link);
0299         fscache_withdraw_cookie(object->cookie);
0300         count++;
0301         if ((count & 63) == 0) {
0302             spin_unlock(&cache->object_list_lock);
0303             cond_resched();
0304             spin_lock(&cache->object_list_lock);
0305         }
0306     }
0307 
0308     spin_unlock(&cache->object_list_lock);
0309     _leave(" [%u objs]", count);
0310 }
0311 
0312 /*
0313  * Withdraw volumes.
0314  */
0315 static void cachefiles_withdraw_volumes(struct cachefiles_cache *cache)
0316 {
0317     _enter("");
0318 
0319     for (;;) {
0320         struct cachefiles_volume *volume = NULL;
0321 
0322         spin_lock(&cache->object_list_lock);
0323         if (!list_empty(&cache->volumes)) {
0324             volume = list_first_entry(&cache->volumes,
0325                           struct cachefiles_volume, cache_link);
0326             list_del_init(&volume->cache_link);
0327         }
0328         spin_unlock(&cache->object_list_lock);
0329         if (!volume)
0330             break;
0331 
0332         cachefiles_withdraw_volume(volume);
0333     }
0334 
0335     _leave("");
0336 }
0337 
0338 /*
0339  * Sync a cache to backing disk.
0340  */
0341 static void cachefiles_sync_cache(struct cachefiles_cache *cache)
0342 {
0343     const struct cred *saved_cred;
0344     int ret;
0345 
0346     _enter("%s", cache->cache->name);
0347 
0348     /* make sure all pages pinned by operations on behalf of the netfs are
0349      * written to disc */
0350     cachefiles_begin_secure(cache, &saved_cred);
0351     down_read(&cache->mnt->mnt_sb->s_umount);
0352     ret = sync_filesystem(cache->mnt->mnt_sb);
0353     up_read(&cache->mnt->mnt_sb->s_umount);
0354     cachefiles_end_secure(cache, saved_cred);
0355 
0356     if (ret == -EIO)
0357         cachefiles_io_error(cache,
0358                     "Attempt to sync backing fs superblock returned error %d",
0359                     ret);
0360 }
0361 
0362 /*
0363  * Withdraw cache objects.
0364  */
0365 void cachefiles_withdraw_cache(struct cachefiles_cache *cache)
0366 {
0367     struct fscache_cache *fscache = cache->cache;
0368 
0369     pr_info("File cache on %s unregistering\n", fscache->name);
0370 
0371     fscache_withdraw_cache(fscache);
0372 
0373     /* we now have to destroy all the active objects pertaining to this
0374      * cache - which we do by passing them off to thread pool to be
0375      * disposed of */
0376     cachefiles_withdraw_objects(cache);
0377     fscache_wait_for_objects(fscache);
0378 
0379     cachefiles_withdraw_volumes(cache);
0380     cachefiles_sync_cache(cache);
0381     cache->cache = NULL;
0382     fscache_relinquish_cache(fscache);
0383 }