permissão recursiva chmod em milhares de arquivos

16

Esta é uma pergunta mais geral sobre 'chmoding' recursivamente.

Eu tenho esse script que em algum momento precisa alterar as permissões recursivamente em uma pasta que possui algumas centenas de milhares de arquivos. Todos os dias, são adicionados novos arquivos nessa pasta, mas os que já estão lá têm as permissões definidas e não são alterados.

Minha pergunta é ... quando ligo

chmod 775. -R

ele tenta definir a permissão para os arquivos que já possuem as permissões corretas, ou apenas para os novos arquivos que não têm as permissões corretas?

Parece que sempre leva séculos para passar esse comando no script, mesmo que os arquivos 'novos' sejam apenas alguns milhares e devam fazer suas permissões rapidamente.

Eu olhei para a página de manual do chmod, mas ela não parece mencionar nada neste caso.

Se o chmod não verificar previamente as permissões, devo começar a combinar 'find' com 'chmod'?

Titi Dumi
fonte
3
Gostaria de saber se é realmente mais lento verificar as permissões e alterá-las se não estiverem corretas do que configurá-las diretamente para o valor correto.
lgeorget
11
se alguém se deparar com isso e quiser o comando find + chmod, aqui está: find. ! 775 -print0 | xargs -0 -I {} chmod 775 {}
Titi Dumi 18/06
@georget, então você está dizendo que é mais lento usar o find | chmod? do que apenas chmod tudo. (desculpe, não entendi do seu comentário). aplausos
Titi dumi
Na minha humilde opinião, provavelmente é mais lento, pois precisa lançar dois processos e redirecionar a saída do primeiro para o segundo, mas não tenho certeza. Depende do tempo necessário para definir permissões, o que pode não ser tão importante, pois são apenas 3 bytes para modificar no inode.
lgeorget
11
@depquid O principal problema de desempenho aqui é a leitura dos dados no cache do disco. Após a primeira execução, tudo fica no cache do disco (a menos que haja muito pouca memória) e, portanto, você está testando o desempenho de algo que não é o gargalo na situação real.
Hauke Laging

Respostas:

9

chmodpode ou não alterar as permissões dos arquivos que já estão definidos para o que você deseja, mas, caso contrário, ainda será necessário verificá-los para ver quais são suas permissões atuais [0]. Com centenas de milhares de arquivos, não acho que isso importe; o tempo provavelmente está sendo gasto pelas ferramentas em stattodos os arquivos.

Você pode tentar usar findarquivos mais recentes que a última execução ou arquivos que precisam chmodser executados, mas acho que você não obterá muita melhoria na velocidade.

Se possível para o seu script, você poderá colocar os novos arquivos em um diretório separado primeiro, como uma área "em espera". Então você pode chmodTHAT diretório (que só tem novos arquivos), e mveles com o resto. Isso deve ser substancialmente mais rápido, mas infelizmente não funcionará para todos os aplicativos.

[0] Mesmo que tente definir a permissão de arquivos que não precisam de alterações, o sistema de arquivos subjacente provavelmente não fará nada com a solicitação, porque é desnecessário.

mrb
fonte
Obrigado por isso. Vou tentar a encontrar | versão chmod e veja se isso torna as coisas mais rápidas. Caso contrário, tentarei modificar o script para implementar uma pasta 'holding' como você sugeriu.
Titi Dumi
O motivo de você não obter uma melhoria de velocidade é que o inode deve ser lido tanto pelos direitos de acesso quanto pelo tempo de execução.
Hauke Laging
10

otimização find / chmod

Ambos finde chmodtem que ler

  1. todas as entradas do diretório
  2. os inodes para todas essas entradas

Você provavelmente obtém uma melhoria de desempenho lendo primeiro todas as entradas e depois todos os inodes (em um disco rotativo) porque a cabeça do disco não se move entre o diretório e os inodes). Como chmod é estúpido (como uma das outras respostas explica), ele deve ser chamado findapenas através . Mas, mesmo assim, pode ser útil ler todos os inodes antes que o primeiro seja gravado (supondo que você tenha RAM livre suficiente para o cache do disco). Eu sugiro isso:

find . -printf "" # reading the file names only
find . ! -perm 775 -printf "" # reading all the inodes (file names are cached)
find . ! -perm 775 -exec chmod 775 + # writing to the cache without reading from disk

A boa solução: ACLs

A boa solução pode ser completamente diferente: se os arquivos forem criados nesse diretório (e não forem movidos de outro lugar), as ACLs poderão executar o trabalho rapidamente. Você apenas precisa definir as ACLs padrão no diretório pai.

Melhorias adicionais podem ser alcançadas pelas otimizações do sistema de arquivos. Se for ext3 / ext4, você poderá executar e2fsck -Dde tempos em tempos. Talvez ajude a colocar esse diretório em um volume separado. Você pode tentar diferentes sistemas de arquivos ou configurações do sistema de arquivos (por exemplo, diferentes tamanhos de inode).

Hauke ​​Laging
fonte
As ACLs são boas desde que você não esteja trabalhando em uma montagem NFSv4.
Ostrokach
A findsolução sobre dobrou meu tempo, chmoding dentro de um recipiente janela de encaixe.
precisa
8

Assumindo que o uso de chmoddo pacote coreutils GNU no Ubuntu 12.10.

chmod 775 . -Rexecuta a fchmodatchamada do sistema para cada arquivo encontrado independentemente de as permissões precisarem ser alteradas ou não. Confirmei isso inspecionando o código e usando strace chmod 775 . -R(snippet abaixo) para listar o comportamento real.

newfstatat(4, "d", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "d", 0775)                  = 0
newfstatat(4, "c", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "c", 0775)                  = 0
newfstatat(4, "a", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "a", 0775)                  = 0
newfstatat(4, "b", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "b", 0775)                  = 0

Existem algumas desvantagens de executar fchmodatem cada arquivo

  • A chamada extra do sistema provavelmente se tornará significativa se um grande número de arquivos for alterado. O método find/ xargs/ chmodmencionado por outras pessoas provavelmente será mais rápido alterando apenas os arquivos que precisam ser alterados.
  • A chamada para fchmodataltera a modificação do status do arquivo (ctime) de cada arquivo. Isso fará com que cada arquivo / inode seja alterado a cada vez e provavelmente causará excesso de gravações no disco. Pode ser possível usar as opções de montagem para interromper essas gravações em excesso.

Um experimento simples mostra as mudanças ctime acontecendo diretamente chmod

auser@duncow:/tmp/blah.test$ ls -lc
total 0
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 a
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 b
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 c
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 d
auser@duncow:/tmp/blah.test$ chmod 775 . -R
auser@duncow:/tmp/blah.test$ ls -lc
total 0
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 a
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 b
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 c
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 d

Mas isso não muda por find/ xargs/ chmodalguns minutos depois

auser@duncow:/tmp/blah.test$ date
Tue Jun 18 18:27:27 BST 2013
auser@duncow:/tmp/blah.test$ find . ! -perm 775 -print0 | xargs -0 -I {} chmod 775 {}
auser@duncow:/tmp/blah.test$ ls -lc
total 0
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 a
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 b
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 c
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 d

Eu sempre tenderia a usar a versão find/ xargs/ chmodporque find dá mais controle sobre a seleção de coisas.

Richm
fonte
1

A [fonte] (1) mostra, que chmod(1)sempre tenta definir o modo e depois verifica novamente com [fstatat (2)] (2).

Os arquivos são processados ​​via [fts (3)] (3), que deve 'stat' todos os objetos do sistema de arquivos percorridos anteriormente para construir sua árvore de dados.

O Unixlore apresenta um [belo artigo] (4) no qual chmod(1)é cronometrado contra uma abordagem find/ xargs: o último vence por magnitudes.

Aqui a linha de comando se adaptou à pergunta original:

find . -print0 | xargs -0 chmod 775

Duas razões:

  1. O percurso do sistema de arquivos é dissociado das operações nos arquivos por meio do canal entre os dois processos, que podem até rodar em núcleos diferentes.

    1. fts(3)operação é minimizada, porque xargs(1)'nivela' a árvore de diretórios.

Então sim: você definitivamente deveria usar find/ xargs. para uma solução simples.

Outras opções:

  • Brinque com o [umask] (5) e o código-fonte do (s) processo (s) que está escrevendo os novos arquivos.

  • Se você estiver usando Linux, é provável que seu sistema tenha ativado o inotifysubsistema de kernel. Nesse caso, você pode criar um script de uma solução eficiente via [inotifywait (1)] (6).


Nota: a menos que você queira executar permissões em seus arquivos, sugiro que modifique a chamada da seguinte forma:

find . -type f -print0 | xargs -0 chmod 664
find . -type d -print0 | xargs -0 chmod 775

Nota para os editores: Não tenho permissão para adicionar mais de dois links à postagem, nem comentar em outras postagens. Deixo os URLs aqui e espero que algum usuário sincero com reputação suficiente os coloque de volta no texto e exclua este parágrafo.


Comente sobre como preparar o cache do disco com find . -printf "":

Isso pode acelerar a execução das seguintes chmodoperações, no entanto, depende da memória disponível e da carga de E / S. Portanto, pode funcionar ou não. A dissociação de traversal ( find) e chmodoperação já fornece armazenamento em cache, portanto, a preparação do cache pode ser supérflua.

  1. https + lingrok.org / xref / coreutils / src / chmod.c # process_file
  2. https + linux.die.net / man / 2 / fstatat
  3. https + linux.die.net / man / 3 / fts
  4. http + www.unixlore.net / articles / speeding-up-bulk-file-operations.html
  5. https + en.wikipedia.org / wiki / Umask
  6. https + linux.die.net / man / 1 / inotifywait
Georg Lehner
fonte
0

Você já pensou em alterar os processos que criam o arquivo para que eles sejam criados no modo 0775? Observe o valor umask no ambiente - 0002 pode ajudar.

D McKeon
fonte