Re: [syzbot] [afs?] BUG: sleeping function called from invalid context in __alloc_frozen_pages_noprof
From: Edward Adam Davis
Date: Sat Mar 29 2025 - 05:51:22 EST
#syz test: upstream 1d0b929fc070b4115403a0a6206a0c6a62dd61f5
diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
index eb20e231d7ac..8d640f6537fc 100644
--- a/fs/afs/dynroot.c
+++ b/fs/afs/dynroot.c
@@ -286,12 +286,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_FAILED ||
READ_ONCE(cell->state) == AFS_CELL_REMOVED) {
ctx->pos += 2;
@@ -305,19 +309,29 @@ 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;
}
@@ -347,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;
}