Open系統調用
下面看看open_namei函數:
這個函數的基本的功能是:
首先我們知道filename,也就是知道路徑了,那麼我們可以根據上級目錄項對象,查詢下一級的目錄項對象,如果在目錄項緩存找到下一級的目錄項對象,則直接傳回,并填充nd的挂載點對象和目錄項對象。否則,建構一個子目錄項對象,并配置設定一個新的inode結構,将子目錄項對象和inode結構相關聯。這樣,一直循環到最後一個路徑分量。最後傳回的是最後一個路徑分量的目錄項對象和挂載點對象。
分成兩點:
第一:如果單純是打開一個已有的檔案,那麼直接跟了lookup函數(細節:注意如果這個名字分量打開的是“符号連結,那麼需要二次查找實際的位置,下面會說到”)找到打開即可
第二:如果是需要建立一個新的檔案,那麼需要得到父目錄的目錄項對象和挂載點,然後再執行建立過程
細節:對于我們的輸入路徑,可以是絕對路徑(從'/'開始),也可以是相對路徑,那麼下面的處理也會根據是絕對路徑還是相對路徑進行不同的處理。另外一些查找的細節後面再說。
總之,下面的函數執行完成之後,就會得到
[cpp] view plain copy print ?
- 1006
- 1020 int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
- 1021 {
- 1022 int acc_mode, error = 0;
- 1023 struct inode *inode;
- 1024 struct dentry *dentry;
- 1025 struct vfsmount *mnt;
- 1026 struct dentry *dir;
- 1027 int count = 0;
- 1028
- 1029 acc_mode = ACC_MODE(flag);
- 1030
- 1031
- 1034 if (!(flag & O_CREAT)) {
- 1035 error = path_lookup(pathname, lookup_flags(flag), nd);
- 1036 if (error)
- 1037 return error;
- 1038 dentry = nd->dentry;
- 1039 goto ok;
- 1040 }
- 1041
- 1042
- 1045 error = path_lookup(pathname, LOOKUP_PARENT, nd);
- 1046 if (error)
- 1047 return error;
- 1048
- 1049
- 1054 error = -EISDIR;
- 1055 if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len])
- 1056 goto exit;
- 1057
- 1058 dir = nd->dentry;
- 1059 down(&dir->d_inode->i_sem);
- 1060 dentry = lookup_hash(&nd->last, nd->dentry);
- 1061
- 1062 do_last:
- 1063 error = PTR_ERR(dentry);
- 1064 if (IS_ERR(dentry)) {
- 1065 up(&dir->d_inode->i_sem);
- 1066 goto exit;
- 1067 }
- 1068
- 1069
- 1070 if (!dentry->d_inode) {
- 1071 error = vfs_create(dir->d_inode, dentry,
- 1072 mode & ~current->fs->umask);
- 1073 up(&dir->d_inode->i_sem);
- 1074 dput(nd->dentry);
- 1075 nd->dentry = dentry;
- 1076 if (error)
- 1077 goto exit;
- 1078
- 1079 acc_mode = 0;
- 1080 flag &= ~O_TRUNC;
- 1081 goto ok;
- 1082 }
- 1083
- 1084
- 1087 up(&dir->d_inode->i_sem);
- 1088
- 1089 error = -EEXIST;
- 1090 if (flag & O_EXCL)
- 1091 goto exit_dput;
- 1092
- 1093 if (d_mountpoint(dentry)) {
- 1094 error = -ELOOP;
- 1095 if (flag & O_NOFOLLOW)
- 1096 goto exit_dput;
- 1097 while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));
- 1098 }
- 1099 error = -ENOENT;
- 1100 if (!dentry->d_inode)
- 1101 goto exit_dput;
- 1102 if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link)
- 1103 goto do_link;
- 1104
- 1105 dput(nd->dentry);
- 1106 nd->dentry = dentry;
- 1107 error = -EISDIR;
- 1108 if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
- 1109 goto exit;
- 1110 ok:
- 1111 error = -ENOENT;
- 1112 inode = dentry->d_inode;
- 1113 if (!inode)
- 1114 goto exit;
- 1115
- 1116 error = -ELOOP;
- 1117 if (S_ISLNK(inode->i_mode))
- 1118 goto exit;
- 1119
- 1120 error = -EISDIR;
- 1121 if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
- 1122 goto exit;
- 1123
- 1124 error = permission(inode,acc_mode);
- 1125 if (error)
- 1126 goto exit;
- 1127
- 1128
- 1133 if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
- 1134 flag &= ~O_TRUNC;
- 1135 } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
- 1136 error = -EACCES;
- 1137 if (nd->mnt->mnt_flags & MNT_NODEV)
- 1138 goto exit;
- 1139
- 1140 flag &= ~O_TRUNC;
- 1141 } else {
- 1142 error = -EROFS;
- 1143 if (IS_RDONLY(inode) && (flag & 2))
- 1144 goto exit;
- 1145 }
- 1146
- 1149 error = -EPERM;
- 1150 if (IS_APPEND(inode)) {
- 1151 if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
- 1152 goto exit;
- 1153 if (flag & O_TRUNC)
- 1154 goto exit;
- 1155 }
- 1156
- 1157
- 1160 error = get_lease(inode, flag);
- 1161 if (error)
- 1162 goto exit;
- 1163
- 1164 if (flag & O_TRUNC) {
- 1165 error = get_write_access(inode);
- 1166 if (error)
- 1167 goto exit;
- 1168
- 1169
- 1172 error = locks_verify_locked(inode);
- 1173 if (!error) {
- 1174 DQUOT_INIT(inode);
- 1175
- 1176 error = do_truncate(dentry, 0);
- 1177 }
- 1178 put_write_access(inode);
- 1179 if (error)
- 1180 goto exit;
- 1181 } else
- 1182 if (flag & FMODE_WRITE)
- 1183 DQUOT_INIT(inode);
- 1184
- 1185 return 0;
- 1186
- 1187 exit_dput:
- 1188 dput(dentry);
- 1189 exit:
- 1190 path_release(nd);
- 1191 return error;
- 1192
- 1193 do_link:
- 1194 error = -ELOOP;
- 1195 if (flag & O_NOFOLLOW)
- 1196 goto exit_dput;
- 1197
- 1207 UPDATE_ATIME(dentry->d_inode);
- 1208 mnt = mntget(nd->mnt);
- 1209 error = dentry->d_inode->i_op->follow_link(dentry, nd);
- 1210 dput(dentry);
- 1211 mntput(mnt);
- 1212 if (error)
- 1213 return error;
- 1214 if (nd->last_type == LAST_BIND) {
- 1215 dentry = nd->dentry;
- 1216 goto ok;
- 1217 }
- 1218 error = -EISDIR;
- 1219 if (nd->last_type != LAST_NORM)
- 1220 goto exit;
- 1221 if (nd->last.name[nd->last.len]) {
- 1222 putname(nd->last.name);
- 1223 goto exit;
- 1224 }
- 1225 error = -ELOOP;
- 1226 if (count++==32) {
- 1227 putname(nd->last.name);
- 1228 goto exit;
- 1229 }
- 1230 dir = nd->dentry;
- 1231 down(&dir->d_inode->i_sem);
- 1232 dentry = lookup_hash(&nd->last, nd->dentry);
- 1233 putname(nd->last.name);
- 1234 goto do_last;
- 1235 }
看一下path_lookup函數:
[cpp] view plain copy print ?
- 755
- 756 int fastcall path_lookup(const char *path, unsigned flags, struct nameidata *nd)
- 757 {
- 758 int error = 0;
- 759 if (path_init(path, flags, nd))
- 760 error = path_walk(path, nd);
- 761 return error;
- 762 }
這個函數涉及到path_init和path_walk函數,下面分别看一下:
path_init函數主要是擷取最初的開目錄項(路徑開始點)
[cpp] view plain copy print ?
- 765
- 766 int fastcall path_init(const char *name, unsigned int flags, struct nameidata *nd)
- 767 {
- 768 nd->last_type = LAST_ROOT;
- 769 nd->flags = flags;
- 770 if (*name=='/')
- 771 return walk_init_root(name,nd);
- 772 read_lock(¤t->fs->lock);
- 773 nd->mnt = mntget(current->fs->pwdmnt);
- 774 nd->dentry = dget(current->fs->pwd);
- 775 read_unlock(¤t->fs->lock);
- 776 return 1;
- 777 }
如果是根目錄的話,看一下這個函數walk_init_root:
[cpp] view plain copy print ?
- 736
- 737 static inline int
- 738 walk_init_root(const char *name, struct nameidata *nd)
- 739 {
- 740 read_lock(¤t->fs->lock);
- 741 if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
- 742 nd->mnt = mntget(current->fs->altrootmnt);
- 743 nd->dentry = dget(current->fs->altroot);
- 744 read_unlock(¤t->fs->lock);
- 745 if (__emul_lookup_dentry(name,nd))
- 746 return 0;
- 747 read_lock(¤t->fs->lock);
- 748 }
- 749 nd->mnt = mntget(current->fs->rootmnt);
- 750 nd->dentry = dget(current->fs->root);
- 751 read_unlock(¤t->fs->lock);
- 752 return 1;
- 753 }
OK,回到上面,繼續看path_walk函數:
[cpp] view plain copy print ?
- 668 int fastcall path_walk(const char * name, struct nameidata *nd)
- 669 {
- 670 current->total_link_count = 0;
- 671 return link_path_walk(name, nd);
- 672 }
注意這個link_path_walk函數主要是根據給定的路徑,找到最後一個路徑分量的目錄項對象和安裝點~
這個函數主要思路:打開一個檔案,如果是僅僅打開,那麼沿着路徑分量不斷往下找,最後傳回最後一個名字分量的目錄項對象就OK,如果是建立檔案,那麼傳回的是倒數第二個分量也就是需要建立的檔案的父目錄的目錄項對象。
細節:
第一:如果是打開的路徑不是符号連結路徑,那麼按照路徑(每個路徑分量)層層去找到,直到找到最後一個路徑分量代表的目錄項對象,也就說最終傳回的就是最後一個分量的目錄項對象和挂載點。
第二:存在有些目錄項對象對應的是符号連結,遇到這種情況,需要二次尋找這個真實的的路徑分量,然後再繼續往下找
[cpp] view plain copy print ?
- 450
- 458 int fastcall link_path_walk(const char * name, struct nameidata *nd)
- 459 {
- 460 struct dentry *dentry;
- 461 struct inode *inode;
- 462 int err;
- 463 unsigned int lookup_flags = nd->flags;
- 464
- 465 while (*name=='/')
- 466 name++;
- 467 if (!*name)
- 468 goto return_reval;
- 469
- 470 inode = nd->dentry->d_inode;
- 471 if (current->link_count)
- 472 lookup_flags = LOOKUP_FOLLOW;
- 473
- 474
- 475 for(;;) {
- 476 unsigned long hash;
- 477 struct qstr this;
- 478 unsigned int c;
- 479
- 480 err = permission(inode, MAY_EXEC);
- 481 dentry = ERR_PTR(err);
- 482 if (err)
- 483 break;
- 484
- 485 this.name = name;
- 486 c = *(const unsigned char *)name;
- 487
- 488 hash = init_name_hash();
- 489 do {
- 490 name++;
- 491 hash = partial_name_hash(c, hash);
- 492 c = *(const unsigned char *)name;
- 493 } while (c && (c != '/'));
- 494 this.len = name - (const char *) this.name;
- 495 this.hash = end_name_hash(hash);
- 496 <span> </span>
- 497
- 498 if (!c)
- 499 goto last_component;
- 500 while (*++name == '/');
- 501 if (!*name)
- 502 goto last_with_slashes;
- 503
- 504
- 509 if (this.name[0] == '.') switch (this.len) {
- 510 default:
- 511 break;
- 512 case 2:
- 513 if (this.name[1] != '.')
- 514 break;
- 515 follow_dotdot(nd);
- 516 inode = nd->dentry->d_inode;
- 517
- 518 case 1:
- 519 continue;
- 520 }
- 521
- 525 if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
- 526 err = nd->dentry->d_op->d_hash(nd->dentry, &this);
- 527 if (err < 0)
- 528 break;
- 529 }
- 530
- 531 dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
- 532 if (!dentry) {
- 533 dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
- 534 err = PTR_ERR(dentry);
- 535 if (IS_ERR(dentry))
- 536 break;
- 537 }
- 538
- 539 while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
- 540 ;
- 541 <span> </span>
- 542 err = -ENOENT;
- 543 inode = dentry->d_inode;
- 544 if (!inode)
- 545 goto out_dput;
- 546 err = -ENOTDIR;
- 547 if (!inode->i_op)
- 548 goto out_dput;
- 549
- 550 if (inode->i_op->follow_link) {
- 551 struct vfsmount *mnt = mntget(nd->mnt);
- 552 err = do_follow_link(dentry, nd);
- 553 dput(dentry);
- 554 mntput(mnt);
- 555 if (err)
- 556 goto return_err;
- 557 err = -ENOENT;
- 558 inode = nd->dentry->d_inode;
- 559 if (!inode)
- 560 break;
- 561 err = -ENOTDIR;
- 562 if (!inode->i_op)
- 563 break;
- 564 } else {
- 565 dput(nd->dentry);
- 566 nd->dentry = dentry;
- 567 }
- 568 err = -ENOTDIR;
- 569 if (!inode->i_op->lookup)
- 570 break;
- 571 continue;
- 572
- 573
- 574 last_with_slashes:
- 575 lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
- 576 last_component:
- 577 if (lookup_flags & LOOKUP_PARENT)
- 578 goto lookup_parent;
- 579 if (this.name[0] == '.') switch (this.len) {
- 580 default:
- 581 break;
- 582 case 2:
- 583 if (this.name[1] != '.')
- 584 break;
- 585 follow_dotdot(nd);
- 586 inode = nd->dentry->d_inode;
- 587
- 588 case 1:
- 589 goto return_reval;
- 590 }
- 591 if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
- 592 err = nd->dentry->d_op->d_hash(nd->dentry, &this);
- 593 if (err < 0)
- 594 break;
- 595 }
- 596 dentry = cached_lookup(nd->dentry, &this, nd->flags);
- 597 if (!dentry) {
- 598 dentry = real_lookup(nd->dentry, &this, nd->flags);
- 599 err = PTR_ERR(dentry);
- 600 if (IS_ERR(dentry))
- 601 break;
- 602 }
- 603 while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
- 604 ;
- 605 inode = dentry->d_inode;
- 606 if ((lookup_flags & LOOKUP_FOLLOW)
- 607 && inode && inode->i_op && inode->i_op->follow_link) {
- 608 struct vfsmount *mnt = mntget(nd->mnt);
- 609 err = do_follow_link(dentry, nd);
- 610 dput(dentry);
- 611 mntput(mnt);
- 612 if (err)
- 613 goto return_err;
- 614 inode = nd->dentry->d_inode;
- 615 } else {
- 616 dput(nd->dentry);
- 617 nd->dentry = dentry;
- 618 }
- 619 err = -ENOENT;
- 620 if (!inode)
- 621 goto no_inode;
- 622 if (lookup_flags & LOOKUP_DIRECTORY) {
- 623 err = -ENOTDIR;
- 624 if (!inode->i_op || !inode->i_op->lookup)
- 625 break;
- 626 }
- 627 goto return_base;
- 628 no_inode:
- 629 err = -ENOENT;
- 630 if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY))
- 631 break;
- 632 goto return_base;
- 633 lookup_parent:
- 634 nd->last = this;
- 635 nd->last_type = LAST_NORM;
- 636 if (this.name[0] != '.')
- 637 goto return_base;
- 638 if (this.len == 1)
- 639 nd->last_type = LAST_DOT;
- 640 else if (this.len == 2 && this.name[1] == '.')
- 641 nd->last_type = LAST_DOTDOT;
- 642 else
- 643 goto return_base;
- 644 return_reval:
- 645
- 649 dentry = nd->dentry;
- 650 if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
- 651 err = -ESTALE;
- 652 if (!dentry->d_op->d_revalidate(dentry, 0)) {
- 653 d_invalidate(dentry);
- 654 break;
- 655 }
- 656 }
- 657 return_base:
- 658 return 0;
- 659 out_dput:
- 660 dput(dentry);
- 661 break;
- 662 }
- 663 path_release(nd);
- 664 return_err:
- 665 return err;
- 666 }
注意這裡面有一個函數叫follow_dotdot,這個函數是回溯到父目錄的函數
[cpp] view plain copy print ?
- 412
- 413 static inline void follow_dotdot(struct nameidata *nd)
- 414 {
- 415 while(1) {
- 416 struct vfsmount *parent;
- 417 struct dentry *dentry;
- 418 read_lock(¤t->fs->lock);
- 419 if (nd->dentry == current->fs->root &&
- 420 nd->mnt == current->fs->rootmnt) {
- 421 read_unlock(¤t->fs->lock);
- 422 break;
- 423 }
- 424 read_unlock(¤t->fs->lock);
- 425 spin_lock(&dcache_lock);
- 426 if (nd->dentry != nd->mnt->mnt_root) {
- 427 dentry = dget(nd->dentry->d_parent);
- 428 spin_unlock(&dcache_lock);
- 429 dput(nd->dentry);
- 430 nd->dentry = dentry;
- 431 break;
- 432 }
- 433 parent=nd->mnt->mnt_parent;
- 434 if (parent == nd->mnt) {
- 435 spin_unlock(&dcache_lock);
- 436 break;
- 437 }
- 438 mntget(parent);
- 439 dentry=dget(nd->mnt->mnt_mountpoint);
- 440 spin_unlock(&dcache_lock);
- 441 dput(nd->dentry);
- 442 nd->dentry = dentry;
- 443 mntput(nd->mnt);
- 444 nd->mnt = parent;
- 445 }
- 446 while (d_mountpoint(nd->dentry) && __follow_down(&nd->mnt, &nd->dentry))
- 447 ;
- 448 }