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 }