negative dentry
Rev.2を表示中。最新版はこちら。
negative dentryはinodeを有していないdentryで、unlinkのプロセスの中で作成されるnegative dentryを見てみます。引数のdirは親ディレクトリ、dentryはunlinkするファイルです。may_delete()/d_mountpoint(dentry)で、対象ファイルをunlinkしてもいいかどうかのチェックし、OKならdir->i_op->unlink()で、実デバイスのdirからdentryを削除し、d_delete()でキャッシュリスト回収の処理を行います。この時、他から参照されていないなら、このdentryはnegative dentryになります。
int vfs_unlink(struct inode *dir, struct dentry *dentry)
{
int error = may_delete(dir, dentry, 0);
if (error)
return error;
if (!dir->i_op->unlink)
return -EPERM;
mutex_lock(&dentry->d_inode->i_mutex);
if (d_mountpoint(dentry))
error = -EBUSY;
else {
error = security_inode_unlink(dir, dentry);
if (!error) {
error = dir->i_op->unlink(dir, dentry);
if (!error)
dont_mount(dentry);
}
}
mutex_unlock(&dentry->d_inode->i_mutex);
if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
fsnotify_link_count(dentry->d_inode);
d_delete(dentry);
}
return error;
}
dentry->d_count == 1は、unlinkコマンド以外(unlinkでコールされた場合)は、このファイルを参照していない時、dentry_unlink_inode()をコールし、dentry->d_inode = NULLとする事で、inodeを有しないdentryとするnegative dentryとし復帰します。__d_drop()はコールされず、dentryキャッシュは存在し続けることになります。なお、dentry->d_flags &= ~DCACHE_CANT_MOUNTとし、マウント不可であってもnegative dentryのディレクトリは全てマウント可能となります。マウントポイントはvfs管理下でinodeの有無と関係ないからです。ただしunlinkから呼ばれる場合、may_delete()でディレクトリの場合だとエラーとなり、このケースでは削除dentryがディレクトリちなることはありません。他のファーズからコールされるケースの処理です。
void d_delete(struct dentry * dentry)
{
struct inode *inode;
int isdir = 0;
again:
spin_lock(&dentry->d_lock);
inode = dentry->d_inode;
isdir = S_ISDIR(inode->i_mode);
if (dentry->d_count == 1) {
if (inode && !spin_trylock(&inode->i_lock)) {
spin_unlock(&dentry->d_lock);
cpu_relax();
goto again;
}
dentry->d_flags &= ~DCACHE_CANT_MOUNT;
dentry_unlink_inode(dentry);
fsnotify_nameremove(dentry, isdir);
return;
}
if (!d_unhashed(dentry))
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
fsnotify_nameremove(dentry, isdir);
}
削除するdentryをdentry->d_inode = NULとしnegative dentryとし、list_del_init()で親のdentryにリストされているノードd_aliasを初期化して、親からのパスを削除します。切り離されたinodeは匿名inodeとなるわけですが、他から参照されていないなら、iput()でinode自身も削除/開放されます。
static void dentry_unlink_inode(struct dentry * dentry)
__releases(dentry->d_lock)
__releases(dentry->d_inode->i_lock)
{
struct inode *inode = dentry->d_inode;
dentry->d_inode = NULL;
list_del_init(&dentry->d_alias);
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
if (!inode->i_nlink)
fsnotify_inoderemove(inode);
if (dentry->d_op && dentry->d_op->d_iput)
dentry->d_op->d_iput(dentry, inode);
else
iput(inode);
}
追記
下記HPを参考にさせて頂きました。negative dentryの目的は?についても説明がされています。hibomaのはてなダイアリ




