lkml.org 
[lkml]   [2020]   [Nov]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[RFC PATCH 31/76] fscache: Allow ->put_super() to be used to wait for cache operations
From
Date
Provide a helper to allow ->put_super() to be used to wait for outstanding
cache operations that are pinning inodes. The helper has a loop that waits
for the first inode that has a non-zero usage and a cookie. It then calls
evict_inodes() to reduce the list and loops round again until it finds no
more candidate inodes.

Without this, evict_inodes() won't get rid of such operations, and the
"VFS: Busy inodes ..." message will be displayed and the inode abandoned.

Signed-off-by: David Howells <dhowells@redhat.com>
---

fs/fscache/io.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fscache.h | 2 ++
2 files changed, 52 insertions(+)

diff --git a/fs/fscache/io.c b/fs/fscache/io.c
index 87ffe84c9f27..de9ffc16eb4f 100644
--- a/fs/fscache/io.c
+++ b/fs/fscache/io.c
@@ -180,3 +180,53 @@ int fscache_set_page_dirty(struct page *page, struct fscache_cookie *cookie)
return 1;
}
EXPORT_SYMBOL(fscache_set_page_dirty);
+
+/**
+ * fscache_put_super - Wait for outstanding ops to complete
+ * @sb: The superblock to wait on
+ * @get_cookie: Function to get the cookie on an inode
+ *
+ * Wait for outstanding cache operations on the inodes of a superblock to
+ * complete as they might be pinning an inode. This is designed to be called
+ * from ->put_super(), right before the "VFS: Busy inodes" check.
+ */
+void fscache_put_super(struct super_block *sb,
+ struct fscache_cookie *(*get_cookie)(struct inode *inode))
+{
+ struct fscache_cookie *cookie;
+ struct inode *inode, *p;
+
+ while (!list_empty(&sb->s_inodes)) {
+ /* Find the first inode that we need to wait on */
+ inode = NULL;
+ cookie = NULL;
+ spin_lock(&sb->s_inode_list_lock);
+ list_for_each_entry(p, &sb->s_inodes, i_sb_list) {
+ if (atomic_inc_not_zero(&p->i_count)) {
+ inode = p;
+ cookie = get_cookie(inode);
+ if (!cookie) {
+ iput(inode);
+ inode = NULL;
+ cookie = NULL;
+ continue;
+ }
+ break;
+ }
+ }
+ spin_unlock(&sb->s_inode_list_lock);
+
+ if (inode) {
+ /* n_ops is kept artificially raised to stop wakeups */
+ atomic_dec(&cookie->n_ops);
+ wait_var_event(&cookie->n_ops, atomic_read(&cookie->n_ops) == 0);
+ atomic_inc(&cookie->n_ops);
+ iput(inode);
+ }
+
+ evict_inodes(sb);
+ if (!inode)
+ break;
+ }
+}
+EXPORT_SYMBOL(fscache_put_super);
diff --git a/include/linux/fscache.h b/include/linux/fscache.h
index d2fc98a5755a..38a252b06b54 100644
--- a/include/linux/fscache.h
+++ b/include/linux/fscache.h
@@ -204,6 +204,8 @@ extern int __fscache_begin_operation(struct fscache_cookie *, struct fscache_op_
extern void __fscache_relinquish_cookie(struct fscache_cookie *, bool);
extern void __fscache_update_cookie(struct fscache_cookie *, const void *, const loff_t *);
extern void __fscache_invalidate(struct fscache_cookie *, loff_t);
+extern void fscache_put_super(struct super_block *,
+ struct fscache_cookie *(*get_cookie)(struct inode *));

/**
* fscache_register_netfs - Register a filesystem as desiring caching services

\
 
 \ /
  Last update: 2020-11-20 16:10    [W:0.373 / U:0.396 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site