summaryrefslogtreecommitdiff
path: root/security/landlock/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/landlock/fs.c')
-rw-r--r--security/landlock/fs.c41
1 files changed, 13 insertions, 28 deletions
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 7d79fc8abe21..9e4d3bd56e3d 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -1228,13 +1228,18 @@ static void hook_inode_free_security_rcu(void *inode_security)
*/
static void hook_sb_delete(struct super_block *const sb)
{
- struct inode *inode, *prev_inode = NULL;
+ struct genradix_iter iter;
+ void **i;
if (!landlock_initialized)
return;
- spin_lock(&sb->s_inode_list_lock);
- list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
+ rcu_read_lock();
+ genradix_for_each(&sb->s_inodes.items, iter, i) {
+ struct inode *inode = *((struct inode **) i);
+ if (!inode)
+ continue;
+
struct landlock_object *object;
/* Only handles referenced inodes. */
@@ -1258,10 +1263,8 @@ static void hook_sb_delete(struct super_block *const sb)
continue;
}
- rcu_read_lock();
object = rcu_dereference(landlock_inode(inode)->object);
if (!object) {
- rcu_read_unlock();
spin_unlock(&inode->i_lock);
continue;
}
@@ -1278,7 +1281,6 @@ static void hook_sb_delete(struct super_block *const sb)
if (object->underobj == inode) {
object->underobj = NULL;
spin_unlock(&object->lock);
- rcu_read_unlock();
/*
* Because object->underobj was not NULL,
@@ -1299,32 +1301,15 @@ static void hook_sb_delete(struct super_block *const sb)
iput(inode);
} else {
spin_unlock(&object->lock);
- rcu_read_unlock();
}
- if (prev_inode) {
- /*
- * At this point, we still own the __iget() reference
- * that we just set in this loop walk. Therefore we
- * can drop the list lock and know that the inode won't
- * disappear from under us until the next loop walk.
- */
- spin_unlock(&sb->s_inode_list_lock);
- /*
- * We can now actually put the inode reference from the
- * previous loop walk, which is not needed anymore.
- */
- iput(prev_inode);
- cond_resched();
- spin_lock(&sb->s_inode_list_lock);
- }
- prev_inode = inode;
+ rcu_read_unlock();
+ iput(inode);
+ cond_resched();
+ rcu_read_lock();
}
- spin_unlock(&sb->s_inode_list_lock);
+ rcu_read_unlock();
- /* Puts the inode reference from the last loop walk, if any. */
- if (prev_inode)
- iput(prev_inode);
/* Waits for pending iput() in release_inode(). */
wait_var_event(&landlock_superblock(sb)->inode_refs,
!atomic_long_read(&landlock_superblock(sb)->inode_refs));