Commit ec9c57a7 authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -73,7 +73,7 @@ busy. ...@@ -73,7 +73,7 @@ busy.
If successful, the cache backend can then start setting up the cache. In the If successful, the cache backend can then start setting up the cache. In the
event that the initialisation fails, the cache backend should call:: 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. to reset and discard the cookie.
...@@ -110,9 +110,9 @@ to withdraw them, calling:: ...@@ -110,9 +110,9 @@ to withdraw them, calling::
on the cookie that each object belongs to. This schedules the specified cookie 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 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 Once all the cookies are withdrawn, a cache backend can withdraw all the
volumes, calling:: volumes, calling::
...@@ -125,7 +125,7 @@ outstanding accesses on the volume to complete before returning. ...@@ -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 When the the cache is completely withdrawn, fscache should be notified by
calling:: 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. to clear fields in the cookie and discard the caller's ref on it.
......
...@@ -404,22 +404,21 @@ schedule a write of that region:: ...@@ -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 And if an error occurs before that point is reached, the marks can be removed
by calling:: by calling::
void fscache_clear_page_bits(struct fscache_cookie *cookie, void fscache_clear_page_bits(struct address_space *mapping,
struct address_space *mapping,
loff_t start, size_t len, loff_t start, size_t len,
bool caching) bool caching)
In both of these functions, the cookie representing the cache object to be In these functions, a pointer to the mapping to which the source pages are
written to and a pointer to the mapping to which the source pages are attached attached is passed in and start and len indicate the size of the region that's
are passed in; start and len indicate the size of the region that's going to be going to be written (it doesn't have to align to page boundaries necessarily,
written (it doesn't have to align to page boundaries necessarily, but it does but it does have to align to DIO boundaries on the backing filesystem). The
have to align to DIO boundaries on the backing filesystem). The caching caching parameter indicates if caching should be skipped, and if false, the
parameter indicates if caching should be skipped, and if false, the functions functions do nothing.
do nothing.
The write function takes some additional parameters: the cookie representing
The write function takes some additional parameters: i_size indicates the size the cache object to be written to, i_size indicates the size of the netfs file
of the netfs file and term_func indicates an optional completion function, to and term_func indicates an optional completion function, to which
which term_func_priv will be passed, along with the error or amount written. 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 Note that the write function will always run asynchronously and will unmark all
the pages upon completion before calling term_func. the pages upon completion before calling term_func.
......
...@@ -616,8 +616,7 @@ static ssize_t afs_write_back_from_locked_folio(struct address_space *mapping, ...@@ -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); _debug("write discard %x @%llx [%llx]", len, start, i_size);
/* The dirty region was entirely beyond the EOF. */ /* The dirty region was entirely beyond the EOF. */
fscache_clear_page_bits(afs_vnode_cache(vnode), fscache_clear_page_bits(mapping, start, len, caching);
mapping, start, len, caching);
afs_pages_written_back(vnode, start, len); afs_pages_written_back(vnode, start, len);
ret = 0; ret = 0;
} }
......
...@@ -57,6 +57,16 @@ static void __cachefiles_unmark_inode_in_use(struct cachefiles_object *object, ...@@ -57,6 +57,16 @@ static void __cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
trace_cachefiles_mark_inactive(object, inode); 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 * Unmark a backing inode and tell cachefilesd that there's something that can
* be culled. * be culled.
...@@ -68,9 +78,7 @@ void cachefiles_unmark_inode_in_use(struct cachefiles_object *object, ...@@ -68,9 +78,7 @@ void cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
if (inode) { if (inode) {
inode_lock(inode); cachefiles_do_unmark_inode_in_use(object, file->f_path.dentry);
__cachefiles_unmark_inode_in_use(object, file->f_path.dentry);
inode_unlock(inode);
if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) { if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
atomic_long_add(inode->i_blocks, &cache->b_released); atomic_long_add(inode->i_blocks, &cache->b_released);
...@@ -484,7 +492,7 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object) ...@@ -484,7 +492,7 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object)
object, d_backing_inode(path.dentry), ret, object, d_backing_inode(path.dentry), ret,
cachefiles_trace_trunc_error); cachefiles_trace_trunc_error);
file = ERR_PTR(ret); file = ERR_PTR(ret);
goto out_dput; goto out_unuse;
} }
} }
...@@ -494,15 +502,20 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object) ...@@ -494,15 +502,20 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object)
trace_cachefiles_vfs_error(object, d_backing_inode(path.dentry), trace_cachefiles_vfs_error(object, d_backing_inode(path.dentry),
PTR_ERR(file), PTR_ERR(file),
cachefiles_trace_open_error); cachefiles_trace_open_error);
goto out_dput; goto out_unuse;
} }
if (unlikely(!file->f_op->read_iter) || if (unlikely(!file->f_op->read_iter) ||
unlikely(!file->f_op->write_iter)) { unlikely(!file->f_op->write_iter)) {
fput(file); fput(file);
pr_notice("Cache does not support read_iter and write_iter\n"); pr_notice("Cache does not support read_iter and write_iter\n");
file = ERR_PTR(-EINVAL); file = ERR_PTR(-EINVAL);
goto out_unuse;
} }
goto out_dput;
out_unuse:
cachefiles_do_unmark_inode_in_use(object, path.dentry);
out_dput: out_dput:
dput(path.dentry); dput(path.dentry);
out: out:
...@@ -590,14 +603,16 @@ static bool cachefiles_open_file(struct cachefiles_object *object, ...@@ -590,14 +603,16 @@ static bool cachefiles_open_file(struct cachefiles_object *object,
check_failed: check_failed:
fscache_cookie_lookup_negative(object->cookie); fscache_cookie_lookup_negative(object->cookie);
cachefiles_unmark_inode_in_use(object, file); cachefiles_unmark_inode_in_use(object, file);
if (ret == -ESTALE) { fput(file);
fput(file); dput(dentry);
dput(dentry); if (ret == -ESTALE)
return cachefiles_create_file(object); return cachefiles_create_file(object);
} return false;
error_fput: error_fput:
fput(file); fput(file);
error: error:
cachefiles_do_unmark_inode_in_use(object, dentry);
dput(dentry); dput(dentry);
return false; return false;
} }
......
...@@ -203,7 +203,7 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume) ...@@ -203,7 +203,7 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
if (!buf) if (!buf)
return false; return false;
buf->reserved = cpu_to_be32(0); buf->reserved = cpu_to_be32(0);
memcpy(buf->data, p, len); memcpy(buf->data, p, volume->vcookie->coherency_len);
ret = cachefiles_inject_write_error(); ret = cachefiles_inject_write_error();
if (ret == 0) if (ret == 0)
......
...@@ -38,6 +38,3 @@ config FSCACHE_DEBUG ...@@ -38,6 +38,3 @@ config FSCACHE_DEBUG
enabled by setting bits in /sys/modules/fscache/parameter/debug. enabled by setting bits in /sys/modules/fscache/parameter/debug.
See Documentation/filesystems/caching/fscache.rst for more information. See Documentation/filesystems/caching/fscache.rst for more information.
config FSCACHE_OLD_API
bool
...@@ -214,7 +214,7 @@ void fscache_relinquish_cache(struct fscache_cache *cache) ...@@ -214,7 +214,7 @@ void fscache_relinquish_cache(struct fscache_cache *cache)
cache->ops = NULL; cache->ops = NULL;
cache->cache_priv = NULL; cache->cache_priv = NULL;
smp_store_release(&cache->state, FSCACHE_CACHE_IS_NOT_PRESENT); fscache_set_cache_state(cache, FSCACHE_CACHE_IS_NOT_PRESENT);
fscache_put_cache(cache, where); fscache_put_cache(cache, where);
} }
EXPORT_SYMBOL(fscache_relinquish_cache); EXPORT_SYMBOL(fscache_relinquish_cache);
......
...@@ -30,7 +30,7 @@ static DEFINE_SPINLOCK(fscache_cookie_lru_lock); ...@@ -30,7 +30,7 @@ static DEFINE_SPINLOCK(fscache_cookie_lru_lock);
DEFINE_TIMER(fscache_cookie_lru_timer, fscache_cookie_lru_timed_out); DEFINE_TIMER(fscache_cookie_lru_timer, fscache_cookie_lru_timed_out);
static DECLARE_WORK(fscache_cookie_lru_work, fscache_cookie_lru_worker); static DECLARE_WORK(fscache_cookie_lru_work, fscache_cookie_lru_worker);
static const char fscache_cookie_states[FSCACHE_COOKIE_STATE__NR] = "-LCAIFUWRD"; static const char fscache_cookie_states[FSCACHE_COOKIE_STATE__NR] = "-LCAIFUWRD";
unsigned int fscache_lru_cookie_timeout = 10 * HZ; static unsigned int fscache_lru_cookie_timeout = 10 * HZ;
void fscache_print_cookie(struct fscache_cookie *cookie, char prefix) void fscache_print_cookie(struct fscache_cookie *cookie, char prefix)
{ {
...@@ -1069,6 +1069,7 @@ void __fscache_invalidate(struct fscache_cookie *cookie, ...@@ -1069,6 +1069,7 @@ void __fscache_invalidate(struct fscache_cookie *cookie,
} }
EXPORT_SYMBOL(__fscache_invalidate); EXPORT_SYMBOL(__fscache_invalidate);
#ifdef CONFIG_PROC_FS
/* /*
* Generate a list of extant cookies in /proc/fs/fscache/cookies * Generate a list of extant cookies in /proc/fs/fscache/cookies
*/ */
...@@ -1145,3 +1146,4 @@ const struct seq_operations fscache_cookies_seq_ops = { ...@@ -1145,3 +1146,4 @@ const struct seq_operations fscache_cookies_seq_ops = {
.stop = fscache_cookies_seq_stop, .stop = fscache_cookies_seq_stop,
.show = fscache_cookies_seq_show, .show = fscache_cookies_seq_show,
}; };
#endif
...@@ -56,7 +56,9 @@ static inline bool fscache_set_cache_state_maybe(struct fscache_cache *cache, ...@@ -56,7 +56,9 @@ static inline bool fscache_set_cache_state_maybe(struct fscache_cache *cache,
* cookie.c * cookie.c
*/ */
extern struct kmem_cache *fscache_cookie_jar; extern struct kmem_cache *fscache_cookie_jar;
#ifdef CONFIG_PROC_FS
extern const struct seq_operations fscache_cookies_seq_ops; extern const struct seq_operations fscache_cookies_seq_ops;
#endif
extern struct timer_list fscache_cookie_lru_timer; extern struct timer_list fscache_cookie_lru_timer;
extern void fscache_print_cookie(struct fscache_cookie *cookie, char prefix); extern void fscache_print_cookie(struct fscache_cookie *cookie, char prefix);
...@@ -137,7 +139,9 @@ int fscache_stats_show(struct seq_file *m, void *v); ...@@ -137,7 +139,9 @@ int fscache_stats_show(struct seq_file *m, void *v);
/* /*
* volume.c * volume.c
*/ */
#ifdef CONFIG_PROC_FS
extern const struct seq_operations fscache_volumes_seq_ops; extern const struct seq_operations fscache_volumes_seq_ops;
#endif
struct fscache_volume *fscache_get_volume(struct fscache_volume *volume, struct fscache_volume *fscache_get_volume(struct fscache_volume *volume,
enum fscache_volume_trace where); enum fscache_volume_trace where);
......
...@@ -235,8 +235,7 @@ static void fscache_wreq_done(void *priv, ssize_t transferred_or_error, ...@@ -235,8 +235,7 @@ static void fscache_wreq_done(void *priv, ssize_t transferred_or_error,
{ {
struct fscache_write_request *wreq = priv; struct fscache_write_request *wreq = priv;
fscache_clear_page_bits(fscache_cres_cookie(&wreq->cache_resources), fscache_clear_page_bits(wreq->mapping, wreq->start, wreq->len,
wreq->mapping, wreq->start, wreq->len,
wreq->set_bits); wreq->set_bits);
if (wreq->term_func) if (wreq->term_func)
...@@ -296,7 +295,7 @@ void __fscache_write_to_cache(struct fscache_cookie *cookie, ...@@ -296,7 +295,7 @@ void __fscache_write_to_cache(struct fscache_cookie *cookie,
abandon_free: abandon_free:
kfree(wreq); kfree(wreq);
abandon: abandon:
fscache_clear_page_bits(cookie, mapping, start, len, cond); fscache_clear_page_bits(mapping, start, len, cond);
if (term_func) if (term_func)
term_func(term_func_priv, ret, false); term_func(term_func_priv, ret, false);
} }
......
...@@ -573,7 +573,6 @@ int fscache_write(struct netfs_cache_resources *cres, ...@@ -573,7 +573,6 @@ int fscache_write(struct netfs_cache_resources *cres,
/** /**
* fscache_clear_page_bits - Clear the PG_fscache bits from a set of pages * fscache_clear_page_bits - Clear the PG_fscache bits from a set of pages
* @cookie: The cookie representing the cache object
* @mapping: The netfs inode to use as the source * @mapping: The netfs inode to use as the source
* @start: The start position in @mapping * @start: The start position in @mapping
* @len: The amount of data to unlock * @len: The amount of data to unlock
...@@ -582,8 +581,7 @@ int fscache_write(struct netfs_cache_resources *cres, ...@@ -582,8 +581,7 @@ int fscache_write(struct netfs_cache_resources *cres,
* Clear the PG_fscache flag from a sequence of pages and wake up anyone who's * Clear the PG_fscache flag from a sequence of pages and wake up anyone who's
* waiting. * waiting.
*/ */
static inline void fscache_clear_page_bits(struct fscache_cookie *cookie, static inline void fscache_clear_page_bits(struct address_space *mapping,
struct address_space *mapping,
loff_t start, size_t len, loff_t start, size_t len,
bool caching) bool caching)
{ {
......
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