ハードlink
リンク可能条件
・リンク先ファイルを有していない
・リンク先親ディレクトリはファイル作成可能(write and exec permissions)
・リンク先親dir.inodeのlinkコールバックが定義されている。(procfs等は定義されておらずリンクできません)
・リンク元ファイルはS_APPEND(chattrコマンド +a:追記のみ)でない
・リンク元ファイルはS_IMMUTABLE(chattrコマンド +i:変更不可)でない
・リンク元はディレクトリでない
old_dentry: リンク元ファイルのdentry
dir : リンク先ファイルの親ディレクトリinode
new_dentry: リンク先ファイルのdentry
new_dentry->d_inode = old_dentry->d_inode;(inodeアドレスを共有します。)
inode->i_nlink++(リンクカウント:リンクファイルが削除されてもinode->i_coun=0であってもinode->i_nlink !=0 ならinodeは削除されません。);
リンクファイルinode->i_dentryにnew_dentry->d_aliasがリストされ、リンクファイル(dentry)からリンクされている全dentryが取得でき、splice/automnt等のinodeでなくキャッシュdentryに掛かる実装故です。
ディレクトリはdentry以外のキャッシュを有する実装故という事なのか、実装からすると何故ディレクトリのハードリンクを不可とするのか疑問です。
#define S_APPEND 8 #define S_IMMUTABLE 16 #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND) #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)・リンク先/リンク元が同じデバイス(dir->i_sb != inode->i_sb)
・リンク先ファイルを有していない
・リンク先親ディレクトリはファイル作成可能(write and exec permissions)
・リンク先親dir.inodeのlinkコールバックが定義されている。(procfs等は定義されておらずリンクできません)
・リンク元ファイルはS_APPEND(chattrコマンド +a:追記のみ)でない
・リンク元ファイルはS_IMMUTABLE(chattrコマンド +i:変更不可)でない
・リンク元はディレクトリでない
old_dentry: リンク元ファイルのdentry
dir : リンク先ファイルの親ディレクトリinode
new_dentry: リンク先ファイルのdentry
new_dentry->d_inode = old_dentry->d_inode;(inodeアドレスを共有します。)
inode->i_nlink++(リンクカウント:リンクファイルが削除されてもinode->i_coun=0であってもinode->i_nlink !=0 ならinodeは削除されません。);
リンクファイルinode->i_dentryにnew_dentry->d_aliasがリストされ、リンクファイル(dentry)からリンクされている全dentryが取得でき、splice/automnt等のinodeでなくキャッシュdentryに掛かる実装故です。
int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
{
struct inode *inode = old_dentry->d_inode;
int error;
if (!inode)
return -ENOENT;
error = may_create(dir, new_dentry, NULL);
if (error)
return error;
if (dir->i_sb != inode->i_sb)
return -EXDEV;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return -EPERM;
if (!dir->i_op || !dir->i_op->link)
return -EPERM;
if (S_ISDIR(old_dentry->d_inode->i_mode))
return -EPERM;
error = security_inode_link(old_dentry, dir, new_dentry);
if (error)
return error;
down(&old_dentry->d_inode->i_sem);
DQUOT_INIT(dir);
error = dir->i_op->link(old_dentry, dir, new_dentry);
up(&old_dentry->d_inode->i_sem);
if (!error) {
inode_dir_notify(dir, DN_CREATE);
security_inode_post_link(old_dentry, dir, new_dentry);
}
return error;
}
static inline int may_create(struct inode *dir, struct dentry *child,
struct nameidata *nd)
{
if (child->d_inode)
return -EEXIST;
if (IS_DEADDIR(dir))
return -ENOENT;
return permission(dir,MAY_WRITE | MAY_EXEC, nd);
}
static struct inode_operations ramfs_dir_inode_operations = {
.create = ramfs_create,
.lookup = simple_lookup,
.link = simple_link,
.unlink = simple_unlink,
.symlink = ramfs_symlink,
.mkdir = ramfs_mkdir,
.rmdir = simple_rmdir,
.mknod = ramfs_mknod,
.rename = simple_rename,
};
int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
inc_nlink(inode);
ihold(inode);
dget(dentry);
d_instantiate(dentry, inode);
return 0;
}
void d_instantiate(struct dentry *entry, struct inode * inode)
{
if (!list_empty(&entry->d_alias)) BUG();
spin_lock(&dcache_lock);
if (inode)
list_add(&entry->d_alias, &inode->i_dentry);
entry->d_inode = inode;
spin_unlock(&dcache_lock);
security_d_instantiate(entry, inode);
}
追記
リンクファイルのタイプスタンプinode->i_ctime(Change)及び、リンク先dirのinode->i_ctime(Change)inode->i_mtime(Modify)が更新されます。リンク先dir更新はリンクに掛かる更新でなく、ファイル作成故の更新です。ディレクトリはdentry以外のキャッシュを有する実装故という事なのか、実装からすると何故ディレクトリのハードリンクを不可とするのか疑問です。





