林です。 柳澤様、詳細なコメントありがとうございます。
私も /usr/src/bin/ls/ls.c のコードで user_from_uid, group_from_gid が 使われているのを参考にして、sftpのコードに手を加えました。 OpenSSHのDevelopersメーリングリストのアーカイブをサーチしてみましたら、 http://marc.info/?l=openssh-unix-dev&m=114689002601405&w=2 からのスレッドで似たような事例が報告されていました。回答では getpwuid, getgrgid のキャッシュバージョンの関数を作成したり、普通は nscd(name service cache daemon)があるはずでは? というコメントがあったりしました が、user_from_uid, group_from_gid を使うというのはありませんでした。 2006年5月の議論でしたが、その後 OpenSSHのソースに反映されてはいません ので、大きな問題とは認識されていないようです。 > > ・FreeBSDの getpwuid および getgrgid はこういうものだから、 > > user_from_uid および group_from_gid を使うのが正しい > > →OpenSSHで対応すべき or FreeBSDの問題? > > user_from_uidおよびgroup_from_gid を使うのが正しいと > lsのソースコード(*1) は示しているように思います。FreeBSD 6.2Rのls.cを > 見てみましたが、 user_from_uidおよびgroup_from_gidを使う実装に > なっていて、getpwuidおよびgetgrgidは登場しません。 > > user_from_uidの実装を見てみましたが、内部でgetpwuidを呼んだ結果を > ダイレクトマップキャッシュしているだけでした。これより、 > getpwuid一回あたりの時間が長いためにディレクトリ全部では莫大な時間が > かかってしまうということだと推測します。 > > > ・FreeBSDの getpwuid および getgrgid でもそんなに時間がかかるわけはな > > いので、私のなんらかの設定がおかしい > > Solarisではキャッシュするから早いのだと思います。 > OpenSolarisのコード (*2) も見てみたのですが、getpwuidからは > 最終的に_getpwuid_rが呼ばれ、このコードはこんな風になっています。 > | struct passwd * > | _getpwuid_r(uid_t uid, struct passwd *result, char *buffer, int > (snip) > | switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { > | case SUCCESS: /* positive cache hit */ > | break; > | case NOTFOUND: /* negative cache hit */ > | return (NULL); > | default: > | return ((struct passwd *)_uncached_getpwuid_r(uid, > | result, buffer, buflen)); > | } > > いつぞやのSoCの成果物にLDAPなどで解決した結果をキャッシュするのが > あったような気がするので、それを使えば速くなりそうです。 > > (*1) FreeBSD 6.2R /usr/src/bin/ls/ls.c > (*2) OpenSolaris 20050612 /usr/src/lib/libc/port/gen/getpwnam_r.c -- 林 周志(はやし ひろし) 東京大学生産技術研究所 e-mail: [メールアドレス保護]