Então, atualmente estou aprendendo a escrever módulos de kernel/drivers de dispositivo e estava analisando a implementação de unregister_chrdev_region
:
https://elixir.bootlin.com/linux/v6.12/source/fs/char_dev.c#L311
/**
* unregister_chrdev_region() - unregister a range of device numbers
* @from: the first in the range of numbers to unregister
* @count: the number of device numbers to unregister
*
* This function will unregister a range of @count device numbers,
* starting with @from. The caller should normally be the one who
* allocated those numbers in the first place...
*/
void unregister_chrdev_region(dev_t from, unsigned count)
{
dev_t to = from + count;
dev_t n, next;
for (n = from; n < to; n = next) {
next = MKDEV(MAJOR(n)+1, 0);
if (next > to)
next = to;
kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
}
}
O que não entendo é a verificação nesta linha:
https://elixir.bootlin.com/linux/v6.12/source/fs/char_dev.c#L318
if (next > to) next = to;
O loop, como eu vejo, já quebra quando a variável do loop é igual ao limite superior to = from + count
. Quando teríamos o caso de encontrarmos o condicional if (next > to)
? Qual é o motivo dessa verificação condicional?
unregister_chrdev_region
cancela o registro de uma série de dispositivos, mas esse cancelamento de registro deve ser tratado por major using__unregister_chrdev_region
. O loop lida com isso:n
é o início do alcance do dispositivo para o principal atualnext = MKDEV(MAJOR(n)+1, 0);
extrai o número principal do dispositivon
e o usa para calcular o início do próximo intervalo principalnext
for maior queto
, o intervalo atual estará totalmente contido no principal atual e o cancelamento do registro precisará parar emto
em vez denext
Em todos os casos,
__unregister_chrdev_region
é chamado para cancelar o registro do que resta no intervalo principal atual enext
é definido como o início do próximo intervalo principal ou o fim do intervalo geral para que a próxima iteração do loop manipule o próximo intervalo principal ou saia se tudo tiver sido manipulado.Vamos dar um exemplo: se você pedisse para cancelar o registro de 1024 dispositivos começando no principal 1 e no secundário 512:
from
é 1536,count
é 1024to
é calculado em 2560n
é 1536next
é calculado em 2048 (maior 2)__unregister_chrdev_region
é chamado para cancelar o registro de 512 dispositivos começando em 1536n
é 2048next
é calculado como 3072 (maior 3)next
é definido comoto
, e__unregister_chrdev_region
é chamado para cancelar o registro de 512 dispositivos a partir de 2048n
é 2560 e o loop terminaVocê está interpretando mal o que o loop faz! O loop não é
que corre exatamente
to - from == count
vezes.É, em vez disso,
nesse caso,
Se você procurar a definição de
MKDEV
eMAJOR
, verá que isso se expande parao que equivale a "arredondar para o próximo múltiplo de 2 20 (mesmo que
n
já seja um múltiplo)".Então, é bem provável que já na primeira iteração seu
next
seja maior queto
!