Commit e5524c2a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fscache-fixes-20220708' of...

Merge tag 'fscache-fixes-20220708' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull fscache fixes from David Howells:

 - Fix a check in fscache_wait_on_volume_collision() in which the
   polarity is reversed. It should complain if a volume is still marked
   acquisition-pending after 20s, but instead complains if the mark has
   been cleared (ie. the condition has cleared).

   Also switch an open-coded test of the ACQUIRE_PENDING volume flag to
   use the helper function for consistency.

 - Not a fix per se, but neaten the code by using a helper to check for
   the DROPPED state.

 - Fix cachefiles's support for erofs to only flush requests associated
   with a released control file, not all requests.

 - Fix a race between one process invalidating an object in the cache
   and another process trying to look it up.

* tag 'fscache-fixes-20220708' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  fscache: Fix invalidation/lookup race
  cachefiles: narrow the scope of flushed requests when releasing fd
  fscache: Introduce fscache_cookie_is_dropped()
  fscache: Fix if condition in fscache_wait_on_volume_collision()
parents 525496a0 85e4ea10
...@@ -21,7 +21,8 @@ static int cachefiles_ondemand_fd_release(struct inode *inode, ...@@ -21,7 +21,8 @@ static int cachefiles_ondemand_fd_release(struct inode *inode,
* anon_fd. * anon_fd.
*/ */
xas_for_each(&xas, req, ULONG_MAX) { xas_for_each(&xas, req, ULONG_MAX) {
if (req->msg.opcode == CACHEFILES_OP_READ) { if (req->msg.object_id == object_id &&
req->msg.opcode == CACHEFILES_OP_READ) {
req->error = -EIO; req->error = -EIO;
complete(&req->done); complete(&req->done);
xas_store(&xas, NULL); xas_store(&xas, NULL);
......
...@@ -372,17 +372,22 @@ static struct fscache_cookie *fscache_alloc_cookie( ...@@ -372,17 +372,22 @@ static struct fscache_cookie *fscache_alloc_cookie(
return NULL; return NULL;
} }
static inline bool fscache_cookie_is_dropped(struct fscache_cookie *cookie)
{
return READ_ONCE(cookie->state) == FSCACHE_COOKIE_STATE_DROPPED;
}
static void fscache_wait_on_collision(struct fscache_cookie *candidate, static void fscache_wait_on_collision(struct fscache_cookie *candidate,
struct fscache_cookie *wait_for) struct fscache_cookie *wait_for)
{ {
enum fscache_cookie_state *statep = &wait_for->state; enum fscache_cookie_state *statep = &wait_for->state;
wait_var_event_timeout(statep, READ_ONCE(*statep) == FSCACHE_COOKIE_STATE_DROPPED, wait_var_event_timeout(statep, fscache_cookie_is_dropped(wait_for),
20 * HZ); 20 * HZ);
if (READ_ONCE(*statep) != FSCACHE_COOKIE_STATE_DROPPED) { if (!fscache_cookie_is_dropped(wait_for)) {
pr_notice("Potential collision c=%08x old: c=%08x", pr_notice("Potential collision c=%08x old: c=%08x",
candidate->debug_id, wait_for->debug_id); candidate->debug_id, wait_for->debug_id);
wait_var_event(statep, READ_ONCE(*statep) == FSCACHE_COOKIE_STATE_DROPPED); wait_var_event(statep, fscache_cookie_is_dropped(wait_for));
} }
} }
...@@ -517,7 +522,14 @@ static void fscache_perform_lookup(struct fscache_cookie *cookie) ...@@ -517,7 +522,14 @@ static void fscache_perform_lookup(struct fscache_cookie *cookie)
} }
fscache_see_cookie(cookie, fscache_cookie_see_active); fscache_see_cookie(cookie, fscache_cookie_see_active);
fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE); spin_lock(&cookie->lock);
if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
__fscache_set_cookie_state(cookie,
FSCACHE_COOKIE_STATE_INVALIDATING);
else
__fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
spin_unlock(&cookie->lock);
wake_up_cookie_state(cookie);
trace = fscache_access_lookup_cookie_end; trace = fscache_access_lookup_cookie_end;
out: out:
...@@ -752,6 +764,9 @@ static void fscache_cookie_state_machine(struct fscache_cookie *cookie) ...@@ -752,6 +764,9 @@ static void fscache_cookie_state_machine(struct fscache_cookie *cookie)
spin_lock(&cookie->lock); spin_lock(&cookie->lock);
} }
if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
fscache_end_cookie_access(cookie, fscache_access_invalidate_cookie_end);
switch (state) { switch (state) {
case FSCACHE_COOKIE_STATE_RELINQUISHING: case FSCACHE_COOKIE_STATE_RELINQUISHING:
fscache_see_cookie(cookie, fscache_cookie_see_relinquish); fscache_see_cookie(cookie, fscache_cookie_see_relinquish);
...@@ -1048,6 +1063,9 @@ void __fscache_invalidate(struct fscache_cookie *cookie, ...@@ -1048,6 +1063,9 @@ void __fscache_invalidate(struct fscache_cookie *cookie,
return; return;
case FSCACHE_COOKIE_STATE_LOOKING_UP: case FSCACHE_COOKIE_STATE_LOOKING_UP:
__fscache_begin_cookie_access(cookie, fscache_access_invalidate_cookie);
set_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags);
fallthrough;
case FSCACHE_COOKIE_STATE_CREATING: case FSCACHE_COOKIE_STATE_CREATING:
spin_unlock(&cookie->lock); spin_unlock(&cookie->lock);
_leave(" [look %x]", cookie->inval_counter); _leave(" [look %x]", cookie->inval_counter);
......
...@@ -143,7 +143,7 @@ static void fscache_wait_on_volume_collision(struct fscache_volume *candidate, ...@@ -143,7 +143,7 @@ static void fscache_wait_on_volume_collision(struct fscache_volume *candidate,
{ {
wait_var_event_timeout(&candidate->flags, wait_var_event_timeout(&candidate->flags,
!fscache_is_acquire_pending(candidate), 20 * HZ); !fscache_is_acquire_pending(candidate), 20 * HZ);
if (!fscache_is_acquire_pending(candidate)) { if (fscache_is_acquire_pending(candidate)) {
pr_notice("Potential volume collision new=%08x old=%08x", pr_notice("Potential volume collision new=%08x old=%08x",
candidate->debug_id, collidee_debug_id); candidate->debug_id, collidee_debug_id);
fscache_stat(&fscache_n_volumes_collision); fscache_stat(&fscache_n_volumes_collision);
...@@ -182,7 +182,7 @@ static bool fscache_hash_volume(struct fscache_volume *candidate) ...@@ -182,7 +182,7 @@ static bool fscache_hash_volume(struct fscache_volume *candidate)
hlist_bl_add_head(&candidate->hash_link, h); hlist_bl_add_head(&candidate->hash_link, h);
hlist_bl_unlock(h); hlist_bl_unlock(h);
if (test_bit(FSCACHE_VOLUME_ACQUIRE_PENDING, &candidate->flags)) if (fscache_is_acquire_pending(candidate))
fscache_wait_on_volume_collision(candidate, collidee_debug_id); fscache_wait_on_volume_collision(candidate, collidee_debug_id);
return true; return true;
......
...@@ -130,6 +130,7 @@ struct fscache_cookie { ...@@ -130,6 +130,7 @@ struct fscache_cookie {
#define FSCACHE_COOKIE_DO_PREP_TO_WRITE 12 /* T if cookie needs write preparation */ #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_HAVE_DATA 13 /* T if this cookie has data stored */
#define FSCACHE_COOKIE_IS_HASHED 14 /* T if this cookie is hashed */ #define FSCACHE_COOKIE_IS_HASHED 14 /* T if this cookie is hashed */
#define FSCACHE_COOKIE_DO_INVALIDATE 15 /* T if cookie needs invalidation */
enum fscache_cookie_state state; enum fscache_cookie_state state;
u8 advice; /* FSCACHE_ADV_* */ u8 advice; /* FSCACHE_ADV_* */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment