天天看點

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 }  

繼續閱讀