Commit e5524c2a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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);
+22 −4
Original line number Diff line number Diff line
@@ -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));
	}
}

@@ -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:
@@ -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);
@@ -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);
+2 −2
Original line number Diff line number Diff line
@@ -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);
@@ -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;

+1 −0
Original line number Diff line number Diff line
@@ -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_* */