aboutsummaryrefslogtreecommitdiff
path: root/fs/afs
diff options
context:
space:
mode:
authorDavid Howells2017-12-01 11:40:16 +0000
committerDavid Howells2020-05-31 15:19:44 +0100
commit3f19b2ab97a97b413c24b66c67ae16daa4f56c35 (patch)
treefd6be1d0f2b76589c05361dd95fefc365408529c /fs/afs
parent9cb1fd0efd195590b828b9b865421ad345a4a145 (diff)
vfs, afs, ext4: Make the inode hash table RCU searchable
Make the inode hash table RCU searchable so that searches that want to access or modify an inode without taking a ref on that inode can do so without taking the inode hash table lock. The main thing this requires is some RCU annotation on the list manipulation operations. Inodes are already freed by RCU in most cases. Users of this interface must take care as the inode may be still under construction or may be being torn down around them. There are at least three instances where this can be of use: (1) Testing whether the inode number iunique() is going to return is currently unique (the iunique_lock is still held). (2) Ext4 date stamp updating. (3) AFS callback breaking. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru> cc: linux-ext4@vger.kernel.org cc: linux-afs@lists.infradead.org
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/callback.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index 2dca8df1a18d..0dcbd40732d1 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -252,6 +252,7 @@ static void afs_break_one_callback(struct afs_server *server,
struct afs_vnode *vnode;
struct inode *inode;
+ rcu_read_lock();
read_lock(&server->cb_break_lock);
hlist_for_each_entry(vi, &server->cb_volumes, srv_link) {
if (vi->vid < fid->vid)
@@ -287,12 +288,16 @@ static void afs_break_one_callback(struct afs_server *server,
} else {
data.volume = NULL;
data.fid = *fid;
- inode = ilookup5_nowait(cbi->sb, fid->vnode,
- afs_iget5_test, &data);
+
+ /* See if we can find a matching inode - even an I_NEW
+ * inode needs to be marked as it can have its callback
+ * broken before we finish setting up the local inode.
+ */
+ inode = find_inode_rcu(cbi->sb, fid->vnode,
+ afs_iget5_test, &data);
if (inode) {
vnode = AFS_FS_I(inode);
afs_break_callback(vnode, afs_cb_break_for_callback);
- iput(inode);
} else {
trace_afs_cb_miss(fid, afs_cb_break_for_callback);
}
@@ -301,6 +306,7 @@ static void afs_break_one_callback(struct afs_server *server,
out:
read_unlock(&server->cb_break_lock);
+ rcu_read_unlock();
}
/*