Re: [syzbot] [afs?] BUG: sleeping function called from invalid context in __alloc_frozen_pages_noprof

From: Edward Adam Davis
Date: Fri Mar 28 2025 - 22:58:58 EST


#syz test

diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
index 691e0ae607a1..829188ef5435 100644
--- a/fs/afs/dynroot.c
+++ b/fs/afs/dynroot.c
@@ -287,12 +287,16 @@ static int afs_dynroot_readdir_cells(struct afs_net *net, struct dir_context *ct

_enter("%llu", ctx->pos);

+ rcu_read_lock();
for (;;) {
unsigned int ix = ctx->pos >> 1;
+ u8 name_len;
+ char *name;
+ unsigned int dynroot_ino;

cell = idr_get_next(&net->cells_dyn_ino, &ix);
if (!cell)
- return 0;
+ goto unlock;
if (READ_ONCE(cell->state) == AFS_CELL_REMOVING ||
READ_ONCE(cell->state) == AFS_CELL_DEAD) {
ctx->pos += 2;
@@ -306,19 +310,28 @@ static int afs_dynroot_readdir_cells(struct afs_net *net, struct dir_context *ct

_debug("pos %llu -> cell %u", ctx->pos, cell->dynroot_ino);

+ name_len = cell->name_len;
+ name = cell->name;
+ dynroot_ino = cell->dynroot_ino;
if ((ctx->pos & 1) == 0) {
- if (!dir_emit(ctx, cell->name, cell->name_len,
- cell->dynroot_ino, DT_DIR))
- return 0;
+ rcu_read_unlock();
+ if (!dir_emit(ctx, name, name_len, dynroot_ino, DT_DIR))
+ goto out;
+ rcu_read_lock();
ctx->pos++;
}
if ((ctx->pos & 1) == 1) {
- if (!dir_emit(ctx, cell->name - 1, cell->name_len + 1,
- cell->dynroot_ino + 1, DT_DIR))
- return 0;
+ rcu_read_unlock();
+ if (!dir_emit(ctx, name - 1, name_len + 1,
+ dynroot_ino + 1, DT_DIR))
+ goto out;
+ rcu_read_lock();
ctx->pos++;
}
}
+unlock:
+ rcu_read_unlock();
+out:
return 0;
}

@@ -348,9 +361,7 @@ static int afs_dynroot_readdir(struct file *file, struct dir_context *ctx)
}

if ((unsigned long long)ctx->pos <= AFS_MAX_DYNROOT_CELL_INO) {
- rcu_read_lock();
ret = afs_dynroot_readdir_cells(net, ctx);
- rcu_read_unlock();
}
return ret;
}