diff options
author | David Howells <dhowells@redhat.com> | 2012-12-20 16:52:36 -0500 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2012-12-20 17:06:08 -0500 |
commit | 9dc8d9bfe4415efb61a5e9390706b8a3bffef329 (patch) | |
tree | 2534486c442b7889a761d894f3bd4dd0403608ca /fs/cachefiles | |
parent | a02de9608595c8ef649ef03ae735b0b45e3d4396 (diff) |
CacheFiles: Implement invalidation
Implement invalidation for CacheFiles. This is in two parts:
(1) Provide an invalidation method (which just truncates the backing file).
(2) Abort attempts to copy anything read from the backing file whilst
invalidation is in progress.
Question: CacheFiles uses truncation in a couple of places. It has been using
notify_change() rather than sys_truncate() or something similar. This means
it bypasses a bunch of checks and suchlike that it possibly should be making
(security, file locking, lease breaking, vfsmount write). Should it be using
vfs_truncate() as added by a preceding patch or should it use notify_write()
and assume that anyone poking around in the cache files on disk gets
everything they deserve?
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/cachefiles')
-rw-r--r-- | fs/cachefiles/interface.c | 49 | ||||
-rw-r--r-- | fs/cachefiles/rdwr.c | 5 |
2 files changed, 53 insertions, 1 deletions
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 9bff0f878cfd..7a9d574b961c 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
@@ -441,6 +441,54 @@ truncate_failed: | |||
441 | } | 441 | } |
442 | 442 | ||
443 | /* | 443 | /* |
444 | * Invalidate an object | ||
445 | */ | ||
446 | static void cachefiles_invalidate_object(struct fscache_operation *op) | ||
447 | { | ||
448 | struct cachefiles_object *object; | ||
449 | struct cachefiles_cache *cache; | ||
450 | const struct cred *saved_cred; | ||
451 | struct path path; | ||
452 | uint64_t ni_size; | ||
453 | int ret; | ||
454 | |||
455 | object = container_of(op->object, struct cachefiles_object, fscache); | ||
456 | cache = container_of(object->fscache.cache, | ||
457 | struct cachefiles_cache, cache); | ||
458 | |||
459 | op->object->cookie->def->get_attr(op->object->cookie->netfs_data, | ||
460 | &ni_size); | ||
461 | |||
462 | _enter("{OBJ%x},[%llu]", | ||
463 | op->object->debug_id, (unsigned long long)ni_size); | ||
464 | |||
465 | if (object->backer) { | ||
466 | ASSERT(S_ISREG(object->backer->d_inode->i_mode)); | ||
467 | |||
468 | fscache_set_store_limit(&object->fscache, ni_size); | ||
469 | |||
470 | path.dentry = object->backer; | ||
471 | path.mnt = cache->mnt; | ||
472 | |||
473 | cachefiles_begin_secure(cache, &saved_cred); | ||
474 | ret = vfs_truncate(&path, 0); | ||
475 | if (ret == 0) | ||
476 | ret = vfs_truncate(&path, ni_size); | ||
477 | cachefiles_end_secure(cache, saved_cred); | ||
478 | |||
479 | if (ret != 0) { | ||
480 | fscache_set_store_limit(&object->fscache, 0); | ||
481 | if (ret == -EIO) | ||
482 | cachefiles_io_error_obj(object, | ||
483 | "Invalidate failed"); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | fscache_op_complete(op); | ||
488 | _leave(""); | ||
489 | } | ||
490 | |||
491 | /* | ||
444 | * dissociate a cache from all the pages it was backing | 492 | * dissociate a cache from all the pages it was backing |
445 | */ | 493 | */ |
446 | static void cachefiles_dissociate_pages(struct fscache_cache *cache) | 494 | static void cachefiles_dissociate_pages(struct fscache_cache *cache) |
@@ -455,6 +503,7 @@ const struct fscache_cache_ops cachefiles_cache_ops = { | |||
455 | .lookup_complete = cachefiles_lookup_complete, | 503 | .lookup_complete = cachefiles_lookup_complete, |
456 | .grab_object = cachefiles_grab_object, | 504 | .grab_object = cachefiles_grab_object, |
457 | .update_object = cachefiles_update_object, | 505 | .update_object = cachefiles_update_object, |
506 | .invalidate_object = cachefiles_invalidate_object, | ||
458 | .drop_object = cachefiles_drop_object, | 507 | .drop_object = cachefiles_drop_object, |
459 | .put_object = cachefiles_put_object, | 508 | .put_object = cachefiles_put_object, |
460 | .sync_cache = cachefiles_sync_cache, | 509 | .sync_cache = cachefiles_sync_cache, |
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c index 93a0815e0498..2c994885520a 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c | |||
@@ -174,7 +174,10 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
174 | _debug("- copy {%lu}", monitor->back_page->index); | 174 | _debug("- copy {%lu}", monitor->back_page->index); |
175 | 175 | ||
176 | recheck: | 176 | recheck: |
177 | if (PageUptodate(monitor->back_page)) { | 177 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, |
178 | &object->fscache.cookie->flags)) { | ||
179 | error = -ESTALE; | ||
180 | } else if (PageUptodate(monitor->back_page)) { | ||
178 | copy_highpage(monitor->netfs_page, monitor->back_page); | 181 | copy_highpage(monitor->netfs_page, monitor->back_page); |
179 | fscache_mark_page_cached(monitor->op, | 182 | fscache_mark_page_cached(monitor->op, |
180 | monitor->netfs_page); | 183 | monitor->netfs_page); |