ハード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以外のキャッシュを有する実装故という事なのか、実装からすると何故ディレクトリのハードリンクを不可とするのか疑問です。