--- x/fs/afs/dynroot.c +++ y/fs/afs/dynroot.c @@ -290,15 +290,21 @@ static int afs_dynroot_readdir_cells(str for (;;) { unsigned int ix = ctx->pos >> 1; + rcu_read_lock(); cell = idr_get_next(&net->cells_dyn_ino, &ix); - if (!cell) + if (!cell) { + rcu_read_unlock(); return 0; + } if (READ_ONCE(cell->state) == AFS_CELL_REMOVING || - READ_ONCE(cell->state) == AFS_CELL_DEAD) { + READ_ONCE(cell->state) == AFS_CELL_DEAD || + !refcount_inc_not_zero(&cell->ref)) { + rcu_read_unlock(); ctx->pos += 2; ctx->pos &= ~1; continue; } + rcu_read_unlock(); newpos = ix << 1; if (newpos > ctx->pos) @@ -308,16 +314,21 @@ static int afs_dynroot_readdir_cells(str if ((ctx->pos & 1) == 0) { if (!dir_emit(ctx, cell->name, cell->name_len, - cell->dynroot_ino, DT_DIR)) + cell->dynroot_ino, DT_DIR)) { + afs_put_cell(cell, afs_cell_trace_put_atcell); return 0; + } ctx->pos++; } if ((ctx->pos & 1) == 1) { if (!dir_emit(ctx, cell->name - 1, cell->name_len + 1, - cell->dynroot_ino + 1, DT_DIR)) + cell->dynroot_ino + 1, DT_DIR)) { + afs_put_cell(cell, afs_cell_trace_put_atcell); return 0; + } ctx->pos++; } + afs_put_cell(cell, afs_cell_trace_put_atcell); } return 0; }