1 // SPDX-License-Identifier: GPL-2.0-or-later 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Manage high-level VFS aspects of a cache. 2 /* Manage high-level VFS aspects of a cache. 3 * 3 * 4 * Copyright (C) 2007, 2021 Red Hat, Inc. All 4 * Copyright (C) 2007, 2021 Red Hat, Inc. All Rights Reserved. 5 * Written by David Howells (dhowells@redhat.c 5 * Written by David Howells (dhowells@redhat.com) 6 */ 6 */ 7 7 8 #include <linux/slab.h> 8 #include <linux/slab.h> 9 #include <linux/statfs.h> 9 #include <linux/statfs.h> 10 #include <linux/namei.h> 10 #include <linux/namei.h> 11 #include <trace/events/fscache.h> << 12 #include "internal.h" 11 #include "internal.h" 13 12 14 /* 13 /* 15 * Bring a cache online. 14 * Bring a cache online. 16 */ 15 */ 17 int cachefiles_add_cache(struct cachefiles_cac 16 int cachefiles_add_cache(struct cachefiles_cache *cache) 18 { 17 { 19 struct fscache_cache *cache_cookie; 18 struct fscache_cache *cache_cookie; 20 struct path path; 19 struct path path; 21 struct kstatfs stats; 20 struct kstatfs stats; 22 struct dentry *graveyard, *cachedir, * 21 struct dentry *graveyard, *cachedir, *root; 23 const struct cred *saved_cred; 22 const struct cred *saved_cred; 24 int ret; 23 int ret; 25 24 26 _enter(""); 25 _enter(""); 27 26 28 cache_cookie = fscache_acquire_cache(c 27 cache_cookie = fscache_acquire_cache(cache->tag); 29 if (IS_ERR(cache_cookie)) 28 if (IS_ERR(cache_cookie)) 30 return PTR_ERR(cache_cookie); 29 return PTR_ERR(cache_cookie); 31 30 32 /* we want to work under the module's 31 /* we want to work under the module's security ID */ 33 ret = cachefiles_get_security_ID(cache 32 ret = cachefiles_get_security_ID(cache); 34 if (ret < 0) 33 if (ret < 0) 35 goto error_getsec; 34 goto error_getsec; 36 35 37 cachefiles_begin_secure(cache, &saved_ 36 cachefiles_begin_secure(cache, &saved_cred); 38 37 39 /* look up the directory at the root o 38 /* look up the directory at the root of the cache */ 40 ret = kern_path(cache->rootdirname, LO 39 ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path); 41 if (ret < 0) 40 if (ret < 0) 42 goto error_open_root; 41 goto error_open_root; 43 42 44 cache->mnt = path.mnt; 43 cache->mnt = path.mnt; 45 root = path.dentry; 44 root = path.dentry; 46 45 47 ret = -EINVAL; 46 ret = -EINVAL; 48 if (is_idmapped_mnt(path.mnt)) { 47 if (is_idmapped_mnt(path.mnt)) { 49 pr_warn("File cache on idmappe 48 pr_warn("File cache on idmapped mounts not supported"); 50 goto error_unsupported; 49 goto error_unsupported; 51 } 50 } 52 51 53 /* Check features of the backing files 52 /* Check features of the backing filesystem: 54 * - Directories must support looking 53 * - Directories must support looking up and directory creation 55 * - We create tmpfiles to handle inva 54 * - We create tmpfiles to handle invalidation 56 * - We use xattrs to store metadata 55 * - We use xattrs to store metadata 57 * - We need to be able to query the a 56 * - We need to be able to query the amount of space available 58 * - We want to be able to sync the fi 57 * - We want to be able to sync the filesystem when stopping the cache 59 * - We use DIO to/from pages, so the 58 * - We use DIO to/from pages, so the blocksize mustn't be too big. 60 */ 59 */ 61 ret = -EOPNOTSUPP; 60 ret = -EOPNOTSUPP; 62 if (d_is_negative(root) || 61 if (d_is_negative(root) || 63 !d_backing_inode(root)->i_op->look 62 !d_backing_inode(root)->i_op->lookup || 64 !d_backing_inode(root)->i_op->mkdi 63 !d_backing_inode(root)->i_op->mkdir || 65 !d_backing_inode(root)->i_op->tmpf 64 !d_backing_inode(root)->i_op->tmpfile || 66 !(d_backing_inode(root)->i_opflags 65 !(d_backing_inode(root)->i_opflags & IOP_XATTR) || 67 !root->d_sb->s_op->statfs || 66 !root->d_sb->s_op->statfs || 68 !root->d_sb->s_op->sync_fs || 67 !root->d_sb->s_op->sync_fs || 69 root->d_sb->s_blocksize > PAGE_SIZ 68 root->d_sb->s_blocksize > PAGE_SIZE) 70 goto error_unsupported; 69 goto error_unsupported; 71 70 72 ret = -EROFS; 71 ret = -EROFS; 73 if (sb_rdonly(root->d_sb)) 72 if (sb_rdonly(root->d_sb)) 74 goto error_unsupported; 73 goto error_unsupported; 75 74 76 /* determine the security of the on-di 75 /* determine the security of the on-disk cache as this governs 77 * security ID of files we create */ 76 * security ID of files we create */ 78 ret = cachefiles_determine_cache_secur 77 ret = cachefiles_determine_cache_security(cache, root, &saved_cred); 79 if (ret < 0) 78 if (ret < 0) 80 goto error_unsupported; 79 goto error_unsupported; 81 80 82 /* get the cache size and blocksize */ 81 /* get the cache size and blocksize */ 83 ret = vfs_statfs(&path, &stats); 82 ret = vfs_statfs(&path, &stats); 84 if (ret < 0) 83 if (ret < 0) 85 goto error_unsupported; 84 goto error_unsupported; 86 85 87 ret = -ERANGE; 86 ret = -ERANGE; 88 if (stats.f_bsize <= 0) 87 if (stats.f_bsize <= 0) 89 goto error_unsupported; 88 goto error_unsupported; 90 89 91 ret = -EOPNOTSUPP; 90 ret = -EOPNOTSUPP; 92 if (stats.f_bsize > PAGE_SIZE) 91 if (stats.f_bsize > PAGE_SIZE) 93 goto error_unsupported; 92 goto error_unsupported; 94 93 95 cache->bsize = stats.f_bsize; 94 cache->bsize = stats.f_bsize; 96 cache->bshift = ilog2(stats.f_bsize); 95 cache->bshift = ilog2(stats.f_bsize); 97 96 98 _debug("blksize %u (shift %u)", 97 _debug("blksize %u (shift %u)", 99 cache->bsize, cache->bshift); 98 cache->bsize, cache->bshift); 100 99 101 _debug("size %llu, avail %llu", 100 _debug("size %llu, avail %llu", 102 (unsigned long long) stats.f_bl 101 (unsigned long long) stats.f_blocks, 103 (unsigned long long) stats.f_ba 102 (unsigned long long) stats.f_bavail); 104 103 105 /* set up caching limits */ 104 /* set up caching limits */ 106 do_div(stats.f_files, 100); 105 do_div(stats.f_files, 100); 107 cache->fstop = stats.f_files * cache-> 106 cache->fstop = stats.f_files * cache->fstop_percent; 108 cache->fcull = stats.f_files * cache-> 107 cache->fcull = stats.f_files * cache->fcull_percent; 109 cache->frun = stats.f_files * cache-> 108 cache->frun = stats.f_files * cache->frun_percent; 110 109 111 _debug("limits {%llu,%llu,%llu} files" 110 _debug("limits {%llu,%llu,%llu} files", 112 (unsigned long long) cache->fru 111 (unsigned long long) cache->frun, 113 (unsigned long long) cache->fcu 112 (unsigned long long) cache->fcull, 114 (unsigned long long) cache->fst 113 (unsigned long long) cache->fstop); 115 114 116 do_div(stats.f_blocks, 100); 115 do_div(stats.f_blocks, 100); 117 cache->bstop = stats.f_blocks * cache- 116 cache->bstop = stats.f_blocks * cache->bstop_percent; 118 cache->bcull = stats.f_blocks * cache- 117 cache->bcull = stats.f_blocks * cache->bcull_percent; 119 cache->brun = stats.f_blocks * cache- 118 cache->brun = stats.f_blocks * cache->brun_percent; 120 119 121 _debug("limits {%llu,%llu,%llu} blocks 120 _debug("limits {%llu,%llu,%llu} blocks", 122 (unsigned long long) cache->bru 121 (unsigned long long) cache->brun, 123 (unsigned long long) cache->bcu 122 (unsigned long long) cache->bcull, 124 (unsigned long long) cache->bst 123 (unsigned long long) cache->bstop); 125 124 126 /* get the cache directory and check i 125 /* get the cache directory and check its type */ 127 cachedir = cachefiles_get_directory(ca 126 cachedir = cachefiles_get_directory(cache, root, "cache", NULL); 128 if (IS_ERR(cachedir)) { 127 if (IS_ERR(cachedir)) { 129 ret = PTR_ERR(cachedir); 128 ret = PTR_ERR(cachedir); 130 goto error_unsupported; 129 goto error_unsupported; 131 } 130 } 132 131 133 cache->store = cachedir; 132 cache->store = cachedir; 134 133 135 /* get the graveyard directory */ 134 /* get the graveyard directory */ 136 graveyard = cachefiles_get_directory(c 135 graveyard = cachefiles_get_directory(cache, root, "graveyard", NULL); 137 if (IS_ERR(graveyard)) { 136 if (IS_ERR(graveyard)) { 138 ret = PTR_ERR(graveyard); 137 ret = PTR_ERR(graveyard); 139 goto error_unsupported; 138 goto error_unsupported; 140 } 139 } 141 140 142 cache->graveyard = graveyard; 141 cache->graveyard = graveyard; 143 cache->cache = cache_cookie; 142 cache->cache = cache_cookie; 144 143 145 ret = fscache_add_cache(cache_cookie, 144 ret = fscache_add_cache(cache_cookie, &cachefiles_cache_ops, cache); 146 if (ret < 0) 145 if (ret < 0) 147 goto error_add_cache; 146 goto error_add_cache; 148 147 149 /* done */ 148 /* done */ 150 set_bit(CACHEFILES_READY, &cache->flag 149 set_bit(CACHEFILES_READY, &cache->flags); 151 dput(root); 150 dput(root); 152 151 153 pr_info("File cache on %s registered\n 152 pr_info("File cache on %s registered\n", cache_cookie->name); 154 153 155 /* check how much space the cache has 154 /* check how much space the cache has */ 156 cachefiles_has_space(cache, 0, 0, cach 155 cachefiles_has_space(cache, 0, 0, cachefiles_has_space_check); 157 cachefiles_end_secure(cache, saved_cre 156 cachefiles_end_secure(cache, saved_cred); 158 _leave(" = 0 [%px]", cache->cache); 157 _leave(" = 0 [%px]", cache->cache); 159 return 0; 158 return 0; 160 159 161 error_add_cache: 160 error_add_cache: 162 cachefiles_put_directory(cache->gravey 161 cachefiles_put_directory(cache->graveyard); 163 cache->graveyard = NULL; 162 cache->graveyard = NULL; 164 error_unsupported: 163 error_unsupported: 165 cachefiles_put_directory(cache->store) 164 cachefiles_put_directory(cache->store); 166 cache->store = NULL; 165 cache->store = NULL; 167 mntput(cache->mnt); 166 mntput(cache->mnt); 168 cache->mnt = NULL; 167 cache->mnt = NULL; 169 dput(root); 168 dput(root); 170 error_open_root: 169 error_open_root: 171 cachefiles_end_secure(cache, saved_cre 170 cachefiles_end_secure(cache, saved_cred); 172 put_cred(cache->cache_cred); 171 put_cred(cache->cache_cred); 173 cache->cache_cred = NULL; 172 cache->cache_cred = NULL; 174 error_getsec: 173 error_getsec: 175 fscache_relinquish_cache(cache_cookie) 174 fscache_relinquish_cache(cache_cookie); 176 cache->cache = NULL; 175 cache->cache = NULL; 177 pr_err("Failed to register: %d\n", ret 176 pr_err("Failed to register: %d\n", ret); 178 return ret; 177 return ret; 179 } 178 } 180 179 181 /* 180 /* 182 * See if we have space for a number of pages 181 * See if we have space for a number of pages and/or a number of files in the 183 * cache 182 * cache 184 */ 183 */ 185 int cachefiles_has_space(struct cachefiles_cac 184 int cachefiles_has_space(struct cachefiles_cache *cache, 186 unsigned fnr, unsigne 185 unsigned fnr, unsigned bnr, 187 enum cachefiles_has_s 186 enum cachefiles_has_space_for reason) 188 { 187 { 189 struct kstatfs stats; 188 struct kstatfs stats; 190 u64 b_avail, b_writing; 189 u64 b_avail, b_writing; 191 int ret; 190 int ret; 192 191 193 struct path path = { 192 struct path path = { 194 .mnt = cache->mnt, 193 .mnt = cache->mnt, 195 .dentry = cache->mnt->mnt_root 194 .dentry = cache->mnt->mnt_root, 196 }; 195 }; 197 196 198 //_enter("{%llu,%llu,%llu,%llu,%llu,%l 197 //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u", 199 // (unsigned long long) cache->f 198 // (unsigned long long) cache->frun, 200 // (unsigned long long) cache->f 199 // (unsigned long long) cache->fcull, 201 // (unsigned long long) cache->f 200 // (unsigned long long) cache->fstop, 202 // (unsigned long long) cache->b 201 // (unsigned long long) cache->brun, 203 // (unsigned long long) cache->b 202 // (unsigned long long) cache->bcull, 204 // (unsigned long long) cache->b 203 // (unsigned long long) cache->bstop, 205 // fnr, bnr); 204 // fnr, bnr); 206 205 207 /* find out how many pages of blockdev 206 /* find out how many pages of blockdev are available */ 208 memset(&stats, 0, sizeof(stats)); 207 memset(&stats, 0, sizeof(stats)); 209 208 210 ret = vfs_statfs(&path, &stats); 209 ret = vfs_statfs(&path, &stats); 211 if (ret < 0) { 210 if (ret < 0) { 212 trace_cachefiles_vfs_error(NUL 211 trace_cachefiles_vfs_error(NULL, d_inode(path.dentry), ret, 213 cac 212 cachefiles_trace_statfs_error); 214 if (ret == -EIO) 213 if (ret == -EIO) 215 cachefiles_io_error(ca 214 cachefiles_io_error(cache, "statfs failed"); 216 _leave(" = %d", ret); 215 _leave(" = %d", ret); 217 return ret; 216 return ret; 218 } 217 } 219 218 220 b_avail = stats.f_bavail; 219 b_avail = stats.f_bavail; 221 b_writing = atomic_long_read(&cache->b 220 b_writing = atomic_long_read(&cache->b_writing); 222 if (b_avail > b_writing) 221 if (b_avail > b_writing) 223 b_avail -= b_writing; 222 b_avail -= b_writing; 224 else 223 else 225 b_avail = 0; 224 b_avail = 0; 226 225 227 //_debug("avail %llu,%llu", 226 //_debug("avail %llu,%llu", 228 // (unsigned long long)stats.f_f 227 // (unsigned long long)stats.f_ffree, 229 // (unsigned long long)b_avail); 228 // (unsigned long long)b_avail); 230 229 231 /* see if there is sufficient space */ 230 /* see if there is sufficient space */ 232 if (stats.f_ffree > fnr) 231 if (stats.f_ffree > fnr) 233 stats.f_ffree -= fnr; 232 stats.f_ffree -= fnr; 234 else 233 else 235 stats.f_ffree = 0; 234 stats.f_ffree = 0; 236 235 237 if (b_avail > bnr) 236 if (b_avail > bnr) 238 b_avail -= bnr; 237 b_avail -= bnr; 239 else 238 else 240 b_avail = 0; 239 b_avail = 0; 241 240 242 ret = -ENOBUFS; 241 ret = -ENOBUFS; 243 if (stats.f_ffree < cache->fstop || 242 if (stats.f_ffree < cache->fstop || 244 b_avail < cache->bstop) 243 b_avail < cache->bstop) 245 goto stop_and_begin_cull; 244 goto stop_and_begin_cull; 246 245 247 ret = 0; 246 ret = 0; 248 if (stats.f_ffree < cache->fcull || 247 if (stats.f_ffree < cache->fcull || 249 b_avail < cache->bcull) 248 b_avail < cache->bcull) 250 goto begin_cull; 249 goto begin_cull; 251 250 252 if (test_bit(CACHEFILES_CULLING, &cach 251 if (test_bit(CACHEFILES_CULLING, &cache->flags) && 253 stats.f_ffree >= cache->frun && 252 stats.f_ffree >= cache->frun && 254 b_avail >= cache->brun && 253 b_avail >= cache->brun && 255 test_and_clear_bit(CACHEFILES_CULL 254 test_and_clear_bit(CACHEFILES_CULLING, &cache->flags) 256 ) { 255 ) { 257 _debug("cease culling"); 256 _debug("cease culling"); 258 cachefiles_state_changed(cache 257 cachefiles_state_changed(cache); 259 } 258 } 260 259 261 //_leave(" = 0"); 260 //_leave(" = 0"); 262 return 0; 261 return 0; 263 262 264 stop_and_begin_cull: 263 stop_and_begin_cull: 265 switch (reason) { 264 switch (reason) { 266 case cachefiles_has_space_for_write: 265 case cachefiles_has_space_for_write: 267 fscache_count_no_write_space() 266 fscache_count_no_write_space(); 268 break; 267 break; 269 case cachefiles_has_space_for_create: 268 case cachefiles_has_space_for_create: 270 fscache_count_no_create_space( 269 fscache_count_no_create_space(); 271 break; 270 break; 272 default: 271 default: 273 break; 272 break; 274 } 273 } 275 begin_cull: 274 begin_cull: 276 if (!test_and_set_bit(CACHEFILES_CULLI 275 if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) { 277 _debug("### CULL CACHE ###"); 276 _debug("### CULL CACHE ###"); 278 cachefiles_state_changed(cache 277 cachefiles_state_changed(cache); 279 } 278 } 280 279 281 _leave(" = %d", ret); 280 _leave(" = %d", ret); 282 return ret; 281 return ret; 283 } 282 } 284 283 285 /* 284 /* 286 * Mark all the objects as being out of servic 285 * Mark all the objects as being out of service and queue them all for cleanup. 287 */ 286 */ 288 static void cachefiles_withdraw_objects(struct 287 static void cachefiles_withdraw_objects(struct cachefiles_cache *cache) 289 { 288 { 290 struct cachefiles_object *object; 289 struct cachefiles_object *object; 291 unsigned int count = 0; 290 unsigned int count = 0; 292 291 293 _enter(""); 292 _enter(""); 294 293 295 spin_lock(&cache->object_list_lock); 294 spin_lock(&cache->object_list_lock); 296 295 297 while (!list_empty(&cache->object_list 296 while (!list_empty(&cache->object_list)) { 298 object = list_first_entry(&cac 297 object = list_first_entry(&cache->object_list, 299 stru 298 struct cachefiles_object, cache_link); 300 cachefiles_see_object(object, 299 cachefiles_see_object(object, cachefiles_obj_see_withdrawal); 301 list_del_init(&object->cache_l 300 list_del_init(&object->cache_link); 302 fscache_withdraw_cookie(object 301 fscache_withdraw_cookie(object->cookie); 303 count++; 302 count++; 304 if ((count & 63) == 0) { 303 if ((count & 63) == 0) { 305 spin_unlock(&cache->ob 304 spin_unlock(&cache->object_list_lock); 306 cond_resched(); 305 cond_resched(); 307 spin_lock(&cache->obje 306 spin_lock(&cache->object_list_lock); 308 } 307 } 309 } 308 } 310 309 311 spin_unlock(&cache->object_list_lock); 310 spin_unlock(&cache->object_list_lock); 312 _leave(" [%u objs]", count); 311 _leave(" [%u objs]", count); 313 } 312 } 314 313 315 /* 314 /* 316 * Withdraw fscache volumes. !! 315 * Withdraw volumes. 317 */ << 318 static void cachefiles_withdraw_fscache_volume << 319 { << 320 struct list_head *cur; << 321 struct cachefiles_volume *volume; << 322 struct fscache_volume *vcookie; << 323 << 324 _enter(""); << 325 retry: << 326 spin_lock(&cache->object_list_lock); << 327 list_for_each(cur, &cache->volumes) { << 328 volume = list_entry(cur, struc << 329 << 330 if (atomic_read(&volume->vcook << 331 continue; << 332 << 333 vcookie = fscache_try_get_volu << 334 << 335 if (vcookie) { << 336 spin_unlock(&cache->ob << 337 fscache_withdraw_volum << 338 fscache_put_volume(vco << 339 goto retry; << 340 } << 341 } << 342 spin_unlock(&cache->object_list_lock); << 343 << 344 _leave(""); << 345 } << 346 << 347 /* << 348 * Withdraw cachefiles volumes. << 349 */ 316 */ 350 static void cachefiles_withdraw_volumes(struct 317 static void cachefiles_withdraw_volumes(struct cachefiles_cache *cache) 351 { 318 { 352 _enter(""); 319 _enter(""); 353 320 354 for (;;) { 321 for (;;) { 355 struct fscache_volume *vcookie << 356 struct cachefiles_volume *volu 322 struct cachefiles_volume *volume = NULL; 357 323 358 spin_lock(&cache->object_list_ 324 spin_lock(&cache->object_list_lock); 359 if (!list_empty(&cache->volume 325 if (!list_empty(&cache->volumes)) { 360 volume = list_first_en 326 volume = list_first_entry(&cache->volumes, 361 327 struct cachefiles_volume, cache_link); 362 vcookie = fscache_try_ << 363 << 364 if (!vcookie) { << 365 spin_unlock(&c << 366 cpu_relax(); << 367 continue; << 368 } << 369 list_del_init(&volume- 328 list_del_init(&volume->cache_link); 370 } 329 } 371 spin_unlock(&cache->object_lis 330 spin_unlock(&cache->object_list_lock); 372 if (!volume) 331 if (!volume) 373 break; 332 break; 374 333 375 cachefiles_withdraw_volume(vol 334 cachefiles_withdraw_volume(volume); 376 fscache_put_volume(vcookie, fs << 377 } 335 } 378 336 379 _leave(""); 337 _leave(""); 380 } 338 } 381 339 382 /* 340 /* 383 * Sync a cache to backing disk. 341 * Sync a cache to backing disk. 384 */ 342 */ 385 static void cachefiles_sync_cache(struct cache 343 static void cachefiles_sync_cache(struct cachefiles_cache *cache) 386 { 344 { 387 const struct cred *saved_cred; 345 const struct cred *saved_cred; 388 int ret; 346 int ret; 389 347 390 _enter("%s", cache->cache->name); 348 _enter("%s", cache->cache->name); 391 349 392 /* make sure all pages pinned by opera 350 /* make sure all pages pinned by operations on behalf of the netfs are 393 * written to disc */ 351 * written to disc */ 394 cachefiles_begin_secure(cache, &saved_ 352 cachefiles_begin_secure(cache, &saved_cred); 395 down_read(&cache->mnt->mnt_sb->s_umoun 353 down_read(&cache->mnt->mnt_sb->s_umount); 396 ret = sync_filesystem(cache->mnt->mnt_ 354 ret = sync_filesystem(cache->mnt->mnt_sb); 397 up_read(&cache->mnt->mnt_sb->s_umount) 355 up_read(&cache->mnt->mnt_sb->s_umount); 398 cachefiles_end_secure(cache, saved_cre 356 cachefiles_end_secure(cache, saved_cred); 399 357 400 if (ret == -EIO) 358 if (ret == -EIO) 401 cachefiles_io_error(cache, 359 cachefiles_io_error(cache, 402 "Attempt t 360 "Attempt to sync backing fs superblock returned error %d", 403 ret); 361 ret); 404 } 362 } 405 363 406 /* 364 /* 407 * Withdraw cache objects. 365 * Withdraw cache objects. 408 */ 366 */ 409 void cachefiles_withdraw_cache(struct cachefil 367 void cachefiles_withdraw_cache(struct cachefiles_cache *cache) 410 { 368 { 411 struct fscache_cache *fscache = cache- 369 struct fscache_cache *fscache = cache->cache; 412 370 413 pr_info("File cache on %s unregisterin 371 pr_info("File cache on %s unregistering\n", fscache->name); 414 372 415 fscache_withdraw_cache(fscache); 373 fscache_withdraw_cache(fscache); 416 cachefiles_withdraw_fscache_volumes(ca << 417 374 418 /* we now have to destroy all the acti 375 /* we now have to destroy all the active objects pertaining to this 419 * cache - which we do by passing them 376 * cache - which we do by passing them off to thread pool to be 420 * disposed of */ 377 * disposed of */ 421 cachefiles_withdraw_objects(cache); 378 cachefiles_withdraw_objects(cache); 422 fscache_wait_for_objects(fscache); 379 fscache_wait_for_objects(fscache); 423 380 424 cachefiles_withdraw_volumes(cache); 381 cachefiles_withdraw_volumes(cache); 425 cachefiles_sync_cache(cache); 382 cachefiles_sync_cache(cache); 426 cache->cache = NULL; 383 cache->cache = NULL; 427 fscache_relinquish_cache(fscache); 384 fscache_relinquish_cache(fscache); 428 } 385 } 429 386
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.