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

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

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

Pull fscache fixes from David Howells:
 "Here's a collection of fscache and cachefiles fixes and misc small
  cleanups. The two main fixes are:

   - Add a missing unmark of the inode in-use mark in an error path.

   - Fix a KASAN slab-out-of-bounds error when setting the xattr on a
     cachefiles volume due to the wrong length being given to memcpy().

  In addition, there's the removal of an unused parameter, removal of an
  unused Kconfig option, conditionalising a bit of procfs-related stuff
  and some doc fixes"

* tag 'fscache-fixes-20220413' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  fscache: remove FSCACHE_OLD_API Kconfig option
  fscache: Use wrapper fscache_set_cache_state() directly when relinquishing
  fscache: Move fscache_cookies_seq_ops specific code under CONFIG_PROC_FS
  fscache: Remove the cookie parameter from fscache_clear_page_bits()
  docs: filesystems: caching/backend-api.rst: fix an object withdrawn API
  docs: filesystems: caching/backend-api.rst: correct two relinquish APIs use
  cachefiles: Fix KASAN slab-out-of-bounds in cachefiles_set_volume_xattr
  cachefiles: unmark inode in use in error path
parents a1994480 61132cee
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -73,7 +73,7 @@ busy.
If successful, the cache backend can then start setting up the cache.  In the
event that the initialisation fails, the cache backend should call::

	void fscache_relinquish_cookie(struct fscache_cache *cache);
	void fscache_relinquish_cache(struct fscache_cache *cache);

to reset and discard the cookie.

@@ -110,9 +110,9 @@ to withdraw them, calling::

on the cookie that each object belongs to.  This schedules the specified cookie
for withdrawal.  This gets offloaded to a workqueue.  The cache backend can
test for completion by calling::
wait for completion by calling::

	bool fscache_are_objects_withdrawn(struct fscache_cookie *cache);
	void fscache_wait_for_objects(struct fscache_cache *cache);

Once all the cookies are withdrawn, a cache backend can withdraw all the
volumes, calling::
@@ -125,7 +125,7 @@ outstanding accesses on the volume to complete before returning.
When the the cache is completely withdrawn, fscache should be notified by
calling::

	void fscache_cache_relinquish(struct fscache_cache *cache);
	void fscache_relinquish_cache(struct fscache_cache *cache);

to clear fields in the cookie and discard the caller's ref on it.

+12 −13
Original line number Diff line number Diff line
@@ -404,22 +404,21 @@ schedule a write of that region::
And if an error occurs before that point is reached, the marks can be removed
by calling::

	void fscache_clear_page_bits(struct fscache_cookie *cookie,
				     struct address_space *mapping,
	void fscache_clear_page_bits(struct address_space *mapping,
				     loff_t start, size_t len,
				     bool caching)

In both of these functions, the cookie representing the cache object to be
written to and a pointer to the mapping to which the source pages are attached
are passed in; start and len indicate the size of the region that's going to be
written (it doesn't have to align to page boundaries necessarily, but it does
have to align to DIO boundaries on the backing filesystem).  The caching
parameter indicates if caching should be skipped, and if false, the functions
do nothing.

The write function takes some additional parameters: i_size indicates the size
of the netfs file and term_func indicates an optional completion function, to
which term_func_priv will be passed, along with the error or amount written.
In these functions, a pointer to the mapping to which the source pages are
attached is passed in and start and len indicate the size of the region that's
going to be written (it doesn't have to align to page boundaries necessarily,
but it does have to align to DIO boundaries on the backing filesystem).  The
caching parameter indicates if caching should be skipped, and if false, the
functions do nothing.

The write function takes some additional parameters: the cookie representing
the cache object to be written to, i_size indicates the size of the netfs file
and term_func indicates an optional completion function, to which
term_func_priv will be passed, along with the error or amount written.

Note that the write function will always run asynchronously and will unmark all
the pages upon completion before calling term_func.
+1 −2
Original line number Diff line number Diff line
@@ -616,8 +616,7 @@ static ssize_t afs_write_back_from_locked_folio(struct address_space *mapping,
		_debug("write discard %x @%llx [%llx]", len, start, i_size);

		/* The dirty region was entirely beyond the EOF. */
		fscache_clear_page_bits(afs_vnode_cache(vnode),
					mapping, start, len, caching);
		fscache_clear_page_bits(mapping, start, len, caching);
		afs_pages_written_back(vnode, start, len);
		ret = 0;
	}
+24 −9
Original line number Diff line number Diff line
@@ -57,6 +57,16 @@ static void __cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
	trace_cachefiles_mark_inactive(object, inode);
}

static void cachefiles_do_unmark_inode_in_use(struct cachefiles_object *object,
					      struct dentry *dentry)
{
	struct inode *inode = d_backing_inode(dentry);

	inode_lock(inode);
	__cachefiles_unmark_inode_in_use(object, dentry);
	inode_unlock(inode);
}

/*
 * Unmark a backing inode and tell cachefilesd that there's something that can
 * be culled.
@@ -68,9 +78,7 @@ void cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
	struct inode *inode = file_inode(file);

	if (inode) {
		inode_lock(inode);
		__cachefiles_unmark_inode_in_use(object, file->f_path.dentry);
		inode_unlock(inode);
		cachefiles_do_unmark_inode_in_use(object, file->f_path.dentry);

		if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
			atomic_long_add(inode->i_blocks, &cache->b_released);
@@ -484,7 +492,7 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object)
				object, d_backing_inode(path.dentry), ret,
				cachefiles_trace_trunc_error);
			file = ERR_PTR(ret);
			goto out_dput;
			goto out_unuse;
		}
	}

@@ -494,15 +502,20 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object)
		trace_cachefiles_vfs_error(object, d_backing_inode(path.dentry),
					   PTR_ERR(file),
					   cachefiles_trace_open_error);
		goto out_dput;
		goto out_unuse;
	}
	if (unlikely(!file->f_op->read_iter) ||
	    unlikely(!file->f_op->write_iter)) {
		fput(file);
		pr_notice("Cache does not support read_iter and write_iter\n");
		file = ERR_PTR(-EINVAL);
		goto out_unuse;
	}

	goto out_dput;

out_unuse:
	cachefiles_do_unmark_inode_in_use(object, path.dentry);
out_dput:
	dput(path.dentry);
out:
@@ -590,14 +603,16 @@ static bool cachefiles_open_file(struct cachefiles_object *object,
check_failed:
	fscache_cookie_lookup_negative(object->cookie);
	cachefiles_unmark_inode_in_use(object, file);
	if (ret == -ESTALE) {
	fput(file);
	dput(dentry);
	if (ret == -ESTALE)
		return cachefiles_create_file(object);
	}
	return false;

error_fput:
	fput(file);
error:
	cachefiles_do_unmark_inode_in_use(object, dentry);
	dput(dentry);
	return false;
}
+1 −1
Original line number Diff line number Diff line
@@ -203,7 +203,7 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
	if (!buf)
		return false;
	buf->reserved = cpu_to_be32(0);
	memcpy(buf->data, p, len);
	memcpy(buf->data, p, volume->vcookie->coherency_len);

	ret = cachefiles_inject_write_error();
	if (ret == 0)
Loading