Skip to content

Commit

Permalink
Merge tag 'fscache-fixes-20220708' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/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()
  • Loading branch information
torvalds committed Jul 8, 2022
2 parents 525496a + 85e4ea1 commit e5524c2
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 7 deletions.
3 changes: 2 additions & 1 deletion fs/cachefiles/ondemand.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ static int cachefiles_ondemand_fd_release(struct inode *inode,
* anon_fd.
*/
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;
complete(&req->done);
xas_store(&xas, NULL);
Expand Down
26 changes: 22 additions & 4 deletions fs/fscache/cookie.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,17 +372,22 @@ static struct fscache_cookie *fscache_alloc_cookie(
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,
struct fscache_cookie *wait_for)
{
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);
if (READ_ONCE(*statep) != FSCACHE_COOKIE_STATE_DROPPED) {
if (!fscache_cookie_is_dropped(wait_for)) {
pr_notice("Potential collision c=%08x old: c=%08x",
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));
}
}

Expand Down Expand Up @@ -517,7 +522,14 @@ static void fscache_perform_lookup(struct fscache_cookie *cookie)
}

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;

out:
Expand Down Expand Up @@ -752,6 +764,9 @@ static void fscache_cookie_state_machine(struct fscache_cookie *cookie)
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) {
case FSCACHE_COOKIE_STATE_RELINQUISHING:
fscache_see_cookie(cookie, fscache_cookie_see_relinquish);
Expand Down Expand Up @@ -1048,6 +1063,9 @@ void __fscache_invalidate(struct fscache_cookie *cookie,
return;

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:
spin_unlock(&cookie->lock);
_leave(" [look %x]", cookie->inval_counter);
Expand Down
4 changes: 2 additions & 2 deletions fs/fscache/volume.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ static void fscache_wait_on_volume_collision(struct fscache_volume *candidate,
{
wait_var_event_timeout(&candidate->flags,
!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",
candidate->debug_id, collidee_debug_id);
fscache_stat(&fscache_n_volumes_collision);
Expand Down Expand Up @@ -182,7 +182,7 @@ static bool fscache_hash_volume(struct fscache_volume *candidate)
hlist_bl_add_head(&candidate->hash_link, 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);
return true;

Expand Down
1 change: 1 addition & 0 deletions include/linux/fscache.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ struct fscache_cookie {
#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_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;
u8 advice; /* FSCACHE_ADV_* */
Expand Down

0 comments on commit e5524c2

Please sign in to comment.