天天看点

Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数

Open系统调用

下面看看open_namei函数:

这个函数的基本的功能是:

首先我们知道filename,也就是知道路径了,那么我们可以根据上级目录项对象,查询下一级的目录项对象,如果在目录项缓存找到下一级的目录项对象,则直接返回,并填充nd的挂载点对象和目录项对象。否则,构建一个子目录项对象,并分配一个新的inode结构,将子目录项对象和inode结构相关联。这样,一直循环到最后一个路径分量。最后返回的是最后一个路径分量的目录项对象和挂载点对象。

分成两点:

第一:如果单纯是打开一个已有的文件,那么直接跟了lookup函数(细节:注意如果这个名字分量打开的是“符号链接,那么需要二次查找实际的位置,下面会说到”)找到打开即可

第二:如果是需要创建一个新的文件,那么需要得到父目录的目录项对象和挂载点,然后再执行创建过程

细节:对于我们的输入路径,可以是绝对路径(从'/'开始),也可以是相对路径,那么下面的处理也会根据是绝对路径还是相对路径进行不同的处理。另外一些查找的细节后面再说。

总之,下面的函数执行完成之后,就会得到

[cpp]  view plain copy print ?

Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
  1. 1006   
  2. 1020 int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)  
  3. 1021 {  
  4. 1022         int acc_mode, error = 0;  
  5. 1023         struct inode *inode;  
  6. 1024         struct dentry *dentry;  
  7. 1025         struct vfsmount *mnt;  
  8. 1026         struct dentry *dir;  
  9. 1027         int count = 0;  
  10. 1028   
  11. 1029         acc_mode = ACC_MODE(flag);  
  12. 1030   
  13. 1031           
  14. 1034         if (!(flag & O_CREAT)) {     
  15. 1035                 error = path_lookup(pathname, lookup_flags(flag), nd);    
  16. 1036                 if (error)  
  17. 1037                         return error;  
  18. 1038                 dentry = nd->dentry;    
  19. 1039                 goto ok;    
  20. 1040         }  
  21. 1041   
  22. 1042           
  23. 1045         error = path_lookup(pathname, LOOKUP_PARENT, nd);     
  24. 1046         if (error)  
  25. 1047                 return error;  
  26. 1048   
  27. 1049           
  28. 1054         error = -EISDIR;   
  29. 1055         if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len])  
  30. 1056                 goto exit;  
  31. 1057   
  32. 1058         dir = nd->dentry;   
  33. 1059         down(&dir->d_inode->i_sem);  
  34. 1060         dentry = lookup_hash(&nd->last, nd->dentry);   
  35. 1061   
  36. 1062 do_last:  
  37. 1063         error = PTR_ERR(dentry);  
  38. 1064         if (IS_ERR(dentry)) {  
  39. 1065                 up(&dir->d_inode->i_sem);  
  40. 1066                 goto exit;  
  41. 1067         }  
  42. 1068   
  43. 1069           
  44. 1070         if (!dentry->d_inode) {   
  45. 1071                 error = vfs_create(dir->d_inode, dentry,      
  46. 1072                                    mode & ~current->fs->umask);  
  47. 1073                 up(&dir->d_inode->i_sem);  
  48. 1074                 dput(nd->dentry);  
  49. 1075                 nd->dentry = dentry;  
  50. 1076                 if (error)  
  51. 1077                         goto exit;  
  52. 1078                   
  53. 1079                 acc_mode = 0;  
  54. 1080                 flag &= ~O_TRUNC;  
  55. 1081                 goto ok;     
  56. 1082         }  
  57. 1083   
  58. 1084           
  59. 1087         up(&dir->d_inode->i_sem);  
  60. 1088   
  61. 1089         error = -EEXIST;  
  62. 1090         if (flag & O_EXCL)  
  63. 1091                 goto exit_dput;  
  64. 1092           
  65. 1093         if (d_mountpoint(dentry)) {  
  66. 1094                 error = -ELOOP;  
  67. 1095                 if (flag & O_NOFOLLOW)  
  68. 1096                         goto exit_dput;  
  69. 1097                 while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));  
  70. 1098         }  
  71. 1099         error = -ENOENT;  
  72. 1100         if (!dentry->d_inode)  
  73. 1101                 goto exit_dput;  
  74. 1102         if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link)  
  75. 1103                 goto do_link;   
  76. 1104   
  77. 1105         dput(nd->dentry);  
  78. 1106         nd->dentry = dentry;  
  79. 1107         error = -EISDIR;  
  80. 1108         if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))  
  81. 1109                 goto exit;  
  82. 1110 ok:  
  83. 1111         error = -ENOENT;  
  84. 1112         inode = dentry->d_inode;   
  85. 1113         if (!inode)  
  86. 1114                 goto exit;  
  87. 1115   
  88. 1116         error = -ELOOP;  
  89. 1117         if (S_ISLNK(inode->i_mode))  
  90. 1118                 goto exit;  
  91. 1119           
  92. 1120         error = -EISDIR;  
  93. 1121         if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))  
  94. 1122                 goto exit;  
  95. 1123   
  96. 1124         error = permission(inode,acc_mode);  
  97. 1125         if (error)  
  98. 1126                 goto exit;  
  99. 1127   
  100. 1128           
  101. 1133         if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {  
  102. 1134                 flag &= ~O_TRUNC;  
  103. 1135         } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {  
  104. 1136                 error = -EACCES;  
  105. 1137                 if (nd->mnt->mnt_flags & MNT_NODEV)  
  106. 1138                         goto exit;  
  107. 1139   
  108. 1140                 flag &= ~O_TRUNC;  
  109. 1141         } else {  
  110. 1142                 error = -EROFS;  
  111. 1143                 if (IS_RDONLY(inode) && (flag & 2))  
  112. 1144                         goto exit;  
  113. 1145         }  
  114. 1146           
  115. 1149         error = -EPERM;   
  116. 1150         if (IS_APPEND(inode)) {  
  117. 1151                 if  ((flag & FMODE_WRITE) && !(flag & O_APPEND))  
  118. 1152                         goto exit;  
  119. 1153                 if (flag & O_TRUNC)  
  120. 1154                         goto exit;  
  121. 1155         }  
  122. 1156   
  123. 1157           
  124. 1160         error = get_lease(inode, flag);  
  125. 1161         if (error)  
  126. 1162                 goto exit;  
  127. 1163   
  128. 1164         if (flag & O_TRUNC) {  
  129. 1165                 error = get_write_access(inode);    
  130. 1166                 if (error)  
  131. 1167                         goto exit;  
  132. 1168   
  133. 1169                   
  134. 1172                 error = locks_verify_locked(inode);  
  135. 1173                 if (!error) {  
  136. 1174                         DQUOT_INIT(inode);  
  137. 1175                           
  138. 1176                         error = do_truncate(dentry, 0);   
  139. 1177                 }  
  140. 1178                 put_write_access(inode);   
  141. 1179                 if (error)  
  142. 1180                         goto exit;  
  143. 1181         } else  
  144. 1182                 if (flag & FMODE_WRITE)  
  145. 1183                         DQUOT_INIT(inode);  
  146. 1184   
  147. 1185         return 0;  
  148. 1186   
  149. 1187 exit_dput:  
  150. 1188         dput(dentry);  
  151. 1189 exit:  
  152. 1190         path_release(nd);  
  153. 1191         return error;  
  154. 1192   
  155. 1193 do_link:  
  156. 1194         error = -ELOOP;  
  157. 1195         if (flag & O_NOFOLLOW)  
  158. 1196                 goto exit_dput;  
  159. 1197           
  160. 1207         UPDATE_ATIME(dentry->d_inode);  
  161. 1208         mnt = mntget(nd->mnt);  
  162. 1209         error = dentry->d_inode->i_op->follow_link(dentry, nd);  
  163. 1210         dput(dentry);  
  164. 1211         mntput(mnt);  
  165. 1212         if (error)  
  166. 1213                 return error;  
  167. 1214         if (nd->last_type == LAST_BIND) {  
  168. 1215                 dentry = nd->dentry;  
  169. 1216                 goto ok;  
  170. 1217         }  
  171. 1218         error = -EISDIR;  
  172. 1219         if (nd->last_type != LAST_NORM)  
  173. 1220                 goto exit;  
  174. 1221         if (nd->last.name[nd->last.len]) {  
  175. 1222                 putname(nd->last.name);  
  176. 1223                 goto exit;  
  177. 1224         }  
  178. 1225         error = -ELOOP;  
  179. 1226         if (count++==32) {  
  180. 1227                 putname(nd->last.name);  
  181. 1228                 goto exit;  
  182. 1229         }  
  183. 1230         dir = nd->dentry;  
  184. 1231         down(&dir->d_inode->i_sem);  
  185. 1232         dentry = lookup_hash(&nd->last, nd->dentry);  
  186. 1233         putname(nd->last.name);  
  187. 1234         goto do_last;  
  188. 1235 }  

看一下path_lookup函数:

[cpp]  view plain copy print ?

Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
  1. 755   
  2. 756 int fastcall path_lookup(const char *path, unsigned flags, struct nameidata *nd)  
  3. 757 {  
  4. 758         int error = 0;  
  5. 759         if (path_init(path, flags, nd))         
  6. 760                 error = path_walk(path, nd);    
  7. 761         return error;  
  8. 762 }  

这个函数涉及到path_init和path_walk函数,下面分别看一下:

path_init函数主要是获取最初的开目录项(路径开始点)

[cpp]  view plain copy print ?

Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
  1. 765   
  2. 766 int fastcall path_init(const char *name, unsigned int flags, struct nameidata *nd)  
  3. 767 {  
  4. 768         nd->last_type = LAST_ROOT;   
  5. 769         nd->flags = flags;  
  6. 770         if (*name=='/')      
  7. 771                 return walk_init_root(name,nd);   
  8. 772         read_lock(&current->fs->lock);           
  9. 773         nd->mnt = mntget(current->fs->pwdmnt);   
  10. 774         nd->dentry = dget(current->fs->pwd);     
  11. 775         read_unlock(&current->fs->lock);   
  12. 776         return 1;      
  13. 777 }  

如果是根目录的话,看一下这个函数walk_init_root:

[cpp]  view plain copy print ?

Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
  1. 736   
  2. 737 static inline int  
  3. 738 walk_init_root(const char *name, struct nameidata *nd)  
  4. 739 {  
  5. 740         read_lock(&current->fs->lock);  
  6. 741         if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {    
  7. 742                 nd->mnt = mntget(current->fs->altrootmnt);  
  8. 743                 nd->dentry = dget(current->fs->altroot);  
  9. 744                 read_unlock(&current->fs->lock);  
  10. 745                 if (__emul_lookup_dentry(name,nd))   
  11. 746                         return 0;                    
  12. 747                 read_lock(&current->fs->lock);  
  13. 748         }  
  14. 749         nd->mnt = mntget(current->fs->rootmnt);   
  15. 750         nd->dentry = dget(current->fs->root);     
  16. 751         read_unlock(&current->fs->lock);  
  17. 752         return 1;  
  18. 753 }  

OK,回到上面,继续看path_walk函数:

[cpp]  view plain copy print ?

Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
  1. 668 int fastcall path_walk(const char * name, struct nameidata *nd)  
  2. 669 {  
  3. 670         current->total_link_count = 0;     
  4. 671         return link_path_walk(name, nd);   
  5. 672 }  

注意这个link_path_walk函数主要是根据给定的路径,找到最后一个路径分量的目录项对象和安装点~

这个函数主要思路:打开一个文件,如果是仅仅打开,那么沿着路径分量不断往下找,最后返回最后一个名字分量的目录项对象就OK,如果是创建文件,那么返回的是倒数第二个分量也就是需要创建的文件的父目录的目录项对象。

细节:

第一:如果是打开的路径不是符号链接路径,那么按照路径(每个路径分量)层层去找到,直到找到最后一个路径分量代表的目录项对象,也就说最终返回的就是最后一个分量的目录项对象和挂载点。

第二:存在有些目录项对象对应的是符号链接,遇到这种情况,需要二次寻找这个真实的的路径分量,然后再继续往下找

[cpp]  view plain copy print ?

Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
  1. 450   
  2. 458 int fastcall link_path_walk(const char * name, struct nameidata *nd)  
  3. 459 {  
  4. 460         struct dentry *dentry;  
  5. 461         struct inode *inode;  
  6. 462         int err;  
  7. 463         unsigned int lookup_flags = nd->flags;  
  8. 464           
  9. 465         while (*name=='/')  
  10. 466                 name++;  
  11. 467         if (!*name)  
  12. 468                 goto return_reval;  
  13. 469           
  14. 470         inode = nd->dentry->d_inode;  
  15. 471         if (current->link_count)  
  16. 472                 lookup_flags = LOOKUP_FOLLOW;  
  17. 473   
  18. 474           
  19. 475         for(;;) {     
  20. 476                 unsigned long hash;  
  21. 477                 struct qstr this;  
  22. 478                 unsigned int c;  
  23. 479                   
  24. 480                 err = permission(inode, MAY_EXEC);  
  25. 481                 dentry = ERR_PTR(err);  
  26. 482                 if (err)  
  27. 483                         break;  
  28. 484   
  29. 485                 this.name = name;  
  30. 486                 c = *(const unsigned char *)name;  
  31. 487                   
  32. 488                 hash = init_name_hash();     
  33. 489                 do {  
  34. 490                         name++;     
  35. 491                         hash = partial_name_hash(c, hash);     
  36. 492                         c = *(const unsigned char *)name;  
  37. 493                 } while (c && (c != '/'));  
  38. 494                 this.len = name - (const char *) this.name;     
  39. 495                 this.hash = end_name_hash(hash);                
  40. 496 <span>        </span>  
  41. 497                   
  42. 498                 if (!c)     
  43. 499                         goto last_component;   
  44. 500                 while (*++name == '/');  
  45. 501                 if (!*name)  
  46. 502                         goto last_with_slashes;  
  47. 503   
  48. 504                   
  49. 509                 if (this.name[0] == '.') switch (this.len) {  
  50. 510                         default:  
  51. 511                                 break;  
  52. 512                         case 2:   
  53. 513                                 if (this.name[1] != '.')     
  54. 514                                         break;  
  55. 515                                 follow_dotdot(nd);     
  56. 516                                 inode = nd->dentry->d_inode;  
  57. 517                                   
  58. 518                         case 1:   
  59. 519                                 continue;  
  60. 520                 }  
  61. 521                     
  62. 525                 if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {  
  63. 526                         err = nd->dentry->d_op->d_hash(nd->dentry, &this);  
  64. 527                         if (err < 0)  
  65. 528                                 break;  
  66. 529                 }  
  67. 530                   
  68. 531                 dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);    
  69. 532                 if (!dentry) {                                                 
  70. 533                         dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);   
  71. 534                         err = PTR_ERR(dentry);  
  72. 535                         if (IS_ERR(dentry))  
  73. 536                                 break;  
  74. 537                 }  
  75. 538                    
  76. 539                 while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))  
  77. 540                         ;  
  78. 541 <span>            </span>  
  79. 542                 err = -ENOENT;  
  80. 543                 inode = dentry->d_inode;    
  81. 544                 if (!inode)  
  82. 545                         goto out_dput;  
  83. 546                 err = -ENOTDIR;   
  84. 547                 if (!inode->i_op)  
  85. 548                         goto out_dput;  
  86. 549                   
  87. 550                 if (inode->i_op->follow_link) {  
  88. 551                         struct vfsmount *mnt = mntget(nd->mnt);  
  89. 552                         err = do_follow_link(dentry, nd);      
  90. 553                         dput(dentry);  
  91. 554                         mntput(mnt);  
  92. 555                         if (err)  
  93. 556                                 goto return_err;  
  94. 557                         err = -ENOENT;  
  95. 558                         inode = nd->dentry->d_inode;     
  96. 559                         if (!inode)  
  97. 560                                 break;  
  98. 561                         err = -ENOTDIR;   
  99. 562                         if (!inode->i_op)  
  100. 563                                 break;  
  101. 564                 } else {  
  102. 565                         dput(nd->dentry);  
  103. 566                         nd->dentry = dentry;      
  104. 567                 }  
  105. 568                 err = -ENOTDIR;   
  106. 569                 if (!inode->i_op->lookup)  
  107. 570                         break;  
  108. 571                 continue;  
  109. 572                   
  110. 573   
  111. 574 last_with_slashes:  
  112. 575                 lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;  
  113. 576 last_component:   
  114. 577                 if (lookup_flags & LOOKUP_PARENT)    
  115. 578                         goto lookup_parent;  
  116. 579                 if (this.name[0] == '.') switch (this.len) {     
  117. 580                         default:  
  118. 581                                 break;  
  119. 582                         case 2:   
  120. 583                                 if (this.name[1] != '.')  
  121. 584                                         break;  
  122. 585                                 follow_dotdot(nd);  
  123. 586                                 inode = nd->dentry->d_inode;  
  124. 587                                   
  125. 588                         case 1:  
  126. 589                                 goto return_reval;  
  127. 590                 }  
  128. 591                 if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {  
  129. 592                         err = nd->dentry->d_op->d_hash(nd->dentry, &this);  
  130. 593                         if (err < 0)  
  131. 594                                 break;  
  132. 595                 }  
  133. 596                 dentry = cached_lookup(nd->dentry, &this, nd->flags);   
  134. 597                 if (!dentry) {  
  135. 598                         dentry = real_lookup(nd->dentry, &this, nd->flags);   
  136. 599                         err = PTR_ERR(dentry);  
  137. 600                         if (IS_ERR(dentry))  
  138. 601                                 break;  
  139. 602                 }  
  140. 603                 while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))   
  141. 604                         ;  
  142. 605                 inode = dentry->d_inode;  
  143. 606                 if ((lookup_flags & LOOKUP_FOLLOW)     
  144. 607                     && inode && inode->i_op && inode->i_op->follow_link) {  
  145. 608                         struct vfsmount *mnt = mntget(nd->mnt);  
  146. 609                         err = do_follow_link(dentry, nd);    
  147. 610                         dput(dentry);  
  148. 611                         mntput(mnt);  
  149. 612                         if (err)  
  150. 613                                 goto return_err;  
  151. 614                         inode = nd->dentry->d_inode;  
  152. 615                 } else {  
  153. 616                         dput(nd->dentry);  
  154. 617                         nd->dentry = dentry;  
  155. 618                 }  
  156. 619                 err = -ENOENT;  
  157. 620                 if (!inode)     
  158. 621                         goto no_inode;  
  159. 622                 if (lookup_flags & LOOKUP_DIRECTORY) {     
  160. 623                         err = -ENOTDIR;   
  161. 624                         if (!inode->i_op || !inode->i_op->lookup)  
  162. 625                                 break;  
  163. 626                 }  
  164. 627                 goto return_base;  
  165. 628 no_inode:  
  166. 629                 err = -ENOENT;  
  167. 630                 if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY))  
  168. 631                         break;  
  169. 632                 goto return_base;  
  170. 633 lookup_parent:    
  171. 634                 nd->last = this;    
  172. 635                 nd->last_type = LAST_NORM;   
  173. 636                 if (this.name[0] != '.')    
  174. 637                         goto return_base;  
  175. 638                 if (this.len == 1)    
  176. 639                         nd->last_type = LAST_DOT;  
  177. 640                 else if (this.len == 2 && this.name[1] == '.')   
  178. 641                         nd->last_type = LAST_DOTDOT;  
  179. 642                 else  
  180. 643                         goto return_base;  
  181. 644 return_reval:  
  182. 645                   
  183. 649                 dentry = nd->dentry;  
  184. 650                 if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {  
  185. 651                         err = -ESTALE;  
  186. 652                         if (!dentry->d_op->d_revalidate(dentry, 0)) {  
  187. 653                                 d_invalidate(dentry);  
  188. 654                                 break;  
  189. 655                         }  
  190. 656                 }  
  191. 657 return_base:  
  192. 658                 return 0;  
  193. 659 out_dput:  
  194. 660                 dput(dentry);  
  195. 661                 break;  
  196. 662         }  
  197. 663         path_release(nd);  
  198. 664 return_err:  
  199. 665         return err;  
  200. 666 }  

注意这里面有一个函数叫follow_dotdot,这个函数是回溯到父目录的函数

[cpp]  view plain copy print ?

Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
Linux文件系统(七)---系统调用之open操作(三) 之 open_namei函数
  1. 412    
  2. 413 static inline void follow_dotdot(struct nameidata *nd)  
  3. 414 {  
  4. 415         while(1) {  
  5. 416                 struct vfsmount *parent;  
  6. 417                 struct dentry *dentry;  
  7. 418                 read_lock(&current->fs->lock);  
  8. 419                 if (nd->dentry == current->fs->root &&    
  9. 420                     nd->mnt == current->fs->rootmnt)  {  
  10. 421                         read_unlock(&current->fs->lock);  
  11. 422                         break;  
  12. 423                 }  
  13. 424                 read_unlock(&current->fs->lock);  
  14. 425                 spin_lock(&dcache_lock);  
  15. 426                 if (nd->dentry != nd->mnt->mnt_root) {      
  16. 427                         dentry = dget(nd->dentry->d_parent);     
  17. 428                         spin_unlock(&dcache_lock);  
  18. 429                         dput(nd->dentry);  
  19. 430                         nd->dentry = dentry;  
  20. 431                         break;  
  21. 432                 }  
  22. 433                 parent=nd->mnt->mnt_parent;     
  23. 434                 if (parent == nd->mnt) {  
  24. 435                         spin_unlock(&dcache_lock);  
  25. 436                         break;  
  26. 437                 }  
  27. 438                 mntget(parent);  
  28. 439                 dentry=dget(nd->mnt->mnt_mountpoint);  
  29. 440                 spin_unlock(&dcache_lock);  
  30. 441                 dput(nd->dentry);  
  31. 442                 nd->dentry = dentry;  
  32. 443                 mntput(nd->mnt);  
  33. 444                 nd->mnt = parent;  
  34. 445         }  
  35. 446         while (d_mountpoint(nd->dentry) && __follow_down(&nd->mnt, &nd->dentry))  
  36. 447                 ;  
  37. 448 }  

继续阅读